Mercurial > dive4elements > river
changeset 7193:7fabae60428b double-precision
Merged changes from default into double-precision branch.
author | Tom Gottfried <tom@intevation.de> |
---|---|
date | Fri, 27 Sep 2013 17:36:50 +0200 |
parents | 28748bb1b676 (current diff) 5be5bf32bead (diff) |
children | 5358a5497b2b |
files | artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffYearInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceYearGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSInfoGenerator.java artifacts/src/main/java/org/dive4elements/river/exports/process/BedheightProcessor.java artifacts/src/main/java/org/dive4elements/river/themes/ThemeAccess.java artifacts/src/main/java/org/dive4elements/river/utils/ThemeUtil.java backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java backend/src/main/java/org/dive4elements/river/importer/ImportWst.java backend/src/main/java/org/dive4elements/river/importer/ImportWstColumn.java |
diffstat | 261 files changed, 11830 insertions(+), 5192 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Fri Sep 13 18:29:01 2013 +0200 +++ b/.hgtags Fri Sep 27 17:36:50 2013 +0200 @@ -66,3 +66,6 @@ 0000000000000000000000000000000000000000 3.0.12 da197a9236fde564d45379c0826510c69a5709ce 3.0.12 71da3d4ffb4a46a2f8de7e6a9e1e4a32657802aa 3.0.13 +84b1e87e86692db4202c5d68e0c521185ef0f9d2 3.0.14 +a18a4376479383d7b6233bfa2d27737c8686c90a 3.0.15 +12248d9eb326472adc2a8824989dc4a52197f7cc 3.0.16
--- a/artifacts/doc/conf/artifacts/chart.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/artifacts/chart.xml Fri Sep 27 17:36:50 2013 +0200 @@ -80,6 +80,7 @@ <outputmode name="longitudinal_section" description="output.discharge_longitudinal_section" mime-type="image/png" type="chart"> <facets> <facet name="empty.facet" decription= "Empty"/> + <facet name="w_differences" decription= "W Differences"/> <facet name="discharge_longitudinal_section.w"/> <facet name="discharge_longitudinal_section.q"/> <facet name="discharge_longitudinal_section.c"/>
--- a/artifacts/doc/conf/artifacts/gaugedischargecurve.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/artifacts/gaugedischargecurve.xml Fri Sep 27 17:36:50 2013 +0200 @@ -18,6 +18,8 @@ <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"/> + <facet name="other.w.interpol" description="Interpolated (likely single) W Values"/> + <facet name="other.wqkms.w" description="facet.other.wqkms"/> </facets> </outputmode> <outputmode name="computed_dischargecurve_at_export" description="output.computed_dischargecurve_at_export" mime-type="text/plain" type="export">
--- a/artifacts/doc/conf/artifacts/winfo.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/artifacts/winfo.xml Fri Sep 27 17:36:50 2013 +0200 @@ -326,6 +326,8 @@ <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.w" description="facet.other.wqkms"/> + <facet name="other.wqkms.q" 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"/> @@ -382,6 +384,8 @@ </outputmode> <outputmode name="waterlevel_export" description="output.waterlevel_export" mime-type="text/plain" type="export"> <facets> + <!-- include other.wqkms.w to be able to include official lines (issue1384) --> + <facet name="other.wqkms.w" description="W-Type of data" /> <facet name="csv" description="facet.waterlevel_export.csv" /> <facet name="wst" description="facet.waterlevel_export.wst" /> <facet name="pdf" description="facet.waterlevel_export.pdf" /> @@ -638,6 +642,7 @@ </outputmode> <outputmode name="historical_discharge_wq" description="output.historical_discharge_wq.description" mime-type="image/png" type="chart"> <facets> + <facet name="discharge_curve.curve"/> <facet name="historical_discharge.wq.q"/> <facet name="historical_discharge.wq.w"/> <facet name="historical_discharge.wq.curve"/>
--- a/artifacts/doc/conf/conf.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/conf.xml Fri Sep 27 17:36:50 2013 +0200 @@ -7,6 +7,8 @@ <!ENTITY rest-server SYSTEM "rest-server.xml"> <!ENTITY floodmap SYSTEM "floodmap.xml"> <!ENTITY rivermap SYSTEM "rivermap.xml"> + <!ENTITY generators SYSTEM "generators.xml"> + <!ENTITY longitudinal-defaults SYSTEM "longitudinal-diagram-defaults.xml"> ]> <artifact-database> <export-secret>YOUR_SECRET</export-secret> @@ -284,104 +286,7 @@ </hook> </hooks> - <output-generators> - <output-generator name="discharge_curve">org.dive4elements.river.exports.DischargeCurveGenerator</output-generator> - <output-generator name="discharge_curve_chartinfo">org.dive4elements.river.exports.DischargeCurveInfoGenerator</output-generator> - <output-generator name="cross_section">org.dive4elements.river.exports.CrossSectionGenerator</output-generator> - <output-generator name="cross_section_chartinfo">org.dive4elements.river.exports.CrossSectionInfoGenerator</output-generator> - <output-generator name="computed_discharge_curve">org.dive4elements.river.exports.ComputedDischargeCurveGenerator</output-generator> - <output-generator name="computed_discharge_curve_chartinfo">org.dive4elements.river.exports.ComputedDischargeCurveInfoGenerator</output-generator> - <output-generator name="longitudinal_section">org.dive4elements.river.exports.LongitudinalSectionGenerator</output-generator> - <output-generator name="longitudinal_section_chartinfo">org.dive4elements.river.exports.LongitudinalSectionInfoGenerator</output-generator> - <output-generator name="duration_curve">org.dive4elements.river.exports.DurationCurveGenerator</output-generator> - <output-generator name="duration_curve_chartinfo">org.dive4elements.river.exports.DurationCurveInfoGenerator</output-generator> - <output-generator name="discharge_longitudinal_section">org.dive4elements.river.exports.DischargeLongitudinalSectionGenerator</output-generator> - <output-generator name="discharge_longitudinal_section_chartinfo">org.dive4elements.river.exports.DischargeLongitudinalSectionInfoGenerator</output-generator> - <output-generator name="waterlevel_export">org.dive4elements.river.exports.WaterlevelExporter</output-generator> - <output-generator name="extreme_wq_curve">org.dive4elements.river.exports.extreme.ExtremeWQCurveGenerator</output-generator> - <output-generator name="extreme_curve_export">org.dive4elements.river.exports.WaterlevelExporter</output-generator> - <output-generator name="extreme_wq_curve_chartinfo">org.dive4elements.river.exports.extreme.ExtremeWQCurveInfoGenerator</output-generator> - <output-generator name="fix_wq_curve">org.dive4elements.river.exports.fixings.FixWQCurveGenerator</output-generator> - <output-generator name="fix_wq_curve_chartinfo">org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator</output-generator> - <output-generator name="durationcurve_export">org.dive4elements.river.exports.DurationCurveExporter</output-generator> - <output-generator name="computed_dischargecurve_export">org.dive4elements.river.exports.ComputedDischargeCurveExporter</output-generator> - <output-generator name="discharge_longitudinal_section_export">org.dive4elements.river.exports.DischargeLongitudinalSectionExporter</output-generator> - <output-generator name="w_differences">org.dive4elements.river.exports.WDifferencesCurveGenerator</output-generator> - <output-generator name="w_differences_chartinfo">org.dive4elements.river.exports.WDifferencesCurveInfoGenerator</output-generator> - <output-generator name="w_differences_export">org.dive4elements.river.exports.WDifferencesExporter</output-generator> - <output-generator name="floodmap">org.dive4elements.river.exports.MapGenerator</output-generator> - <output-generator name="map">org.dive4elements.river.exports.MapGenerator</output-generator> - <output-generator name="reference_curve">org.dive4elements.river.exports.ReferenceCurveGenerator</output-generator> - <output-generator name="reference_curve_normalized">org.dive4elements.river.exports.NormalizedReferenceCurveGenerator</output-generator> - <output-generator name="reference_curve_normalized_chartinfo">org.dive4elements.river.exports.NormalizedReferenceCurveInfoGenerator</output-generator> - <output-generator name="reference_curve_chartinfo">org.dive4elements.river.exports.ReferenceCurveInfoGenerator</output-generator> - <output-generator name="reference_curve_export">org.dive4elements.river.exports.ReferenceCurveExporter</output-generator> - <output-generator name="historical_discharge">org.dive4elements.river.exports.HistoricalDischargeCurveGenerator</output-generator> - <output-generator name="historical_discharge_chartinfo">org.dive4elements.river.exports.HistoricalDischargeCurveInfoGenerator</output-generator> - <output-generator name="historical_discharge_wq">org.dive4elements.river.exports.HistoricalDischargeWQCurveGenerator</output-generator> - <output-generator name="historical_discharge_wq_chartinfo">org.dive4elements.river.exports.HistoricalDischargeWQCurveInfoGenerator</output-generator> - <output-generator name="historical_discharge_export">org.dive4elements.river.exports.HistoricalDischargeCurveExporter</output-generator> - <output-generator name="flow_velocity">org.dive4elements.river.exports.FlowVelocityGenerator</output-generator> - <output-generator name="flow_velocity_chartinfo">org.dive4elements.river.exports.FlowVelocityInfoGenerator</output-generator> - <output-generator name="flow_velocity_export">org.dive4elements.river.exports.FlowVelocityExporter</output-generator> - <output-generator name="bedheight_middle">org.dive4elements.river.exports.MiddleBedHeightGenerator</output-generator> - <output-generator name="bedheight_middle_chartinfo">org.dive4elements.river.exports.MiddleBedHeightInfoGenerator</output-generator> - <output-generator name="bedheight_middle_export">org.dive4elements.river.exports.MiddleBedHeightExporter</output-generator> - <output-generator name="bed_longitudinal_section">org.dive4elements.river.exports.minfo.BedQualityGenerator</output-generator> - <output-generator name="bed_longitudinal_section_chartinfo">org.dive4elements.river.exports.minfo.BedQualityInfoGenerator</output-generator> - <output-generator name="bed_quality_export">org.dive4elements.river.exports.minfo.BedQualityExporter</output-generator> - <output-generator name="bed_difference_year">org.dive4elements.river.exports.minfo.BedDifferenceYearGenerator</output-generator> - <output-generator name="bed_difference_year_chartinfo">org.dive4elements.river.exports.minfo.BedDiffYearInfoGenerator</output-generator> - <output-generator name="bed_difference_epoch">org.dive4elements.river.exports.minfo.BedDifferenceEpochGenerator</output-generator> - <output-generator name="bed_difference_epoch_chartinfo">org.dive4elements.river.exports.minfo.BedDiffEpochInfoGenerator</output-generator> - <output-generator name="bed_difference_height_year">org.dive4elements.river.exports.minfo.BedDiffHeightYearGenerator</output-generator> - <output-generator name="bed_difference_height_year_chartinfo">org.dive4elements.river.exports.minfo.BedDiffHeightYearInfoGenerator</output-generator> - <output-generator name="bedheight_difference_export">org.dive4elements.river.exports.minfo.BedDifferenceExporter</output-generator> - <output-generator name="sq_relation_a">org.dive4elements.river.exports.sq.SQRelationGeneratorA</output-generator> - <output-generator name="sq_relation_b">org.dive4elements.river.exports.sq.SQRelationGeneratorB</output-generator> - <output-generator name="sq_relation_c">org.dive4elements.river.exports.sq.SQRelationGeneratorC</output-generator> - <output-generator name="sq_relation_d">org.dive4elements.river.exports.sq.SQRelationGeneratorD</output-generator> - <output-generator name="sq_relation_e">org.dive4elements.river.exports.sq.SQRelationGeneratorE</output-generator> - <output-generator name="sq_relation_f">org.dive4elements.river.exports.sq.SQRelationGeneratorF</output-generator> - <output-generator name="sq_relation_a_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_b_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_c_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_d_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_e_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_f_chartinfo">org.dive4elements.river.exports.sq.SQRelationInfoGenerator</output-generator> - <output-generator name="sq_relation_export">org.dive4elements.river.exports.sq.SQRelationExporter</output-generator> - <output-generator name="sq_overview">org.dive4elements.river.exports.sq.SQOverviewGenerator</output-generator> - <output-generator name="fix_parameters_export">org.dive4elements.river.exports.fixings.ParametersExporter</output-generator> - <output-generator name="fix_deltawt_export">org.dive4elements.river.exports.fixings.DeltaWtExporter</output-generator> - <output-generator name="fix_deltawt_curve">org.dive4elements.river.exports.fixings.FixDeltaWtGenerator</output-generator> - <output-generator name="fix_deltawt_curve_chartinfo">org.dive4elements.river.exports.fixings.FixDeltaWtInfoGenerator</output-generator> - <output-generator name="fix_longitudinal_section_curve">org.dive4elements.river.exports.fixings.FixLongitudinalSectionGenerator</output-generator> - <output-generator name="fix_longitudinal_section_curve_chartinfo">org.dive4elements.river.exports.fixings.FixLongitudinalSectionInfoGenerator</output-generator> - <output-generator name="fix_derivate_curve">org.dive4elements.river.exports.fixings.FixDerivedCurveGenerator</output-generator> - <output-generator name="fix_derivate_curve_chartinfo">org.dive4elements.river.exports.fixings.FixDerivedCurveInfoGenerator</output-generator> - <output-generator name="fix_waterlevel_export">org.dive4elements.river.exports.WaterlevelExporter</output-generator> - <output-generator name="fix_vollmer_wq_curve">org.dive4elements.river.exports.fixings.FixWQCurveGenerator</output-generator> - <output-generator name="fix_vollmer_wq_curve_chartinfo">org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator</output-generator> - <output-generator name="sedimentload_ls">org.dive4elements.river.exports.minfo.SedimentLoadLSGenerator</output-generator> - <output-generator name="sedimentload_ls_export">org.dive4elements.river.exports.minfo.SedimentLoadExporter</output-generator> - <output-generator name="sedimentload_ls_chartinfo">org.dive4elements.river.exports.minfo.SedimentLoadLSInfoGenerator</output-generator> - <!-- Error report generators. --> - <output-generator name="discharge_longitudinal_section_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="waterlevel_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="computed_dischargecurve_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="durationcurve_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="wsplgen_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="historical_discharge_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="reference_curve_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="fix_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="extreme_curve_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <output-generator name="sedimentload_ls_report">org.dive4elements.river.exports.ReportGenerator</output-generator> - <!-- AT exporter. --> - <output-generator name="computed_dischargecurve_at_export">org.dive4elements.river.exports.ATExporter</output-generator> - <output-generator name="gauge_discharge_curve_at_export">org.dive4elements.river.exports.ATExporter</output-generator> - <output-generator name="fix_wq_curve_at_export">org.dive4elements.river.exports.fixings.FixATExport</output-generator> - <output-generator name="wsplgen">org.dive4elements.river.exports.ShapeExporter</output-generator> - </output-generators> + &generators; <!-- Path to the template file of the meta data. --> <metadata>
--- a/artifacts/doc/conf/floodmap.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/floodmap.xml Fri Sep 27 17:36:50 2013 +0200 @@ -14,127 +14,106 @@ <river name="Saar"> <srid value="31467"/> - <dgm-srid value="31466"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Saar"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Mosel"> <srid value="31467"/> - <dgm-srid value="31466"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Mosel"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Elbe"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Elbe"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Donau"> <srid value="31467"/> - <dgm-srid value="25833"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Donau"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Donau (Regensburg Nordarm)"> <srid value="31467"/> - <dgm-srid value="25833"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Donau (Regensburg Nordarm)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Donau (Schleusenkanäle)"> <srid value="31467"/> - <dgm-srid value="25833"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Donau (Schleusenkanäle)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Fulda (Winter)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Fulda (Winter)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Fulda (Sommer)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Fulda (Sommer)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Lahn"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Lahn"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Main"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Main"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Main (Wehrarm Limbach)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Main (Wehrarm Limbach)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Main (Wehrarm Volkach)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Main (Wehrarm Volkach)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Neckar"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Neckar"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Neckar (über Wehrarme)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Neckar (über Wehrarme)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Rhein"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Rhein"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Saale"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Saale"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Saale-Thüringen"> <srid value="31467"/> - <dgm-srid value="31468"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Saale-Thüringen"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Saar (Wiltinger Bogen)"> <srid value="31467"/> - <dgm-srid value="31466"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Saar (Wiltinger Bogen)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Werra (Winter)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Werra (Winter)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Werra (Sommer)"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Werra (Sommer)"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river> <river name="Weser"> <srid value="31467"/> - <dgm-srid value="31467"/> <river-wms url="http://example.com/cgi-bin/river-wms" layers="Weser"/> <background-wms url="http://osm.intevation.de/mapcache/?" layers="OSM-WMS-Dienst"/> </river>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/doc/conf/generators.xml Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<output-generators> + <output-generator names="discharge_curve" class="org.dive4elements.river.exports.DischargeCurveGenerator"/> + <output-generator names="discharge_curve_chartinfo" class="org.dive4elements.river.exports.DischargeCurveInfoGenerator"/> + <output-generator names="cross_section" class="org.dive4elements.river.exports.CrossSectionGenerator"/> + <output-generator names="cross_section_chartinfo" class="org.dive4elements.river.exports.CrossSectionInfoGenerator"/> + <output-generator names="computed_discharge_curve" class="org.dive4elements.river.exports.ComputedDischargeCurveGenerator"/> + <output-generator names="computed_discharge_curve_chartinfo" class="org.dive4elements.river.exports.ComputedDischargeCurveInfoGenerator"/> + <output-generator + names="longitudinal_section,longitudinal_section_chartinfo,discharge_longitudinal_section,discharge_longitudinal_section_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.longitudinal.section.title" default="W-Längsschnitt"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" axis="W"/> + </output-generator> + <output-generator + names="w_differences,w_differences_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.w_differences.title" default="Differences"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" axis="W"/> + <subtitle key="chart.w_differences.subtitle" default="-"> + <arg expr="artifact.river"/> + </subtitle> + </output-generator> + <output-generator + names="fix_longitudinal_section_curve,fix_longitudinal_section_curve_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.fixings.longitudinalsection.title" default="Fixierungsanalyse"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" axis="deltaW"/> + </output-generator> + <output-generator + names="bedheight_middle,bedheight_middle_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.bedheight_middle.section.title" default="Mittlere Sohlhöhe"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" axis="BedHeight"/> + </output-generator> + <output-generator + names="bed_difference_height_year,bed_difference_height_year_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.beddifference.height.title" default="Sohlenhöhen Differenz"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="diffBed/Y"/> + </output-generator> + <output-generator names="bed_difference_year,bed_difference_year_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.beddifference.year.title" default="Sohlenhöhen Differenz"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="diffBed"/> + </output-generator> + <output-generator names="bed_longitudinal_section,bed_longitudinal_section_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.bedquality.title" default="Sohlen Längsschnitt"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="diffBed"/> + </output-generator> + <output-generator + names="sedimentload_ls,sedimentload_ls_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.sedimentload.ls.title" default="Sedimentfracht"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="SedimentLoad"/> + </output-generator> + <output-generator + names="flow_velocity,flow_velocity_chartinfo" + class="org.dive4elements.river.exports.LongitudinalSectionGenerator2" + converter="org.dive4elements.river.exports.DiagramAttributes"> + <title key="chart.flow_velocity.section.title" default="Geschwindigkeit- und Schubspannung"/> + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="Velocity"/> + </output-generator> + <output-generator names="duration_curve" class="org.dive4elements.river.exports.DurationCurveGenerator"/> + <output-generator names="duration_curve_chartinfo" class="org.dive4elements.river.exports.DurationCurveInfoGenerator"/> + <output-generator names="waterlevel_export" class="org.dive4elements.river.exports.WaterlevelExporter"/> + <output-generator names="extreme_wq_curve" class="org.dive4elements.river.exports.extreme.ExtremeWQCurveGenerator"/> + <output-generator names="extreme_curve_export" class="org.dive4elements.river.exports.WaterlevelExporter"/> + <output-generator names="extreme_wq_curve_chartinfo" class="org.dive4elements.river.exports.extreme.ExtremeWQCurveInfoGenerator"/> + <output-generator names="fix_wq_curve" class="org.dive4elements.river.exports.fixings.FixWQCurveGenerator"/> + <output-generator names="fix_wq_curve_chartinfo" class="org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator"/> + <output-generator names="durationcurve_export" class="org.dive4elements.river.exports.DurationCurveExporter"/> + <output-generator names="computed_dischargecurve_export" class="org.dive4elements.river.exports.ComputedDischargeCurveExporter"/> + <output-generator names="discharge_longitudinal_section_export" class="org.dive4elements.river.exports.DischargeLongitudinalSectionExporter"/> + <output-generator names="w_differences_export" class="org.dive4elements.river.exports.WDifferencesExporter"/> + <output-generator names="floodmap" class="org.dive4elements.river.exports.MapGenerator"/> + <output-generator names="map" class="org.dive4elements.river.exports.MapGenerator"/> + <output-generator names="reference_curve" class="org.dive4elements.river.exports.ReferenceCurveGenerator"/> + <output-generator names="reference_curve_normalized" class="org.dive4elements.river.exports.NormalizedReferenceCurveGenerator"/> + <output-generator names="reference_curve_normalized_chartinfo" class="org.dive4elements.river.exports.NormalizedReferenceCurveInfoGenerator"/> + <output-generator names="reference_curve_chartinfo" class="org.dive4elements.river.exports.ReferenceCurveInfoGenerator"/> + <output-generator names="reference_curve_export" class="org.dive4elements.river.exports.ReferenceCurveExporter"/> + <output-generator names="historical_discharge" class="org.dive4elements.river.exports.HistoricalDischargeCurveGenerator"/> + <output-generator names="historical_discharge_chartinfo" class="org.dive4elements.river.exports.HistoricalDischargeCurveInfoGenerator"/> + <output-generator names="historical_discharge_wq" class="org.dive4elements.river.exports.HistoricalDischargeWQCurveGenerator"/> + <output-generator names="historical_discharge_wq_chartinfo" class="org.dive4elements.river.exports.HistoricalDischargeWQCurveInfoGenerator"/> + <output-generator names="historical_discharge_export" class="org.dive4elements.river.exports.HistoricalDischargeCurveExporter"/> + <output-generator names="flow_velocity_export" class="org.dive4elements.river.exports.FlowVelocityExporter"/> + <output-generator names="bedheight_middle_export" class="org.dive4elements.river.exports.MiddleBedHeightExporter"/> + <output-generator names="bed_quality_export" class="org.dive4elements.river.exports.minfo.BedQualityExporter"/> + <output-generator names="bed_difference_epoch" class="org.dive4elements.river.exports.minfo.BedDifferenceEpochGenerator"/> + <output-generator names="bed_difference_epoch_chartinfo" class="org.dive4elements.river.exports.minfo.BedDiffEpochInfoGenerator"/> + <output-generator names="bedheight_difference_export" class="org.dive4elements.river.exports.minfo.BedDifferenceExporter"/> + <output-generator names="sq_relation_a" class="org.dive4elements.river.exports.sq.SQRelationGeneratorA"/> + <output-generator names="sq_relation_b" class="org.dive4elements.river.exports.sq.SQRelationGeneratorB"/> + <output-generator names="sq_relation_c" class="org.dive4elements.river.exports.sq.SQRelationGeneratorC"/> + <output-generator names="sq_relation_d" class="org.dive4elements.river.exports.sq.SQRelationGeneratorD"/> + <output-generator names="sq_relation_e" class="org.dive4elements.river.exports.sq.SQRelationGeneratorE"/> + <output-generator names="sq_relation_f" class="org.dive4elements.river.exports.sq.SQRelationGeneratorF"/> + <output-generator names="sq_relation_a_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_b_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_c_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_d_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_e_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_f_chartinfo" class="org.dive4elements.river.exports.sq.SQRelationInfoGenerator"/> + <output-generator names="sq_relation_export" class="org.dive4elements.river.exports.sq.SQRelationExporter"/> + <output-generator names="sq_overview" class="org.dive4elements.river.exports.sq.SQOverviewGenerator"/> + <output-generator names="fix_parameters_export" class="org.dive4elements.river.exports.fixings.ParametersExporter"/> + <output-generator names="fix_deltawt_export" class="org.dive4elements.river.exports.fixings.DeltaWtExporter"/> + <output-generator names="fix_deltawt_curve" class="org.dive4elements.river.exports.fixings.FixDeltaWtGenerator"/> + <output-generator names="fix_deltawt_curve_chartinfo" class="org.dive4elements.river.exports.fixings.FixDeltaWtInfoGenerator"/> + <output-generator names="fix_derivate_curve" class="org.dive4elements.river.exports.fixings.FixDerivedCurveGenerator"/> + <output-generator names="fix_derivate_curve_chartinfo" class="org.dive4elements.river.exports.fixings.FixDerivedCurveInfoGenerator"/> + <output-generator names="fix_waterlevel_export" class="org.dive4elements.river.exports.WaterlevelExporter"/> + <output-generator names="fix_vollmer_wq_curve" class="org.dive4elements.river.exports.fixings.FixWQCurveGenerator"/> + <output-generator names="fix_vollmer_wq_curve_chartinfo" class="org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator"/> + <output-generator names="sedimentload_ls_export" class="org.dive4elements.river.exports.minfo.SedimentLoadExporter"/> + <!-- Error report generators. --> + <output-generator names="discharge_longitudinal_section_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="waterlevel_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="computed_dischargecurve_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="durationcurve_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="wsplgen_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="historical_discharge_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="reference_curve_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="fix_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="extreme_curve_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <output-generator names="sedimentload_ls_report" class="org.dive4elements.river.exports.ReportGenerator"/> + <!-- AT exporter. --> + <output-generator names="computed_dischargecurve_at_export" class="org.dive4elements.river.exports.ATExporter"/> + <output-generator names="gauge_discharge_curve_at_export" class="org.dive4elements.river.exports.ATExporter"/> + <output-generator names="fix_wq_curve_at_export" class="org.dive4elements.river.exports.fixings.FixATExport"/> + <output-generator names="wsplgen" class="org.dive4elements.river.exports.ShapeExporter"/> +</output-generators> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/doc/conf/longitudinal-diagram-defaults.xml Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<longitudinal-defaults> + <axis name="W"/> + <axis name="diffW"/> + <axis name="deltaW"/> + <axis name="diffBed"/> + <axis name="diffBed/Y"/> + <axis name="BedHeight"/> + <axis name="SoundingWidth"/> + <axis name="Width"/> + <axis name="Diameter"/> + <axis name="Density"/> + <axis name="Porosity"/> + <axis name="SedimentLoad"/> + <axis name="Velocity"/> + <axis name="Tau"/> + <axis name="Q" include-zero="true"/> + <domain-axis key="chart.longitudinal.section.xaxis.label" default="Fluss-Km" + inverted="org.dive4elements.river.exports.IsKmUpEvaluator()"> + <arg expr="artifact.river"/> + </domain-axis> + <!-- Default longitudinal section Processors --> + <processor class="org.dive4elements.river.exports.process.DeltaWProcessor" axis="deltaW"/> + <processor class="org.dive4elements.river.exports.process.AnnotationProcessor" axis="none"/> + <processor class="org.dive4elements.river.exports.process.AreaProcessor" axis="none"/> + <processor class="org.dive4elements.river.exports.process.WDiffProcessor" axis="diffW"/> + <processor class="org.dive4elements.river.exports.process.WOutProcessor" axis="W"/> + <processor class="org.dive4elements.river.exports.process.QOutProcessor" axis="Q"/> + <processor class="org.dive4elements.river.exports.process.BedHeightSoundingProcessor" axis="SoundingWidth"/> + <processor class="org.dive4elements.river.exports.process.BedWidthProcessor" axis="Width"/> + <processor class="org.dive4elements.river.exports.process.BedDiffYearProcessor" axis="diffBed"/> + <processor class="org.dive4elements.river.exports.process.BedDiffHeightYearProcessor" axis="diffBed/Y"/> + <processor class="org.dive4elements.river.exports.process.MiddleBedHeightProcessor" axis="BedHeight"/> + <processor class="org.dive4elements.river.exports.process.BedQualityDiameterProcessor" axis="Diameter"/> + <processor class="org.dive4elements.river.exports.process.BedQualityPorosityProcessor" axis="Porosity"/> + <processor class="org.dive4elements.river.exports.process.BedQualityDensityProcessor" axis="Density"/> + <processor class="org.dive4elements.river.exports.process.SedimentLoadProcessor" axis="SedimentLoad"/> + <processor class="org.dive4elements.river.exports.process.FlowVelocityProcessor" axis="Velocity"/> + <processor class="org.dive4elements.river.exports.process.ShearStressProcessor" axis="Tau"/> +</longitudinal-defaults>
--- a/artifacts/doc/conf/mapserver/barrier_lines_class.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/barrier_lines_class.vm Fri Sep 27 17:36:50 2013 +0200 @@ -1,6 +1,6 @@ CLASS NAME "Damm" - EXPRESSION ("[TYP]"="Damm") + EXPRESSION /damm/i STYLE SIZE 5 OUTLINECOLOR "#008000" @@ -8,7 +8,7 @@ END CLASS NAME "Rohr 1" - EXPRESSION ("[TYP]"="Rohr 1") + EXPRESSION /rohr.1/i STYLE SIZE 5 OUTLINECOLOR "#800080" @@ -16,7 +16,7 @@ END CLASS NAME "Rohr 2" - EXPRESSION ("[TYP]"="Rohr 2") + EXPRESSION /rohr.2/i STYLE SIZE 5 OUTLINECOLOR "#808080" @@ -24,7 +24,7 @@ END CLASS NAME "Graben" - EXPRESSION ("[TYP]"="Graben") + EXPRESSION /graben/i STYLE SIZE 5 OUTLINECOLOR "#800000" @@ -32,7 +32,7 @@ END CLASS NAME "Ringdeich" - EXPRESSION ("[TYP]"="Ringdeich") + EXPRESSION /ringdeich/i STYLE SIZE 5 OUTLINECOLOR "#800000"
--- a/artifacts/doc/conf/mapserver/barrier_polygons_class.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/barrier_polygons_class.vm Fri Sep 27 17:36:50 2013 +0200 @@ -1,6 +1,6 @@ CLASS NAME "Ringdeich" - EXPRESSION ("[TYP]"="Ringdeich") + EXPRESSION /ringdeich/i STYLE SIZE 5 OUTLINECOLOR "#FF8000"
--- a/artifacts/doc/conf/mapserver/mapfile.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/mapfile.vm Fri Sep 27 17:36:50 2013 +0200 @@ -19,23 +19,26 @@ WEB METADATA "wms_title" "FLYS Web Map Service" - "wms_onlineresource" "$MAPSERVERURL" + "wms_onlineresource" "${MAPSERVERURL}user-wms" "wms_encoding" "UTF-8" "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_address" "" + "wms_city" "" + "wms_stateorprovince" "" + "wms_postcode" "" + "wms_country" "" + "wms_contactperson" "" + "wms_contactorganization" "" + "wms_contactelectronicmailaddress" "" + "wms_contactvoicetelephone" "" "wms_srs" "EPSG:4326 EPSG:31466 EPSG:31467" - "wms_feature_info_mime_type" "text/html" + "wms_getmap_formatlist" "image/png,image/png; mode=24bit,image/jpeg" "ows_enable_request" "*" + "ows_sld_enabled" "false" + "ows_title" "FLYS Web Map Service" + "ows_extent" "3233232 5303455 3421524 5585825" END END
--- a/artifacts/doc/conf/mapserver/river-mapfile.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/river-mapfile.vm Fri Sep 27 17:36:50 2013 +0200 @@ -19,7 +19,7 @@ WEB METADATA "wms_title" "FLYS Rivers Web Map Service" - #"wms_onlineresource" "http://localhost:7777/river-wms" # "$MAPSERVERURL" + "wms_onlineresource" "${MAPSERVERURL}river-wms" "wms_encoding" "UTF-8" "wms_accessconstraints" "none" "wms_fees" "none" @@ -34,7 +34,6 @@ "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
--- a/artifacts/doc/conf/mapserver/shapefile_layer.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/shapefile_layer.vm Fri Sep 27 17:36:50 2013 +0200 @@ -21,6 +21,8 @@ "wms_group_title" "$LAYER.getGroupTitle()" #end END + + CLASSITEM "TYP" #if ( !$LAYER.getStyle() ) #if ( $LAYER.getGroupTitle() )
--- a/artifacts/doc/conf/mapserver/wsplgen_layer.vm Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/mapserver/wsplgen_layer.vm Fri Sep 27 17:36:50 2013 +0200 @@ -19,6 +19,7 @@ "gml_include_items" "all" "ows_enable_request" "GetFeatureInfo" "wms_feature_info_mime_type" "gml" + "wms_srs" "EPSG:4326 EPSG:31466 EPSG:31467" #if ( $LAYER.getGroupTitle() ) "wms_group_title" "$LAYER.getGroupTitle()" #end
--- a/artifacts/doc/conf/meta-data.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/meta-data.xml Fri Sep 27 17:36:50 2013 +0200 @@ -141,6 +141,7 @@ </dc:when> <dc:when test="$out = 'longitudinal_section'"> <dc:call-macro name="longitudinal-section-prototype"/> + <dc:call-macro name="bedheight_differences"/> </dc:when> <dc:when test="$out = 'w_differences'"> <dc:call-macro name="longitudinal-section-prototype"/> @@ -166,7 +167,7 @@ <dc:call-macro name="discharge_table_gauge"/> <dc:call-macro name="basedata_2_fixations_wqkms"/> <dc:call-macro name="basedata_5_flood-protections"/> - <dc:call-macro name="basedata_0"/> + <dc:call-macro name="basedata_0_wq"/> <dc:call-macro name="basedata_1_additionals"/> <dc:call-macro name="basedata_4_heightmarks-points"/> <computed_discharge_curve> @@ -285,8 +286,8 @@ <dc:call-macro name="discharge_table_gauge"/> <dc:call-macro name="basedata_2_fixations_wqkms"/> <dc:call-macro name="basedata_5_flood-protections"/> - <dc:call-macro name="basedata_0"/> - <dc:call-macro name="basedata_1_additionals"/> + <dc:call-macro name="basedata_0_wq"/> + <dc:call-macro name="basedata_1_additionals_wq"/> <dc:call-macro name="basedata_4_heightmarks-points"/> <computed_discharge_curve> <dc:call-macro name="mainvalues"/> @@ -353,6 +354,17 @@ <dc:when test="$out = 'longitudinal_section'"> <dc:call-macro name="longitudinal"/> <dc:call-macro name="differences"/> + <dc:call-macro name="bedheight_differences"/> + <dc:call-macro name="bedquality-bed"/> + <dc:call-macro name="bedquality-load"/> + <dc:call-macro name="flow-velocity"/> + <dc:call-macro name="sediment-load"/> + <dc:call-macro name="bedquality-density"/> + <dc:call-macro name="bedquality-porosity"/> + <dc:call-macro name="waterlevels-discharge"/> + <dc:call-macro name="differenceable-fix"/> + <dc:call-macro name="delta-wt-ls"/> + <dc:call-macro name="longitudinal-section"/> </dc:when> <dc:when test="$out = 'discharge_longitudinal_section'"> <dc:call-macro name="longitudinal"/> @@ -401,6 +413,7 @@ <dc:when test="$out = 'bedheight_middle'"> <dc:call-macro name="waterlevels-discharge"/> <dc:call-macro name="differenceable-fix"/> + <dc:call-macro name="differences"/> </dc:when> <dc:when test="$out = 'floodmap-hws'"> <dc:call-macro name="floodmap-hws-user"/> @@ -485,22 +498,22 @@ <dc:macro name="historical_discharge_curve"> + <dc:variable name="refgauge" type="number" expr="$reference_gauge"/> <dc:context> <dc:statement> SELECT g.id AS gauge_id, - g.name AS gauge_name, - dt.id AS dt_id, - t.start_time AS start_time, - t.stop_time AS stop_time, - dt.description AS desc, - dt.bfg_id AS bfg_id + g.name AS gauge_name, + dt.id AS dt_id, + t.start_time AS start_time, + t.stop_time AS stop_time, + dt.bfg_id AS bfg_id FROM gauges g JOIN discharge_tables dt ON g.id = dt.gauge_id LEFT JOIN time_intervals t ON dt.time_interval_id = t.id WHERE g.river_id = ${river_id} AND dt.kind <> 0 - AND g.station = ${fromkm} - AND g.station = ${tokm} + AND ((g.station = ${fromkm} AND g.station = ${tokm}) + OR g.official_number = ${refgauge}) ORDER BY start_time </dc:statement> <dc:if test="dc:has-result()"> @@ -508,9 +521,6 @@ <dc:group expr="$gauge_name"> <dc:for-each> <dc:variable name="combined_desc" expr="concat($bfg_id, ' ', dc:date-format('dd.MM.yyyy', $start_time), ' - ', dc:date-format('dd.MM.yyyy', $stop_time))"/> - <dc:message> - Hallo ANDRE23 {dc:dump-variables()} - </dc:message> <histdis name="{$combined_desc}" description="{$combined_desc}" factory="gaugedischarge" target_out="{$out}" @@ -877,7 +887,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="bed_longitudinal_section"/> </dc:element> </dc:for-each> @@ -901,7 +911,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="bed_longitudinal_section"/> </dc:element> </dc:for-each> @@ -926,7 +936,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="bed_longitudinal_section"/> </dc:element> </dc:for-each> @@ -951,7 +961,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="bed_longitudinal_section"/> </dc:element> </dc:for-each> @@ -978,7 +988,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="flow_velocity"/> </dc:element> </dc:for-each> @@ -1001,7 +1011,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="sedimentload_ls"/> </dc:element> </dc:for-each> @@ -1040,7 +1050,7 @@ <dc:filter expr="$out_name = 'discharge_longitudinal_section' and $facet_name = 'discharge_longitudinal_section.w'"> <dc:if test="dc:has-result()"> <waterlevels-discharge> - <dc:group expr="concat($oid, ' ', $river, ' ', $a_id, ' ', dc:date-format('dd.MM.yyyy - H:mm:ss', $a_creation), ' ', $collection_name)"> + <dc:group expr="concat($oid, ' ', $river, ' ', $a_gid, ' ', dc:date-format('dd.MM.yyyy - H:mm:ss', $a_creation), ' ', $collection_name)"> <discharge description="{dc:group-key()}"> <dc:for-each> <dc:element name="${facet_name}"> @@ -1048,7 +1058,7 @@ <dc:attribute name="target_out" value="${out}"/> <dc:attribute name="description" value="${facet_description}"/> <dc:attribute name="ids" value="${facet_num}-${facet_name}"/> - <dc:attribute name="artifact-id" value="${a_id}"/> + <dc:attribute name="artifact-id" value="${a_gid}"/> <dc:attribute name="out" value="longitudinal_section"/> </dc:element> </dc:for-each> @@ -1210,8 +1220,74 @@ <dc:call-macro name="basedata_3_officials"/> <dc:call-macro name="basedata_5_flood-protections"/> <dc:call-macro name="annotations_per_type"/> + <minfo> + <dc:call-macro name="basedata_6_delta_w"/> + <dc:call-macro name="basedata_7_waterlevels"/> + <dc:call-macro name="minfo-heights"/> + <dc:call-macro name="sounding-width"/> + <dc:call-macro name="yields"/> + </minfo> </dc:macro> + <dc:macro name="yields"> + <yields> + <years> + <dc:context> + <dc:statement> + SELECT DISTINCT + sy.id AS syid, + sy.description AS description, + ti.start_time AS year + FROM sediment_yield sy + JOIN rivers r ON sy.river_id = r.id + JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id + JOIN time_intervals ti ON sy.time_interval_id = ti.id + WHERE r.name = 'Elbe' + AND ti.stop_time IS NULL + AND syv.station BETWEEN ${fromkm} AND ${tokm} + </dc:statement> + <dc:if test="dc:has-result()"> + <dc:for-each> + <year description="{$description}" + factory="sedimentyield" + target_out="{$out}" + info="infome" + ids="{$syid}" /> + </dc:for-each> + </dc:if> + </dc:context> + </years> + <epochs> + <dc:context> + <dc:statement> + SELECT DISTINCT + sy.id AS syid, + sy.description AS description, + ti.start_time AS year + FROM sediment_yield sy + JOIN rivers r ON sy.river_id = r.id + JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id + JOIN time_intervals ti ON sy.time_interval_id = ti.id + WHERE r.name = 'Elbe' + AND ti.stop_time IS NOT NULL + AND syv.station BETWEEN ${fromkm} AND ${tokm} + </dc:statement> + <dc:if test="dc:has-result()"> + <dc:for-each> + <epoch description="{$description}" + factory="sedimentyield" + target_out="{$out}" + info="infome" + ids="{$syid}" /> + </dc:for-each> + </dc:if> + </dc:context> + </epochs> + + </yields> + </dc:macro> + + <dc:macro name="basedata_5_flood-protections"> <dc:filter expr="$kind=5"> <dc:if test="dc:has-result()"> @@ -1306,20 +1382,59 @@ </dc:filter> </dc:macro> + + <dc:macro name="basedata_7_waterlevels"> + <dc:filter expr="$kind=7"> + <dc:if test="dc:has-result()"> + <wlevel> + <dc:group expr="dc:replace($wst_description, 'CSV/', '')"> + <relativepoint name="{dc:group-key()}"> + <dc:for-each> + <column name="{$wst_column_name}" + ids="additionals-wstv-{$wst_column_position}-{$wst_id}" + factory="staticwqkms" target_out="{$out}" + info="{$info} [km {$deffrom} - {$defto}]"/> + </dc:for-each> + </relativepoint> + </dc:group> + </wlevel> + </dc:if> + </dc:filter> + </dc:macro> + + <dc:macro name="basedata_6_delta_w"> <dc:filter expr="$kind=6"> <dc:if test="dc:has-result()"> <delta_w> - <dc:group expr="$wst_description"> - <relativepoint name="{dc:group-key()}"> - <dc:for-each> - <column name="{$wst_column_name}" - ids="delta_w-wstv-{$wst_column_position}-{$wst_id}" - factory="staticwkms" target_out="{$out}" - info="{$info} [km {$deffrom} - {$defto}]"/> - </dc:for-each> - </relativepoint> - </dc:group> + <delta_w_cm> + <dc:filter expr="contains($wst_description, 'cm.csv')"> + <dc:group expr="dc:replace($wst_description, 'CSV/', '')"> + <relativepoint name="{dc:group-key()}"> + <dc:for-each> + <column name="{$wst_column_name}" + ids="delta_w-wstv-{$wst_column_position}-{$wst_id}" + factory="staticwkms" target_out="{$out}" + info="{$info} [km {$deffrom} - {$defto}]"/> + </dc:for-each> + </relativepoint> + </dc:group> + </dc:filter> + </delta_w_cm> + <delta_w_cma> + <dc:filter expr="contains($wst_description, 'cm-a.csv')"> + <dc:group expr="dc:replace($wst_description, 'CSV/', '')"> + <relativepoint name="{dc:group-key()}"> + <dc:for-each> + <column name="{$wst_column_name}" + ids="delta_w-wstv-{$wst_column_position}-{$wst_id}" + factory="staticwkms" target_out="{$out}" + info="{$info} [km {$deffrom} - {$defto}]"/> + </dc:for-each> + </relativepoint> + </dc:group> + </dc:filter> + </delta_w_cma> </delta_w> </dc:if> </dc:filter> @@ -1337,17 +1452,14 @@ LEFT JOIN time_intervals t ON dt.time_interval_id = t.id WHERE g.river_id = ${river_id} AND dt.kind = 0 - AND g.station = ${fromkm} - AND g.station = ${tokm} + AND ((g.station = ${fromkm} AND g.station = ${tokm}) + OR g.official_number = ${refgauge}) </dc:statement> <dc:if test="dc:has-result()"> - <current_gauge> - <dc:for-each> - <gauge name="{$gauge_name} ({dc:date-format('dd.MM.yyyy', $start_time)})" - factory="gaugedischarge" target_out="{$out}" - ids="{$gauge_name}"/> - </dc:for-each> - </current_gauge> + <dc:for-each> + <current_gauge factory="gaugedischarge" target_out="{$out}" + ids="{$gauge_name}"/> + </dc:for-each> </dc:if> </dc:context> </dc:macro>
--- a/artifacts/doc/conf/themes.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/themes.xml Fri Sep 27 17:36:50 2013 +0200 @@ -177,9 +177,12 @@ <mapping from="other.wq" to="WQPoints" /> <mapping from="other.wkms" to="WKms" /> <mapping from="other.wkms.marks" to="WKmsAnnotation" /> + <mapping from="other.wqkms" to="WQKmsHorizontal" masterAttr="calculation_mode==calc.discharge.curve" /> <mapping from="other.wqkms" to="WQKms" /> + <mapping from="other.wqkms.w" to="WQKmsHorizontal" masterAttr="calculation_mode==calc.discharge.curve" /> <mapping from="other.wqkms.w" to="WQKms" /> <mapping from="other.wqkms.q" to="WQKms" /> + <mapping from="other.w.interpol" to="MainValuesW" /> <mapping from="heightmarks_points" to="heightmarks_points" /> <mapping from="area" to="Area" /> <mapping from="cross_section.area" to="CrossSectionArea" /> @@ -207,6 +210,7 @@ <mapping from="flow_velocity.mainchannel.filtered" to="FlowVelocityVMainChannel" /> <mapping from="flow_velocity.tau.filtered" to="FlowVelocityTau" /> <mapping from="flow_velocity.discharge" to="FlowVelocityDischarge" /> + <mapping from="flow_velocity.measurement" to="FlowVelocityDischarge" /> <mapping from="bedheight_middle.single" to="MiddleBedHeightSingle" /> <mapping from="bedheight_middle.epoch" to="MiddleBedHeightEpoch" /> <mapping from="bed_longitudinal_section.porosity_toplayer" to="PorosityTopLayer" /> @@ -273,6 +277,7 @@ <mapping from="fix_analysis_events_wq" to="FixingAnalysisEventsWQ" /> <mapping from="fix_outlier" to="FixingOutlier" /> <mapping from="fix_wq_curve" to="FixingWQCurve" /> + <mapping from="fix_wq_ls" to="FixingCalculatedPoint" /> <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" />
--- a/artifacts/doc/conf/themes/default.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/themes/default.xml Fri Sep 27 17:36:50 2013 +0200 @@ -84,6 +84,8 @@ display="Punktbeschriftung anzeigen" default="false" hints="hidden" /> <field name="linecolor" type="Color" display="Linienfarbe" default="204, 204, 204" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> </fields> </theme> @@ -116,6 +118,19 @@ </fields> </theme> + <theme name="WQKmsHorizontal"> + <inherits> + <inherit from="WQKms" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Linienfarbe" + default="204, 204, 204" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="true" /> + </fields> + </theme> + + <theme name="WQPoints"> <inherits> <inherit from="Points" /> @@ -152,7 +167,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> </fields> </theme> <!-- top level classes defining additional attributes--> @@ -1185,7 +1200,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> </fields> </theme> @@ -1254,7 +1269,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="true"/> </fields> </theme> @@ -1455,7 +1470,21 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingCalculatedPoint"> + <inherits> + <inherit from="FixPoints" /> + </inherits> + <fields> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 0, 0" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5"/> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> </fields> </theme> @@ -1561,9 +1590,21 @@ </fields> </theme> + <theme name="FixingDeltaWtAverage"> + <inherits> + <inherit from="FixLines" /> + </inherits> + <fields> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false" hints="hidden"/> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="true" /> + </fields> + </theme> + <theme name="FixingDeltaWtAverage0"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1573,7 +1614,7 @@ <theme name="FixingDeltaWtAverage1"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1583,7 +1624,7 @@ <theme name="FixingDeltaWtAverage2"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1593,7 +1634,7 @@ <theme name="FixingDeltaWtAverage3"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe"
--- a/artifacts/doc/conf/themes/second.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/doc/conf/themes/second.xml Fri Sep 27 17:36:50 2013 +0200 @@ -14,6 +14,20 @@ </fields> </theme> + <theme name="MainValuesQVerticalText"> + <inherits> + <inherit from="Lines" /> + </inherits> + <fields> + <field name="linecolor" type="Color" display="Farbe" + default="200, 0, 15" /> + <field name="textorientation" type="boolean" display="Textausrichtung" + default="false" /> + <field name="showlinelabel" type="boolean" + display="Linienbeschriftung anzeigen" default="false" hints="hidden" /> + </fields> + </theme> + <theme name="MainValuesW"> <inherits> <inherit from="Lines" /> @@ -28,20 +42,6 @@ </fields> </theme> - <theme name="MainValuesQVerticalText"> - <inherits> - <inherit from="Lines" /> - </inherits> - <fields> - <field name="linecolor" type="Color" display="Farbe" - default="200, 0, 15" /> - <field name="textorientation" type="boolean" display="Textausrichtung" - default="false" /> - <field name="showlinelabel" type="boolean" - display="Linienbeschriftung anzeigen" default="false" hints="hidden" /> - </fields> - </theme> - <theme name="RelativePoint"> <inherits> <inherit from="Points" /> @@ -152,7 +152,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> </fields> </theme> <!-- top level classes defining additional attributes--> @@ -843,7 +843,7 @@ <field name="showlines" type="boolean" display="Linie anzeigen" default="true" /> <field name="linesize" type="int" display="Liniendicke" - default="2" /> + default="1" /> <field name="linetype" type="Dash" display="Linienart" default="10" /> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1185,7 +1185,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> </fields> </theme> @@ -1254,7 +1254,7 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="true"/> </fields> </theme> @@ -1455,7 +1455,21 @@ <field name="showarea" type="boolean" display="Flaeche anzeigen" default="true" hints="hidden" /> <field name="showarealabel" type="boolean" - display="Flächenbeschriftung anzeigen" default="false" hints="hidden" /> + display="Flächenbeschriftung anzeigen" default="false"/> + </fields> + </theme> + + <theme name="FixingCalculatedPoint"> + <inherits> + <inherit from="FixPoints" /> + </inherits> + <fields> + <field name="pointcolor" type="Color" display="Punktfarbe" + default="0, 0, 0" /> + <field name="pointsize" type="int" display="Punktdicke" + default="5"/> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false"/> </fields> </theme> @@ -1561,9 +1575,21 @@ </fields> </theme> + <theme name="FixingDeltaWtAverage"> + <inherits> + <inherit from="FixLines" /> + </inherits> + <fields> + <field name="showpointlabel" type="boolean" + display="Punktbeschriftung anzeigen" default="false" hints="hidden"/> + <field name="showlinelabel" type="boolean" + display="Beschriftung anzeigen" default="true" /> + </fields> + </theme> + <theme name="FixingDeltaWtAverage0"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1573,7 +1599,7 @@ <theme name="FixingDeltaWtAverage1"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1583,7 +1609,7 @@ <theme name="FixingDeltaWtAverage2"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe" @@ -1593,7 +1619,7 @@ <theme name="FixingDeltaWtAverage3"> <inherits> - <inherit from="FixLines" /> + <inherit from="FixingDeltaWtAverage" /> </inherits> <fields> <field name="linecolor" type="Color" display="Linienfarbe"
--- a/artifacts/pom.xml Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/pom.xml Fri Sep 27 17:36:50 2013 +0200 @@ -75,9 +75,9 @@ <version>1.0-SNAPSHOT</version> </dependency> <dependency> - <groupId>jfree</groupId> + <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> - <version>1.0.13</version> + <version>1.0.15</version> </dependency> <dependency> <groupId>org.apache.xmlgraphics</groupId>
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/CrossSectionArtifact.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/CrossSectionArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -135,7 +135,8 @@ 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)); + String dataKmValue = getDataAsString(DATA_KM); + double dataKm = (dataKmValue != null) ? Double.valueOf(dataKmValue) : Double.MIN_VALUE; if (dataKm < csl.getKm().doubleValue()) { addStringData(DATA_KM, csl.getKm().toString()); } @@ -248,6 +249,10 @@ */ private double getParentKm() { String val = getDataAsString(PARENT_KM); + if (val == null) { + logger.warn("Empty data: " + PARENT_KM); + return 0; + } try { return Double.valueOf(val); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/D4EArtifact.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/D4EArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -1305,8 +1305,9 @@ for (Output out: list) { log.debug("check facets for output: " + out.getName()); + String outName = out.getName(); Output o = new DefaultOutput( - out.getName(), + outName, out.getDescription(), out.getMimeType(), out.getType()); @@ -1323,7 +1324,14 @@ for (Facet f: fs) { String type = f.getName(); - if (outTypes.contains(type)) { + /* Match the facets to the output configuration. + * This is only done when we are not already bound to an out. + * If we are bound we come from the datacage so the user has + * explicitly requested our nice and shiny facets. And who + * are we to deny them to him. */ + if (outTypes.contains(type) || + (boundToOut != null && + boundToOut.equals(outName))) { if (debug) { log.debug("Add facet " + f); } @@ -1491,7 +1499,7 @@ /** * Method to dump the artifacts state/data. */ - protected void dumpArtifact() { + public void dumpArtifact() { log.debug("++++++++++++++ DUMP ARTIFACT DATA +++++++++++++++++"); // Include uuid, type, name log.debug(" - Name: " + getName()); @@ -1525,7 +1533,7 @@ } - protected void debugFacets() { + public void debugFacets() { log.debug("######### FACETS #########"); for (Map.Entry<String, List<Facet>> entry: facets.entrySet()) { @@ -1541,7 +1549,7 @@ } - protected void dumpFilterFacets() { + public void dumpFilterFacets() { log.debug("######## FILTER FACETS ########"); if (filterFacets == null || filterFacets.isEmpty()) {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/FlowVelocityMeasurementArtifact.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/FlowVelocityMeasurementArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,6 +8,8 @@ package org.dive4elements.river.artifacts; +import java.text.DateFormat; + import java.util.ArrayList; import java.util.List; @@ -29,6 +31,8 @@ import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.utils.Formatter; + /** Artefact to access flow velocity measurements. */ public class FlowVelocityMeasurementArtifact @@ -111,13 +115,24 @@ List<Facet> fs = new ArrayList<Facet>(); String code = getDatacageIDValue(data); + DateFormat dateFormatter = Formatter.getDateFormatter( + callMeta, "dd.MM.yyy HH:mm"); if (code != null) { // parse code, interact with factory, add real facets. // store relevant parts of code as data. + FlowVelocityMeasurementValue.FastFlowVelocityMeasurementValue + flowVelocityMeasurement = + FlowVelocityMeasurementFactory.getFlowVelocityMeasurement( + Integer.parseInt(code)); + String name = flowVelocityMeasurement.getDescription(); + logger.debug ("datetime " + flowVelocityMeasurement.getDatetime()); + name += " - " + dateFormatter.format( + flowVelocityMeasurement.getDatetime()); + Facet facet = new FlowVelocityMeasurementFacet( FLOW_VELOCITY_MEASUREMENT, - "flowvelocity-name"); + name); fs.add(facet); addFacets(state.getID(), fs); addStringData(DATA_NAME, code);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/SedimentYieldArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,229 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; + +import org.dive4elements.artifactdatabase.state.DefaultOutput; +import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifactdatabase.state.FacetActivity; +import org.dive4elements.artifactdatabase.state.State; +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.ArtifactFactory; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.minfo.SedimentLoad; +import org.dive4elements.river.artifacts.model.minfo.SedimentLoadFacet; +import org.dive4elements.river.artifacts.model.minfo.SedimentLoadFactory; +import org.dive4elements.river.artifacts.model.minfo.SedimentLoadResult; +import org.dive4elements.river.artifacts.states.StaticState; + +import org.dive4elements.river.artifacts.model.FacetTypes; + +import org.dive4elements.river.utils.Formatter; + + +/** Artifact to access sediment yield measurements (inspired from flow velocity artifact). */ +public class SedimentYieldArtifact +extends StaticD4EArtifact +implements FacetTypes +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(SedimentYieldArtifact.class); + + /** Artifact key name. */ + private static final String NAME = "sedimentyield"; + + /** Spawn only inactive facets. */ + static { + // TODO: Move to configuration. + FacetActivity.Registry.getInstance() + .register(NAME, FacetActivity.INACTIVE); + } + + /** Need to give the state an id. */ + public static final String STATIC_STATE_NAME = + "state.sedimentyield.static"; + + /** One and only state to be in. */ + protected transient State state = null; + + protected String DATA_NAME = "ID"; + + /** + * Trivial Constructor. + */ + public SedimentYieldArtifact() { + logger.debug("SedimentYieldArtifact.SedimentYieldArtifact"); + } + + + /** Get artifact key name. */ + @Override + public String getName() { + return NAME; + } + + + private Object getSedimentLoad() { + logger.debug("SedimentYieldArtifact.getSedimentLoad"); + String id = getDataAsString(DATA_NAME); + String river = getDataAsString("river"); + + SedimentLoad myLoad = SedimentLoadFactory.getSedimentLoadWithDataUncached(id, river); + return new CalculationResult( + new SedimentLoadResult[] { + new SedimentLoadResult(1983,2042,myLoad) + }, new Calculation()); + } + + + /** Create a new state with bogus output. */ + protected State spawnState() { + state = new StaticState(STATIC_STATE_NAME) { + + public Object staticCompute(List<Facet> facets) { + return getSedimentLoad(); + } + }; + List<Facet> fs = getFacets(STATIC_STATE_NAME); + DefaultOutput output = new DefaultOutput( + "general", + "general", + "image/png", + fs, + "chart"); + + state.getOutputs().add(output); + + return state; + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("SedimentYieldArtifact.setup"); + + // Refactor? this happens at another place, too + // Store id, yield yields. + state = new StaticState(STATIC_STATE_NAME) { + + public Object staticCompute(List<Facet> facets) { + return getSedimentLoad(); + } + }; + if (logger.isDebugEnabled()) { + logger.debug(XMLUtils.toString(data)); + } + + List<Facet> fs = new ArrayList<Facet>(); + String code = getDatacageIDValue(data); + + // TODO need river, too. + // + if (code != null) { + String name = SedimentLoadFactory.getSedimentYieldDescription(Integer.valueOf(code)); + + Facet facet = new SedimentLoadFacet( + 0, + SEDIMENT_LOAD_COARSE, + name, + //???? + ComputeType.ADVANCE, state.getID(), "hash" + ); + fs.add(facet); + addFacets(state.getID(), fs); + addStringData(DATA_NAME, code); + } + + 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 + : spawnState(); + } + + + /** + * Called via setup. Overridden to avoid cloning all data. + * + * @param artifact The master-artifact. + */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + logger.debug("SedimentYieldArtifact.initialize"); + importData((D4EArtifact) artifact, "river"); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/StaticWQKmsArtifact.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/StaticWQKmsArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -104,7 +104,7 @@ // Store the 'ids' (from datacage). if (logger.isDebugEnabled()) { - logger.debug("StaticWQKmsArtiact.setup" + XMLUtils.toString(data)); + logger.debug("StaticWQKmsArtifact.setup" + XMLUtils.toString(data)); } String code = getDatacageIDValue(data);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/WQKmsInterpolArtifact.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/WQKmsInterpolArtifact.java Fri Sep 27 17:36:50 2013 +0200 @@ -132,7 +132,15 @@ name = STATIC_WKMS_INTERPOL; } else { - name = STATIC_WQ; + // If all Qs are zero, add different facet to + // signalize that we want data to be drawn as marks + // on axis. + if (wstValueHasZeroQ()) { + name = STATIC_W_INTERPOL; + } + else { + name = STATIC_WQ; + } } Facet wQFacet = new WQFacet(name, @@ -204,23 +212,51 @@ } + /** True if Wst has only 'fake' (zero) Q-ranges. */ + private boolean wstValueHasZeroQ() { + WstValueTable table = getValueTable(); + return table.hasEmptyQ(); + } + + + /** Get the WstValueTable that matches parameterization. */ + private WstValueTable getValueTable() { + // Get WstValueTable + int wstId = getDataAsInt("wst_id"); + if (getDataAsString("col_pos") != null) { + return WstValueTableFactory.getWstColumnTable( + wstId, getDataAsInt("col_pos")); + } + else { + return WstValueTableFactory.getTable(wstId); + } + } + + + /** + * Get WQ Values at a certain km, interpolating only if distance + * between two stations is smaller than given distance. + */ + public double [][] getWQAtKm( + Double currentKm, + double maxKmInterpolDistance + ) { + // TODO yet to be implemented (issue1378). + return null; + } + + /** * Get WQ at a given km. + * * @param currentKm the requested km. If NULL, ld_location data * will be used. + * @return [[q1,q2,q2],[w1,w2,w3]] ... */ 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")); - } + // TODO issue1378: only interpolate if dist <= 100m + WstValueTable interpolator = getValueTable(); Double tmp = (currentKm != null) ? currentKm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/access/DGMAccess.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,35 @@ +package org.dive4elements.river.artifacts.access; + +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.model.DGM; + +public class DGMAccess +extends RangeAccess +{ + private DGM dgm; + + private String geoJSON; + + public DGMAccess() { + } + + public DGMAccess(D4EArtifact artifact) { + super(artifact); + } + + public DGM getDGM() { + if (dgm == null) { + Integer sridId = getInteger("dgm"); + dgm = DGM.getDGM(sridId); + } + return dgm; + } + + public String getGeoJSON() { + if (geoJSON == null) { + geoJSON = getString("uesk.barriers"); + } + return geoJSON; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/access/RangeAccess.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/access/RangeAccess.java Fri Sep 27 17:36:50 2013 +0200 @@ -37,6 +37,8 @@ private KM_MODE mode; + public RangeAccess() { + } public RangeAccess(D4EArtifact artifact) { super(artifact); @@ -111,6 +113,14 @@ return locations.toNativeArray(); } + public boolean hasFrom() { + return from != null || (from = getDouble("ld_from")) != null; + } + + public boolean hasTo() { + return to != null || (to = getDouble("ld_to")) != null; + } + /** Return ld_from data (in km). */ public double getFrom() {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,11 +9,13 @@ package org.dive4elements.river.artifacts.access; import java.util.Date; +import java.util.List; import org.apache.log4j.Logger; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.DateRange; +import org.dive4elements.river.model.MeasurementStation; public class SQRelationAccess extends RiverAccess @@ -28,6 +30,8 @@ private String method; + protected MeasurementStation measurementStation; + public SQRelationAccess() { } @@ -80,5 +84,30 @@ } return method; } + + public String getMeasurementStationName() { + MeasurementStation station = getMeasurementStation(); + return station == null ? null : station.getName(); + } + + public String getMeasurementStationGaugeName() { + MeasurementStation station = getMeasurementStation(); + return station == null ? null : station.getGaugeName(); + } + + public MeasurementStation getMeasurementStation() { + if (measurementStation != null) { + return measurementStation; + } + List<MeasurementStation> candidates = MeasurementStation.getStationsAtKM( + getRiver(), getLocation()); + if (candidates != null) { + // Just take the first one as we only use the name + // and that "should" be unique at the location + measurementStation = candidates.get(0); + } + + return measurementStation; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContext.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContext.java Fri Sep 27 17:36:50 2013 +0200 @@ -17,6 +17,7 @@ import org.dive4elements.artifactdatabase.DefaultArtifactContext; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.exports.OutGenerator; +import org.dive4elements.river.utils.Pair; /** @@ -99,17 +100,26 @@ ? (RiverContext) context : (RiverContext) context.globalContext(); - Map<String, Class> generators = (Map<String, Class>) - flysContext.get(RiverContext.OUTGENERATORS_KEY); + Map<String, Pair<Class<OutGenerator>, Object>> generators = + (Map<String, Pair<Class<OutGenerator>, Object>>)flysContext + .get(RiverContext.OUTGENERATORS_KEY); if (generators == null) { return null; } - Class clazz = generators.get(name); + Pair<Class<OutGenerator>, Object> pair = generators.get(name); + + if (pair == null) { + logger.warn("No generator class found for " + name); + return null; + } try { - return clazz != null ? (OutGenerator) clazz.newInstance() : null; + Class<OutGenerator> clazz = pair.getA(); + OutGenerator generator = clazz.newInstance(); + generator.setup(pair.getB()); + return generator; } catch (InstantiationException ie) { logger.error(ie, ie);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,24 +8,8 @@ package org.dive4elements.river.artifacts.context; -import org.dive4elements.artifactdatabase.state.State; -import org.dive4elements.artifactdatabase.state.StateEngine; -import org.dive4elements.artifactdatabase.transition.Transition; -import org.dive4elements.artifactdatabase.transition.TransitionEngine; -import org.dive4elements.artifacts.ArtifactContextFactory; -import org.dive4elements.artifacts.GlobalContext; -import org.dive4elements.artifacts.common.utils.Config; -import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.river.artifacts.model.Module; -import org.dive4elements.river.artifacts.model.ZoomScale; -import org.dive4elements.river.artifacts.states.StateFactory; -import org.dive4elements.river.artifacts.transitions.TransitionFactory; -import org.dive4elements.river.themes.Theme; -import org.dive4elements.river.themes.ThemeFactory; -import org.dive4elements.river.themes.ThemeGroup; -import org.dive4elements.river.themes.ThemeMapping; +import java.io.File; -import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -34,12 +18,41 @@ import javax.xml.xpath.XPathConstants; import org.apache.log4j.Logger; + +import org.dive4elements.artifactdatabase.state.State; +import org.dive4elements.artifactdatabase.state.StateEngine; + +import org.dive4elements.artifactdatabase.transition.Transition; +import org.dive4elements.artifactdatabase.transition.TransitionEngine; + +import org.dive4elements.artifacts.ArtifactContextFactory; +import org.dive4elements.artifacts.GlobalContext; + +import org.dive4elements.artifacts.common.utils.Config; +import org.dive4elements.artifacts.common.utils.ElementConverter; +import org.dive4elements.artifacts.common.utils.XMLUtils; + +import org.dive4elements.river.artifacts.model.Module; +import org.dive4elements.river.artifacts.model.ZoomScale; + +import org.dive4elements.river.artifacts.states.StateFactory; + +import org.dive4elements.river.artifacts.transitions.TransitionFactory; + +import org.dive4elements.river.exports.OutGenerator; + +import org.dive4elements.river.themes.Theme; +import org.dive4elements.river.themes.ThemeFactory; +import org.dive4elements.river.themes.ThemeGroup; +import org.dive4elements.river.themes.ThemeMapping; + +import org.dive4elements.river.utils.Pair; + import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; - /** * The ArtifactContextFactory is used to initialize basic components and put * them into the global context of the application. @@ -93,6 +106,8 @@ private static final String XPATH_DGM_PATH = "/artifact-database/options/dgm-path/text()"; + private static GlobalContext GLOBAL_CONTEXT_INSTANCE; + /** * Creates a new D4EArtifactContext object and initialize all @@ -115,9 +130,17 @@ configureZoomScales(config, context); configureDGMPath(config, context); + synchronized (RiverContextFactory.class) { + GLOBAL_CONTEXT_INSTANCE = context; + } + return context; } + public static synchronized GlobalContext getGlobalContext() { + return GLOBAL_CONTEXT_INSTANCE; + } + private void configureDGMPath(Document config, RiverContext context) { String dgmPath = (String) XMLUtils.xpath( @@ -297,7 +320,6 @@ * @param context the RiverContext. */ protected void configureOutGenerators(Document config, RiverContext context){ - Map<String, Class<?>> generators = new HashMap<String, Class<?>>(); NodeList outGenerators = (NodeList) XMLUtils.xpath( config, @@ -313,28 +335,60 @@ logger.info("Found " + num + " configured output generators."); + Map<String, Pair<Class<OutGenerator>, Object>> generators = + new HashMap<String, Pair<Class<OutGenerator>, Object>>(); + int idx = 0; for (int i = 0; i < num; i++) { - Node item = outGenerators.item(i); + Element item = (Element)outGenerators.item(i); - String name = (String) XMLUtils.xpath( - item, "@name", XPathConstants.STRING); + String names = item.getAttribute("names").trim(); + String clazz = item.getAttribute("class").trim(); + String converter = item.getAttribute("converter").trim(); - String clazz = (String) XMLUtils.xpath( - item, "text()", XPathConstants.STRING); - - if (name == null || clazz == null) { + if (names.isEmpty() || clazz.isEmpty()) { continue; } + Class<OutGenerator> generatorClass = null; + try { - generators.put(name, Class.forName(clazz)); - - idx++; + generatorClass = (Class<OutGenerator>)Class.forName(clazz); } catch (ClassNotFoundException cnfe) { - logger.warn(cnfe, cnfe); + logger.error(cnfe, cnfe); + continue; + } + + Object cfg = null; + + if (!converter.isEmpty()) { + try { + ElementConverter ec = + (ElementConverter)Class.forName(converter) + .newInstance(); + cfg = ec.convert(item); + } + catch (ClassNotFoundException cnfe) { + logger.error(cnfe, cnfe); + } + catch (InstantiationException ie) { + logger.error(ie); + } + catch (IllegalAccessException iae) { + logger.error(iae); + } + } + + Pair<Class<OutGenerator>, Object> pair = + new Pair<Class<OutGenerator>, Object>(generatorClass, cfg); + + for (String key: names.split("[\\s,]")) { + if (!(key = key.trim()).isEmpty()) { + generators.put(key, pair); + idx++; + } } }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Datacage.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Datacage.java Fri Sep 27 17:36:50 2013 +0200 @@ -896,8 +896,8 @@ @Override public boolean doIt() throws SQLException { prepareStatement(SQL_UPDATE_ARTIFACT_STATE); - stmnt.setInt(1, artifactId); - stmnt.setString(2, artifact.getCurrentStateId()); + stmnt.setString(1, artifact.getCurrentStateId()); + stmnt.setInt(2, artifactId); stmnt.execute(); conn.commit(); return true;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Recommendations.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Recommendations.java Fri Sep 27 17:36:50 2013 +0200 @@ -142,6 +142,7 @@ ) { parameters.put("CURRENT-STATE-ID", artifact.getCurrentStateId()); parameters.put("ARTIFACT-ID", artifact.identifier()); + parameters.put("ARTIFACT-NAME", artifact.getName()); for (StateData sd: artifact.getAllData()) { Object value = sd.getValue();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/FunctionResolver.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/FunctionResolver.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,10 +10,12 @@ import java.text.SimpleDateFormat; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.HashMap; +import java.util.Set; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -25,6 +27,10 @@ import javax.xml.xpath.XPathFunctionResolver; import org.apache.log4j.Logger; +import org.dive4elements.artifactdatabase.transition.TransitionEngine; +import org.dive4elements.artifacts.GlobalContext; +import org.dive4elements.river.artifacts.context.RiverContext; +import org.dive4elements.river.artifacts.context.RiverContextFactory; /** Resolves functions (e.g. dc:contains) in Datacage/Meta-Data system. */ @@ -151,6 +157,19 @@ return StackFrames.NULL; } }); + + addFunction("all-state-successors", 2, new XPathFunction() { + @Override + public Object evaluate(List args) throws XPathFunctionException { + Object artifactName = args.get(0); + Object stateId = args.get(1); + + return artifactName instanceof String + && stateId instanceof String + ? allStateSuccessors((String)artifactName, (String)stateId) + : Collections.<String>emptySet(); + } + }); } /** @@ -378,5 +397,18 @@ } return ""; } + + public Set<String> allStateSuccessors(String artifactName, String stateId) { + GlobalContext gc = RiverContextFactory.getGlobalContext(); + if (gc == null) { + return Collections.<String>emptySet(); + } + Object o = gc.get(RiverContext.TRANSITION_ENGINE_KEY); + if (o instanceof TransitionEngine) { + TransitionEngine te = (TransitionEngine)o; + return te.allRecursiveSuccessorStateIds(artifactName, stateId); + } + return Collections.<String>emptySet(); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/math/MovingAverage.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/math/MovingAverage.java Fri Sep 27 17:36:50 2013 +0200 @@ -37,7 +37,11 @@ return new double [][] { xs, ys }; } - public static double[][] weighted(double[][] values, double radius) { + /** Build moving average over values. Weight them. */ + public static double[][] weighted( + double[][] values, + double radius + ) { TreeMap<Double, Double> map = toMap(values); int N = map.size(); double [] xs = new double[N]; @@ -62,6 +66,7 @@ return new double [][] { xs, ys }; } + /** From [x1,x2][y1,y2] makes {x1:y1,x2:y2}. Sorted by x! */ private static TreeMap<Double, Double> toMap(double[][] values) { TreeMap<Double, Double> map = new TreeMap<Double, Double>(); double [] xs = values[0];
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/Calculation6.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/Calculation6.java Fri Sep 27 17:36:50 2013 +0200 @@ -37,6 +37,7 @@ private long [] timerange; private double [] values; private Long officialGaugeNumber; + private String riverName; public Calculation6(HistoricalDischargeAccess access) { @@ -45,6 +46,7 @@ double [] vs = mode != null && mode == EvaluationMode.W ? access.getWs() : access.getQs(); + riverName = access.getRiver(); Long officialGaugeNumber = access.getOfficialGaugeNumber(); @@ -98,7 +100,8 @@ return null; } - Gauge gauge = Gauge.getGaugeByOfficialNumber(officialGaugeNumber); + Gauge gauge = Gauge.getGaugeByOfficialNumber(officialGaugeNumber, + riverName); if (gauge == null) { // TODO: i18n return error("hist.discharge.gauge.not.found");
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/CrossSectionFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/CrossSectionFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -30,7 +30,7 @@ protected final static String CACHE_NAME = "cross_sections"; - // TODO use caching consistently, streamline acces. + // TODO use caching consistently, streamline access. /** * Get CrossSections for an instantiated River. *
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Fri Sep 27 17:36:50 2013 +0200 @@ -240,6 +240,7 @@ String STATIC_WQKMS_W = "other.wqkms.w"; String STATIC_WQKMS_Q = "other.wqkms.q"; String STATIC_WKMS_INTERPOL = "other.wkms.interpol"; + String STATIC_W_INTERPOL = "other.w.interpol"; String HEIGHTMARKS_POINTS = "heightmarks_points";
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FixingsOverview.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FixingsOverview.java Fri Sep 27 17:36:50 2013 +0200 @@ -28,8 +28,10 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.dive4elements.river.utils.BatchLoader; -/** Generate Fixings Table chart. */ + +/** Generate Fixings Table overview data structure to be stored in cache. */ public class FixingsOverview implements Serializable { @@ -56,39 +58,156 @@ "WHERE" + " river_id = :river_id AND kind = 2"; - /** All columns from given wst. */ - 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_COLUMNS_BATCH = + "SELECT " + + "wc.wst_id AS wst_id," + + "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 IN ($IDS) " + + "ORDER BY wc.wst_id, 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_Q_RANGES_BATCH = + "SELECT " + + "wcqr.wst_column_id AS wst_column_id," + + "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 IN ($IDS) " + + "ORDER BY wcqr.wst_column_id, 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 final String SQL_FIXING_COLUMN_KM_RANGE_BATCH = + "SELECT " + + "wst_column_id," + + "MIN(position) AS start_km," + + "MAX(position) AS stop_km " + + "FROM " + + "wst_column_values " + + "WHERE " + + "wst_column_id IN ($IDS) " + + "GROUP BY wst_column_id"; + public static final class KMRangeLoader extends BatchLoader<double []> { + + public KMRangeLoader(List<Integer> columns, Session session) { + super(columns, session, SQL_FIXING_COLUMN_KM_RANGE_BATCH); + } + + @Override + protected void fill(SQLQuery query) { + query + .addScalar("wst_column_id", StandardBasicTypes.INTEGER) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + List<Object []> ranges = query.list(); + for (Object [] r: ranges) { + Integer cid = (Integer)r[0]; + double [] vs = new double [] { (Double)r[1], (Double)r[2] }; + cache(cid, vs); + } + } + } // class KMRangeLoader + + public static final class ColumnQRangeLoader + extends BatchLoader<List<double []>> + { + public ColumnQRangeLoader(List<Integer> columns, Session session) { + super(columns, session, SQL_FIXING_COLUMN_Q_RANGES_BATCH); + } + + @Override + protected void fill(SQLQuery query) { + query + .addScalar("wst_column_id", StandardBasicTypes.INTEGER) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("start_km", StandardBasicTypes.DOUBLE) + .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + int lastId = Integer.MIN_VALUE; + List<double []> column = new ArrayList<double []>(); + + List<Object []> ranges = query.list(); + for (Object [] r: ranges) { + int cid = (Integer)r[0]; + + if (cid != lastId && !column.isEmpty()) { + cache(lastId, column); + column = new ArrayList<double []>(); + } + column.add(new double [] { + (Double)r[1], + (Double)r[2], + (Double)r[3] + }); + + lastId = cid; + } + + if (!column.isEmpty()) { + cache(lastId, column); + } + } + } // class ColumnQRangeLoader + + /** Helper class to store data from batching fixing columns. */ + private static final class FixColumn { + int columnId; + Date startTime; + String name; + + FixColumn(int columnId, Date startTime, String name) { + this.columnId = columnId; + this.startTime = startTime; + this.name = name; + } + } // class FixColumn + + public static final class FixColumnLoader + extends BatchLoader<List<FixColumn>> + { + public FixColumnLoader(List<Integer> columns, Session session) { + super(columns, session, SQL_FIXING_COLUMNS_BATCH); + } + + @Override + protected void fill(SQLQuery query) { + query + .addScalar("wst_id", StandardBasicTypes.INTEGER) + .addScalar("wst_column_id", StandardBasicTypes.INTEGER) + .addScalar("start_time", StandardBasicTypes.TIMESTAMP) + .addScalar("name", StandardBasicTypes.STRING); + + int lastId = Integer.MIN_VALUE; + List<FixColumn> cols = new ArrayList<FixColumn>(); + + List<Object []> columns = query.list(); + for (Object [] c: columns) { + int wid = (Integer)c[0]; + + if (wid != lastId && !cols.isEmpty()) { + cache(lastId, cols); + cols = new ArrayList<FixColumn>(); + } + cols.add(new FixColumn( + (Integer)c[1], + (Date) c[2], + (String) c[3])); + + lastId = wid; + } + if (!cols.isEmpty()) { + cache(lastId, cols); + } + } + } // class FixColumnLoader public static class QRange extends Range { @@ -255,34 +374,35 @@ } // for all Q ranges } - public void loadKmRange(SQLQuery query) { - query.setInteger("column_id", columnId); - - List<Object []> kms = query.list(); + public void loadKmRange(KMRangeLoader loader) { - if (kms.isEmpty()) { + double [] range = loader.get(columnId); + + if (range == null) { log.warn("No km range for column " + columnId + "."); + return; } - else { - Object [] obj = kms.get(0); - start = (Double)obj[0]; - end = (Double)obj[1]; - } + start = range[0]; + end = range[1]; } public void loadQRanges( - SQLQuery query, - GaugeFinder gaugeFinder + ColumnQRangeLoader loader, + GaugeFinder gaugeFinder ) { - query.setInteger("column_id", columnId); - List<Object []> list = query.list(); + List<double []> qrs = loader.get(columnId); + if (qrs == null) { + log.warn("No q ranges found for column " + columnId); + return; + } - List<QRange> qRanges = new ArrayList<QRange>(list.size()); + List<QRange> qRanges = new ArrayList<QRange>(qrs.size()); - for (Object [] row: list) { - double q = (Double)row[0]; - double start = (Double)row[1]; - double end = (Double)row[2]; + for (double [] qr: qrs) { + double q = qr[0]; + double start = qr[1]; + double end = qr[2]; + QRange qRange = new QRange(start, end, q); if (qRange.clip(this)) { qRanges.add(qRange); @@ -314,20 +434,26 @@ 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 allColumnIds(List<Integer> cIds) { + for (Column column: columns) { + cIds.add(column.columnId); } } - public void loadColumnsKmRange(SQLQuery query) { + public void loadColumns(FixColumnLoader loader) { + List<FixColumn> fcs = loader.get(wstId); + if (fcs == null) { + log.warn("No columns for wst " + wstId); + return; + } + for (FixColumn fc: fcs) { + columns.add(new Column(fc.columnId, fc.startTime, fc.name)); + } + } + + public void loadColumnsKmRange(KMRangeLoader loader) { for (Column column: columns) { - column.loadKmRange(query); + column.loadKmRange(loader); } } @@ -338,11 +464,11 @@ } public void loadColumnsQRanges( - SQLQuery query, - GaugeFinder gaugeFinder + ColumnQRangeLoader loader, + GaugeFinder gaugeFinder ) { for (Column column: columns) { - column.loadQRanges(query, gaugeFinder); + column.loadQRanges(loader, gaugeFinder); } } @@ -427,23 +553,40 @@ } 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); + + FixColumnLoader loader = new FixColumnLoader( + allFixingIds(), + session); for (Fixing fixing: fixings) { - fixing.loadColumns(query); + fixing.loadColumns(loader); } } + protected List<Integer> allFixingIds() { + List<Integer> ids = new ArrayList<Integer>(fixings.size()); + for (Fixing fixing: fixings) { + ids.add(fixing.getId()); + } + return ids; + } + + protected List<Integer> allColumnIds() { + List<Integer> cIds = new ArrayList<Integer>(); + for (Fixing fixing: fixings) { + fixing.allColumnIds(cIds); + } + return cIds; + } + protected void loadFixingsColumnsKmRange(Session session) { - SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE) - .addScalar("start_km", StandardBasicTypes.DOUBLE) - .addScalar("stop_km", StandardBasicTypes.DOUBLE); + + KMRangeLoader loader = new KMRangeLoader( + allColumnIds(), + session); for (Fixing fixing: fixings) { - fixing.loadColumnsKmRange(query); + fixing.loadColumnsKmRange(loader); } } @@ -451,13 +594,13 @@ 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); + + ColumnQRangeLoader loader = new ColumnQRangeLoader( + allColumnIds(), + session); for (Fixing fixing: fixings) { - fixing.loadColumnsQRanges(query, gaugeFinder); + fixing.loadColumnsQRanges(loader, gaugeFinder); } } @@ -627,14 +770,21 @@ protected Date end; public DateRangeFilter(Date start, Date end) { - this.start = start; - this.end = end; + if (start.before(end)) { + this.start = start; + this.end = end; + } + else { + this.start = end; + this.end = start; + } } @Override public boolean accept(Fixing.Column column) { Date date = column.getStartTime(); - return start.compareTo(date) <= 0 && end.compareTo(date) >= 0; + // start <= date <= end + return !(date.before(start) || date.after(end)); } } // class DateRangeFilter
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/ManagedFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/ManagedFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,7 +16,7 @@ import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.ArtifactNamespaceContext; import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; - +import org.dive4elements.river.utils.CompareUtil; /** * Facet with user-supplied theme-control-information (pos in list, @@ -140,5 +140,24 @@ return 0; } } + + /** + * Returns true if the other is likely the same facet. + * This happens if a facet is defined for two outs. + */ + public boolean isSame(Object other) { + if (!(other instanceof ManagedFacet)) { + return false; + } + ManagedFacet otherFacet = (ManagedFacet) other; + return this.getVisible() == otherFacet.getVisible() && + this.getActive() == otherFacet.getActive() && + CompareUtil.areSame(this.getArtifact(), otherFacet.getArtifact()) && + this.getIndex() == otherFacet.getIndex() && + CompareUtil.areSame(this.getName(), otherFacet.getName()) && + CompareUtil.areSame(this.getBoundToOut(), otherFacet.getBoundToOut()) && + CompareUtil.areSame(this.getDescription(), otherFacet.getDescription()); + // Missing properties are blackboard, data, position. + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java Fri Sep 27 17:36:50 2013 +0200 @@ -274,6 +274,18 @@ return list; } + private static List<ValueRange> filterByQValues(double[] values, List<ValueRange> ranges) { + List<ValueRange> list = new ArrayList<ValueRange>(ranges.size()); + for (ValueRange r: ranges) { + for (double val: values) { + if (r.sameValue(val) && !list.contains(r)) { + list.add(r); + } + } + } + return list; + } + private static boolean isQ(D4EArtifact artifact) { Boolean b = artifact.getDataAsBoolean("wq_isq"); return b != null && b; @@ -286,25 +298,23 @@ public static final Range Q_OUT_OF_RANGE = new Range(-10000, -9999); - private static Range singleQs(D4EArtifact artifact) { + private static double[] singleQs(D4EArtifact artifact) { String singleData = nn(artifact.getDataAsString("wq_single")); - double min = Double.MAX_VALUE; - double max = -Double.MAX_VALUE; + String[] values = singleData.split(" "); + double[] ret = new double[values.length]; + int i = 0; - for (String value: singleData.split(" ")) { + for (String value: values) { try { - double x = Double.parseDouble(value); - if (x < min) min = x; - if (x > max) max = x; + ret[i] = Double.parseDouble(value); } catch (NumberFormatException nfe) { + ret[i] = -1; // INVALID_Q_VALUE } + i++; } - return min == Double.MAX_VALUE - ? Q_OUT_OF_RANGE - : new Range(min, max); - + return ret; } private static Range qRange(D4EArtifact artifact) { @@ -383,21 +393,20 @@ return Collections.<ValueRange>emptyList(); } - Range qRange = isRange(artifact) - ? qRange(artifact) - : singleQs(artifact); - - if (qRange == Q_OUT_OF_RANGE) { - qRange = tripleQRange(artifact); + if (isRange(artifact)) { + Range qRange = qRange(artifact); + if (qRange == Q_OUT_OF_RANGE) { + qRange = tripleQRange(artifact); + } + ranges = filterByQRange(qRange, ranges); + if (debug) { + log.debug("Q range filter: " + qRange); + } + } else { + ranges = filterByQValues(singleQs(artifact), ranges); } if (debug) { - log.debug("Q range filter: " + qRange); - } - - ranges = filterByQRange(qRange, ranges); - - if (debug) { log.debug("After q range filter: " + ranges); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/QRangeTree.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/QRangeTree.java Fri Sep 27 17:36:50 2013 +0200 @@ -84,6 +84,7 @@ return m*pos + n; } + /** @param pos the station (km). */ public double findQ(double pos) { Node current = this; @@ -297,6 +298,7 @@ return max; } + /** @param pos the station (km). */ public double findQ(double pos) { return root != null ? root.findQ(pos) : Double.NaN; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/W.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/W.java Fri Sep 27 17:36:50 2013 +0200 @@ -109,7 +109,7 @@ } public boolean guessWaterIncreasing(float factor) { - return DataUtil.guessWaterIncreasing(ws, factor); + return DataUtil.guessDataIncreasing(ws, factor); } public int [] longestIncreasingWRangeIndices() {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKms.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKms.java Fri Sep 27 17:36:50 2013 +0200 @@ -24,5 +24,10 @@ TDoubleArrayList allWs(); boolean guessWaterIncreasing(); + + /** Guess if the Water flows from right to left. + * + * @return True if km's and ws's both grow in the same direction */ + boolean guessRTLData(); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKmsImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKmsImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -82,11 +82,16 @@ @Override public boolean guessWaterIncreasing() { - return guessWaterIncreasing(0.05f); + return guessDataIncreasing(0.05f); } - protected boolean guessWaterIncreasing(float factor) { - return DataUtil.guessWaterIncreasing(ws, factor); + protected boolean guessDataIncreasing(float factor) { + return DataUtil.guessDataIncreasing(ws, factor); + } + + @Override + public boolean guessRTLData() { + return DataUtil.guessSameDirectionData(ws, allKms()); } @Override
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WQKms.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WQKms.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.artifacts.model; +import org.dive4elements.river.utils.DataUtil; import org.dive4elements.river.utils.DoubleUtil; import gnu.trove.TDoubleArrayList; @@ -153,5 +154,10 @@ /* Behold the first km might be larger then the last! */ return new double[] {getKm(0), getKm(size()-1)}; } + + @Override + public boolean guessRTLData() { + return DataUtil.guessSameDirectionData(ws, allKms()); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java Fri Sep 27 17:36:50 2013 +0200 @@ -265,6 +265,7 @@ } double [] splineQs = new double[W]; + double [] splineWs = new double[W]; for (int i = 0; i < W; ++i) { double sq = table.getQIndex(i, km); @@ -273,12 +274,15 @@ km, "no.q.found.in.column", (i+1)); } splineQs[i] = sq; + splineWs[i] = ws[i]; } + DoubleUtil.sortByFirst(splineQs, splineWs); + try { SplineInterpolator interpolator = new SplineInterpolator(); PolynomialSplineFunction spline = - interpolator.interpolate(splineQs, ws); + interpolator.interpolate(splineQs, splineWs); return new SplineFunction(spline, splineQs, ws); } @@ -973,7 +977,7 @@ for (int col = 0; col < columns.length; col++) { qs[col] = columns[col].getQRangeTree().findQ(km); - if (startRow.km == km && startRow.ws[col] != Double.NaN) { + if (startRow.km == km && !Double.isNaN(startRow.ws[col])) { // Great. W is defined at km. ws[col] = startRow.ws[col]; continue; @@ -1275,6 +1279,27 @@ } + /** True if no QRange is given or Q equals zero. */ + public boolean hasEmptyQ() { + for (Column column: columns) { + if (column.getQRangeTree() == null) { + return true; + } + else { + if (Math.abs(column.getQRangeTree().maxQ()) <= 0.01d) { + return true; + } + } + } + + if (columns.length == 0) { + log.warn("No columns in WstValueTable."); + } + + return false; + } + + /** Find ranges that are between km1 and km2 (inclusive?) */ public List<Range> findSegments(double km1, double km2) { return columns.length != 0
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/ZoomScale.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/ZoomScale.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,6 +18,7 @@ import org.dive4elements.river.artifacts.math.Linear; +/** Has to do with adaptive smoothing based on current diagram extent. */ public class ZoomScale { private static Logger logger = Logger.getLogger(ZoomScale.class);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/DateUniqueMaker.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,41 @@ +package org.dive4elements.river.artifacts.model.fixings; + +import java.util.Date; + +import gnu.trove.TIntObjectHashMap; +import gnu.trove.TLongHashSet; + +public class DateUniqueMaker { + + private TLongHashSet times; + private TIntObjectHashMap already; + + public DateUniqueMaker() { + times = new TLongHashSet(); + already = new TIntObjectHashMap(); + } + + public <T extends QWI> void makeUnique(T t) { + + // Map same index to same new value + if (already.containsKey(t.index)) { + t.date = (Date)already.get(t.index); + return; + } + long time = t.date.getTime(); + if (!times.add(time)) { // same found before + do { + time += 30L*1000L; // Add 30secs + } + while (!times.add(time)); + Date newDate = new Date(time); + already.put(t.index, newDate); + // Write back modified time. + t.date = newDate; + } + else { + // register as seen. + already.put(t.index, t.date); + } + } +}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/Fitting.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/Fitting.java Fri Sep 27 17:36:50 2013 +0200 @@ -121,8 +121,9 @@ double maxQ = -Double.MAX_VALUE; if (referenced != null) { for (QWI qw: referenced) { - if (qw.getQ() > maxQ) { - maxQ = qw.getQ(); + double q = qw.getQ(); + if (q > maxQ) { + maxQ = q; } } }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java Fri Sep 27 17:36:50 2013 +0200 @@ -101,6 +101,15 @@ fitResult.getOutliers(), analysisPeriods); + // Workaraound to deal with same dates in data set + far.makeReferenceEventsDatesUnique(); + far.remapReferenceIndicesToRank(); + + far.makeAnalysisEventsUnique(); + for (int i = 0; i < this.analysisPeriods.length; ++i) { + far.remapAnalysisEventsIndicesToRank(i); + } + return new CalculationResult(far, this); } @@ -117,7 +126,7 @@ Function function, Parameters parameters, FixingsOverview overview, - ColumnCache cc + ColumnCache cc ) { Range range = new Range(from, to); @@ -141,15 +150,28 @@ TIntIntHashMap [] col2indices = new TIntIntHashMap[analysisPeriods.length]; + DateRangeFilter [] drfs = new DateRangeFilter[analysisPeriods.length]; + + boolean debug = log.isDebugEnabled(); + for (int i = 0; i < analysisPeriods.length; ++i) { col2indices[i] = new TIntIntHashMap(); + drfs[i] = new DateRangeFilter( + analysisPeriods[i].getFrom(), + analysisPeriods[i].getTo()); + + if (debug) { + log.debug("Analysis period " + (i+1) + " date range: " + + analysisPeriods[i].getFrom() + " - " + + analysisPeriods[i].getTo()); + } } 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. + // This is the parameterized function for a given km. org.dive4elements.river.artifacts.math.Function instance = function.instantiate(parameterValues); @@ -162,9 +184,7 @@ DateRange analysisPeriod = analysisPeriods[ap]; TIntIntHashMap col2index = col2indices[ap]; - DateRangeFilter drf = new DateRangeFilter( - analysisPeriod.getFrom(), - analysisPeriod.getTo()); + DateRangeFilter drf = drfs[ap]; QWD [] qSectorAverages = new QWD[4]; double [] qSectorStdDevs = new double[4]; @@ -282,8 +302,9 @@ parameters.set(row, maxQIndex, maxQ); } - results.add(km, periodResults.toArray( - new AnalysisPeriod[periodResults.size()])); + AnalysisPeriod [] rap = new AnalysisPeriod[periodResults.size()]; + periodResults.toArray(rap); + results.add(km, rap); } return results;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisEventsFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisEventsFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -64,48 +64,47 @@ public Object getData(Artifact artifact, CallContext context) { logger.debug("FixAnalysisEventsFacet.getData"); - if (artifact instanceof D4EArtifact) { - D4EArtifact flys = (D4EArtifact)artifact; - - CalculationResult res = - (CalculationResult) flys.compute(context, - ComputeType.ADVANCE, - false); - - FixAnalysisResult result = (FixAnalysisResult) res.getData(); - double currentKm = getCurrentKm(context); - - 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 { + if (!(artifact instanceof D4EArtifact)) { logger.debug("Not an instance of FixationArtifact."); return null; } + D4EArtifact flys = (D4EArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixAnalysisResult result = (FixAnalysisResult) res.getData(); + double currentKm = getCurrentKm(context); + + 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 (QWD qwd: qwdData) { + if (qwd.getIndex() == ndy) { + return qwd; + } + } + return null; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisResult.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisResult.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,10 +8,14 @@ package org.dive4elements.river.artifacts.model.fixings; +import gnu.trove.TIntObjectHashMap; + import java.util.Collection; import java.util.Date; +import java.util.TreeMap; import java.util.TreeSet; +import org.apache.log4j.Logger; import org.dive4elements.river.artifacts.model.Parameters; import org.dive4elements.river.utils.KMIndex; @@ -19,6 +23,9 @@ public class FixAnalysisResult extends FixResult { + private static Logger log = + Logger.getLogger(FixAnalysisResult.class); + protected KMIndex<AnalysisPeriod []> analysisPeriods; public FixAnalysisResult() { @@ -49,31 +56,70 @@ 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); + + public void makeAnalysisEventsUnique() { + TIntObjectHashMap dums = new TIntObjectHashMap(); + + for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) { + AnalysisPeriod [] aps = entry.getValue(); + for (int i = 0; i < aps.length; ++i) { + AnalysisPeriod ap = aps[i]; + QWD [] qwds = ap.getQWDs(); + if (qwds == null) { + continue; + } + DateUniqueMaker dum = (DateUniqueMaker)dums.get(i); + if (dum == null) { + dums.put(i, dum = new DateUniqueMaker()); + } + for (QWD qwd: qwds) { + dum.makeUnique(qwd); + } } } - 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); + if (qwds != null) { + for (QWD qwd: qwds) { + dates.add(qwd.date); + } } } return dates; } + public Collection<Integer> getAnalysisEventsIndices(int analysisPeriod) { + TreeMap<Date, Integer> dates = new TreeMap<Date, Integer>(); + for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) { + QWD [] qwds = entry.getValue()[analysisPeriod].getQWDs(); + if (qwds != null) { + for (QWD qwd: qwds) { + dates.put(qwd.date, qwd.index); + } + } + } + return dates.values(); + } + + public void remapAnalysisEventsIndicesToRank(int analysisPeriod) { + RankRemapper remapper = new RankRemapper(); + for (Integer index: getAnalysisEventsIndices(analysisPeriod)) { + remapper.toMap(index); + } + for (KMIndex.Entry<AnalysisPeriod []> entry: analysisPeriods) { + QWD [] qwds = entry.getValue()[analysisPeriod].getQWDs(); + if (qwds != null) { + for (QWD qwd: qwds) { + remapper.remap(qwd); + } + } + } + } + public KMIndex<AnalysisPeriod []> getAnalysisPeriods() { return analysisPeriods; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.java Fri Sep 27 17:36:50 2013 +0200 @@ -114,6 +114,10 @@ return index; } + public int getId() { + return meta.getId(); + } + public boolean getQW( double km, double [] qs, @@ -313,7 +317,7 @@ column.getDate(), interpolated[i], 0d, - column.getIndex()); + column.getId()); // Use database id here } } log.warn("cannot find column for (" + q + ", " + w + ")"); @@ -364,7 +368,9 @@ continue; } - referenced.add(km, fitting.referencedToArray()); + QWD [] refs = fitting.referencedToArray(); + + referenced.add(km, refs); if (fitting.hasOutliers()) { outliers.add(km, fitting.outliersToArray());
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixReferenceEventsFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixReferenceEventsFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -61,38 +61,36 @@ public Object getData(Artifact artifact, CallContext context) { logger.debug("FixReferenceEventsFacet.getData"); - if (artifact instanceof D4EArtifact) { - D4EArtifact flys = (D4EArtifact)artifact; - - CalculationResult res = - (CalculationResult) flys.compute(context, - ComputeType.ADVANCE, - false); - - FixResult result = (FixResult) res.getData(); - double currentKm = getCurrentKm(context); - - logger.debug("current km in FRE: " + currentKm); - - 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 { + if (!(artifact instanceof D4EArtifact)) { logger.debug("Not an instance of FixationArtifact."); return null; } + + D4EArtifact flys = (D4EArtifact)artifact; + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixResult result = (FixResult) res.getData(); + double currentKm = getCurrentKm(context); + + if (logger.isDebugEnabled()) { + logger.debug("current km in FRE: " + currentKm); + } + + KMIndex<QWD []> kmQWs = result.getReferenced(); + KMIndex.Entry<QWD []> kmQWsEntry = kmQWs.binarySearch(currentKm); + if (kmQWsEntry != null) { + int ndx = index & 255; + for (QWD qwd: kmQWsEntry.getValue()) { + if (qwd.getIndex() == ndx) { + return qwd; + } + } + } + return null; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixResult.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixResult.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,15 +8,23 @@ package org.dive4elements.river.artifacts.model.fixings; +import org.apache.log4j.Logger; import org.dive4elements.river.artifacts.model.Parameters; import org.dive4elements.river.utils.KMIndex; import java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.TreeMap; +import java.util.TreeSet; public class FixResult implements Serializable { + private static Logger log = + Logger.getLogger(FixResult.class); + protected Parameters parameters; protected KMIndex<QWD []> referenced; protected KMIndex<QWI []> outliers; @@ -42,6 +50,48 @@ this.referenced = referenced; } + public void makeReferenceEventsDatesUnique() { + DateUniqueMaker dum = new DateUniqueMaker(); + for (KMIndex.Entry<QWD []> entry: referenced) { + for (QWD ref: entry.getValue()) { + dum.makeUnique(ref); + } + } + } + + public Collection<Integer> getReferenceEventsIndices() { + TreeMap<Date, Integer> dates = new TreeMap<Date, Integer>(); + for (KMIndex.Entry<QWD []> entry: referenced) { + for (QWD value: entry.getValue()) { + dates.put(value.date, value.index); + } + } + return dates.values(); + } + + public void remapReferenceIndicesToRank() { + RankRemapper remapper = new RankRemapper(); + for (Integer idx: getReferenceEventsIndices()) { + remapper.toMap(idx); + } + for (KMIndex.Entry<QWD []> entry: referenced) { + for (QWD value: entry.getValue()) { + remapper.remap(value); + } + } + } + + public Collection<Date> getReferenceEventsDates() { + TreeSet<Date> dates = new TreeSet<Date>(); + for (KMIndex.Entry<QWD []> entry: referenced) { + for (QWD qwd: entry.getValue()) { + dates.add(qwd.date); + } + } + return dates; + } + + public KMIndex<QWI []> getOutliers() { return outliers; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixWQCurveFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixWQCurveFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -66,57 +66,57 @@ */ @Override public Object getData(Artifact artifact, CallContext context) { - logger.debug("getData"); - if (artifact instanceof D4EArtifact) { - D4EArtifact flys = (D4EArtifact)artifact; - FixAnalysisAccess access = new FixAnalysisAccess(flys); - - CalculationResult res = - (CalculationResult) flys.compute(context, - ComputeType.ADVANCE, - false); - - FixResult result = (FixResult) res.getData(); - double currentKm = getCurrentKm(context); - - 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; - } - - org.dive4elements.river.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("getData"); + if (!(artifact instanceof D4EArtifact)) { logger.debug("Not an instance of D4EArtifact / FixationArtifact."); return null; } + + D4EArtifact flys = (D4EArtifact)artifact; + FixAnalysisAccess access = new FixAnalysisAccess(flys); + + CalculationResult res = + (CalculationResult) flys.compute(context, + ComputeType.ADVANCE, + false); + + FixResult result = (FixResult) res.getData(); + double currentKm = getCurrentKm(context); + + 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; + } + + org.dive4elements.river.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; } /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/RankRemapper.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,44 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.model.fixings; + +import java.util.IdentityHashMap; + +import org.apache.log4j.Logger; + +import gnu.trove.TIntIntHashMap; + +public class RankRemapper { + + private static Logger log = Logger.getLogger(RankRemapper.class); + + private TIntIntHashMap index2rank; + private IdentityHashMap<QWI, Boolean> visited; + + public RankRemapper() { + index2rank = new TIntIntHashMap(); + visited = new IdentityHashMap<QWI, Boolean>(); + } + + public void toMap(int index) { + index2rank.put(index, index2rank.size()); + } + + public <I extends QWI> void remap(I qwi) { + if (!visited.containsKey(qwi)) { + int idx = qwi.index; + if (index2rank.containsKey(idx)) { + qwi.index = index2rank.get(idx); + } else if (log.isDebugEnabled()) { + log.debug("Cannot remap " + idx); + } + visited.put(qwi, true); + } + } +}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffCalculation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffCalculation.java Fri Sep 27 17:36:50 2013 +0200 @@ -180,3 +180,4 @@ s2.getName()); } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearFilterFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearFilterFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -50,6 +50,7 @@ Double end = (Double)context.getContextValue("endkm"); if(start != null && end != null) { RiverContext fc = (RiverContext)context.globalContext(); + // Adaptive smoothing, based on zoom factor/diagram extents. ZoomScale scales = (ZoomScale)fc.get("zoomscale"); RiverAccess access = new RiverAccess((D4EArtifact)artifact); String river = access.getRiver();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearResult.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearResult.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,10 +11,10 @@ import gnu.trove.TDoubleArrayList; +/** Result of a bed diff year calculation. */ public class BedDiffYearResult extends BedDifferencesResult { - protected TDoubleArrayList bedHeights; protected TDoubleArrayList dataGap; protected TDoubleArrayList morphWidth; @@ -115,3 +115,4 @@ }; } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedHeightFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedHeightFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -24,6 +24,8 @@ import org.dive4elements.river.artifacts.model.StaticBedHeightCacheKey; import org.dive4elements.river.backend.SessionHolder; + +/** Create BedHeights from database. */ public class BedHeightFactory { /** Private logger to use here. */ private static Logger log = Logger.getLogger(BedHeightFactory.class);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/FlowVelocityMeasurementFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/FlowVelocityMeasurementFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,12 +8,15 @@ package org.dive4elements.river.artifacts.model.minfo; +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.dive4elements.river.model.FlowVelocityMeasurementValue; import org.dive4elements.river.backend.SessionHolder; @@ -40,7 +43,13 @@ log.debug("FlowVelocityMeasurementFactory.getFlowVelocityMeasurementValue"); Session session = SessionHolder.HOLDER.get(); SQLQuery sqlQuery = null; - sqlQuery = session.createSQLQuery(SQL_SELECT_ONE); + sqlQuery = session.createSQLQuery(SQL_SELECT_ONE) + .addScalar("station", StandardBasicTypes.DOUBLE) + .addScalar("datetime", StandardBasicTypes.DATE) + .addScalar("w", StandardBasicTypes.DOUBLE) + .addScalar("q", StandardBasicTypes.DOUBLE) + .addScalar("v", StandardBasicTypes.DOUBLE) + .addScalar("description", StandardBasicTypes.STRING); sqlQuery.setParameter("id", id); List<Object []> results = sqlQuery.list(); @@ -50,10 +59,12 @@ return null; } return FlowVelocityMeasurementValue.getUnmapped( - Double.parseDouble(row[0].toString()), - Double.parseDouble(row[2].toString()), - Double.valueOf(row[3].toString()), - Double.valueOf(row[4].toString()), null, row[5].toString()); + (Double) row[0], + (Double) row[2], + (Double) row[3], + (Double) row[4], + (Date) row[1], + (String) row[5]); } return null; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurement.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurement.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,8 +11,11 @@ import java.util.Date; import java.util.Map; +import org.apache.log4j.Logger; +/** A measurement of the bed quality, serving different diameter at given km. */ public class QualityMeasurement { + private static Logger logger = Logger.getLogger(QualityMeasurements.class); private double km; private Date date; @@ -20,7 +23,7 @@ private double depth2; private Map<String, Double> charDiameter; - public QualityMeasurement() { + private QualityMeasurement() { } @@ -61,8 +64,16 @@ this.charDiameter = charDiameter; } + /** + * Get the stored diameter for given key (e.g. d10). + * @return NaN if no data found in this measurement. + */ public double getDiameter(String key) { - return charDiameter.get(key); + Double diameter = charDiameter.get(key); + if (diameter == null) { + logger.warn("No Diameter at km " + km + " for " + key); + } + return (diameter != null) ? diameter : Double.NaN; } public void setDiameter(String key, double value) {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -86,14 +86,18 @@ " m.datum BETWEEN :start AND :end " + "ORDER BY m.km"; + /** Transform query result into objects, use INSTANCE singleton. */ public static final class QualityMeasurementResultTransformer extends BasicTransformerAdapter { - public static QualityMeasurementResultTransformer INSTANCE = new QualityMeasurementResultTransformer(); + // Make a singleton + public static QualityMeasurementResultTransformer INSTANCE = + new QualityMeasurementResultTransformer(); - public QualityMeasurementResultTransformer() { + private QualityMeasurementResultTransformer() { } + /** tuples is a row. */ @Override public Object transformTuple(Object[] tuple, String[] aliases) { Map<String, Double> map = new HashMap<String, Double>(); @@ -172,6 +176,7 @@ return new QualityMeasurements(query.list()); } + /** Get all measurements. */ public static QualityMeasurements getBedMeasurements( String river, double from,
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurements.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurements.java Fri Sep 27 17:36:50 2013 +0200 @@ -56,3 +56,4 @@ this.measurements.add(qm); } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensity.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensity.java Fri Sep 27 17:36:50 2013 +0200 @@ -65,23 +65,25 @@ this.years = years; } + /** + * Get the density at year. + * measured densities are valid until the next measurement. + * if no measurement was found 1.8 is returned. + */ public double getDensity(double km, int year) { Collections.sort(this.years); - if (this.years.size() == 1) { - return getDensityAtKm(densities.get(year), km); + if (this.years.size() == 1 && years.get(0) <= year) { + logger.debug("get density from year " + year + " at km " + km); + return getDensityAtKm(densities.get(years.get(0)), km); } - else { + else if (this.years.size() > 1) { for (int i = 0; i < years.size() -1; i++) { int y1 = years.get(i); int y2 = years.get(i + 1); - int mid = Math.round((y1 + y2) / 2); - if (year < mid) { + if (year >= y1 && year < y2) { return getDensityAtKm(densities.get(y1), km); } - else if (i == years.size() -1) { - continue; - } - else { + else if (year >= y2 && i == years.size() -1) { return getDensityAtKm(densities.get(y2), km); } } @@ -93,15 +95,12 @@ List<SedimentDensityValue> values, double km ) { - boolean found = true; SedimentDensityValue prev = null; SedimentDensityValue next = null; for (SedimentDensityValue sdv: values) { -logger.debug("year: " + sdv.getYear()); - if (sdv.getKm() == km) { - prev = sdv; - found = true; - break; + logger.debug("year: " + sdv.getYear()); + if (Math.abs(sdv.getKm() - km) < 0.00001) { + return prev.getDensity(); } if (sdv.getKm() > km) { next = sdv; @@ -109,32 +108,39 @@ } prev = sdv; } - if (found) { - return prev.getDensity(); - } - else { - return spline(prev, next, km); - } + return spline(prev, next, km); } - private double spline( + private static double spline( SedimentDensityValue prev, SedimentDensityValue next, double km ) { + if (prev == null && next == null) { + logger.warn("prev and next are null -> NaN"); + return Double.NaN; + } + + if (prev == null) return next.getDensity(); + if (next == null) return prev.getDensity(); + + // XXX: This is no spline interpolation! double lower = prev.getKm(); double upper = next.getKm(); double upperDensity = next.getDensity(); double lowerDensity = prev.getDensity(); - double m =(upperDensity - lowerDensity)/(upper - lower) * km; - double b = lowerDensity - - ((upperDensity - lowerDensity)/(upper - lower) * lower); - return (m * km) + b; + double m = (upperDensity - lowerDensity)/(upper - lower); + double b = lowerDensity - (m * lower); + return m * km + b; } + + /** If multiple values for same year and station are found, + * build and store average, dismiss multiple values. */ public void cleanUp() { Set<Integer> keys = densities.keySet(); + // Walk over years for (Integer key : keys) { List<SedimentDensityValue> list = densities.get(key); if (list.size() == 0) { @@ -146,6 +152,7 @@ int counter = 0; double sum = 0d; for (SedimentDensityValue value : list) { + // Apparently we can assume that values are ordered by km. if (value.getKm() == prevkm) { sum += value.getDensity(); counter++; @@ -164,3 +171,4 @@ } } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -79,14 +79,13 @@ int year ) { log.debug("getSedimentDensityUncached"); - List<Object[]> results = null; Session session = SessionHolder.HOLDER.get(); SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_DENSITY) .addScalar("km", StandardBasicTypes.DOUBLE) .addScalar("density", StandardBasicTypes.DOUBLE) .addScalar("year", StandardBasicTypes.INTEGER); sqlQuery.setString("name", river); - results = sqlQuery.list(); + List<Object[]> results = sqlQuery.list(); SedimentDensity density = new SedimentDensity(); for (Object[] row : results) { if (row[0] != null && row[1] != null && row[2] != null) { @@ -98,3 +97,4 @@ return density; } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityValue.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityValue.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,7 +8,7 @@ package org.dive4elements.river.artifacts.model.minfo; - +/** A density value at a km, year. */ public class SedimentDensityValue {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoad.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoad.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,27 +9,35 @@ package org.dive4elements.river.artifacts.model.minfo; import java.util.Date; -import java.util.HashMap; +import java.util.Map; import java.util.Set; +import java.util.TreeMap; import org.dive4elements.river.artifacts.model.NamedObjectImpl; import org.dive4elements.river.artifacts.model.Range; +import org.dive4elements.river.utils.EpsilonComparator; + +import org.apache.log4j.Logger; /** Gives access to Fractions (at kms). */ public class SedimentLoad extends NamedObjectImpl { + /** Private logger. */ + private static final Logger logger = Logger + .getLogger(SedimentLoad.class); + protected String description; protected Date start; protected Date end; protected boolean isEpoch; protected String unit; - protected HashMap<Double, SedimentLoadFraction> kms; + protected Map<Double, SedimentLoadFraction> kms; public SedimentLoad() { - kms = new HashMap<Double, SedimentLoadFraction>(); + kms = new TreeMap<Double, SedimentLoadFraction>(EpsilonComparator.CMP); } public SedimentLoad( @@ -88,124 +96,107 @@ } public SedimentLoadFraction getFraction(double km) { - if (kms.get(km) == null) { - return new SedimentLoadFraction(); + SedimentLoadFraction f = kms.get(km); + if (f == null) { + f = new SedimentLoadFraction(); + kms.put(km, f); } - return kms.get(km); + return f; } public void setCoarse(double km, double coarse, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setCoarse(coarse); + if (range == null) { + logger.error("coarse/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setCoarse(coarse); - f.setCoarseRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setCoarse(coarse); + f.setCoarseRange(range); } public void setFineMiddle(double km, double fine_middle, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setFineMiddle(fine_middle); - kms.get(km).setFineMiddleRange(range); + if (range == null) { + logger.error("finemiddle/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setFineMiddle(fine_middle); - f.setFineMiddleRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setFineMiddle(fine_middle); + f.setFineMiddleRange(range); } + public void setSand(double km, double sand, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setSand(sand); - kms.get(km).setSandRange(range); + if (range == null) { + logger.error("sand/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setSand(sand); - f.setSandRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setSand(sand); + f.setSandRange(range); } public void setSuspSand(double km, double susp_sand, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setSuspSand(susp_sand); - kms.get(km).setSuspSandRange(range); + if (range == null) { + logger.error("suspsand/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setSuspSand(susp_sand); - f.setSuspSandRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setSuspSand(susp_sand); + f.setSuspSandRange(range); } public void setSuspSandBed(double km, double susp_sand_bed, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setSuspSandBed(susp_sand_bed); - kms.get(km).setSuspSandBedRange(range); + if (range == null) { + logger.error("suspsandbed/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setSuspSandBed(susp_sand_bed); - f.setSuspSandBedRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setSuspSandBed(susp_sand_bed); + f.setSuspSandBedRange(range); } public void setSuspSediment(double km, double susp_sediment, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setSuspSediment(susp_sediment); - kms.get(km).setSuspSedimentRange(range); + if (range == null) { + logger.error("suspsed/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setSuspSediment(susp_sediment); - f.setSuspSedimentRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setSuspSediment(susp_sediment); + f.setSuspSedimentRange(range); } public void setLoadTotal(double km, double total) { - if (kms.containsKey(km)) { - kms.get(km).setLoadTotal(total); + setLoadTotal(km, total, null); + } + + public void setLoadTotal(double km, double total, Range range) { + if (range == null) { + logger.error("loadtotal/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setLoadTotal(total); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setLoadTotal(total); + f.setLoadTotalRange(range); } public void setTotal(double km, double total, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setTotal(total); - kms.get(km).setTotalRange(range); + if (range == null) { + logger.error("total/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setTotal(total); - f.setTotalRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setTotal(total); + f.setTotalRange(range); } public void setUnknown(double km, double unknown, Range range) { - if (kms.containsKey(km)) { - kms.get(km).setUnknown(unknown); - kms.get(km).setUnknownRange(range); + if (range == null) { + logger.error("unknown/range is null!"); + return; } - else { - SedimentLoadFraction f = new SedimentLoadFraction(); - f.setUnknown(unknown); - f.setUnknownRange(range); - kms.put(km, f); - } + SedimentLoadFraction f = getFraction(km); + f.setUnknown(unknown); + f.setUnknownRange(range); } public String getUnit() {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadCalculation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadCalculation.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,7 +11,6 @@ import gnu.trove.TDoubleArrayList; import java.util.ArrayList; -import java.util.TreeSet; import java.util.List; import org.apache.log4j.Logger; @@ -122,9 +121,99 @@ return new CalculationResult( results.toArray(new SedimentLoadResult[results.size()]), this); } + else { + logger.error("Unknown mode " + yearEpoch); + } return null; } + + /** Returns val if not NaN, 0d otherwise. */ + private static double makeNaN0(double val) { + return Double.isNaN(val) + ? 0d + : val; + } + + /** + * Take Loads and build average of all fractions at given km. + * The average fractions value is set in resLoad. + * + * @param km km at which to build fractions average. + * @param epochLoads the loads to build average over. + * @param[out] resLoad resulting SedimentLoad. + */ + private void calculateEpochKm( + List<SedimentLoad> epochLoads, + SedimentLoad resLoad, + double km + ) { + int cSum = 0; + int fmSum = 0; + int sSum = 0; + int ssSum = 0; + int ssbSum = 0; + int sseSum = 0; + for (SedimentLoad load : epochLoads) { + SedimentLoadFraction f = load.getFraction(km); + if (f.getCoarse() > 0d) { + double c = makeNaN0(resLoad.getFraction(km).getCoarse()); + resLoad.setCoarse(km, c + f.getCoarse(), f.getCoarseRange()); + cSum++; + } + if (f.getFineMiddle() > 0d) { + double fm = makeNaN0(resLoad.getFraction(km).getFineMiddle()); + resLoad.setFineMiddle(km, fm + f.getFineMiddle(), f.getFineMiddleRange()); + fmSum++; + } + if (f.getSand() > 0d) { + double s = makeNaN0(resLoad.getFraction(km).getSand()); + resLoad.setSand(km, s + f.getSand(), f.getSandRange()); + sSum++; + } + if (f.getSuspSand() > 0d) { + double s = makeNaN0(resLoad.getFraction(km).getSuspSand()); + resLoad.setSuspSand(km, s + f.getSuspSand(), f.getSuspSandRange()); + ssSum++; + } + if (f.getSuspSandBed() > 0d) { + double s = makeNaN0(resLoad.getFraction(km).getSuspSandBed()); + resLoad.setSuspSandBed(km, s + f.getSuspSandBed(), f.getSuspSandBedRange()); + ssbSum++; + } + if (f.getSuspSediment() > 0d) { + double s = makeNaN0(resLoad.getFraction(km).getSuspSediment()); + resLoad.setSuspSediment(km, s + f.getSuspSediment(), f.getSuspSedimentRange()); + sseSum++; + } + } + + SedimentLoadFraction fr = resLoad.getFraction(km); + // Prevent divisions by zero. + if (cSum != 0) { + resLoad.setCoarse(km, fr.getCoarse()/cSum, fr.getCoarseRange()); + } + if (fmSum != 0) { + resLoad.setFineMiddle(km, fr.getFineMiddle()/fmSum, + fr.getFineMiddleRange()); + } + if (sSum != 0) { + resLoad.setSand(km, fr.getSand()/sSum, fr.getSandRange()); + } + if (ssSum != 0) { + resLoad.setSuspSand(km, fr.getSuspSand()/ssSum, + fr.getSuspSandRange()); + } + if (ssbSum != 0) { + resLoad.setSuspSandBed(km, fr.getSuspSandBed()/ssbSum, + fr.getSuspSandBedRange()); + } + if (sseSum != 0) { + resLoad.setSuspSediment(km, fr.getSuspSediment()/sseSum, fr.getSuspSedimentRange()); + } + } + + /** Calculate result for an epoch. */ private SedimentLoadResult calculateEpoch(int i) { List<SedimentLoad> epochLoads = new ArrayList<SedimentLoad>(); for (int j = epoch[i][0]; j < epoch[i][1]; j++) { @@ -133,8 +222,8 @@ this.yearEpoch, this.kmLow, this.kmUp, - j, - j)); + j, //syear + j)); //eyear } SedimentLoad resLoad = new SedimentLoad(); @@ -149,93 +238,27 @@ } for (int j = 0; j < kms.size(); j++) { - int cSum = 0; - int fmSum = 0; - int sSum = 0; - int ssSum = 0; - int ssbSum = 0; - int sseSum = 0; - double km = kms.get(j); - for (SedimentLoad load : epochLoads) { - SedimentLoadFraction f = load.getFraction(km); - if (f.getCoarse() > 0d) { - double c = resLoad.getFraction(km).getCoarse(); - resLoad.setCoarse(km, c + f.getCoarse(), f.getCoarseRange()); - cSum++; - } - if (f.getFineMiddle() > 0d) { - double fm = resLoad.getFraction(km).getFineMiddle(); - resLoad.setFineMiddle(km, fm + f.getFineMiddle(), f.getFineMiddleRange()); - fmSum++; - } - if (f.getSand() > 0d) { - double s = resLoad.getFraction(km).getSand(); - resLoad.setSand(km, s + f.getSand(), f.getSandRange()); - sSum++; - } - if (f.getSuspSand() > 0d) { - double s = resLoad.getFraction(km).getSuspSand(); - resLoad.setSuspSand(km, s + f.getSuspSand(), f.getSuspSandRange()); - ssSum++; - } - if (f.getSuspSandBed() > 0d) { - double s = resLoad.getFraction(km).getSuspSandBed(); - resLoad.setSuspSandBed(km, s + f.getSuspSandBed(), f.getSuspSandBedRange()); - ssbSum++; - } - if (f.getSuspSediment() > 0d) { - double s = resLoad.getFraction(km).getSuspSediment(); - resLoad.setSuspSediment(km, s + f.getSuspSediment(), f.getSuspSedimentRange()); - sseSum++; - } - } - SedimentLoadFraction fr = resLoad.getFraction(km); - // Prevent divisions by zero, the fraction defaults to 0d. - if (cSum != 0) { - resLoad.setCoarse(km, fr.getCoarse()/cSum, fr.getCoarseRange()); - } - if (fmSum != 0) { - resLoad.setFineMiddle(km, fr.getFineMiddle()/fmSum, - fr.getFineMiddleRange()); - } - if (sSum != 0) { - resLoad.setSand(km, fr.getSand()/sSum, fr.getSandRange()); - } - if (ssSum != 0) { - resLoad.setSuspSand(km, fr.getSuspSand()/ssSum, - fr.getSuspSandRange()); - } - if (ssbSum != 0) { - resLoad.setSuspSandBed(km, fr.getSuspSandBed()/ssbSum, - fr.getSuspSandBedRange()); - } - if (sseSum != 0) { - resLoad.setSuspSediment(km, fr.getSuspSediment()/sseSum, fr.getSuspSedimentRange()); - } + calculateEpochKm(epochLoads, resLoad, kms.get(j)); } resLoad.setDescription(""); resLoad.setEpoch(true); - SedimentLoadResult result; SedimentLoad sl = calculateTotalLoad(resLoad, this.epoch[i][0]); + if (this.unit.equals("m3_per_a")) { - SedimentLoad slu = calculateUnit(sl, this.epoch[i][0]); - result = new SedimentLoadResult( - this.epoch[i][0], - this.epoch[i][1], - slu); - } - else { - result = new SedimentLoadResult( - this.epoch[i][0], - this.epoch[i][1], - sl); + sl = calculateUnit(sl, this.epoch[i][0]); } - return result; + return new SedimentLoadResult( + this.epoch[i][0], + this.epoch[i][1], + sl); } - /** Calculate/Fetch values at off. epochs. */ + /** + * Calculate/Fetch values at off. epochs. + * @param i index in epochs. + */ private SedimentLoadResult calculateOffEpoch(int i) { SedimentLoad load = SedimentLoadFactory.getLoadWithData( this.river, @@ -321,35 +344,6 @@ } - /** Returns true if all fraction values except SuspSediment are unset. */ - private boolean hasOnlySuspValues(SedimentLoadFraction fraction) { - return (fraction.getSuspSediment() != 0d && - fraction.getCoarse() == 0d && - fraction.getFineMiddle() == 0d && - fraction.getSand() == 0d && - fraction.getSuspSand() == 0d); - } - - - /** Returns true if all fraction values except SuspSediment are set. */ - private boolean hasButSuspValues(SedimentLoadFraction fraction) { - return (fraction.getSuspSediment() == 0d && - fraction.getCoarse() != 0d && - fraction.getFineMiddle() != 0d && - fraction.getSand() != 0d && - fraction.getSuspSand() != 0d); - } - - - /** Returns true if all fraction needed for total calculation are set. */ - private boolean complete(SedimentLoadFraction fraction) { - return (fraction.getCoarse() != 0d && - fraction.getFineMiddle() != 0d && - fraction.getSand() != 0d && - fraction.getSuspSand() != 0d && - fraction.getSuspSediment() != 0d); - } - /** * Set total values in load. @@ -364,6 +358,7 @@ * @return input param load, with total values set. */ private SedimentLoad partialTotal(SedimentLoad load) { + // The load with balanced ranges, will be returned. SedimentLoad fairLoad = load; Range lastOtherRange = null; @@ -372,12 +367,10 @@ Range lastSuspRange = null; double lastSuspValue = 0d; - TreeSet<Double> kms = new TreeSet<Double>(load.getKms()); - - for (double km: kms) { + for (double km: load.getKms()) { // kms are already sorted! logger.debug ("Trying to add at km " + km); SedimentLoadFraction fraction = load.getFraction(km); - if (complete(fraction)) { + if (fraction.isComplete()) { double total = fraction.getCoarse() + fraction.getFineMiddle() + fraction.getSand() + @@ -405,7 +398,7 @@ else { // Geschiebe is longer. // Adjust and remember other values. - lastOtherRange = (Range) fraction.getSuspSedimentRange().clone(); + lastOtherRange = (Range) fraction.getCoarseRange().clone(); lastOtherRange.setStart(fraction.getSuspSedimentRange().getEnd()); lastOtherValue = (total - fraction.getSuspSediment()); lastSuspRange = null; @@ -413,7 +406,7 @@ } } } - else if (hasOnlySuspValues(fraction) && lastOtherRange != null) { + else if (fraction.hasOnlySuspValues() && lastOtherRange != null) { // Split stuff. Range suspSedimentRange = fraction.getSuspSedimentRange(); // if intersects with last other range, cool! merge and add! @@ -438,11 +431,12 @@ lastOtherRange.setStart(suspSedimentRange.getEnd()); lastSuspRange = null; } - if (Math.abs(suspSedimentRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) { + if (lastOtherRange != null + && Math.abs(suspSedimentRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) { lastOtherRange = null; lastSuspRange = null; } - fairLoad.setTotal(km, total + fraction.getSuspSediment(), totalRange); + fairLoad.setTotal(km, total, totalRange); } else { lastSuspRange = suspSedimentRange; @@ -450,7 +444,7 @@ lastOtherRange = null; } } - else if (hasButSuspValues(fraction) && lastSuspRange != null) { + else if (fraction.hasButSuspValues() && lastSuspRange != null) { // If intersects with last suspsed range, merge and add double total = fraction.getCoarse() + fraction.getFineMiddle() + @@ -475,7 +469,9 @@ lastSuspRange = null; lastOtherValue = total - lastSuspValue; } - if (lastSuspRange != null && Math.abs(lastSuspRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) { + if (lastSuspRange != null + && lastOtherRange != null + && Math.abs(lastSuspRange.getEnd() - lastOtherRange.getEnd()) < 0.1d) { lastOtherRange = null; lastSuspRange = null; } @@ -491,7 +487,7 @@ else { // Some values are missing or no intersection with former values. // Stay as we are. - if (hasButSuspValues(fraction)) { + if (fraction.hasButSuspValues()) { double total = fraction.getCoarse() + fraction.getFineMiddle() + fraction.getSand() + @@ -500,7 +496,7 @@ lastOtherValue = total; lastSuspRange = null; } - else if (hasOnlySuspValues(fraction)) { + else if (fraction.hasOnlySuspValues()) { lastSuspRange = fraction.getSuspSedimentRange(); lastSuspValue = fraction.getSuspSediment(); lastOtherRange = null; @@ -513,12 +509,18 @@ /** * Transform values in load. + * Background is to transform values measured in + * t/a to m^3/a using the specific measured densities. + * * @param load The load of which values should be transformed. + * @param year The year at which to look at density (e.g. 2003). + * * @return parameter load with transformed values. */ private SedimentLoad calculateUnit(SedimentLoad load, int year) { SedimentDensity density = SedimentDensityFactory.getSedimentDensity(river, kmLow, kmUp, year); + for (double km: load.getKms()) { double dens = density.getDensity(km, year); SedimentLoadFraction fraction = load.getFraction(km); @@ -529,6 +531,7 @@ double bedSand = fraction.getSuspSandBed(); double sediment = fraction.getSuspSediment(); double total = fraction.getTotal(); + double loadTotal = fraction.getLoadTotal(); load.setCoarse(km, (coarse * dens), fraction.getCoarseRange()); load.setFineMiddle(km, (fineMiddle * dens), fraction.getFineMiddleRange()); load.setSand(km, (sand * dens), fraction.getSandRange()); @@ -536,6 +539,7 @@ load.setSuspSandBed(km, (bedSand * dens), fraction.getSuspSandBedRange()); load.setSuspSediment(km, (sediment * dens), fraction.getSuspSedimentRange()); load.setTotal(km, (total * dens), fraction.getTotalRange()); + load.setLoadTotal(km, (loadTotal * dens), fraction.getLoadTotalRange()); } return load; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.TreeSet; import java.util.TreeMap; import org.apache.log4j.Logger; @@ -105,7 +106,7 @@ TDoubleArrayList xPos = new TDoubleArrayList(); TDoubleArrayList yPos = new TDoubleArrayList(); double lastX = -1d; - for (double km: load.getKms()) { + for (double km: new TreeSet<Double>(load.getKms())) { SedimentLoadFraction fraction = load.getFraction(km); if (fraction.getTotal() != 0) { if (Math.abs(lastX-km) >= EPSILON) {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -54,6 +54,13 @@ " AND ti.stop_time IS NULL " + " AND syv.station BETWEEN :startKm AND :endKm"; + /** Query to get description of single sediment_yield. */ + public static final String SQL_SELECT_SINGLE_BY_ID = + "SELECT DISTINCT " + + " sy.description AS description " + + " FROM sediment_yield sy " + + " WHERE sy.id = :id "; + /** Query to get description, name and time range for official * epoch-type sediment yields. */ public static final String SQL_SELECT_OFFEPOCHS = @@ -86,6 +93,20 @@ " AND ti.stop_time IS NOT NULL " + " AND syv.station BETWEEN :startKm AND :endKm"; + public static final String SQL_SELECT_SINGLES_DATA_BY_ID = + "SELECT" + + " sy.description AS description, " + + " syv.value AS load, " + + " syv.station AS km, " + + " u.name AS unit, " + + " gf.name AS fraction " + + " FROM sediment_yield sy " + + " JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " + + " JOIN units u ON u.id = sy.unit_id" + + " JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " + + " WHERE sy.id = :id" + + " ORDER BY syv.station"; + public static final String SQL_SELECT_SINGLES_DATA = "SELECT" + " sy.description AS description, " + @@ -137,6 +158,7 @@ " JOIN units u ON sy.unit_id = u.id " + "WHERE r.name = :river " + " AND gf.name = 'unknown' " + + " AND sy.kind = :type " + " AND u.name = :unit"; public static final String SQL_SELECT_EPOCHS_DATA = @@ -204,7 +226,8 @@ /** * Get a sedimentLoad filled with data from db (or cache). - * @param type "epoch","off_epoch" or "single" + * @param type "epoch", "off_epoch" or "single" + * @return A Sedimentload filled with values from db or cache. */ public static SedimentLoad getLoadWithData( String river, @@ -247,7 +270,7 @@ eyear); if (values != null && key != null) { - log.debug("Store static bed height values in cache."); + log.debug("Store sediment loads in cache."); element = new Element(key, values); cache.put(element); } @@ -255,6 +278,26 @@ } /** + * Get sediment load description. + * @param id the sediment yield by id. + * @return sediment yields description + */ + public static String getSedimentYieldDescription(int id) { + log.debug("SedimentLoadFactory.getSedimentYieldDescription"); + + Session session = SessionHolder.HOLDER.get(); + SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLE_BY_ID) + .addScalar("description", StandardBasicTypes.STRING); + sqlQuery.setDouble("id", id); + + List<Object> results = sqlQuery.list(); + + return (String) results.get(0); + + } + + + /** * Get sediment loads from db. * @param river the river * @param type the sediment load type (year or epoch) @@ -341,9 +384,106 @@ } /** + * Get a specific sediment load from db. + * + * @param id the sediment yields id. + * + * @return according sediment load. + */ + public static SedimentLoad getSedimentLoadWithDataUncached( + String id, + String river + ) { + log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached / id " + id); + Session session = SessionHolder.HOLDER.get(); + SQLQuery sqlQuery = null; + + // Measurement stations: all, for float-stuff, for suspended stuff. + // Because they need fast sorted access, use TreeMaps. + // They map the starting validity range km to the station itself. + List<MeasurementStation> allStations = + RiverFactory.getRiver(river).getMeasurementStations(); + TreeMap<Double,MeasurementStation> floatStations = + new TreeMap<Double, MeasurementStation>(); + TreeMap<Double,MeasurementStation> suspStations = + new TreeMap<Double, MeasurementStation>(); + + // From all stations, sort into the two kinds, skip undefined ones. + for (MeasurementStation measurementStation: allStations) { + if (measurementStation.getMeasurementType() == null || + measurementStation.getRange() == null) { + continue; + } + if (measurementStation.getMeasurementType().equals("Schwebstoff")) { + suspStations.put( + measurementStation.getRange().getA().doubleValue(), + measurementStation); + } + else if (measurementStation.getMeasurementType().equals("Geschiebe")) { + floatStations.put( + measurementStation.getRange().getA().doubleValue(), + measurementStation); + } + } + + sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES_DATA_BY_ID) + .addScalar("description", StandardBasicTypes.STRING) + .addScalar("load", StandardBasicTypes.DOUBLE) + .addScalar("km", StandardBasicTypes.DOUBLE) + .addScalar("fraction", StandardBasicTypes.STRING) + .addScalar("unit", StandardBasicTypes.STRING); + sqlQuery.setInteger("id", Integer.valueOf(id)); + + List<Object []> results = sqlQuery.list(); + SedimentLoad load = new SedimentLoad(); + if (results.isEmpty()) { + log.warn("Empty result for year calculation."); + } + else { + Object[] row = results.get(0); + load = new SedimentLoad( + (String) row[0], //description + null,//(Date) row[1], //start + null, //end + false, //isEpoch + (String) row[4]); //unit + + String fraction = (String) row[3]; + + TreeMap<Double,MeasurementStation> relevantStations = + fraction.equals("suspended_sediment") /* || TODO clarify: fraction.equals("susp_sand") */ + ? suspStations + : floatStations; + + for (int i = 0; i < results.size(); i++) { + row = results.get(i); + double km = (Double) row[2]; + Range range = findMeasurementStationRange(relevantStations, km); + if (range == null) { + log.warn("No measurement station for " + fraction + " km " + km); + continue; + } + + double v = -1; + + if (row[1] != null) { + v = ((Double)row[1]).doubleValue(); + } + + setLoadFraction(load, km, v, range, fraction); + } + + } + + return load; + } + + /** * Get sediment loads from db. + * * @param river the river * @param type the sediment load type (year, epoch or off_epoch) + * * @return according sediment loads. */ public static SedimentLoad getSedimentLoadWithDataUncached( @@ -358,22 +498,35 @@ Session session = SessionHolder.HOLDER.get(); SQLQuery sqlQuery = null; - List<MeasurementStation> allStations = RiverFactory.getRiver(river).getMeasurementStations(); - TreeMap<Double,MeasurementStation> floatStations = new TreeMap<Double, MeasurementStation>(); - TreeMap<Double,MeasurementStation> suspStations = new TreeMap<Double, MeasurementStation>(); + // Measurement stations: all, for float-stuff, for suspended stuff. + // Because they need fast sorted access, use TreeMaps. + // They map the starting validity range km to the station itself. + List<MeasurementStation> allStations = + RiverFactory.getRiver(river).getMeasurementStations(); + TreeMap<Double,MeasurementStation> floatStations = + new TreeMap<Double, MeasurementStation>(); + TreeMap<Double,MeasurementStation> suspStations = + new TreeMap<Double, MeasurementStation>(); + + // From all stations, sort into the two kinds, skip undefined ones. for (MeasurementStation measurementStation: allStations) { if (measurementStation.getMeasurementType() == null || measurementStation.getRange() == null) { continue; } if (measurementStation.getMeasurementType().equals("Schwebstoff")) { - suspStations.put(measurementStation.getRange().getA().doubleValue(), measurementStation); + suspStations.put( + measurementStation.getRange().getA().doubleValue(), + measurementStation); } else if (measurementStation.getMeasurementType().equals("Geschiebe")) { - floatStations.put(measurementStation.getRange().getA().doubleValue(), measurementStation); + floatStations.put( + measurementStation.getRange().getA().doubleValue(), + measurementStation); } } + // Construct date constraint. Calendar start = Calendar.getInstance(); start.set(syear - 1, 11, 31); Calendar end = Calendar.getInstance(); @@ -394,19 +547,24 @@ sqlQuery.setString("grain", "total"); List<Object []> results = sqlQuery.list(); SedimentLoad load = new SedimentLoad(); - Object[] row = results.get(0); - load = new SedimentLoad( - (String) row[0], - (Date) row[1], - null, - false, - (String) row[4]); - getValues("coarse", sqlQuery, load, floatStations); - getValues("fine_middle", sqlQuery, load, floatStations); - getValues("sand", sqlQuery, load, floatStations); - getValues("suspended_sediment", sqlQuery, load, suspStations); - getValues("susp_sand_bed", sqlQuery, load, floatStations); - getValues("susp_sand", sqlQuery, load, floatStations); + if (results.isEmpty()) { + log.warn("Empty result for year calculation."); + } + else { + Object[] row = results.get(0); + load = new SedimentLoad( + (String) row[0], //description + (Date) row[1], //start + null, //end + false, //isEpoch + (String) row[4]); //unit + } + load = getValues("coarse", sqlQuery, load, floatStations); + load = getValues("fine_middle", sqlQuery, load, floatStations); + load = getValues("sand", sqlQuery, load, floatStations); + load = getValues("suspended_sediment", sqlQuery, load, suspStations); + load = getValues("susp_sand_bed", sqlQuery, load, floatStations); + load = getValues("susp_sand", sqlQuery, load, floatStations); return load; } @@ -467,6 +625,30 @@ return new SedimentLoad(); } + protected static Range findMeasurementStationRange( + TreeMap<Double, MeasurementStation> stations, + double km + ) { + MeasurementStation station = stations.get(km); + if (station == null) { + return null; + } + + double endKm; + + if (stations.ceilingEntry(km + 0.1d) != null) { + MeasurementStation nextStation = stations.ceilingEntry(km + 0.1d).getValue(); + endKm = nextStation.getRange().getA().doubleValue(); + } + else { + // TODO end-of-river instead of B. + endKm = station.getRange().getB().doubleValue(); + } + + return new Range( + station.getRange().getA().doubleValue(), + endKm); + } /** * Run query with grain parameter set to fraction, feed result into @@ -501,53 +683,54 @@ for (int i = 0; i < results.size(); i++) { Object[] row = results.get(i); double km = (Double)row[3]; - MeasurementStation station = stations.get(km); - MeasurementStation nextStation = null; - if (stations.ceilingEntry(km + 0.1d) != null) { - nextStation = stations.ceilingEntry(km + 0.1d).getValue(); - } - Range range = null; - if (station == null) { + Range range = findMeasurementStationRange(stations, km); + if (range == null) { log.warn("No measurement station for " + fraction + " km " + km); continue; } - else { - if (nextStation != null) - range = new Range(station.getRange().getA().doubleValue(), - nextStation.getRange().getA().doubleValue()); - else { - // TODO end-of-river instead of B. - range = new Range(station.getRange().getA().doubleValue(), - station.getRange().getB().doubleValue()); - } - } double v = -1; + if (row[2] != null) { v = ((Double)row[2]).doubleValue(); } - if (fraction.equals("coarse")) { - load.setCoarse(km, v, range); - } - else if (fraction.equals("sand")) { - load.setSand(km, v, range); - } - else if (fraction.equals("fine_middle")) { - load.setFineMiddle(km, v, range); - } - else if (fraction.equals("suspended_sediment")) { - load.setSuspSediment(km, v, range); - } - else if (fraction.equals("susp_sand")) { - load.setSuspSand(km, v, range); - } - else if (fraction.equals("susp_sand_bed")) { - load.setSuspSandBed(km, v, range); - } + + setLoadFraction(load, km, v, range, fraction); + } + + if (results.isEmpty()) { + log.warn("No " + fraction + " values found."); } return load; } + + /** Set a fraction value of load to given km, value and range. */ + private static void setLoadFraction( + SedimentLoad load, double km, double v, Range range, String fraction) { + if (fraction.equals("coarse")) { + load.setCoarse(km, v, range); + } + else if (fraction.equals("sand")) { + load.setSand(km, v, range); + } + else if (fraction.equals("fine_middle")) { + load.setFineMiddle(km, v, range); + } + else if (fraction.equals("suspended_sediment")) { + load.setSuspSediment(km, v, range); + } + else if (fraction.equals("susp_sand")) { + load.setSuspSand(km, v, range); + } + else if (fraction.equals("susp_sand_bed")) { + load.setSuspSandBed(km, v, range); + } + else { + log.error("Unknown fraction type " + fraction); + } + } + public static SedimentLoad getLoadUnknown( String river, String description @@ -627,9 +810,14 @@ /** * Return sediment loads with 'unknown' fraction type. + * @param river Name of the river * @param unit Restrict result set to those of given unit. + * @param type Type like year, epoch, off_epoch */ - public static SedimentLoad[] getSedimentLoadUnknown(String river, String unit) { + public static SedimentLoad[] getSedimentLoadUnknown( + String river, + String unit, + String type) { Session session = SessionHolder.HOLDER.get(); SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN) .addScalar("description", StandardBasicTypes.STRING) @@ -637,6 +825,12 @@ .addScalar("end", StandardBasicTypes.DATE); sqlQuery.setString("river", river); sqlQuery.setString("unit", unit); + if (type.equals("off_epoch")) { + sqlQuery.setInteger("type", 1); + } + else { + sqlQuery.setInteger("type", 0); + } List<Object[]> results = sqlQuery.list(); SedimentLoad[] loads = new SedimentLoad[results.size()]; int counter = 0;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFraction.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFraction.java Fri Sep 27 17:36:50 2013 +0200 @@ -25,25 +25,25 @@ double total; double unknown; /** Values are valid within this km range. */ - Range sandRange = null; - Range fineMiddleRange = null; - Range coarseRange = null; - Range suspSandRange = null; - Range suspSandBedRange = null; - Range suspSedimentRange = null; - Range loadTotalRange = null; - Range totalRange = null; - Range unknownRange = null; + Range sandRange; + Range fineMiddleRange; + Range coarseRange; + Range suspSandRange; + Range suspSandBedRange; + Range suspSedimentRange; + Range loadTotalRange; + Range totalRange; + Range unknownRange; public SedimentLoadFraction() { - sand = 0d; - fineMiddle = 0d; - coarse = 0d; - suspSand = 0d; - suspSandBed = 0d; - suspSediment = 0d; - loadTotal = 0d; - unknown = 0d; + sand = Double.NaN; + fineMiddle = Double.NaN; + coarse = Double.NaN; + suspSand = Double.NaN; + suspSandBed = Double.NaN; + suspSediment = Double.NaN; + loadTotal = Double.NaN; + unknown = Double.NaN; } public double getSand() { @@ -166,6 +166,10 @@ this.loadTotal = total; } + public Range getLoadTotalRange() { + return this.loadTotalRange; + } + public void setLoadTotalRange(Range range) { this.loadTotalRange = range; } @@ -185,5 +189,35 @@ public void setUnknownRange(Range unknownRange) { this.unknownRange = unknownRange; } + + /** Returns true if all fraction values except SuspSediment are unset. */ + public boolean hasOnlySuspValues() { + return + !Double.isNaN(getSuspSediment()) && + Double.isNaN(getCoarse()) && + Double.isNaN(getFineMiddle()) && + Double.isNaN(getSand()) && + Double.isNaN(getSuspSand()); + } + + /** Returns true if all fraction values except SuspSediment are set. */ + public boolean hasButSuspValues() { + return + Double.isNaN(getSuspSediment()) && + !Double.isNaN(getCoarse()) && + !Double.isNaN(getFineMiddle()) && + !Double.isNaN(getSand()) && + !Double.isNaN(getSuspSand()); + } + + /** Returns true if all fraction needed for total calculation are set. */ + public boolean isComplete() { + return + !Double.isNaN(getCoarse()) && + !Double.isNaN(getFineMiddle()) && + !Double.isNaN(getSand()) && + !Double.isNaN(getSuspSand()) && + !Double.isNaN(getSuspSediment()); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadUnknownFacet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadUnknownFacet.java Fri Sep 27 17:36:50 2013 +0200 @@ -35,7 +35,10 @@ String river = access.getRiver(); String unit = access.getUnit(); SedimentLoad[] unknown = - SedimentLoadFactory.getSedimentLoadUnknown(river, unit.replace("_per_","/")); + SedimentLoadFactory.getSedimentLoadUnknown( + river, + unit.replace("_per_","/"), + access.getYearEpoch()); SedimentLoad load = SedimentLoadFactory.getLoadUnknown( river, unknown[index].getDescription());
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.artifacts.model.sq; +import org.dive4elements.artifacts.common.utils.StringUtils; import org.dive4elements.river.artifacts.math.fitting.Function; import java.util.ArrayList; @@ -18,12 +19,17 @@ import org.apache.commons.math.optimization.fitting.CurveFitter; import org.apache.commons.math.optimization.general.LevenbergMarquardtOptimizer; +import org.apache.commons.math.stat.regression.SimpleRegression; import org.apache.log4j.Logger; public class Fitting implements Outlier.Callback { + // XXX: Hack to force linear fitting! + private static final boolean USE_NON_LINEAR_FITTING = + Boolean.getBoolean("minfo.sq.fitting.nonlinear"); + private static Logger log = Logger.getLogger(Fitting.class); public interface Callback { @@ -47,13 +53,15 @@ protected Callback callback; + protected SQ.View sqView; + public Fitting() { } - public Fitting(Function function, double stdDevFactor) { - this(); + public Fitting(Function function, double stdDevFactor, SQ.View sqView) { this.function = function; this.stdDevFactor = stdDevFactor; + this.sqView = sqView; } public Function getFunction() { @@ -75,12 +83,70 @@ @Override public void initialize(List<SQ> sqs) throws MathException { - LevenbergMarquardtOptimizer lmo = + if (USE_NON_LINEAR_FITTING + || function.getParameterNames().length != 2) { + nonLinearFitting(sqs); + } + else { + linearFitting(sqs); + } + } + + protected void linearFitting(List<SQ> sqs) { + coeffs = linearRegression(sqs); + instance = function.instantiate(coeffs); + } + + protected double [] linearRegression(List<SQ> sqs) { + + String [] pns = function.getParameterNames(); + double [] result = new double[pns.length]; + + if (sqs.size() < 2) { + log.debug("not enough points"); + return result; + } + + SimpleRegression reg = new SimpleRegression(); + + for (SQ sq: sqs) { + double s = sqView.getS(sq); + double q = sqView.getQ(sq); + reg.addData(q, s); + } + + double m = reg.getIntercept(); + double b = reg.getSlope(); + + if (log.isDebugEnabled()) { + log.debug("m: " + m); + log.debug("b: " + b); + } + + int mIdx = StringUtils.indexOf("m", pns); + int bIdx = StringUtils.indexOf("b", pns); + + if (mIdx == -1 || bIdx == -1) { + log.error("index not found: " + mIdx + " " + bIdx); + return result; + } + + result[bIdx] = m; + result[mIdx] = b; + + return result; + } + + + protected void nonLinearFitting(List<SQ> sqs) throws MathException { + + LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer(); - CurveFitter cf = new CurveFitter(lmo); + CurveFitter cf = new CurveFitter(optimizer); + for (SQ sq: sqs) { - cf.addObservedPoint(sq.getQ(), sq.getS()); + cf.addObservedPoint(sqView.getQ(sq), sqView.getS(sq)); } coeffs = cf.fit( @@ -88,13 +154,13 @@ instance = function.instantiate(coeffs); - chiSqr = lmo.getChiSquare(); + chiSqr = optimizer.getChiSquare(); } @Override public double eval(SQ sq) { - double s = instance.value(sq.q); - return sq.s - s; + double s = instance.value(sqView.getQ(sq)); + return sqView.getS(sq) - s; } @Override @@ -119,28 +185,15 @@ 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, String method, Callback callback) { - - sqs = onlyValid(sqs); + public boolean fit(List<SQ> sqs, String method, Callback callback) { if (sqs.size() < 2) { log.warn("Too less points for fitting."); return false; } + sqs = new ArrayList<SQ>(sqs); + this.callback = callback; try {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/LogSQ.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,68 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.model.sq; + +public class LogSQ extends SQ { + + public static final View LOG_SQ_VIEW = new View() { + @Override + public double getS(SQ sq) { + return ((LogSQ)sq).getLogS(); + } + + @Override + public double getQ(SQ sq) { + return ((LogSQ)sq).getLogQ(); + } + }; + + public static final Factory LOG_SQ_FACTORY = new Factory() { + @Override + public SQ createSQ(double s, double q) { + return new LogSQ(s, q); + } + }; + + protected double logS; + protected double logQ; + + protected boolean logTrans; + + public LogSQ() { + } + + public LogSQ(double s, double q) { + super(s, q); + } + + /** important: We cannot process negative s/q. */ + @Override + public boolean isValid() { + return super.isValid() && s > 0d && q > 0d; + } + + protected void ensureLogTrans() { + if (!logTrans) { + logTrans = true; + logS = Math.log(s); + logQ = Math.log(q); + } + } + + public double getLogS() { + ensureLogTrans(); + return logS; + } + + public double getLogQ() { + ensureLogTrans(); + return logQ; + } +} +
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java Fri Sep 27 17:36:50 2013 +0200 @@ -58,32 +58,32 @@ "gp.LFDNR AS LFDNR," + "g.UFERABST AS UFERABST," + "g.UFERABLINKS AS UFERABLINKS," + - "m.TSCHWEB AS TSCHWEB," + - "m.TSAND AS TSAND," + - "gp.GTRIEB_F AS GTRIEB," + - "m.TGESCHIEBE AS TGESCHIEBE," + - "si.SIEB01 AS SIEB01, si.SIEB02 AS SIEB02," + - "si.SIEB03 AS SIEB03, si.SIEB04 AS SIEB04," + - "si.SIEB05 AS SIEB05, si.SIEB06 AS SIEB06," + - "si.SIEB07 AS SIEB07, si.SIEB08 AS SIEB08," + - "si.SIEB09 AS SIEB09, si.SIEB10 AS SIEB10," + - "si.SIEB11 AS SIEB11, si.SIEB12 AS SIEB12," + - "si.SIEB13 AS SIEB13, si.SIEB14 AS SIEB14," + - "si.SIEB15 AS SIEB15, si.SIEB16 AS SIEB16," + - "si.SIEB17 AS SIEB17, si.SIEB18 AS SIEB18," + - "si.SIEB19 AS SIEB19, si.SIEB20 AS SIEB20," + - "si.SIEB21 AS SIEB21," + - "gs.RSIEB01 AS RSIEB01, gs.RSIEB02 AS RSIEB02," + - "gs.RSIEB03 AS RSIEB03, gs.RSIEB04 AS RSIEB04," + - "gs.RSIEB05 AS RSIEB05, gs.RSIEB06 AS RSIEB06," + - "gs.RSIEB07 AS RSIEB07, gs.RSIEB08 AS RSIEB08," + - "gs.RSIEB09 AS RSIEB09, gs.RSIEB10 AS RSIEB10," + - "gs.RSIEB11 AS RSIEB11, gs.RSIEB12 AS RSIEB12," + - "gs.RSIEB13 AS RSIEB13, gs.RSIEB14 AS RSIEB14," + - "gs.RSIEB15 AS RSIEB15, gs.RSIEB16 AS RSIEB16," + - "gs.RSIEB17 AS RSIEB17, gs.RSIEB18 AS RSIEB18," + - "gs.RSIEB19 AS RSIEB19, gs.RSIEB20 AS RSIEB20," + - "gs.RSIEB21 AS RSIEB21, gs.REST AS REST " + + "COALESCE(m.TSCHWEB, 0) AS TSCHWEB," + + "COALESCE(m.TSAND, 0) AS TSAND," + + "COALESCE(gp.GTRIEB_F, 0) AS GTRIEB," + + "COALESCE(m.TGESCHIEBE, 0) AS TGESCHIEBE," + + "COALESCE(si.SIEB01, 0) AS SIEB01, COALESCE(si.SIEB02, 0) AS SIEB02," + + "COALESCE(si.SIEB03, 0) AS SIEB03, COALESCE(si.SIEB04, 0) AS SIEB04," + + "COALESCE(si.SIEB05, 0) AS SIEB05, COALESCE(si.SIEB06, 0) AS SIEB06," + + "COALESCE(si.SIEB07, 0) AS SIEB07, COALESCE(si.SIEB08, 0) AS SIEB08," + + "COALESCE(si.SIEB09, 0) AS SIEB09, COALESCE(si.SIEB10, 0) AS SIEB10," + + "COALESCE(si.SIEB11, 0) AS SIEB11, COALESCE(si.SIEB12, 0) AS SIEB12," + + "COALESCE(si.SIEB13, 0) AS SIEB13, COALESCE(si.SIEB14, 0) AS SIEB14," + + "COALESCE(si.SIEB15, 0) AS SIEB15, COALESCE(si.SIEB16, 0) AS SIEB16," + + "COALESCE(si.SIEB17, 0) AS SIEB17, COALESCE(si.SIEB18, 0) AS SIEB18," + + "COALESCE(si.SIEB19, 0) AS SIEB19, COALESCE(si.SIEB20, 0) AS SIEB20," + + "COALESCE(si.SIEB21, 0) AS SIEB21," + + "COALESCE(gs.RSIEB01, 0) AS RSIEB01, COALESCE(gs.RSIEB02, 0) AS RSIEB02," + + "COALESCE(gs.RSIEB03, 0) AS RSIEB03, COALESCE(gs.RSIEB04, 0) AS RSIEB04," + + "COALESCE(gs.RSIEB05, 0) AS RSIEB05, COALESCE(gs.RSIEB06, 0) AS RSIEB06," + + "COALESCE(gs.RSIEB07, 0) AS RSIEB07, COALESCE(gs.RSIEB08, 0) AS RSIEB08," + + "COALESCE(gs.RSIEB09, 0) AS RSIEB09, COALESCE(gs.RSIEB10, 0) AS RSIEB10," + + "COALESCE(gs.RSIEB11, 0) AS RSIEB11, COALESCE(gs.RSIEB12, 0) AS RSIEB12," + + "COALESCE(gs.RSIEB13, 0) AS RSIEB13, COALESCE(gs.RSIEB14, 0) AS RSIEB14," + + "COALESCE(gs.RSIEB15, 0) AS RSIEB15, COALESCE(gs.RSIEB16, 0) AS RSIEB16," + + "COALESCE(gs.RSIEB17, 0) AS RSIEB17, COALESCE(gs.RSIEB18, 0) AS RSIEB18," + + "COALESCE(gs.RSIEB19, 0) AS RSIEB19, COALESCE(gs.RSIEB20, 0) AS RSIEB20," + + "COALESCE(gs.RSIEB21, 0) AS RSIEB21, COALESCE(gs.REST , 0) AS REST " + "FROM MESSUNG m " + "JOIN STATION s ON m.STATIONID = s.STATIONID " + "JOIN GEWAESSER r ON s.GEWAESSERID = r.GEWAESSERID " + @@ -190,9 +190,10 @@ } public static Measurements getMeasurements( - String river, - double location, - DateRange dateRange + String river, + double location, + DateRange dateRange, + SQ.Factory sqFactory ) { Session session = SedDBSessionHolder.HOLDER.get(); try { @@ -202,7 +203,7 @@ List<Measurement> accumulated = loadFractions( session, river, location, dateRange); - return new Measurements(totals, accumulated); + return new Measurements(totals, accumulated, sqFactory); } finally { session.close();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java Fri Sep 27 17:36:50 2013 +0200 @@ -66,13 +66,17 @@ protected List<Measurement> measuments; protected List<Measurement> accumulated; + protected SQ.Factory sqFactory; + public Measurements() { } public Measurements( List<Measurement> measuments, - List<Measurement> accumulated + List<Measurement> accumulated, + SQ.Factory sqFactory ) { + this.sqFactory = sqFactory; if (log.isDebugEnabled()) { log.debug("number of measuments: " + measuments.size()); log.debug("number of accumulated: " + accumulated.size()); @@ -81,14 +85,14 @@ this.accumulated = accumulated; } - public static List<SQ> extractSQ( + public List<SQ> extractSQ( List<Measurement> measuments, SExtractor extractor ) { List<SQ> result = new ArrayList<SQ>(measuments.size()); int invalid = 0; for (Measurement measument: measuments) { - SQ sq = new SQ(extractor.getS(measument), measument.Q()); + SQ sq = sqFactory.createSQ(extractor.getS(measument), measument.Q()); if (sq.isValid()) { result.add(sq); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,8 +11,37 @@ import java.io.Serializable; +/** Represents S/Q pairs. They are immutable! */ public class SQ implements Serializable { + public interface Factory { + SQ createSQ(double s, double q); + } + + public static final Factory SQ_FACTORY = new Factory() { + @Override + public SQ createSQ(double s, double q) { + return new SQ(s, q); + } + }; + + public interface View { + double getS(SQ sq); + double getQ(SQ sq); + } + + public static final View SQ_VIEW = new View() { + @Override + public double getS(SQ sq) { + return sq.getS(); + } + + @Override + public double getQ(SQ sq) { + return sq.getQ(); + } + }; + protected double s; protected double q; @@ -29,19 +58,10 @@ 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); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,6 +8,7 @@ package org.dive4elements.river.artifacts.model.sq; +import org.dive4elements.artifacts.common.utils.StringUtils; import org.dive4elements.river.artifacts.access.SQRelationAccess; import org.dive4elements.river.artifacts.math.fitting.Function; @@ -21,6 +22,7 @@ import org.dive4elements.river.backend.SedDBSessionHolder; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.log4j.Logger; @@ -30,7 +32,20 @@ private static final Logger log = Logger.getLogger(SQRelationCalculation.class); - public static final String SQ_FUNCTION_NAME = "sq-pow"; + public static final boolean NON_LINEAR_FITTING = + Boolean.getBoolean("minfo.sq.calcution.non.linear.fitting"); + + public static final String SQ_POW_FUNCTION_NAME = "sq-pow"; + public static final String SQ_LIN_FUNCTION_NAME = "linear"; + + public static final String [] EXTRA_PARAMETERS = { + "chi_sqr", + "std_dev", + "max_q", + "c_ferguson", + "c_duan", + "r2" + }; protected String river; protected double location; @@ -49,8 +64,6 @@ Double outliers = access.getOutliers(); String method = access.getOutlierMethod(); - //river = "Rhein"; - if (river == null) { // TODO: i18n addProblem("sq.missing.river"); @@ -102,31 +115,95 @@ } } + public interface TransformCoeffs { + double [] transform(double [] coeffs); + } + + public static final TransformCoeffs IDENTITY_TRANS = + new TransformCoeffs() { + @Override + public double [] transform(double [] coeffs) { + return coeffs; + } + }; + + public static final TransformCoeffs LINEAR_TRANS = + new TransformCoeffs() { + @Override + public double [] transform(double [] coeffs) { + log.debug("before transform: " + Arrays.toString(coeffs)); + if (coeffs.length == 2) { + coeffs = new double [] { Math.exp(coeffs[1]), coeffs[0] }; + } + log.debug("after transform: " + Arrays.toString(coeffs)); + return coeffs; + } + }; + protected CalculationResult internalCalculate() { - Function function = FunctionFactory + Function powFunction = FunctionFactory .getInstance() - .getFunction(SQ_FUNCTION_NAME); + .getFunction(SQ_POW_FUNCTION_NAME); - if (function == null) { - log.error("No '" + SQ_FUNCTION_NAME + "' function found."); + if (powFunction == null) { + log.error("No '" + SQ_POW_FUNCTION_NAME + "' function found."); // TODO: i18n addProblem("sq.missing.sq.function"); + return new CalculationResult(new SQResult[0], this); + } + + Function function; + SQ.View sqView; + SQ.Factory sqFactory; + ParameterCreator pc; + + if (NON_LINEAR_FITTING) { + log.debug("Use non linear fitting."); + sqView = SQ.SQ_VIEW; + sqFactory = SQ.SQ_FACTORY; + function = powFunction; + pc = new ParameterCreator( + powFunction.getParameterNames(), + powFunction.getParameterNames(), + powFunction, + sqView); + } + else { + log.debug("Use linear fitting."); + sqView = LogSQ.LOG_SQ_VIEW; + sqFactory = LogSQ.LOG_SQ_FACTORY; + function = FunctionFactory + .getInstance() + .getFunction(SQ_LIN_FUNCTION_NAME); + if (function == null) { + log.error("No '" + SQ_LIN_FUNCTION_NAME + "' function found."); + // TODO: i18n + addProblem("sq.missing.sq.function"); + return new CalculationResult(new SQResult[0], this); + } + pc = new LinearParameterCreator( + powFunction.getParameterNames(), + function.getParameterNames(), + function, + sqView); } Measurements measurements = - MeasurementFactory.getMeasurements(river, location, period); + MeasurementFactory.getMeasurements( + river, location, period, sqFactory); 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); + doFitting(function, sqs, sqView, pc); if (iterations == null) { // TODO: i18n @@ -148,13 +225,15 @@ } protected List<SQFractionResult.Iteration> doFitting( - final Function function, - List<SQ> sqs + final Function function, + List<SQ> sqs, + SQ.View sqView, + final ParameterCreator pc ) { final List<SQFractionResult.Iteration> iterations = new ArrayList<SQFractionResult.Iteration>(); - boolean success = new Fitting(function, outliers).fit( + boolean success = new Fitting(function, outliers, sqView).fit( sqs, method, new Fitting.Callback() { @@ -166,11 +245,11 @@ double standardDeviation, double chiSqr ) { - Parameters parameters = createParameters( - function.getParameterNames(), + Parameters parameters = pc.createParameters( coeffs, standardDeviation, - chiSqr); + chiSqr, + measurements); iterations.add(new SQFractionResult.Iteration( parameters, measurements, @@ -181,22 +260,178 @@ 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; + public static class ParameterCreator { + + protected String [] origNames; + protected String [] proxyNames; + + protected Function function; + protected SQ.View view; + + public ParameterCreator( + String [] origNames, + String [] proxyNames, + Function function, + SQ.View view + ) { + this.origNames = origNames; + this.proxyNames = proxyNames; + this.function = function; + this.view = view; + } + + protected double [] transformCoeffs(double [] coeffs) { + return coeffs; + } + + private static double maxQ(SQ [] sqs) { + double max = -Double.MAX_VALUE; + for (SQ sq: sqs) { + double q = sq.getQ(); // Don't use view here! + if (q > max) { + max = q; + } + } + return Math.max(0d, max); + } + + private double cFerguson( + org.dive4elements.river.artifacts.math.Function instance, + SQ [] sqs + ) { + double sqrSum = 0d; + + for (SQ sq: sqs) { + double s = view.getS(sq); + double q = view.getQ(sq); + double diffS = s - instance.value(q); + sqrSum += diffS*diffS; + } + + return Math.exp(0.5d * sqrSum/(sqs.length-2)); + } + + private double cDuan( + org.dive4elements.river.artifacts.math.Function instance, + SQ [] sqs + ) { + double sum = 0d; + + for (SQ sq: sqs) { + double s = view.getS(sq); + double q = view.getQ(sq); + double diffS = s - instance.value(q); + sum += Math.exp(diffS); + } + return sum / sqs.length; + } + + private double r2( + org.dive4elements.river.artifacts.math.Function instance, + SQ [] sqs + ) { + double xm = 0; + double ym = 0; + for (SQ sq: sqs) { + double s = view.getS(sq); + double q = view.getQ(sq); + double fs = instance.value(q); + xm += s; + ym += fs; + } + xm /= sqs.length; + ym /= sqs.length; + + double mixXY = 0d; + double sumX = 0d; + double sumY = 0d; + + for (SQ sq: sqs) { + double s = view.getS(sq); + double q = view.getQ(sq); + double fs = instance.value(q); + + double xDiff = xm - s; + double yDiff = ym - fs; + + mixXY += xDiff*yDiff; + + sumX += xDiff*xDiff; + sumY += yDiff*yDiff; + } + + double r = mixXY/Math.sqrt(sumX*sumY); + return r*r; + } + + + public Parameters createParameters( + double [] coeffs, + double standardDeviation, + double chiSqr, + SQ [] measurements + ) { + String [] columns = StringUtils.join(EXTRA_PARAMETERS, origNames); + + Parameters parameters = new Parameters(columns); + int row = parameters.newRow(); + parameters.set(row, origNames, transformCoeffs(coeffs)); + parameters.set(row, "chi_sqr", chiSqr); + parameters.set(row, "std_dev", standardDeviation); + parameters.set(row, "max_q", maxQ(measurements)); + + // We need to instantiate the function to calculate + // the remaining values. + org.dive4elements.river.artifacts.math.Function f = + function.instantiate(coeffs); + + parameters.set(row, "c_ferguson", cFerguson(f, measurements)); + parameters.set(row, "c_duan", cDuan(f, measurements)); + parameters.set(row, "r2", r2(f, measurements)); + + return parameters; + } + } + + /** We need to transform the coeffs back to the original function. */ + public static class LinearParameterCreator extends ParameterCreator { + + public LinearParameterCreator( + String [] origNames, + String [] proxyNames, + Function function, + SQ.View view + ) { + super(origNames, proxyNames, function, view); + } + + @Override + protected double [] transformCoeffs(double [] coeffs) { + + int bP = StringUtils.indexOf("m", proxyNames); + int mP = StringUtils.indexOf("b", proxyNames); + + int aO = StringUtils.indexOf("a", origNames); + int bO = StringUtils.indexOf("b", origNames); + + if (bP == -1 || mP == -1 || aO == -1 || bO == -1) { + log.error("index not found: " + + bP + " " + mP + " " + + aO + " " + bO); + return coeffs; + } + + double [] ncoeffs = (double [])coeffs.clone(); + ncoeffs[aO] = Math.exp(coeffs[mP]); + ncoeffs[bO] = coeffs[bP]; + + if (log.isDebugEnabled()) { + log.debug("before transform: " + Arrays.toString(coeffs)); + log.debug("after transform: " + Arrays.toString(ncoeffs)); + } + + return ncoeffs; + } } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationJRDataSource.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationJRDataSource.java Fri Sep 27 17:36:50 2013 +0200 @@ -73,6 +73,12 @@ else if ("periods".equals(fieldName)) { value = metaData.get("periods"); } + else if ("msName".equals(fieldName)) { + value = metaData.get("msName"); + } + else if ("msGauge".equals(fieldName)) { + value = metaData.get("msGauge"); + } else if ("km".equals(fieldName)) { value = data.get(index)[0]; } @@ -86,12 +92,24 @@ value = data.get(index)[3]; } else if ("total".equals(fieldName)) { - value = data.get(index)[4]; + value = data.get(index)[7]; } else if ("out".equals(fieldName)) { + value = data.get(index)[8]; + } + else if ("sd".equals(fieldName)) { + value = data.get(index)[4]; + } + else if ("qmax".equals(fieldName)) { value = data.get(index)[5]; } - else if ("variance".equals(fieldName)) { + else if ("cferg".equals(fieldName)) { + value = data.get(index)[10]; + } + else if ("cduan".equals(fieldName)) { + value = data.get(index)[9]; + } + else if ("r2".equals(fieldName)) { value = data.get(index)[6]; } return value;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/D4EService.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/D4EService.java Fri Sep 27 17:36:50 2013 +0200 @@ -44,6 +44,7 @@ } + /** Override to do the meat work (called in processXML). */ protected abstract Document doProcess( Document data, GlobalContext globalContext, @@ -56,6 +57,7 @@ } + /** Called when processing done, close session. */ protected void shutdown() { logger.debug("shutdown"); Session session = SessionHolder.HOLDER.get();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DischargeInfoService.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DischargeInfoService.java Fri Sep 27 17:36:50 2013 +0200 @@ -40,6 +40,8 @@ public static final String GAUGE_XPATH = "/art:gauge/text()"; + public static final String RIVER_NAME_XPATH = "/art:gauge/art:river/text()"; + public DischargeInfoService() { } @@ -58,30 +60,39 @@ String gaugeNumber = XMLUtils.xpathString( data, GAUGE_XPATH, ArtifactNamespaceContext.INSTANCE); + String river = XMLUtils.xpathString( + data, RIVER_NAME_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); + logger.debug("Getting discharge for gauge: " + gaugeNumber + " at river: " + river); long gn; try { gn = Long.parseLong(gaugeNumber); } catch (NumberFormatException nfe) { - logger.warn("Invalid gauge number. Cannot return discharg info."); + logger.warn("Invalid gauge number. Cannot return discharge info."); return XMLUtils.newDocument(); } - Gauge gauge = Gauge.getGaugeByOfficialNumber(gn); + Gauge gauge; + if (river == null || river.isEmpty()) { + gauge = Gauge.getGaugeByOfficialNumber(gn); + } else { + gauge = Gauge.getGaugeByOfficialNumber(gn, river); + } + if (gauge == null) { logger.warn("No such gauge found."); return XMLUtils.newDocument(); } - logger.debug("Found gauge: " + gauge.getName()); + logger.debug("Found gauge: " + gauge.getName() + " id: " + gauge.getId()); return buildDocument(gauge); }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/RiverInfoService.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/RiverInfoService.java Fri Sep 27 17:36:50 2013 +0200 @@ -37,6 +37,7 @@ protected River river; protected Element riverele; + @Override protected Document doProcess( Document data, GlobalContext globalContext, @@ -91,3 +92,4 @@ ? Double.toString(value.doubleValue()) : ""; } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/CalculationSelect.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/CalculationSelect.java Fri Sep 27 17:36:50 2013 +0200 @@ -77,7 +77,7 @@ CALCULATION_DISCHARGE_CURVE, CALCULATION_HISTORICAL_DISCHARGE_CURVE, CALCULATION_DURATION_CURVE, -// CALCULATION_DISCHARGE_LONGITUDINAL_CURVE, + CALCULATION_DISCHARGE_LONGITUDINAL_CURVE, CALCULATION_W_DIFFERENCES, CALCULATION_REFERENCE_CURVE //, // CALCULATION_EXTREME
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodMapState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodMapState.java Fri Sep 27 17:36:50 2013 +0200 @@ -30,6 +30,7 @@ import org.dive4elements.artifacts.GlobalContext; import org.dive4elements.artifacts.common.utils.FileTools; import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.access.DGMAccess; import org.dive4elements.river.artifacts.access.RangeAccess; import org.dive4elements.river.artifacts.context.RiverContext; import org.dive4elements.river.artifacts.model.CalculationMessage; @@ -412,7 +413,7 @@ MapfileGenerator.MS_LAYER_PREFIX + HWS_LINES, HWS_LINES_SHAPE, "LINE", - "31467", + "31467", // XXX: This should be dynamically fetched from database. "hws"); job.addLin(artifactDir + "/" + HWS_LINES_SHAPE); facetCreator.createShapeFacet(I18N_HWS_LINES_OFFICIAL, @@ -536,16 +537,18 @@ File dir, WSPLGENJob job ) { - String river = artifact.getDataAsString("river"); - String geoJSON = artifact.getDataAsString("uesk.barriers"); - String srid = RiverUtils.getRiverDGMSrid(river); - String srs = "EPSG:" + srid; + DGMAccess access = new DGMAccess(artifact); + String geoJSON = access.getGeoJSON(); if (geoJSON == null || geoJSON.length() == 0) { logger.debug("No barrier features in parameterization existing."); return; } + String srid = String.valueOf(access.getDGM().getSrid()); + + String srs = "EPSG:" + srid; + SimpleFeatureType ft = getBarriersFeatureType( "barriers", srs, Geometry.class); @@ -748,9 +751,10 @@ protected void setAxis(D4EArtifact artifact, File dir, WSPLGENJob job) { - String river = artifact.getDataAsString("river"); - String srid = RiverUtils.getRiverDGMSrid(river); - String srs = "EPSG:" + srid; + DGMAccess access = new DGMAccess(artifact); + String river = access.getRiver(); + String srid = String.valueOf(access.getDGM().getSrid()); + String srs = "EPSG:" + srid; List<RiverAxis> axes = null; try { @@ -794,9 +798,10 @@ protected void setPro(D4EArtifact artifact, File dir, WSPLGENJob job) { - String river = artifact.getDataAsString("river"); - String srid = RiverUtils.getRiverDGMSrid(river); - String srs = "EPSG:" + srid; + DGMAccess access = new DGMAccess(artifact); + String river = access.getRiver(); + String srid = String.valueOf(access.getDGM().getSrid()); + String srs = "EPSG:" + srid; List<CrossSectionTrack> cst = CrossSectionTrack.getCrossSectionTrack(river, WSPLGEN_QPS_NAME); @@ -838,33 +843,25 @@ protected void setDgm( D4EArtifact artifact, - WSPLGENJob job, + WSPLGENJob job, CallContext context ) { - 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); + DGMAccess access = new DGMAccess(artifact); + DGM dgm = access.getDGM(); if (dgm == null) { logger.warn("Could not find specified DGM."); - return; } - File dgmPath = new File (dgm.getPath()); + File dgmPath = new File(dgm.getPath()); if (dgmPath.isAbsolute()) { job.setDgm(dgm.getPath()); } else { RiverContext fc = (RiverContext)context.globalContext(); - String prefix = (String) fc.get("dgm-path"); - job.setDgm(prefix.trim() + dgm.getPath().trim()); + File prefix = new File((String)fc.get("dgm-path")); + job.setDgm(new File(prefix, dgm.getPath()).getAbsolutePath()); } } @@ -876,17 +873,29 @@ return; } - String river = artifact.getDataAsString("river"); - String srid = RiverUtils.getRiverDGMSrid(river); + DGMAccess access = new DGMAccess(artifact); + String river = access.getRiver(); + String srid = String.valueOf(access.getDGM().getSrid()); String srs = "EPSG:" + srid; Floodplain plain = Floodplain.getFloodplain(river); + if (plain == null) { + logger.debug("No flood plain for river '" + river + "'"); + return; + } + + Polygon polygon = plain.getGeom(); + if (polygon == null) { + logger.warn("Floodplain has no geometry."); + return; + } + SimpleFeatureType ft = GeometryUtils.buildFeatureType( "talaue", srs, Polygon.class); SimpleFeatureBuilder builder = new SimpleFeatureBuilder(ft); - builder.add(plain.getGeom()); + builder.add(polygon); FeatureCollection collection = FeatureCollections.newCollection(); collection.add(builder.buildFeature("0")); @@ -1002,8 +1011,5 @@ } } } - - - } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeDischargeState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeDischargeState.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,6 +10,8 @@ import java.util.List; +import java.text.DateFormat; + import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallMeta; @@ -31,7 +33,10 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.DischargeTable; +import org.dive4elements.river.model.TimeInterval; +import org.dive4elements.river.utils.Formatter; /** * The only state for an GaugeDischargeState (River and km known). @@ -64,9 +69,18 @@ } Gauge gauge = artifact.getGauge(); + DischargeTable mdt = gauge.fetchMasterDischargeTable(); + TimeInterval validity = mdt.getTimeInterval(); + DateFormat df = Formatter.getDateFormatter(meta, "dd.MM.yyyy"); + String start = validity.getStartTime() != null ? + df.format(validity.getStartTime()) : "Unknown"; + String stop = validity.getStopTime() != null ? + df.format(validity.getStopTime()) : ""; + Object[] args = new Object[] { gauge.getName(), - gauge.getStation() + start, + stop }; String name = Resources.getMsg(
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeTimerangeState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeTimerangeState.java Fri Sep 27 17:36:50 2013 +0200 @@ -67,7 +67,8 @@ } } - logger.warn("Could not determine time range for gauge: " + gauge); + logger.warn("Could not determine time range for gauge: " + gauge.getName() + + " id: " + gauge.getId()); return null; }
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticState.java Fri Sep 27 17:36:50 2013 +0200 @@ -80,6 +80,7 @@ return staticCompute(facets); } + /** End-point and most important compute-method. Override for desired effect. */ public Object staticCompute(List<Facet> facets) { return null; } @@ -133,7 +134,7 @@ } /** - * Allow to set the uiprovider for displaying the static data + * Allow to set the uiprovider for displaying the static data. */ public void setUIProvider(String uiprovider) { this.uiprovider = uiprovider;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticWQKmsState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticWQKmsState.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,6 +10,8 @@ import java.util.List; +import gnu.trove.TDoubleArrayList; + import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallContext; @@ -79,18 +81,30 @@ name = STATIC_WQKMS; } */ + // Spawn Q Facet only if at least one discharge value + // is != -1 + boolean qEmpty = true; + TDoubleArrayList qs = wqkms.allQs(); + for (int i = 0; i < qs.size(); i++) { + if (qs.getQuick(i) != -1d) { + qEmpty = false; + break; + } + } String wkmsName = wqkms.getName(); - Facet qfacet = new WQKmsFacet( - STATIC_WQKMS_Q, - wkmsName - // TODO re-enable translations. - /* - Resources.getMsg( - metaLocale, - wkmsName, - wkmsName)*/); - facets.add(qfacet); + if (!qEmpty) { + Facet qfacet = new WQKmsFacet( + STATIC_WQKMS_Q, + wkmsName + // TODO re-enable translations. + /* + Resources.getMsg( + metaLocale, + wkmsName, + wkmsName)*/); + facets.add(qfacet); + } Facet rpFacet = new RelativePointFacet(wkmsName); facets.add(rpFacet);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java Fri Sep 27 17:36:50 2013 +0200 @@ -49,10 +49,6 @@ 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() { @@ -65,6 +61,9 @@ throws IllegalArgumentException { D4EArtifact flys = (D4EArtifact) artifact; + if (artifact instanceof ChartArtifact) { + return true; + } StateData data = flys.getData("diffids");
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/fixation/FixAnalysisCompute.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/fixation/FixAnalysisCompute.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,6 +9,7 @@ package org.dive4elements.river.artifacts.states.fixation; import java.text.DateFormat; +import java.util.Collection; import java.util.Date; import java.util.List; @@ -41,7 +42,9 @@ import org.dive4elements.river.artifacts.model.fixings.FixWQCurveFacet; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.artifacts.states.DefaultState; +import org.dive4elements.river.utils.Formatter; import org.dive4elements.river.utils.IdGenerator; +import org.dive4elements.river.utils.UniqueDateFormatter; /** * @author <a href="mailto:raimund.renkert@intevation.de">Raimund Renkert</a> @@ -76,8 +79,6 @@ "fix.hq5" }; - // TODO Why does this happen here? In other cases its implemented in the - // respective artifact, not State. static { // Active/deactivate facets. FacetActivity.Registry.getInstance().register( @@ -171,15 +172,15 @@ int qsS = access.getQSectorStart(); int qsE = access.getQSectorEnd(); - // TODO: i18n - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM); + DateFormat df = Formatter.getDateFormatter(context.getMeta(), "dd.MM.yyyy"); + DateFormat lf = Formatter.getDateFormatter(context.getMeta(), "dd.MM.yyyy'T'HH:mm"); 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()); + String endDate = df.format(period.getTo()); for (int j = qsS; j <= qsE; j++) { @@ -233,19 +234,22 @@ I18N_ANALYSIS, I18N_ANALYSIS); + Collection<Date> aeds = fr.getAnalysisEventsDates(i); + UniqueDateFormatter cf = new UniqueDateFormatter(df, lf, aeds); + int k = 0; - for (Date d: fr.getAnalysisEventsDates(i)) { + for (Date d: aeds) { int anaNdx = i << 8; anaNdx = anaNdx | k; facets.add(new FixAnalysisEventsFacet(anaNdx, FIX_ANALYSIS_EVENTS_DWT, - eventDesc + (i+1) + " - " + df.format(d))); + eventDesc + (i+1) + " - " + cf.format(d))); facets.add(new FixLongitudinalAnalysisFacet(anaNdx, FIX_ANALYSIS_EVENTS_LS, - eventDesc + (i+1) + " - " + df.format(d))); + eventDesc + (i+1) + " - " + cf.format(d))); facets.add(new FixAnalysisEventsFacet(anaNdx, FIX_ANALYSIS_EVENTS_WQ, - eventDesc + (i+1) +" - " + df.format(d))); + eventDesc + (i+1) +" - " + cf.format(d))); k++; } } @@ -259,27 +263,29 @@ I18N_REFERENCEDEVIATION, I18N_REFERENCEDEVIATION); + Collection<Date> reds = fr.getReferenceEventsDates(); + UniqueDateFormatter cf = new UniqueDateFormatter(df, lf, reds); + int i = 0; - for (Date d: fr.getReferenceEventsDates()) { + for (Date d: reds) { int refNdx = idg.next() << 8; refNdx |= i; facets.add(new FixReferenceEventsFacet(refNdx, FIX_REFERENCE_EVENTS_DWT, - i18n_ref + " - " + df.format(d))); + i18n_ref + " - " + cf.format(d))); refNdx = idg.next() << 8; refNdx = refNdx | i; facets.add(new FixLongitudinalReferenceFacet(refNdx, FIX_REFERENCE_EVENTS_LS, - i18n_ref + " - " + df.format(d))); + i18n_ref + " - " + cf.format(d))); refNdx = idg.next() << 8; refNdx |= i; facets.add(new FixReferenceEventsFacet(refNdx, FIX_REFERENCE_EVENTS_WQ, - i18n_ref + " - " + df.format(d))); + i18n_ref + " - " + cf.format(d))); i++; } - facets.add(new FixLongitudinalDeviationFacet(idg.next(), FIX_DEVIATION_LS, i18n_dev));
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java Fri Sep 27 17:36:50 2013 +0200 @@ -98,8 +98,14 @@ return res; } - protected void generateFacets(CallContext context, List<Facet> newFacets, - BedDifferencesResult[] results, String stateId, String hash) { + /** Generate Facets based on given results. */ + protected void generateFacets( + CallContext context, + List<Facet> newFacets, + BedDifferencesResult[] results, + String stateId, + String hash + ) { logger.debug("DifferencesState.generateFacets"); CallMeta meta = context.getMeta(); @@ -121,9 +127,7 @@ newFacets.add(new BedDiffYearFacet( idx, BED_DIFFERENCE_MORPH_WIDTH, - createBedDiffMorphDescription( - meta, - (BedDiffYearResult)results[idx]), + createBedDiffMorphDescription(meta), ComputeType.ADVANCE, stateId, hash)); @@ -336,12 +340,9 @@ } protected String createBedDiffMorphDescription( - CallMeta meta, - BedDiffYearResult result) { - String range = result.getStart() + " - " + result.getEnd(); - + CallMeta meta) { return Resources.getMsg(meta, I18N_FACET_BED_DIFF_MORPH, - I18N_FACET_BED_DIFF_MORPH, new Object[] { range }); + I18N_FACET_BED_DIFF_MORPH); } protected String createBedDiffAbsoluteDescription(
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/SedimentLoadCalculate.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/SedimentLoadCalculate.java Fri Sep 27 17:36:50 2013 +0200 @@ -140,10 +140,6 @@ return res; } - String river = access.getRiver(); - SedimentLoad[] unknown = - SedimentLoadFactory.getSedimentLoadUnknown(river, access.getUnit().replace("_per_","/")); - String type = access.getYearEpoch(); if (type.equals("year")) { generateYearFacets(context, newFacets, results, getID(), hash); @@ -155,6 +151,12 @@ generateOffEpochFacets(context, newFacets, results, getID(), hash); } logger.debug("Created " + newFacets.size() + " new Facets."); + + String river = access.getRiver(); + SedimentLoad[] unknown = + SedimentLoadFactory.getSedimentLoadUnknown(river, + access.getUnit().replace("_per_","/"), type); + if (res.getReport().hasProblems()) { newFacets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); }
--- a/artifacts/src/main/java/org/dive4elements/river/collections/AttributeParser.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/collections/AttributeParser.java Fri Sep 27 17:36:50 2013 +0200 @@ -51,6 +51,7 @@ protected CollectionAttribute attribute; + /** Just store reference to document. */ public AttributeParser(Document attributeDocument) { this.attributeDocument = attributeDocument; }
--- a/artifacts/src/main/java/org/dive4elements/river/collections/AttributeWriter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/collections/AttributeWriter.java Fri Sep 27 17:36:50 2013 +0200 @@ -195,7 +195,11 @@ logger.debug("Try to add Facet: " + facet.getName()); } - if (!compatibleFacets.contains(facet.getName())) { + String bondage = facet.getBoundToOut(); + if (bondage != null && bondage.equals(outputName)) { + logger.debug("Adding bound facet regardless of compatibility: " + + facet.getName()); + } else if (!compatibleFacets.contains(facet.getName())) { logger.debug("Have incompatible facet, skip: " + facet.getName()); continue; } else if (facet.getBoundToOut() != null && @@ -211,7 +215,12 @@ ManagedFacet picked = pickFacet(facet, oldFacets); if (facet.equals(picked)) { - genuinelyNewFacets.add(picked); + if (!facetInTwoOuts(facet, genuinelyNewFacets)) { + genuinelyNewFacets.add(picked); + } + else { + logger.debug("Skip clone facet that shall be present in two outs"); + } } else { currentFacets.add(picked); @@ -260,17 +269,20 @@ // Preparations to be able to detect gaps. Map<Integer, ManagedFacet> mfmap = new HashMap<Integer, ManagedFacet>(); - int max = 0; + int maxPosition = 0; for (ManagedFacet mf: currentFacets) { int pos = mf.getPosition(); mfmap.put(Integer.valueOf(pos), mf); - if (pos > max) max = pos; + if (pos > maxPosition) maxPosition = pos; } - // Finally do gap correction. - if (max != currentFacets.size()) { + // TODO issue1458: debug what happens + + // Finally do gap correction + // (note that posistions start at 1, not at zero). + if (maxPosition != currentFacets.size()) { int gap = 0; - for (int i = 1; i <= max; i++) { + for (int i = 1; i <= maxPosition; i++) { ManagedFacet mf = mfmap.get(Integer.valueOf(i)); if (mf == null) { gap++; @@ -281,14 +293,27 @@ } // Now add all facets. - for (ManagedFacet oldMF: currentFacets) { - attribute.addFacet(outputName, oldMF); + for (ManagedFacet facet: currentFacets) { + attribute.addFacet(outputName, facet); } return !currentFacets.isEmpty(); } + /** Returns true if a likely clone of facet is + * contained in genuinelyNewFacets, as happens when same facet is defined + * for two outs. */ + private boolean facetInTwoOuts(ManagedFacet facet, List<ManagedFacet> genuinelyNewFacets) { + for (ManagedFacet otherFacet: genuinelyNewFacets) { + if (facet.isSame(otherFacet)) { + return true; + } + } + return false; + } + + /** * Returns the facet to be added to Document. * Return the new facet only if the "same" facet was not present before.
--- a/artifacts/src/main/java/org/dive4elements/river/collections/CollectionAttribute.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/collections/CollectionAttribute.java Fri Sep 27 17:36:50 2013 +0200 @@ -30,7 +30,11 @@ import org.dive4elements.artifactdatabase.state.Settings; -/** Create attribute part of collection document. */ +/** + * Create attribute part of collection document. + * + * Has outputs, settings, facets and list of loaded recommendations. + */ public class CollectionAttribute { /** Privately owned logger. */ @@ -66,6 +70,7 @@ } + /** Remove outputs without facets from outputMap. */ public void cleanEmptyOutputs() { if (outputMap == null) { return; @@ -95,14 +100,14 @@ } if (outputMap == null) { - logger.warn("Tried to add facet but no Outputs are existing yet."); + logger.warn("Tried to add settings 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); + logger.warn("Tried to add settings for unknown Output: " + outputKey); return; } @@ -112,7 +117,7 @@ public void addFacet(String outputKey, Facet facet) { if (facet == null) { - logger.warn("Tried to add empty facet."); + logger.warn("Tried to add null facet."); return; } @@ -139,6 +144,7 @@ } + /** Empty facets list for outputKey output. */ public void clearFacets(String outputKey) { if (outputKey == null || outputKey.length() == 0) { logger.warn("Tried to clear Facets, but no Output key specified!");
--- a/artifacts/src/main/java/org/dive4elements/river/collections/D4EArtifactCollection.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/collections/D4EArtifactCollection.java Fri Sep 27 17:36:50 2013 +0200 @@ -74,6 +74,22 @@ public static final String XPATH_LOADED_RECOMMENDATIONS = "/art:attribute/art:loaded-recommendations"; + private CallContext context; + + private ArtifactDatabase db; + + protected CallContext getContext() { + return this.context; + } + + protected ArtifactDatabase getArtifactDB() { + return this.db; + } + + protected void setContext(CallContext context) { + this.context = context; + this.db = context.getDatabase(); + } /** * Create and return description Document for this collection. @@ -82,26 +98,26 @@ public Document describe(CallContext context) { log.debug("D4EArtifactCollection.describe: " + identifier); + setContext(context); + 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); + String[] aUUIDs = getArtifactUUIDs(); - oldAttrs = removeAttributes(oldAttrs, context); + oldAttrs = removeAttributes(oldAttrs); parser = new AttributeParser(oldAttrs); - CollectionAttribute newAttr = mergeAttributes( - db, context, parser, aUUIDs); + CollectionAttribute newAttr = mergeAttributes(parser, aUUIDs); - if (checkOutputSettings(newAttr, context)) { - saveCollectionAttribute(db, context, newAttr); + if (checkOutputSettings(newAttr)) { + saveCollectionAttribute(newAttr); } helper.setAttribute(newAttr); @@ -129,13 +145,11 @@ * @param uuids Artifact uuids. */ protected CollectionAttribute mergeAttributes( - ArtifactDatabase db, - CallContext context, AttributeParser oldParser, String[] uuids ) { CollectionAttribute cAttribute = - buildOutAttributes(db, context, oldParser, uuids); + buildOutAttributes(oldParser, uuids); if (cAttribute == null) { log.warn("mergeAttributes: cAttribute == null"); @@ -145,13 +159,19 @@ cAttribute.setLoadedRecommendations( getLoadedRecommendations(oldParser.getAttributeDocument())); - saveCollectionAttribute(db, context, cAttribute); + saveCollectionAttribute(cAttribute); return cAttribute; } - protected Document removeAttributes(Document attrs, CallContext context) { + /** + * Remove those output-elements which have a name that does + * not appear in master artifacts out-list. + * @param attr[in,out] Document to clean and return. + * @return param attr. + */ + protected Document removeAttributes(Document attrs) { Node outs = (Node) XMLUtils.xpath( attrs, "/art:attribute/art:outputs", @@ -167,7 +187,7 @@ if (nodes != null) { for (int i = 0; i < nodes.getLength(); i++) { Element e = (Element)nodes.item(i); - if(!outputExists(e.getAttribute("name"), context)) { + if(!outputExists(e.getAttribute("name"))) { outs.removeChild(e); } } @@ -182,9 +202,9 @@ * @param context current context * @return true if current master artifact has given output. */ - protected boolean outputExists(String name, CallContext context) { - D4EArtifact master = getMasterArtifact(context); - List<Output> outList = master.getOutputs(context); + protected boolean outputExists(String name) { + D4EArtifact master = getMasterArtifact(); + List<Output> outList = master.getOutputs(getContext()); for (Output o : outList) { if (name.equals(o.getName())) { @@ -203,8 +223,6 @@ * @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."); @@ -213,7 +231,7 @@ try { // Save the merged document into database. - db.setCollectionAttribute(identifier(), context.getMeta(), doc); + getArtifactDB().setCollectionAttribute(identifier(), getContext().getMeta(), doc); log.info("Saving CollectionAttribute was successful."); @@ -254,8 +272,7 @@ * @return true, if the CollectionAttribute was modified, otherwise false. */ protected boolean checkOutputSettings( - CollectionAttribute attribute, - CallContext cc + CollectionAttribute attribute ) { boolean modified = false; @@ -281,7 +298,7 @@ if (settings == null) { log.debug("No Settings set for Output '" + outName + "'."); output.setSettings( - createInitialOutputSettings(cc, attribute, outName)); + createInitialOutputSettings(attribute, outName)); modified = true; } @@ -302,11 +319,10 @@ * @return a default Settings object for the specified Output. */ protected Settings createInitialOutputSettings( - CallContext cc, CollectionAttribute attr, String out ) { - OutGenerator outGen = RiverContext.getOutGenerator(cc, out, null); + OutGenerator outGen = RiverContext.getOutGenerator(getContext(), out, null); if (outGen == null) { return null; @@ -314,13 +330,13 @@ // 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); + outGen.init(out, XMLUtils.newDocument(), null, getContext()); + prepareMasterArtifact(outGen); try { - Document outAttr = getAttribute(cc, attr, out); + Document outAttr = getAttribute(attr, out); OutputHelper helper = new OutputHelper(identifier()); - helper.doOut(outGen, out, out, outAttr, cc); + helper.doOut(outGen, out, out, outAttr, getContext()); } catch (ArtifactDatabaseException adbe) { log.error(adbe, adbe); @@ -343,6 +359,8 @@ { boolean debug = log.isDebugEnabled(); + setContext(context); + long reqBegin = System.currentTimeMillis(); if (debug) { @@ -362,16 +380,14 @@ log.debug("-> Output subtype = " + subtype); } - OutGenerator generator = null; - if (type != null - && type.length() > 0 - && type.indexOf("chartinfo") > 0) - { - generator = RiverContext.getOutGenerator(context, type, subtype); - } - else { - generator = RiverContext.getOutGenerator(context, name, subtype); - } + // If type contains 'chartinfo' use a generator that + // just allow access to width, height etc. + + String key = type != null && !type.isEmpty() && type.indexOf("chartinfo") > 0 + ? type + : name; + + OutGenerator generator = RiverContext.getOutGenerator(context, key, subtype); if (generator == null) { log.error("There is no generator specified for output: " + name); @@ -397,13 +413,13 @@ } } - generator.init(format, out, context); + generator.init(key, format, out, context); generator.setSettings(settings); generator.setCollection(this); - prepareMasterArtifact(generator, context); + prepareMasterArtifact(generator); try { - Document attr = getAttribute(context, cAttr, name); + Document attr = getAttribute(cAttr, name); OutputHelper helper = new OutputHelper(identifier()); if (name.equals("sq_overview")) { helper.doOut(generator, name, subtype, format, context); @@ -426,12 +442,11 @@ * 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 + protected void prepareMasterArtifact(OutGenerator generator ) { // Get master artifact. - D4EArtifact master = getMasterArtifact(cc); + D4EArtifact master = getMasterArtifact(); if (master != null) { log.debug("Set master Artifact to uuid: " + master.identifier()); generator.setMasterArtifact(master); @@ -445,18 +460,18 @@ /** * @return masterartifact or null if exception/not found. */ - protected D4EArtifact getMasterArtifact(CallContext context) + protected D4EArtifact getMasterArtifact() { try { - ArtifactDatabase db = context.getDatabase(); - CallMeta callMeta = context.getMeta(); + ArtifactDatabase db = getArtifactDB(); + CallMeta callMeta = getContext().getMeta(); Document document = db.getCollectionsMasterArtifact( identifier(), callMeta); String masterUUID = XMLUtils.xpathString( document, XPATH_MASTER_UUID, ArtifactNamespaceContext.INSTANCE); D4EArtifact masterArtifact = - (D4EArtifact) getArtifact(masterUUID, context); + (D4EArtifact) getArtifact(masterUUID); return masterArtifact; } catch (ArtifactDatabaseException ade) { @@ -471,8 +486,6 @@ * @param uuids List of artifact uuids. */ protected CollectionAttribute buildOutAttributes( - ArtifactDatabase db, - CallContext context, AttributeParser aParser, String[] uuids) { @@ -485,14 +498,16 @@ return null; } - D4EArtifact masterArtifact = getMasterArtifact(context); + D4EArtifact masterArtifact = getMasterArtifact(); if (masterArtifact == null) { log.debug("buildOutAttributes: masterArtifact == null"); return null; } - OutputParser oParser = new OutputParser(db, context); + OutputParser oParser = new OutputParser( + getArtifactDB(), + getContext()); if (uuids != null) { for (String uuid: uuids) { @@ -508,7 +523,7 @@ aParser.parse(); AttributeWriter aWriter = new AttributeWriter( - db, + getArtifactDB(), aParser.getCollectionAttribute(), aParser.getOuts(), aParser.getFacets(), @@ -531,7 +546,6 @@ * @return the attribute for the desired output type. */ protected Document getAttribute( - CallContext context, CollectionAttribute cAttr, String output) throws ArtifactDatabaseException @@ -570,13 +584,13 @@ * * @return a list of uuids. */ - protected String[] getArtifactUUIDs(CallContext context) + protected String[] getArtifactUUIDs() throws ArtifactDatabaseException { log.debug("D4EArtifactCollection.getArtifactUUIDs"); - ArtifactDatabase db = context.getDatabase(); - CallMeta meta = context.getMeta(); + ArtifactDatabase db = getArtifactDB(); + CallMeta meta = getContext().getMeta(); Document itemList = db.listCollectionArtifacts(identifier(), meta); NodeList items = (NodeList) XMLUtils.xpath( @@ -617,7 +631,7 @@ * * @return an Artifact. */ - protected Artifact getArtifact(String uuid, CallContext context) + protected Artifact getArtifact(String uuid) throws ArtifactDatabaseException { log.debug("D4EArtifactCollection.getArtifact"); @@ -629,7 +643,7 @@ } /** - * Returns artifacts that name facetName. + * Returns artifacts with name name. * * @param name The Artifact name to search * @param context The CallContext @@ -638,11 +652,25 @@ */ public List<Artifact> getArtifactsByName(String name, CallContext context) { + setContext(context); + return getArtifactsByName(name); + } + + + /** + * Returns artifacts with name name. + * + * @param name The Artifact name to search + * + * @return a list of artifacts matching this name. + */ + protected List<Artifact> getArtifactsByName(String name) + { log.debug("Searching for Artifacts: " + name); List<Artifact> ret = new ArrayList<Artifact>(); try { - for (String uuid: getArtifactUUIDs(context)) { - D4EArtifact subArt = (D4EArtifact)getArtifact(uuid, context); + for (String uuid: getArtifactUUIDs()) { + D4EArtifact subArt = (D4EArtifact) getArtifact(uuid); if (subArt.getName() != null && subArt.getName().equals(name)) { ret.add(subArt); }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ATExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ATExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -30,6 +30,7 @@ import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; import org.dive4elements.river.model.TimeInterval; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import org.dive4elements.river.artifacts.access.RangeAccess; @@ -43,7 +44,8 @@ protected WQ data; protected CallContext context; protected OutputStream out; - protected D4EArtifact master; + protected D4EArtifact master; + protected String outName; protected D4EArtifactCollection collection; @@ -52,7 +54,13 @@ } @Override - public void init(Document request, OutputStream out, CallContext context) { + public void setup(Object config) { + logger.debug("ATExporter.setup"); + } + + @Override + public void init(String outName, Document request, OutputStream out, CallContext context) { + this.outName = outName; this.context = context; this.out = out; } @@ -71,8 +79,8 @@ @Override public void doOut( ArtifactAndFacet artifactf, - Document attr, - boolean visible + ThemeDocument attr, + boolean visible ) { data = (WQ)artifactf.getData(context); }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AbstractExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AbstractExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -32,6 +32,7 @@ import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; @@ -59,11 +60,14 @@ public static final String DEFAULT_CSV_CHARSET = "UTF-8"; /** The default separator for the CSV export. */ - public static final char DEFAULT_CSV_SEPARATOR = ','; + 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 out name to serve. */ + protected String outName; + /** The document of the incoming out() request. */ protected Document request; @@ -114,11 +118,21 @@ */ protected abstract void addData(Object data); + public void setup(Object config) { + logger.debug("AbstractExporter.setup"); + } + @Override - public void init(Document request, OutputStream out, CallContext context) { + public void init( + String outName, + Document request, + OutputStream out, + CallContext context + ) { logger.debug("AbstractExporter.init"); + this.outName = outName; this.request = request; this.out = out; this.context = context; @@ -158,7 +172,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactFacet.getFacetName();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java Fri Sep 27 17:36:50 2013 +0200 @@ -28,6 +28,9 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; + +import java.text.NumberFormat; + import org.jfree.chart.ChartRenderingInfo; import javax.imageio.ImageIO; @@ -47,6 +50,8 @@ import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.utils.Formatter; + /** * This class is a helper class which supports some methods to export charts @@ -75,7 +80,7 @@ public static final String DEFAULT_ENCODING = "UTF-8"; /** The default separator for the CSV export. */ - public static final char DEFAULT_CSV_SEPARATOR = ','; + public static final char DEFAULT_CSV_SEPARATOR = ';'; /** @@ -300,6 +305,9 @@ log.warn("Wrong encoding for CSV export."); return; } + + NumberFormat format = Formatter.getCSVFormatter(context); + XYPlot plot = chart.getXYPlot(); int count = plot.getDatasetCount(); for (int i = 0; i < count; i++) { @@ -309,7 +317,7 @@ Comparable seriesKey = data.getSeriesKey(j); log.debug("series key: " + seriesKey.toString()); writeCSVHeader(writer, seriesKey.toString()); - writeCSVData(writer, data); + writeCSVData(writer, data, format); } } try { @@ -329,15 +337,41 @@ } - protected static void writeCSVData(CSVWriter writer, XYDataset data) { + /** Get x/y data from axis set and write it, on pair per line. */ + protected static void writeCSVData( + CSVWriter writer, XYDataset data, NumberFormat format) { 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)); + + /* + // Skip (NaN,NaN) datapoints. + if (java.lang.Double.isNaN(data.getYValue(i,j)) + && java.lang.Double.isNaN(data.getXValue(i,j))) { + continue; + } + */ + + String xString; + String yString; + + try { + xString = java.lang.Double.isNaN(data.getXValue(i,j)) + ? "" + : format.format(data.getX(i, j)); + yString = java.lang.Double.isNaN(data.getYValue(i, j)) + ? "" + : format.format(data.getY(i, j)); + } + catch (NumberFormatException nfe) { + xString = data.getX(i, j).toString(); + yString = data.getY(i, j).toString(); + } writer.writeNext(new String[] { - data.getX(i, j).toString(), - data.getY(i, j).toString()}); + xString, + yString}); } } }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -30,12 +30,12 @@ import org.dive4elements.river.jfree.Style; import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.StyledSeries; +import org.dive4elements.river.jfree.AxisDataset; import org.dive4elements.river.model.River; import org.dive4elements.river.themes.LineStyle; import org.dive4elements.river.themes.TextStyle; -import org.dive4elements.river.themes.ThemeAccess; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; -import org.dive4elements.river.utils.ThemeUtil; import java.awt.BasicStroke; import java.awt.Color; @@ -137,6 +137,8 @@ /** List of annotations to insert in plot. */ protected List<RiverAnnotation> annotations = new ArrayList<RiverAnnotation>(); + protected String outName; + /** * A mini interface that allows to walk over the YAXIS enums defined in * subclasses. @@ -150,26 +152,6 @@ - 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 - /** @@ -179,6 +161,10 @@ datasets = new TreeMap<Integer, AxisDataset>(); } + @Override + public void setup(Object config) { + logger.debug("ChartGenerator.setup"); + } /** * Adds annotations to list. The given annotation will be visible. @@ -198,7 +184,7 @@ ChartArea area, LineStyle lineStyle, TextStyle textStyle, - Document theme + ThemeDocument theme ) { // OPTIMIZE pre-calculate area-related values final float TEXT_OFF = 0.03f; @@ -249,7 +235,7 @@ area2, annotation.getPos(), lineStyle); if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { // New line annotation to hit curve. - if (ThemeUtil.parseShowVerticalLine(theme)) { + if (theme.parseShowVerticalLine()) { XYLineAnnotation hitLineAnnotation = createStickyLineAnnotation( StickyAxisAnnotation.SimpleAxis.X_AXIS, @@ -258,7 +244,7 @@ plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, org.jfree.ui.Layer.BACKGROUND); } - if (ThemeUtil.parseShowHorizontalLine(theme)) { + if (theme.parseShowHorizontalLine()) { XYLineAnnotation lineBackAnnotation = createStickyLineAnnotation( StickyAxisAnnotation.SimpleAxis.Y_AXIS2, @@ -277,7 +263,7 @@ lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle); if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { // New line annotation to hit curve. - if (ThemeUtil.parseShowHorizontalLine(theme)) { + if (theme.parseShowHorizontalLine()) { XYLineAnnotation hitLineAnnotation = createStickyLineAnnotation( StickyAxisAnnotation.SimpleAxis.Y_AXIS, @@ -286,7 +272,7 @@ plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, org.jfree.ui.Layer.BACKGROUND); } - if (ThemeUtil.parseShowVerticalLine(theme)) { + if (theme.parseShowVerticalLine()) { XYLineAnnotation lineBackAnnotation = createStickyLineAnnotation( StickyAxisAnnotation.SimpleAxis.X_AXIS, @@ -452,15 +438,14 @@ for (RiverAnnotation fa: annotations) { // Access text styling, if any. - Document theme = fa.getTheme(); + ThemeDocument 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(); + textStyle = theme.parseComplexTextStyle(); + lineStyle = theme.parseComplexLineStyle(); if (fa.getLabel() != null) { LegendItemCollection lic = new LegendItemCollection(); LegendItemCollection old = plot.getFixedLegendItems(); @@ -509,7 +494,7 @@ @Override public abstract void doOut( ArtifactAndFacet bundle, - Document attr, + ThemeDocument attr, boolean visible); @@ -619,10 +604,10 @@ * @param theme Theme document for given annotations. * @param visible The visibility of the annotations. */ - protected void doAnnotations( + public void doAnnotations( RiverAnnotation annotations, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ){ logger.debug("doAnnotations"); @@ -701,9 +686,10 @@ @Override - public void init(Document request, OutputStream out, CallContext context) { + public void init(String outName, Document request, OutputStream out, CallContext context) { logger.debug("ChartGenerator.init"); + this.outName = outName; this.request = request; this.out = out; this.context = context; @@ -1834,11 +1820,14 @@ * * @return a new LegendItem instance. */ - public LegendItem createLegendItem(Document theme, String name) { + public LegendItem createLegendItem(ThemeDocument theme, String name) { // OPTIMIZE Pass font, parsed Theme items. - ThemeAccess themeAccess = new ThemeAccess(theme); - Color color = themeAccess.parseLineColorField(); + Color color = theme.parseLineColorField(); + if (color == null) { + color = Color.BLACK; + } + LegendItem legendItem = new LegendItem(name, color); legendItem.setLabelFont(createLegendLabelFont());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,1572 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.exports; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.Transparency; + +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.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifactdatabase.state.Settings; + +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.ArtifactNamespaceContext; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.PreferredLocale; + +import org.dive4elements.artifacts.common.utils.XMLUtils; + +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.river.artifacts.access.RangeAccess; + +import org.dive4elements.river.artifacts.resources.Resources; + +import org.dive4elements.river.collections.D4EArtifactCollection; + +import org.dive4elements.river.java2d.NOPGraphics2D; + +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.jfree.Bounds; +import org.dive4elements.river.jfree.DoubleBounds; +import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.jfree.StableXYDifferenceRenderer; +import org.dive4elements.river.jfree.Style; +import org.dive4elements.river.jfree.StyledAreaSeriesCollection; +import org.dive4elements.river.jfree.StyledSeries; + +import org.dive4elements.river.model.River; + +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.utils.Formatter; +import org.dive4elements.river.utils.RiverUtils; + +import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; + +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.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Implementation of the OutGenerator interface for charts. + * It should provide some basic things that equal in all chart types. + * + */ +public abstract class ChartGenerator2 implements OutGenerator { + + private static Logger logger = Logger.getLogger(ChartGenerator2.class); + + public static final boolean USE_NOP_GRAPHICS = + Boolean.getBoolean("info.rendering.nop.graphics"); + + + 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"; + + + 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 D4EArtifactCollection 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<RiverAnnotation> annotations = new ArrayList<RiverAnnotation>(); + + protected abstract List<AxisSection> buildYAxisSections(); + + protected String outName; + + /** + * Default constructor that initializes internal data structures. + */ + public ChartGenerator2() { + datasets = new TreeMap<Integer, AxisDataset>(); + } + + /** + * Adds annotations to list. The given annotation will be visible. + */ + public void addAnnotations(RiverAnnotation annotation) { + annotations.add(annotation); + } + + /** + * 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(); + + + /** For every outable (i.e. facets), this function is + * called and handles the data accordingly. */ + @Override + public abstract void doOut( + ArtifactAndFacet bundle, + ThemeDocument attr, + boolean visible); + + + + 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(); + + protected abstract String getDefaultYAxisLabel(String axisName); + + + /** + * 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 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)); + } + } + + /** + * Generate chart. + */ + @Override + public void generate() throws IOException { + + logger.debug("ChartGenerator2.generate"); + + if (outName.indexOf("chartinfo") > 0) { + generateInfo(); + } + else { + generateImage(); + } + } + + + /** Generate only meta infos */ + private void generateInfo() throws IOException { + + logger.debug("ChartInfoGenerator2.generateInfo"); + + JFreeChart chart = generateChart(); + + int[] size = getSize(); + if (size == null) { + size = 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"); + } + + + InfoGeneratorHelper2 helper = new InfoGeneratorHelper2(this); + Document doc = helper.createInfoDocument(chart, info); + + XMLUtils.toStream(doc, out); + } + + /** Generate the diagram as an image. */ + private void generateImage() throws IOException { + logger.debug("ChartGenerator2.generateImage"); + + 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(String outName, Document request, OutputStream out, CallContext context) { + logger.debug("ChartGenerator2.init"); + + this.outName = outName; + this.request = request; + this.out = out; + this.context = context; + } + + + /** Sets the master artifact. */ + @Override + public void setMasterArtifact(Artifact master) { + this.master = master; + } + + + /** + * Gets the master artifact. + * @return the master artifact. + */ + public Artifact getMaster() { + return master; + } + + + /** Sets the collection. */ + @Override + public void setCollection(D4EArtifactCollection 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; + } + + + /** + * 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; + } + + /** + * Glue between axis names and index. + */ + protected abstract String axisIndexToName(int index); + + /** + * 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 index) { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return DEFAULT_FONT_SIZE; + } + + AxisSection as = chartSettings.getAxisSection(axisIndexToName(index)); + if (as == null) { + return DEFAULT_FONT_SIZE; + } + 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 }; + } + + protected abstract String getYAxisLabel(String axisName); + + /** + * 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); + + if (as == null) { + return null; + } + + 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); + } + + + /** + * Look up \param key in i18n dictionary. + * @param key key for which to find i18nd version. + * @param def default, returned if lookup failed. + * @return value found in i18n dictionary, \param def if no value found. + */ + public String msg(String key, String def) { + return Resources.getMsg(context.getMeta(), key, def); + } + + /** + * Look up \param key in i18n dictionary. + * @param key key for which to find i18nd version. + * @return value found in i18n dictionary, key itself if failed. + */ + public String msg(String key) { + return Resources.getMsg(context.getMeta(), key, key); + } + + public String msg(String key, String def, Object[] args) { + return Resources.getMsg(context.getMeta(), key, def, args); + } + + + protected String getRiverName() { + D4EArtifact flys = (D4EArtifact) master; + + River river = RiverUtils.getRiver(flys); + return (river != null) ? river.getName() : ""; + } + + + protected double[] getRange() { + D4EArtifact flys = (D4EArtifact) master; + + RangeAccess rangeAccess = new RangeAccess(flys); + return rangeAccess.getKmRange(); + } + + + /** + * 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. + * If the (x|y)range elements are not found in request document, return + * null (i.e. not zoomed). + * + * @return a String array with [lower, upper], null if not in document. + */ + 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 }; + } + + + /** Returns null if the (x|y)range-element was not found in request document. + * This usally means that the axis are not manually zoomed, i.e. showing + * full data extent. */ + 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) { + return new IdentifiableNumberAxis(axisIndexToName(idx), label); + } + + + /** + * Create Y (range) axis for given index. + * Shall be overriden by subclasses. + */ + protected NumberAxis createYAxis(int index) { + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getYAxisFontSize(index)); + + String axisName = axisIndexToName(index); + + IdentifiableNumberAxis axis = new IdentifiableNumberAxis( + axisName, getYAxisLabel(axisName)); + + 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(ThemeDocument theme, String name) { + // OPTIMIZE Pass font, parsed Theme items. + + Color color = theme.parseLineColorField(); + if (color == null) { + color = Color.BLACK; + } + + 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); + } + + /** + * Retuns the call context. May be null if init hasn't been called yet. + * + * @return the CallContext instance + */ + public CallContext getCallContext() { + return context; + } +}
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartInfoGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,6 +10,7 @@ import org.dive4elements.river.collections.D4EArtifactCollection; import org.dive4elements.river.java2d.NOPGraphics2D; +import org.dive4elements.river.themes.ThemeDocument; import java.io.IOException; import java.io.OutputStream; @@ -68,6 +69,10 @@ this.generator = generator; } + public void setup(Object config) { + logger.debug("ChartInfoGenerator.setup"); + } + /** * Dispatches the operation to the instantiated generator. @@ -76,10 +81,10 @@ * @param out * @param context */ - public void init(Document request, OutputStream out, CallContext context) { + public void init(String outName, Document request, OutputStream out, CallContext context) { this.out = out; - generator.init(request, out, context); + generator.init(outName, request, out, context); } @@ -106,9 +111,10 @@ /** * Dispatches the operation to the instantiated generator. */ + @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { generator.doOut(artifactFacet, attr, visible);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -19,8 +19,6 @@ import java.text.DateFormat; import java.util.Locale; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; import au.com.bytecode.opencsv.CSVWriter; @@ -32,7 +30,6 @@ import org.dive4elements.artifacts.common.utils.Config; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.D4EArtifact; @@ -82,15 +79,10 @@ protected boolean isCalculated; protected Date validSince; - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("ComputedDischargeCurveExporter.init"); - - super.init(request, out, context); - - this.data = new ArrayList<WQKms>(); + public ComputedDischargeCurveExporter() { + data = new ArrayList<WQKms>(); } - @Override protected void addData(Object d) { if (d instanceof CalculationResult) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,10 +16,12 @@ import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.WKms; import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.exports.process.DischargeProcessor; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StickyAxisAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import java.awt.Font; @@ -32,11