# HG changeset patch # User Tom Gottfried # Date 1380296210 -7200 # Node ID 7fabae60428b8ee3573397b7d8118da6db4ac7d4 # Parent 28748bb1b676dbe52057bda505bd5fa28efa684f# Parent 5be5bf32bead5e947c5f5262ddb5f66c8ded1008 Merged changes from default into double-precision branch. diff -r 28748bb1b676 -r 7fabae60428b .hgtags --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/artifacts/chart.xml --- 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 @@ + diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/artifacts/gaugedischargecurve.xml --- 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 @@ + + diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/artifacts/winfo.xml --- 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 @@ + + @@ -382,6 +384,8 @@ + + @@ -638,6 +642,7 @@ + diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/conf.xml --- 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 @@ + + ]> YOUR_SECRET @@ -284,104 +286,7 @@ - - org.dive4elements.river.exports.DischargeCurveGenerator - org.dive4elements.river.exports.DischargeCurveInfoGenerator - org.dive4elements.river.exports.CrossSectionGenerator - org.dive4elements.river.exports.CrossSectionInfoGenerator - org.dive4elements.river.exports.ComputedDischargeCurveGenerator - org.dive4elements.river.exports.ComputedDischargeCurveInfoGenerator - org.dive4elements.river.exports.LongitudinalSectionGenerator - org.dive4elements.river.exports.LongitudinalSectionInfoGenerator - org.dive4elements.river.exports.DurationCurveGenerator - org.dive4elements.river.exports.DurationCurveInfoGenerator - org.dive4elements.river.exports.DischargeLongitudinalSectionGenerator - org.dive4elements.river.exports.DischargeLongitudinalSectionInfoGenerator - org.dive4elements.river.exports.WaterlevelExporter - org.dive4elements.river.exports.extreme.ExtremeWQCurveGenerator - org.dive4elements.river.exports.WaterlevelExporter - org.dive4elements.river.exports.extreme.ExtremeWQCurveInfoGenerator - org.dive4elements.river.exports.fixings.FixWQCurveGenerator - org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator - org.dive4elements.river.exports.DurationCurveExporter - org.dive4elements.river.exports.ComputedDischargeCurveExporter - org.dive4elements.river.exports.DischargeLongitudinalSectionExporter - org.dive4elements.river.exports.WDifferencesCurveGenerator - org.dive4elements.river.exports.WDifferencesCurveInfoGenerator - org.dive4elements.river.exports.WDifferencesExporter - org.dive4elements.river.exports.MapGenerator - org.dive4elements.river.exports.MapGenerator - org.dive4elements.river.exports.ReferenceCurveGenerator - org.dive4elements.river.exports.NormalizedReferenceCurveGenerator - org.dive4elements.river.exports.NormalizedReferenceCurveInfoGenerator - org.dive4elements.river.exports.ReferenceCurveInfoGenerator - org.dive4elements.river.exports.ReferenceCurveExporter - org.dive4elements.river.exports.HistoricalDischargeCurveGenerator - org.dive4elements.river.exports.HistoricalDischargeCurveInfoGenerator - org.dive4elements.river.exports.HistoricalDischargeWQCurveGenerator - org.dive4elements.river.exports.HistoricalDischargeWQCurveInfoGenerator - org.dive4elements.river.exports.HistoricalDischargeCurveExporter - org.dive4elements.river.exports.FlowVelocityGenerator - org.dive4elements.river.exports.FlowVelocityInfoGenerator - org.dive4elements.river.exports.FlowVelocityExporter - org.dive4elements.river.exports.MiddleBedHeightGenerator - org.dive4elements.river.exports.MiddleBedHeightInfoGenerator - org.dive4elements.river.exports.MiddleBedHeightExporter - org.dive4elements.river.exports.minfo.BedQualityGenerator - org.dive4elements.river.exports.minfo.BedQualityInfoGenerator - org.dive4elements.river.exports.minfo.BedQualityExporter - org.dive4elements.river.exports.minfo.BedDifferenceYearGenerator - org.dive4elements.river.exports.minfo.BedDiffYearInfoGenerator - org.dive4elements.river.exports.minfo.BedDifferenceEpochGenerator - org.dive4elements.river.exports.minfo.BedDiffEpochInfoGenerator - org.dive4elements.river.exports.minfo.BedDiffHeightYearGenerator - org.dive4elements.river.exports.minfo.BedDiffHeightYearInfoGenerator - org.dive4elements.river.exports.minfo.BedDifferenceExporter - org.dive4elements.river.exports.sq.SQRelationGeneratorA - org.dive4elements.river.exports.sq.SQRelationGeneratorB - org.dive4elements.river.exports.sq.SQRelationGeneratorC - org.dive4elements.river.exports.sq.SQRelationGeneratorD - org.dive4elements.river.exports.sq.SQRelationGeneratorE - org.dive4elements.river.exports.sq.SQRelationGeneratorF - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationInfoGenerator - org.dive4elements.river.exports.sq.SQRelationExporter - org.dive4elements.river.exports.sq.SQOverviewGenerator - org.dive4elements.river.exports.fixings.ParametersExporter - org.dive4elements.river.exports.fixings.DeltaWtExporter - org.dive4elements.river.exports.fixings.FixDeltaWtGenerator - org.dive4elements.river.exports.fixings.FixDeltaWtInfoGenerator - org.dive4elements.river.exports.fixings.FixLongitudinalSectionGenerator - org.dive4elements.river.exports.fixings.FixLongitudinalSectionInfoGenerator - org.dive4elements.river.exports.fixings.FixDerivedCurveGenerator - org.dive4elements.river.exports.fixings.FixDerivedCurveInfoGenerator - org.dive4elements.river.exports.WaterlevelExporter - org.dive4elements.river.exports.fixings.FixWQCurveGenerator - org.dive4elements.river.exports.fixings.FixWQCurveInfoGenerator - org.dive4elements.river.exports.minfo.SedimentLoadLSGenerator - org.dive4elements.river.exports.minfo.SedimentLoadExporter - org.dive4elements.river.exports.minfo.SedimentLoadLSInfoGenerator - - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - org.dive4elements.river.exports.ReportGenerator - - org.dive4elements.river.exports.ATExporter - org.dive4elements.river.exports.ATExporter - org.dive4elements.river.exports.fixings.FixATExport - org.dive4elements.river.exports.ShapeExporter - + &generators; diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/floodmap.xml --- 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 @@ - - - - - - - - - - - - - - - - - - - - - diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/generators.xml --- /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 @@ + + + + + + + + + + + &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> + diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/jasper/sqrelation.jasper Binary file artifacts/doc/conf/jasper/sqrelation.jasper has changed diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/jasper/sqrelation_en.jasper Binary file artifacts/doc/conf/jasper/sqrelation_en.jasper has changed diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/longitudinal-diagram-defaults.xml --- /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> diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/barrier_lines_class.vm --- 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" diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/barrier_polygons_class.vm --- 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" diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/mapfile.vm --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/river-mapfile.vm --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/shapefile_layer.vm --- 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() ) diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/mapserver/wsplgen_layer.vm --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/meta-data.xml --- 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> diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/themes.xml --- 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" /> diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/themes/default.xml --- 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" diff -r 28748bb1b676 -r 7fabae60428b artifacts/doc/conf/themes/second.xml --- 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" diff -r 28748bb1b676 -r 7fabae60428b artifacts/pom.xml --- 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> diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/CrossSectionArtifact.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/D4EArtifact.java --- 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()) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/FlowVelocityMeasurementArtifact.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/SedimentYieldArtifact.java --- /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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/StaticWQKmsArtifact.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/WQKmsInterpolArtifact.java --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/access/DGMAccess.java --- /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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/access/RangeAccess.java --- 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() { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContext.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java --- 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++; + } } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Datacage.java --- 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; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/Recommendations.java --- 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(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/datacage/templating/FunctionResolver.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/math/MovingAverage.java --- 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]; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/Calculation6.java --- 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"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/CrossSectionFactory.java --- 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. * diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java --- 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"; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/FixingsOverview.java --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/ManagedFacet.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/OfficialLineFinder.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/QRangeTree.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/W.java --- 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() { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKms.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/WKmsImpl.java --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/WQKms.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/WstValueTable.java --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/ZoomScale.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/DateUniqueMaker.java --- /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); + } + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/Fitting.java --- 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; } } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisCalculation.java --- 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; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisEventsFacet.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixAnalysisResult.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixCalculation.java --- 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()); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixReferenceEventsFacet.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixResult.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixWQCurveFacet.java --- 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; } /** diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/RankRemapper.java --- /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); + } + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffCalculation.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearFilterFacet.java --- 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(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedDiffYearResult.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/BedHeightFactory.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/FlowVelocityMeasurementFactory.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurement.java --- 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) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurementFactory.java --- 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, diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/QualityMeasurements.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensity.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityFactory.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentDensityValue.java --- 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 { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoad.java --- 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() { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadCalculation.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFacet.java --- 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) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java --- 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; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFraction.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadUnknownFacet.java --- 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()); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Fitting.java --- 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 { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/LogSQ.java --- /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; + } +} + diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/MeasurementFactory.java --- 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(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/Measurements.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQ.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationCalculation.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/SQRelationJRDataSource.java --- 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; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/services/D4EService.java --- 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(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/services/DischargeInfoService.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/services/RiverInfoService.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/CalculationSelect.java --- 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 diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodMapState.java --- 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 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeDischargeState.java --- 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( diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/GaugeTimerangeState.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticState.java --- 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; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/StaticWQKmsState.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java --- 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"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/fixation/FixAnalysisCompute.java --- 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)); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/DifferencesState.java --- 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( diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/SedimentLoadCalculate.java --- 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)); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/collections/AttributeParser.java --- 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; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/collections/AttributeWriter.java --- 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. diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/collections/CollectionAttribute.java --- 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!"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/collections/D4EArtifactCollection.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ATExporter.java --- 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); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/AbstractExporter.java --- 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(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java --- 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}); } } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java --- 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()); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java --- /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; + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ChartInfoGenerator.java --- 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); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveExporter.java --- 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) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ComputedDischargeCurveGenerator.java --- 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 +34,10 @@ import org.apache.log4j.Logger; -import org.w3c.dom.Document; - /** - * An OutGenerator that generates discharge curves. + * An OutGenerator that generates discharge curves, also at locations + * not at a gauge. * * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ @@ -104,6 +105,7 @@ * Create Y (range) axis for given index, here with a special axis * that depends on other axis (does translation and scaling for * special case at gauge in cm). + * @return A NumberAxis, possibly scaled. */ @Override protected NumberAxis createYAxis(int index) { @@ -138,7 +140,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactFacet.getFacetName(); @@ -150,9 +152,11 @@ return; } - //XXX DEAD CODE // Facet facet = artifactFacet.getFacet(); - - if (name.equals(COMPUTED_DISCHARGE_Q)) { + DischargeProcessor dProcessor = new DischargeProcessor(getRange()[0]); + if (dProcessor.canHandle(name)) { + dProcessor.doOut(this, artifactFacet, attr, visible, YAXIS.W.idx); + } + else if (name.equals(COMPUTED_DISCHARGE_Q)) { doDischargeQOut((WQKms) artifactFacet.getData(context), artifactFacet, attr, visible); } else if (name.equals(STATIC_WQ)) { @@ -165,18 +169,9 @@ attr, visible); } - else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) - || name.equals(MAINVALUES_Q) - || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) - || name.equals(MAINVALUES_W) - ) { - RiverAnnotation mainValues = (RiverAnnotation) artifactFacet.getData(context); - translateRiverAnnotation(mainValues); - doAnnotations( - mainValues, - artifactFacet, attr, visible); - } - else if (name.equals(STATIC_WKMS_INTERPOL) || name.equals(HEIGHTMARKS_POINTS)) { + else if (STATIC_WKMS_INTERPOL.equals(name) || + HEIGHTMARKS_POINTS.equals(name) || + STATIC_WQKMS_W.equals(name)) { doWAnnotations( artifactFacet.getData(context), artifactFacet, @@ -212,16 +207,16 @@ /** * Add WQ Data to plot. - * @param wqkms data as double[][] + * @param wq data as double[][] */ protected void doWQOut( - Object wqkms, + Object wq, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("ComputedDischargeCurveGenerator: doWQOut"); - double [][] data = (double [][]) wqkms; + double [][] data = (double [][]) wq; XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); StyledSeriesBuilder.addPoints(series, data, true); @@ -238,7 +233,7 @@ protected void doDischargeQOut( WQKms wqkms, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("ComputedDischargeCurveGenerator: doDischargeQOut"); @@ -270,7 +265,7 @@ protected void doQOut( WQKms wqkms, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("ComputedDischargeCurveGenerator: doQOut (add W/Q data)."); @@ -289,7 +284,7 @@ protected void doWQAnnotations( Object wqkms, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); @@ -315,7 +310,7 @@ protected void doWAnnotations( Object wqkms, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { Facet facet = aandf.getFacet(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -21,7 +21,6 @@ import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.DataProvider; @@ -36,10 +35,9 @@ import org.dive4elements.river.model.FastCrossSectionLine; 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.Formatter; -import org.dive4elements.river.utils.ThemeUtil; /** @@ -72,7 +70,6 @@ /** Trivial Constructor. */ public CrossSectionGenerator() { - super(); } @@ -185,14 +182,13 @@ for(RiverAnnotation fa : this.annotations) { // Access text styling, if any. - Document theme = fa.getTheme(); + ThemeDocument theme = fa.getTheme(); TextStyle textStyle = null; // XXX: DEAD CODE // LineStyle lineStyle = null; // Get Themeing information and add legend item. if (theme != null) { - ThemeAccess themeAccess = new ThemeAccess(theme); - textStyle = themeAccess.parseTextStyle(); + textStyle = theme.parseComplexTextStyle(); // XXX: DEAD CODE // lineStyle = themeAccess.parseLineStyle(); if (fa.getLabel() != null) { LegendItemCollection lic = new LegendItemCollection(); @@ -258,7 +254,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactFacet.getFacetName(); @@ -332,7 +328,7 @@ protected void doCrossSectionWaterLineOut( Object o, String seriesName, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("CrossSectionGenerator.doCrossSectionWaterLineOut"); @@ -341,10 +337,10 @@ // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); - if (!ThemeUtil.parseShowLineLabel(theme)) { + if (!theme.parseShowLineLabel()) { series.setLabel(""); } - if (ThemeUtil.parseShowWidth(theme)) { + if (theme.parseShowWidth()) { NumberFormat nf = Formatter.getMeterFormat(this.context); String labelAdd = "b=" + nf.format(lines.width) + "m"; if (series.getLabel().length() == 0) { @@ -354,7 +350,7 @@ series.setLabel(series.getLabel() + ", " + labelAdd); } } - if (ThemeUtil.parseShowLevel(theme) && lines.points.length > 1 + if (theme.parseShowLevel() && lines.points.length > 1 && lines.points[1].length > 0) { NumberFormat nf = Formatter.getMeterFormat(this.context); D4EArtifact flys = (D4EArtifact) master; @@ -369,7 +365,7 @@ series.setLabel(series.getLabel() + ", " + labelAdd); } } - if (ThemeUtil.parseShowMiddleHeight(theme) && lines.width != 0) { + if (theme.parseShowMiddleHeight() && lines.width != 0) { NumberFormat nf = Formatter.getMeterFormat(this.context); String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m"; // : " + lines.area + "/" + lines.width); @@ -391,7 +387,7 @@ protected void doHyk( Object o, String seriesName, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("CrossSectionGenerator.doHyk"); @@ -419,7 +415,7 @@ protected void doCrossSectionOut( Object o, String seriesName, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("CrossSectionGenerator.doCrossSectionOut"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DiagramAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DiagramAttributes.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,532 @@ +/* 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.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import org.dive4elements.river.exports.process.Processor; + +import org.apache.log4j.Logger; + +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.artifacts.common.utils.ElementConverter; + +public class DiagramAttributes +implements ElementConverter +{ + private static Logger log = Logger.getLogger(DiagramAttributes.class); + + public interface Evaluator { + Object evaluate(D4EArtifact artifact, CallContext context); + } // interface Evaluator + + public static final Evaluator TRUE = new Evaluator() { + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + return Boolean.TRUE; + } + }; + + public static final Evaluator FALSE = new Evaluator() { + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + return Boolean.FALSE; + } + }; + + public class Instance { + + private List<Processor> processors; + + public Instance() { + processors = createProcessors(); + } + + private List<Processor> createProcessors() { + List<Processor> processors = + new ArrayList<Processor>(axesProcessors.size()); + for (AxisProcessor ap: axesProcessors) { + Processor pr = ap.createProcessor(); + if (pr != null) { + processors.add(pr); + } + } + return processors; + } + + public List<Processor> getProcessorsForAxisName(String axisName) { + List<Processor> retval = new ArrayList<Processor>(5); + for (Processor pr: processors) { + String aName = pr.getAxisName(); + if (aName != null && axisName.equals(aName)) { + retval.add(pr); + } + } + return retval; + } + + public List<Processor> getProcessors() { + return processors; + } + + public Title getTitle() { + return DiagramAttributes.this.getTitle(); + } + + public Title getSubtitle() { + return DiagramAttributes.this.getSubtitle(); + } + + public DomainAxisAttributes getDomainAxis() { + return DiagramAttributes.this.getDomainAxis(); + } + + public int getAxisIndex(String axisName) { + return DiagramAttributes.this.getAxisIndex(axisName); + } + + public String getAxisName(int index) { + return DiagramAttributes.this.getAxisName(index); + } + + public List<AxisAttributes> getAxesAttributes() { + return DiagramAttributes.this.getAxesAttributes(); + } + } // class Instance + + public static class AxisAttributes { + private String name; + private boolean isLeftAlign; // TODO: Remove! + private boolean forceAlign; // TODO: Remove! + private boolean includeZero; // TODO: Use Evaluator + + private Evaluator isInverted; + + public AxisAttributes() { + } + + public AxisAttributes( + String name, + boolean isLeftAlign, + boolean forceAlign, + boolean includeZero, + Evaluator isInverted + ) { + this.name = name; + this.isLeftAlign = isLeftAlign; + this.forceAlign = forceAlign; + this.includeZero = includeZero; + this.isInverted = isInverted; + } + + public String getName() { + return name; + } + + public boolean isLeftAlign() { + return isLeftAlign; + } + + public boolean forceAlign() { + return forceAlign; + } + + public boolean includeZero() { + return includeZero; + } + + public Evaluator isInverted() { + return isInverted; + } + } // class AxisAttributes + + public class DomainAxisAttributes extends AxisAttributes { + + private Title title; + + public DomainAxisAttributes() { + } + + public DomainAxisAttributes( + String name, + boolean isLeftAlign, + boolean forceAlign, + boolean includeZero, + Evaluator isInverted, + Title title + ) { + super(name, isLeftAlign, forceAlign, includeZero, isInverted); + this.title = title; + } + + public Title getTitle() { + return title; + } + } // class DomainAxisAttributes + + public static class AxisProcessor { + + private Class<Processor> processorClass; + private String axisName; + + public AxisProcessor(Class<Processor> processorClass, String axisName) { + this.processorClass = processorClass; + this.axisName = axisName; + } + + public Processor createProcessor() { + try { + Processor pr = processorClass.newInstance(); + pr.setAxisName(axisName); + return pr; + } + catch (InstantiationException ie) { + log.error(ie, ie); + } + catch (IllegalAccessException iae) { + log.error(iae, iae); + } + return null; + } + + } // class AxisProcessor + + public abstract static class ConvertEvaluator + implements Evaluator + { + protected String key; + protected String type; + + public ConvertEvaluator() { + } + + public ConvertEvaluator(String key, String type) { + this.key = key; + this.type = type; + } + + protected Object convert(Object value) { + if (value == null || type == null || type.isEmpty()) { + return value; + } + if (value instanceof String) { + String v = (String)value; + if ("double".equals(type)) { + return Double.valueOf(v); + } + if ("int".equals(type)) { + return Integer.valueOf(v); + } + if ("string".equals(type)) { + return v; + } + } + // TODO: Support more types + return value; + } + } // class ConvertEvaluator + + public static class ContextEvaluator extends ConvertEvaluator { + + public ContextEvaluator() { + } + + public ContextEvaluator(String key, String type) { + super(key, type); + } + + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + return convert(context.getContextValue(key)); + } + } // class ContextEvaluator + + public static class ArtifactEvaluator extends ConvertEvaluator { + + public ArtifactEvaluator() { + } + + public ArtifactEvaluator(String key, String type) { + super(key, type); + } + + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + return convert(artifact.getDataAsString(key)); + } + } // class ContextEvaluator + + public static class StringEvaluator implements Evaluator { + + private String value; + + public StringEvaluator() { + } + public StringEvaluator(String value) { + this.value = value; + } + + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + return value; + } + } // class StringEvaluator + + public static class Title { + + private String key; + private String def; + private List<Evaluator> arguments; + + public Title() { + arguments = new ArrayList<Evaluator>(5); + } + + public Title(String key) { + this(key, key); + } + + public Title(String key, String def) { + this(); + this.key = key; + this.def = def; + } + + public String getKey() { + return key; + } + + public void addArgument(Evaluator argument) { + arguments.add(argument); + } + + public String evaluate(D4EArtifact artifact, CallContext context) { + if (key == null || key.isEmpty()) { + return def; + } + Object [] args = new Object[arguments.size()]; + for (int i = 0; i < args.length; ++i) { + args[i] = arguments.get(i).evaluate(artifact, context); + } + return Resources.getMsg(context.getMeta(), key, def, args); + } + } // class Title + + private List<AxisAttributes> axesAttrs; + private List<AxisProcessor> axesProcessors; + + private Title title; + private Title subtitle; + + private DomainAxisAttributes domainAxis; + + public DiagramAttributes() { + axesAttrs = new ArrayList<AxisAttributes>(5); + axesProcessors = new ArrayList<AxisProcessor>(5); + } + + @Override + public Object convert(Element config) { + parseAxis(config); + parseProcessors(config); + parseTitle(config); + parseSubtitle(config); + parseDomainAxis(config); + return this; + } + + public List<AxisAttributes> getAxesAttributes() { + return axesAttrs; + } + + private void parseAxis(Element config) { + NodeList axisNodes = config.getElementsByTagName("axis"); + + for (int i = 0, N = axisNodes.getLength(); i < N; ++i) { + Element axisElement = (Element)axisNodes.item(i); + String name = axisElement.getAttribute("name").trim(); + String align = axisElement.getAttribute("align").trim(); + String includeZero = + axisElement.getAttribute("include-zero").trim(); + + String isInverted = axisElement.getAttribute("inverted"); + + if (name.isEmpty()) { + continue; + } + boolean isleftAlign = false; + boolean forceAlign = false; + for (String part: align.split("[\\s,]")) { + part = part.trim(); + if ("left" .equals(part)) isleftAlign = true; + else if ("right".equals(part)) isleftAlign = false; + else if ("force".equals(part)) forceAlign = true; + } + + Evaluator isInvertedE = parseEvaluator(isInverted, FALSE); + + axesAttrs.add(new AxisAttributes( + name, isleftAlign, forceAlign, + includeZero.equals("true"), + isInvertedE)); + } + } + + private static Evaluator createDynamicEvaluator( + String className, + Evaluator def + ) { + try { + Class<Evaluator> clazz = (Class<Evaluator>)Class.forName(className); + return clazz.newInstance(); + } + catch (ClassNotFoundException cnfe) { + log.error(cnfe, cnfe); + } + catch (InstantiationException ie) { + log.error(ie, ie); + } + catch (IllegalAccessException iae) { + log.error(iae, iae); + } + return def; + } + + private static Evaluator parseEvaluator(String s, Evaluator def) { + if ((s = s.trim()).isEmpty()) return def; + if ("true".equals(s)) return TRUE; + if ("false".equals(s)) return FALSE; + if (s.endsWith("()")) { + return createDynamicEvaluator( + s.substring(0, s.length()-2).trim(), + def); + } + return def; + } + + public List<AxisProcessor> getAxesProcessors() { + return axesProcessors; + } + + public Title getTitle() { + return title; + } + + public Title getSubtitle() { + return subtitle; + } + + public DomainAxisAttributes getDomainAxis() { + return domainAxis; + } + + private void parseProcessors(Element config) { + NodeList processorNodes = config.getElementsByTagName("processor"); + + for (int i = 0, N = processorNodes.getLength(); i < N; ++i) { + Element processorElement = (Element)processorNodes.item(i); + String className = processorElement.getAttribute("class").trim(); + String axisName = processorElement.getAttribute("axis").trim(); + if (className.isEmpty() || axisName.isEmpty()) { + continue; + } + + try { + Class<Processor> processorClass = + (Class<Processor>)Class.forName(className); + axesProcessors.add(new AxisProcessor(processorClass, axisName)); + } + catch (ClassNotFoundException cnfe) { + log.error(cnfe, cnfe); + } + } + } + + private void parseTitle(Element config) { + title = extractTitle(config, "title"); + } + + private void parseSubtitle(Element config) { + subtitle = extractTitle(config, "subtitle"); + } + + private void parseDomainAxis(Element config) { + Title title = extractTitle(config, "domain-axis"); + String includeZero = config.getAttribute("include-zero"); + String isInverted = config.getAttribute("inverted"); + + domainAxis = new DomainAxisAttributes( + "X", + false, + false, + includeZero.equals("true"), + parseEvaluator(isInverted, FALSE), + title); + } + + private static Title extractTitle(Element config, String tagName) { + NodeList titleNodes = config.getElementsByTagName(tagName); + if (titleNodes.getLength() < 1) { + return null; + } + Element titleElement = (Element)titleNodes.item(0); + String key = titleElement.getAttribute("key"); + String def = titleElement.getAttribute("default"); + Title title = new Title(key, def); + NodeList argumentNodes = titleElement.getElementsByTagName("arg"); + for (int i = 0, N = argumentNodes.getLength(); i < N; ++i) { + Element argumentElement = (Element)argumentNodes.item(i); + String expression = argumentElement.getAttribute("expr"); + String type = argumentElement.getAttribute("type"); + + Evaluator ev = new StringEvaluator(expression); + + if (expression.endsWith("()")) { + ev = createDynamicEvaluator( + expression.substring(0, expression.length()-2).trim(), + ev); + } + else if (expression.startsWith("artifact.")) { + ev = new ArtifactEvaluator( + expression.substring("artifact.".length()), type); + } + else if (expression.startsWith("context.")) { + ev = new ContextEvaluator( + expression.substring("context.".length()), type); + } + + title.addArgument(ev); + } + return title; + } + + public int getAxisIndex(String axisName) { + for (int i = axesAttrs.size()-1; i >= 0; --i) { + if (axesAttrs.get(i).getName().equals(axisName)) { + return i; + } + } + return -1; + } + + public String getAxisName(int index) { + return index < 0 || index >= axesAttrs.size() + ? "" // null? + : axesAttrs.get(index).getName(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,1167 @@ +/* Copyright (C) 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.Color; +import java.awt.Font; + +import java.text.NumberFormat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import java.io.OutputStream; + +import javax.swing.ImageIcon; + +import org.apache.log4j.Logger; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifactdatabase.state.Facet; + +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.river.exports.process.Processor; + +import org.dive4elements.river.jfree.AnnotationHelper; +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.jfree.Bounds; +import org.dive4elements.river.jfree.DoubleBounds; +import org.dive4elements.river.jfree.StyledAreaSeriesCollection; + +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.utils.RiverUtils; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; + +import org.jfree.chart.annotations.XYAnnotation; +import org.jfree.chart.annotations.XYImageAnnotation; + +import org.jfree.chart.axis.LogarithmicAxis; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; + +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.chart.plot.XYPlot; + +import org.jfree.data.Range; + +import org.jfree.data.general.Series; + +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import org.w3c.dom.Document; + + +/** + * The main diagram creation class. + * + * This class is the glue between output processors and facets. + * The generator creates one diagram and calls the appropiate + * processors for the state and + * + * With respect to datasets, ranges and axis, there are following requirements: + * <ul> + * <li> First in, first drawn: "Early" datasets should be of lower Z-Oder + * than later ones (only works per-axis). </li> + * <li> Visible axis should initially show the range of all datasets that + * show data for this axis (even invisible ones). Motivation: Once + * a dataset (theme) has been activated, it should be on screen. </li> + * <li> There should always be a Y-Axis on the "left". </li> + * </ul> + */ +public class DiagramGenerator extends ChartGenerator2 { + + public static final int AXIS_SPACE = 5; + + /** The logger that is used in this generator. */ + private static Logger logger = Logger.getLogger(DiagramGenerator.class); + + protected List<Marker> domainMarkers = new ArrayList<Marker>(); + + protected List<Marker> valueMarkers = new ArrayList<Marker>(); + + /** The max X range to include all X values of all series for each axis. */ + protected Map<Integer, Bounds> xBounds; + + /** The max Y range to include all Y values of all series for each axis. */ + protected Map<Integer, Bounds> yBounds; + + /** Whether or not the plot is inverted (left-right). */ + private boolean inverted; + + protected DiagramAttributes.Instance diagramAttributes; + + public DiagramGenerator() { + super(); + + xBounds = new HashMap<Integer, Bounds>(); + yBounds = new HashMap<Integer, Bounds>(); + } + + @Override + public void setup(Object config) { + + if (!(config instanceof DiagramAttributes)) { + logger.error("invalid config type"); + return; + } + DiagramAttributes da = (DiagramAttributes)config; + diagramAttributes = da.new Instance(); + } + + @Override + public void init( + String outName, + Document request, + OutputStream out, + CallContext context + ) { + super.init(outName, request, out, context); + + RiverUtils.setKMFromRequestInContext(request, context); + + setInvertedFromConfig(); + } + + private void setInvertedFromConfig() { + DiagramAttributes.DomainAxisAttributes dx = + diagramAttributes.getDomainAxis(); + + if (dx != null) { + inverted = (Boolean)dx.isInverted() + .evaluate((D4EArtifact)getMaster(), context); + logger.debug("setInvertedFromConfig: " + inverted); + } else { + logger.debug("setInvertedFromConfig no domain axis found?"); + } + } + + /** + * Generate the chart anew (including localized axis and all). + */ + @Override + public JFreeChart generateChart() { + logger.debug("DiagramGenerator.generateChart"); + + JFreeChart chart = ChartFactory.createXYLineChart( + getChartTitle(), + "", + "", + null, + PlotOrientation.VERTICAL, + isLegendVisible(), + false, + false); + + XYPlot plot = (XYPlot) chart.getPlot(); + ValueAxis axis = createXAxis(getXAxisLabel()); + plot.setDomainAxis(axis); + + chart.setBackgroundPaint(Color.WHITE); + plot.setBackgroundPaint(Color.WHITE); + addSubtitles(chart); + adjustPlot(plot); + + //debugAxis(plot); + + addDatasets(plot); + + //debugDatasets(plot); + + addMarkers(plot); + + recoverEmptyPlot(plot); + preparePointRanges(plot); + + //debugAxis(plot); + + localizeAxes(plot); + adjustAxes(plot); + if (!(axis instanceof LogarithmicAxis)) { + // XXX: + // The auto zoom without a range tries + // to include 0 in a logarithmic axis + // which triggers a bug in jfreechart that causes + // the values to be drawn carthesian + autoZoom(plot); + } + + //debugAxis(plot); + + // These have to go after the autozoom. + AnnotationHelper.addAnnotationsToRenderer(annotations, plot, + getChartSettings(), datasets); + + // Add a logo (maybe). + addLogo(plot); + + aggregateLegendEntries(plot); + + return chart; + } + + public String getOutName() { + return outName; + } + + /** + * Return left most data points x value (on first axis). + */ + protected double getLeftX() { + if (inverted) { + return (Double)getXBounds(0).getUpper(); + } + return (Double)getXBounds(0).getLower(); + } + + + /** + * Return right most data points x value (on first axis). + */ + protected double getRightX() { + if (inverted) { + return (Double)getXBounds(0).getLower(); + } + return (Double)getXBounds(0).getUpper(); + } + + + /** Add a logo as background annotation to plot. */ + protected void addLogo(XYPlot plot) { + String logo = showLogo(); + if (logo == null) { + logger.debug("No logo to show chosen"); + return; + } + + ImageIcon imageIcon = null; + if (logo.equals("none")) { + return; + } + /* + If you want to add images, remember to change code in these places: + flys-artifacts: + DiagramGenerator.java + Timeseries*Generator.java and + in the flys-client projects Chart*Propert*Editor.java. + Also, these images have to be put in + flys-artifacts/src/main/resources/images/ + flys-client/src/main/webapp/images/ + */ + java.net.URL imageURL; + if (logo.equals("Intevation")) { + imageURL = DiagramGenerator.class.getResource("/images/intevation.png"); + } + else { // TODO else if ... + imageURL = DiagramGenerator.class.getResource("/images/bfg_logo.gif"); + } + imageIcon = new ImageIcon(imageURL); + + + double xPos = 0d, yPos = 0d; + + String placeh = logoHPlace(); + String placev = logoVPlace(); + + if (placev == null || placev.equals("none")) { + placev = "top"; + } + if (placev.equals("top")) { + yPos = (Double)getYBounds(0).getUpper(); + } + else if (placev.equals("bottom")) { + yPos = (Double)getYBounds(0).getLower(); + } + else if (placev.equals("center")) { + yPos = ((Double)getYBounds(0).getUpper() + (Double)getYBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-v value: " + placev); + } + + if (placeh == null || placeh.equals("none")) { + placeh = "center"; + } + if (placeh.equals("left")) { + xPos = getLeftX(); + } + else if (placeh.equals("right")) { + xPos = getRightX(); + } + else if (placeh.equals("center")) { + xPos = ((Double)getXBounds(0).getUpper() + (Double)getXBounds(0).getLower())/2d; + } + else { + logger.debug("Unknown place-h value: " + placeh); + } + + logger.debug("logo position: " + xPos + "/" + yPos); + + org.jfree.ui.RectangleAnchor anchor + = org.jfree.ui.RectangleAnchor.TOP; + if (placev.equals("top")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.TOP_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.TOP; + } + } + else if (placev.equals("bottom")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM_RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.BOTTOM; + } + } + else if (placev.equals("center")) { + if (placeh.equals("left")) { + anchor = org.jfree.ui.RectangleAnchor.LEFT; + } + else if (placeh.equals("right")) { + anchor = org.jfree.ui.RectangleAnchor.RIGHT; + } + else if (placeh.equals("center")) { + anchor = org.jfree.ui.RectangleAnchor.CENTER; + } + } + + XYAnnotation xyannotation = + new XYImageAnnotation(xPos, yPos, imageIcon.getImage(), anchor); + plot.getRenderer().addAnnotation(xyannotation, org.jfree.ui.Layer.BACKGROUND); + } + + + protected NumberAxis createXAxis(String label) { + return new NumberAxis(label); + } + + + @Override + protected Series getSeriesOf(XYDataset dataset, int idx) { + return ((XYSeriesCollection) dataset).getSeries(idx); + } + + + @Override + protected AxisDataset createAxisDataset(int idx) { + logger.debug("Create new AxisDataset for index: " + idx); + return new AxisDataset(idx); + } + + + /** + * Put debug output about datasets. + */ + public void debugDatasets(XYPlot plot) { + logger.debug("Number of datasets: " + plot.getDatasetCount()); + for (int i = 0, P = plot.getDatasetCount(); i < P; i++) { + if (plot.getDataset(i) == null) { + logger.debug("Dataset #" + i + " is null"); + continue; + } + logger.debug("Dataset #" + i + ":" + plot.getDataset(i)); + XYSeriesCollection series = (XYSeriesCollection) plot.getDataset(i); + logger.debug("X-Extend of Dataset: " + series.getSeries(0).getMinX() + + " " + series.getSeries(0).getMaxX()); + logger.debug("Y-Extend of Dataset: " + series.getSeries(0).getMinY() + + " " + series.getSeries(0).getMaxY()); + } + } + + + /** + * Put debug output about axes. + */ + public void debugAxis(XYPlot plot) { + logger.debug("..............."); + for (int i = 0, P = plot.getRangeAxisCount(); i < P; i++) { + if (plot.getRangeAxis(i) == null) + logger.debug("Range-Axis #" + i + " == null"); + else { + logger.debug("Range-Axis " + i + " != null [" + + plot.getRangeAxis(i).getRange().getLowerBound() + + " " + plot.getRangeAxis(i).getRange().getUpperBound() + + "]"); + } + } + for (int i = 0, P = plot.getDomainAxisCount(); i < P; i++) { + if (plot.getDomainAxis(i) == null) + logger.debug("Domain-Axis #" + i + " == null"); + else { + logger.debug("Domain-Axis " + i + " != null [" + + plot.getDomainAxis(i).getRange().getLowerBound() + + " " + plot.getDomainAxis(i).getRange().getUpperBound() + + "]"); + } + } + logger.debug("..............."); + } + + /** + * Registers an area to be drawn. + * @param area Area to be drawn. + * @param axisName Name of the axis. + * @param visible Whether or not to be visible (important for range calculations). + */ + public void addAreaSeries(StyledAreaSeriesCollection area, String axisName, boolean visible) { + addAreaSeries(area, diagramAttributes.getAxisIndex(axisName), visible); + } + + /** + * Registers an area to be drawn. + * @param area Area to be drawn. + * @param index 'axis index' + * @param visible Whether or not to be visible (important for range calculations). + */ + public void addAreaSeries(StyledAreaSeriesCollection area, int index, boolean visible) { + if (area == null) { + logger.warn("Cannot yet render above/under curve."); + return; + } + + AxisDataset axisDataset = (AxisDataset) getAxisDataset(index); + + if (visible) { + axisDataset.addArea(area); + } + else { + /* No range merging, for areas extending to infinity this + * causes problems. */ + } + } + + /** + * Add given series if visible, if not visible adjust ranges (such that + * all points in data would be plotted once visible). + * @param series the data series to include in plot. + * @param index index of the axis. + * @param visible whether or not the data should be plotted. + */ + public void addAxisSeries(XYSeries series, int index, boolean visible) { + if (series == null) { + return; + } + + logger.debug("Y Range of XYSeries: " + + series.getMinY() + " | " + series.getMaxY()); + + addAxisDataset(new XYSeriesCollection(series), index, visible); + } + + /** + * Add given series if visible, if not visible adjust ranges (such that + * all points in data would be plotted once visible). + * @param series the data series to include in plot. + * @param axisName name of the axis. + * @param visible whether or not the data should be plotted. + */ + public void addAxisSeries(XYSeries series, String axisName, boolean visible) { + addAxisSeries(series, diagramAttributes.getAxisIndex(axisName), visible); + } + + public void addAxisDataset(XYDataset dataset, String axisName, boolean visible) { + addAxisDataset(dataset, diagramAttributes.getAxisIndex(axisName), visible); + } + + /** + * Add the given vertical marker to the chart. + */ + public void addDomainMarker(Marker marker) { + addDomainMarker(marker, true); + } + + + /** + * Add the given vertical marker to the chart.<b>Note:</b> the marker is + * added to the chart only if it is not null and if <i>visible</i> is true. + * @param marker The marker that should be added to the chart. + * @param visible The visibility of the marker. + */ + public void addDomainMarker(Marker marker, boolean visible) { + if (visible && marker != null) { + domainMarkers.add(marker); + } + } + + + /** + * Add the given vertical marker to the chart. + */ + public void addValueMarker(Marker marker) { + addValueMarker(marker, true); + } + + + /** + * Add the given horizontal marker to the chart.<b>Note:</b> the marker is + * added to the chart only if it is not null and if <i>visible</i> is true. + * @param marker The marker that should be added to the chart. + * @param visible The visibility of the marker. + */ + public void addValueMarker(Marker marker, boolean visible) { + if (visible && marker != null) { + valueMarkers.add(marker); + } + } + + + protected void addMarkers(XYPlot plot) { + for(Marker marker : domainMarkers) { + plot.addDomainMarker(marker); + } + for(Marker marker : valueMarkers) { + plot.addRangeMarker(marker); + } + } + + + /** + * Effect: extend range of x axis to include given limits. + * + * @param bounds the given ("minimal") bounds. + * @param index index of axis to be merged. + */ + @Override + protected void combineXBounds(Bounds bounds, int index) { + if (!(bounds instanceof DoubleBounds)) { + logger.warn("Unsupported Bounds type: " + bounds.getClass()); + return; + } + + DoubleBounds dBounds = (DoubleBounds) bounds; + + if (dBounds == null + || Double.isNaN((Double) dBounds.getLower()) + || Double.isNaN((Double) dBounds.getUpper())) { + return; + } + + Bounds old = getXBounds(index); + + if (old != null) { + dBounds = (DoubleBounds) dBounds.combine(old); + } + + setXBounds(index, dBounds); + } + + + @Override + protected void combineYBounds(Bounds bounds, int index) { + if (!(bounds instanceof DoubleBounds)) { + logger.warn("Unsupported Bounds type: " + bounds.getClass()); + return; + } + + DoubleBounds dBounds = (DoubleBounds) bounds; + + if (dBounds == null + || Double.isNaN((Double) dBounds.getLower()) + || Double.isNaN((Double) dBounds.getUpper())) { + return; + } + + Bounds old = getYBounds(index); + + if (old != null) { + dBounds = (DoubleBounds) dBounds.combine(old); + } + + setYBounds(index, dBounds); + } + + + /** + * If no data is visible, draw at least empty axis. + */ + private void recoverEmptyPlot(XYPlot plot) { + if (plot.getRangeAxis() == null) { + logger.debug("debug: No range axis"); + plot.setRangeAxis(createYAxis(0)); + } + } + + + /** + * Expands X axes if only a point is shown. + */ + private void preparePointRanges(XYPlot plot) { + for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) { + + Integer key = Integer.valueOf(i); + Bounds b = getXBounds(key); + + + if (b != null && b.getLower().equals(b.getUpper())) { + logger.debug("Check whether to expand a x axis.i ("+b.getLower() + "-" + b.getUpper()+")"); + setXBounds(key, ChartHelper.expandBounds(b, 5)); + } + } + } + + + /** + * This method zooms the plot to the specified ranges in the attribute + * document or to the ranges specified by the min/max values in the + * datasets. <b>Note:</b> We determine the range manually if no zoom ranges + * are given, because JFreeCharts auto-zoom adds a margin to the left and + * right of the data area. + * + * @param plot The XYPlot. + */ + protected void autoZoom(XYPlot plot) { + logger.debug("Zoom to specified ranges."); + + Range xrange = getDomainAxisRange(); + Range yrange = getValueAxisRange(); + + ValueAxis xAxis = plot.getDomainAxis(); + + Range fixedXRange = getRangeForAxisFromSettings("X"); + if (fixedXRange != null) { + xAxis.setRange(fixedXRange); + } + else { + zoomX(plot, xAxis, getXBounds(0), xrange); + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis yaxis = plot.getRangeAxis(i); + + if (yaxis instanceof IdentifiableNumberAxis) { + IdentifiableNumberAxis idAxis = (IdentifiableNumberAxis) yaxis; + + Range fixedRange = getRangeForAxisFromSettings(idAxis.getId()); + if (fixedRange != null) { + yaxis.setRange(fixedRange); + continue; + } + } + + if (yaxis == null) { + logger.debug("Zoom problem: no Y Axis for index: " + i); + continue; + } + + logger.debug("Prepare zoom settings for y axis at index: " + i); + zoomY(plot, yaxis, getYBounds(Integer.valueOf(i)), yrange); + } + } + + + protected Range getDomainAxisRange() { + String[] ranges = getDomainAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No zoom range for domain axis specified."); + return null; + } + + if (ranges[0].length() > 0 && ranges[1].length() > 0) { + try { + double from = Double.parseDouble(ranges[0]); + double to = Double.parseDouble(ranges[1]); + + if (from == 0 && to == 0) { + logger.debug("No range specified. Lower and upper X == 0"); + return null; + } + + if (from > to) { + double tmp = to; + to = from; + from = tmp; + } + + return new Range(from, to); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for domain axis range."); + } + } + + return null; + } + + + protected Range getValueAxisRange() { + String[] ranges = getValueAxisRangeFromRequest(); + + if (ranges == null || ranges.length < 2) { + logger.debug("No range specified. Lower and upper Y == 0"); + return null; + } + + if (ranges[0].length() > 0 && ranges[1].length() > 0) { + try { + double from = Double.parseDouble(ranges[0]); + double to = Double.parseDouble(ranges[1]); + + if (from == 0 && to == 0) { + logger.debug("No range specified. Lower and upper Y == 0"); + return null; + } + + return from > to + ? new Range(to, from) + : new Range(from, to); + } + catch (NumberFormatException nfe) { + logger.warn("Wrong values for value axis range."); + } + } + + return null; + } + + + protected boolean zoomX(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + return zoom(plot, axis, bounds, x); + } + + + protected boolean zoomY(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + return zoom(plot, axis, bounds, x); + } + + + /** + * Zooms the x axis to the range specified in the attribute document. + * + * @param plot The XYPlot. + * @param axis The axis the shoud be modified. + * @param bounds The whole range specified by a dataset. + * @param x A user defined range (null permitted). + * + * @return true, if a zoom range was specified, otherwise false. + */ + protected boolean zoom(XYPlot plot, ValueAxis axis, Bounds bounds, Range x) { + + if (bounds == null) { + return false; + } + + if (x != null) { + Bounds computed = calculateZoom(bounds, x); + computed.applyBounds(axis, AXIS_SPACE); + + logger.debug("Zoom axis to: " + computed); + + return true; + } + + bounds.applyBounds(axis, AXIS_SPACE); + return false; + } + + /** + * Calculates the start and end km for zoomed charts. + * @param bounds The given total bounds (unzoomed). + * @param range The range specifying the zoom. + * + * @return The start and end km for the zoomed chart. + */ + protected Bounds calculateZoom(Bounds bounds, Range range) { + double min = bounds.getLower().doubleValue(); + double max = bounds.getUpper().doubleValue(); + + if (logger.isDebugEnabled()) { + logger.debug("Minimum is: " + min); + logger.debug("Maximum is: " + max); + logger.debug("Lower zoom is: " + range.getLowerBound()); + logger.debug("Upper zoom is: " + range.getUpperBound()); + } + + double diff = max > min ? max - min : min - max; + + DoubleBounds computed = new DoubleBounds( + min + range.getLowerBound() * diff, + min + range.getUpperBound() * diff); + return computed; + } + + /** + * Extract the minimum and maximum values for x and y axes + * which are stored in <i>xRanges</i> and <i>yRanges</i>. + * + * @param index The index of the y-Axis. + * + * @return a Range[] as follows: [x-Range, y-Range]. + */ + @Override + public Range[] getRangesForAxis(int index) { + logger.debug("getRangesForAxis " + index); + + Bounds rx = getXBounds(Integer.valueOf(0)); + Bounds ry = getYBounds(Integer.valueOf(index)); + + if (rx == null) { + logger.warn("Range for x axis not set." + + " Using default values: 0 - 1."); + rx = new DoubleBounds(0, 1); + } + if (ry == null) { + logger.warn("Range for y" + index + + " axis not set. Using default values: 0 - 1."); + ry = new DoubleBounds(0, 1); + } + + return new Range[] { + new Range(rx.getLower().doubleValue(), rx.getUpper().doubleValue()), + new Range(ry.getLower().doubleValue(), ry.getUpper().doubleValue()) + }; + } + + + /** Get X (usually horizontal) extent for given axis. */ + @Override + public Bounds getXBounds(int axis) { + return xBounds.get(axis); + } + + + /** Set X (usually horizontal) extent for given axis. */ + @Override + protected void setXBounds(int axis, Bounds bounds) { + if (bounds.getLower() == bounds.getUpper()) { + xBounds.put(axis, ChartHelper.expandBounds(bounds, 5d)); + } + else { + xBounds.put(axis, bounds); + } + } + + + /** Get Y (usually vertical) extent for given axis. */ + @Override + public Bounds getYBounds(int axis) { + return yBounds.get(axis); + } + + + /** Set Y (usually vertical) extent for given axis. */ + @Override + protected void setYBounds(int axis, Bounds bounds) { + yBounds.put(axis, bounds); + } + + + /** + * Adjusts the axes of a plot. This method sets the <i>labelFont</i> of the + * X axis and applies the inversion if inverted is true. + * + * (Duplicate in TimeseriesChartGenerator) + * + * @param plot The XYPlot of the chart. + */ + protected void adjustAxes(XYPlot plot) { + ValueAxis xaxis = plot.getDomainAxis(); + + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return; + } + + Font labelFont = new Font( + DEFAULT_FONT_NAME, + Font.BOLD, + getXAxisLabelFontSize()); + + xaxis.setLabelFont(labelFont); + xaxis.setTickLabelFont(labelFont); + + logger.debug("Adjusting xAxis. Inverted?: " + inverted); + if (inverted) { + xaxis.setInverted(true); + } + } + + + /** + * This method walks over all axes (domain and range) of <i>plot</i> and + * calls localizeDomainAxis() for domain axes or localizeRangeAxis() for + * range axes. + * + * @param plot The XYPlot. + */ + private void localizeAxes(XYPlot plot) { + for (int i = 0, num = plot.getDomainAxisCount(); i < num; i++) { + ValueAxis axis = plot.getDomainAxis(i); + + if (axis != null) { + localizeDomainAxis(axis); + } + else { + logger.warn("Domain axis at " + i + " is null."); + } + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis axis = plot.getRangeAxis(i); + + if (axis != null) { + localizeRangeAxis(axis); + } + else { + logger.warn("Range axis at " + i + " is null."); + } + } + } + + + /** + * Overrides the NumberFormat with the NumberFormat for the current locale + * that is provided by getLocale(). + * + * @param domainAxis The domain axis that needs localization. + */ + protected void localizeDomainAxis(ValueAxis domainAxis) { + NumberFormat nf = NumberFormat.getInstance(getLocale()); + ((NumberAxis) domainAxis).setNumberFormatOverride(nf); + } + + + /** + * Overrides the NumberFormat with the NumberFormat for the current locale + * that is provided by getLocale(). + * + * @param rangeAxis The domain axis that needs localization. + */ + protected void localizeRangeAxis(ValueAxis rangeAxis) { + NumberFormat nf = NumberFormat.getInstance(getLocale()); + ((NumberAxis) rangeAxis).setNumberFormatOverride(nf); + } + + + /** + * Create a hash from a legenditem. + * This hash can then be used to merge legend items labels. + * @return hash for given legenditem to identify mergeables. + */ + public static String legendItemHash(LegendItem li) { + // TODO Do proper implementation. Ensure that only mergable sets are created. + // getFillPaint() + // getFillPaintTransformer() + // getLabel() + // getLine() + // getLinePaint() + // getLineStroke() + // getOutlinePaint() + // getOutlineStroke() + // Shape getShape() + // String getToolTipText() + // String getURLText() + // boolean isLineVisible() + // boolean isShapeFilled() + // boolean isShapeOutlineVisible() + // boolean isShapeVisible() + String hash = li.getLinePaint().toString(); + String label = li.getLabel(); + if (label.startsWith("W (") || label.startsWith("W(")) { + hash += "-W-"; + } + else if (label.startsWith("Q(") || label.startsWith("Q (")) { + hash += "-Q-"; + } + + // WQ.java holds example of using regex Matcher/Pattern. + + return hash; + } + + /** True if x axis has been inverted. */ + public boolean isInverted() { + return inverted; + } + + + /** Set to true if x axis should be inverted. + * This can not be set to false afterwards. */ + public void setInverted(boolean value) { + /* One request to invert dominates. */ + if (!inverted) { + inverted = value; + } + } + + @Override + public String getDefaultChartTitle() { + DiagramAttributes.Title dTitle = diagramAttributes.getTitle(); + if (dTitle == null) { + return "Title not configured in conf.xml"; + } + + return dTitle.evaluate((D4EArtifact)getMaster(), context); + } + + @Override + public String getDefaultChartSubtitle() { + DiagramAttributes.Title dTitle = diagramAttributes.getSubtitle(); + if (dTitle == null) { + /* Subtitle is optional */ + return null; + } + + return dTitle.evaluate((D4EArtifact)getMaster(), context); + } + + /** + * Get internationalized label for the x axis. + */ + @Override + protected String getDefaultXAxisLabel() { + DiagramAttributes.DomainAxisAttributes dx = + diagramAttributes.getDomainAxis(); + + if (dx != null) { + DiagramAttributes.Title t = dx.getTitle(); + if (t != null) { + return t.evaluate((D4EArtifact)getMaster(), context); + } + } + return "Domain Axis Title not configured in conf.xml"; + } + + @Override + protected String getDefaultYAxisLabel(String axisName) { + String label; + for (Processor pr: diagramAttributes.getProcessorsForAxisName(axisName)) { + label = pr.getAxisLabel(this); + if (label != null) { + return label; + } + } + return "No configured axis label"; + } + + + /** + * Creates a list of Section for the chart's Y axes. + * + * @return a list of Y axis sections. + */ + protected List<AxisSection> buildYAxisSections() { + List<AxisSection> axisSections = new ArrayList<AxisSection>(); + + List<DiagramAttributes.AxisAttributes> axesAttrs = diagramAttributes.getAxesAttributes(); + + for (int i = 0, n = axesAttrs.size(); i < n; i++) { + AxisSection ySection = new AxisSection(); + String axisName = diagramAttributes.getAxisName(i); + ySection.setIdentifier(axisName); + ySection.setLabel(getYAxisLabel(axisName)); + ySection.setFontSize(14); + ySection.setFixed(false); + + // XXX We are able to find better default ranges that [0,0], the + // only problem is, that we do NOT have a better range than [0,0] + // for each axis, because the initial chart will not have a dataset + // for each axis set! + ySection.setUpperRange(0d); + ySection.setLowerRange(0d); + + axisSections.add(ySection); + } + + return axisSections; + } + + /** + * Returns the Y-Axis label of a chart at position <i>pos</i>. + * + * @return the Y-Axis label of a chart at position <i>0</i>. + */ + protected String getYAxisLabel(String axisName) { + ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return getDefaultYAxisLabel(axisName); + } + AxisSection as = chartSettings.getAxisSection(axisName); + if (as != null) { + String label = as.getLabel(); + if (label != null) { + return label; + } + } + + return getDefaultYAxisLabel(axisName); + } + + protected String axisIndexToName(int index) { + return diagramAttributes.getAxisName(index); + } + + /** Add the acutal data to the diagram according to the processors. + * For every outable facets, this function is + * called and handles the data accordingly. */ + @Override + public void doOut( + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible + ) { + String facetName = bundle.getFacetName(); + Facet facet = bundle.getFacet(); + + /* A conservative security check */ + if (facetName == null || facet == null) { + /* Can't happen,.. */ + logger.error("doOut called with null facet."); + return; + } + + logger.debug("DoOut for facet: " + facetName); + + boolean found = false; + List<Processor> prL = diagramAttributes.getProcessors(); + for (Processor pr: prL) { + if (pr.canHandle(facetName)) { + found = true; + pr.doOut(this, bundle, theme, visible); + } + } + if (!found) { + logger.warn("No processor found for: " + facetName); + if (logger.isDebugEnabled()) { + logger.debug("Configured processors for this diagram are:"); + for (Processor pr: prL) { + logger.debug(pr.getClass().getName()); + } + } + } + } + + @Override + protected NumberAxis createYAxis(int index) { + NumberAxis axis = super.createYAxis(index); + + if (diagramAttributes.getAxesAttributes().get(index).includeZero()) { + axis.setAutoRangeIncludesZero(true); + } + return axis; + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,16 +8,22 @@ package org.dive4elements.river.exports; +import java.util.ArrayList; +import java.util.List; + import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.exports.process.DischargeProcessor; +import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StickyAxisAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import org.apache.log4j.Logger; @@ -26,7 +32,6 @@ import org.jfree.chart.plot.XYPlot; import org.jfree.data.Range; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; /** @@ -38,6 +43,7 @@ extends XYChartGenerator implements FacetTypes { + /** Beware, in this implementation, the W axis is also in cm! */ public static enum YAXIS { WCm(0), W(1); @@ -76,6 +82,10 @@ // Get gauge which is defined for km Gauge gauge = RiverUtils.getRiver(artifact).determineGauge(km-0.1d, km+0.1d); + if (gauge == null) { + logger.error("No Gauge could be found at station " + km + "!"); + return 0d; + } double subtractPNP = 0d; // Compare to km. if (Math.abs(km - gauge.getStation().doubleValue()) < tolerance) { @@ -85,6 +95,7 @@ } + /** Get the current Gauge datum with default distance tolerance. */ public double getCurrentGaugeDatum() { return getCurrentGaugeDatum(getRange()[0], (D4EArtifact) getMaster(), 1e-4); @@ -178,13 +189,18 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document theme, + ThemeDocument theme, boolean visible ) { String name = artifactFacet.getFacetName(); logger.debug("DischargeCurveGenerator.doOut: " + name); - if (name.equals(DISCHARGE_CURVE) + DischargeProcessor dProcessor = new DischargeProcessor(getRange()[0]); + if (dProcessor.canHandle(name)) { + // In Base DischargeCurveGenerator, always at gauge, use WCm axis. + dProcessor.doOut(this, artifactFacet, theme, visible, YAXIS.WCm.idx); + } + else if (name.equals(DISCHARGE_CURVE) || name.equals(GAUGE_DISCHARGE_CURVE)) { doDischargeOut( (D4EArtifact)artifactFacet.getArtifact(), @@ -193,22 +209,17 @@ theme, visible); } - else if (name.equals(COMPUTED_DISCHARGE_MAINVALUES_Q) - || name.equals(MAINVALUES_Q) - || name.equals(COMPUTED_DISCHARGE_MAINVALUES_W) - || name.equals(MAINVALUES_W)) - { - RiverAnnotation mainValues = (RiverAnnotation) artifactFacet.getData(context); - translateRiverAnnotation(mainValues); - doAnnotations( - mainValues, - artifactFacet, theme, visible); - } else if (FacetTypes.IS.MANUALPOINTS(name)) { doPoints(artifactFacet.getData(context), artifactFacet, theme, visible, YAXIS.W.idx); } + else if (STATIC_WQ.equals(name)) { + doWQOut(artifactFacet.getData(context), + artifactFacet, + theme, + visible); + } else { logger.warn("DischargeCurveGenerator.doOut: Unknown facet name: " + name); return; @@ -223,9 +234,10 @@ D4EArtifact artifact, Object o, String description, - Document theme, + ThemeDocument theme, boolean visible) { + logger.debug("DischargeCurveGenerator.doDischargeOut"); WQKms wqkms = (WQKms) o; String gaugeName = wqkms.getName(); @@ -250,5 +262,134 @@ addAxisSeries(series, YAXIS.W.idx, visible); } + + /** + * Add W/Q-Series to plot. + * @param wqkms actual data + * @param theme theme to use. + */ + protected void doQOut( + Object wqkms, + ArtifactAndFacet aaf, + ThemeDocument theme, + boolean visible + ) { + logger.debug("DischargeCurveGenerator: doQOut (add W/Q data)."); + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + + StyledSeriesBuilder.addPointsQW(series, (WQKms) wqkms); + + addAxisSeries(series, YAXIS.W.idx, visible); + } + + + /** Add a point annotation at given x and y coordinates. */ + protected void addPointTextAnnotation( + String title, + double x, + double y, + ThemeDocument theme + ) { + List<XYTextAnnotation> textAnnos = + new ArrayList<XYTextAnnotation>(); + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + title, + x, + y); + textAnnos.add(anno); + RiverAnnotation flysAnno = new RiverAnnotation( + null, null, null, theme); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); + } + + + /** + * Return true if all values in data[0] are smaller than zero + * (in imported data they are set to -1 symbolically). + * Return false if data is null or empty + */ + private boolean hasNoDischarge(double[][] data) { + if (data == null || data.length == 0) { + return false; + } + + double[] qs = data[0]; + for (double q: qs) { + if (q > 0d) { + return false; + } + } + + return true; + } + + + /** + * Add WQ Data to plot. + * @param wq data as double[][] + */ + protected void doWQOut( + Object wq, + ArtifactAndFacet aaf, + ThemeDocument theme, + boolean visible + ) { + logger.debug("DischargeCurveGenerator: doWQOut"); + double [][] data = (double [][]) wq; + String title = aaf.getFacetDescription(); + + double translate = getCurrentGaugeDatum(); + + // If no Q values (i.e. all -1) found, add annotations. + if (hasNoDischarge(data)) { + List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); + + for (double y: data[1]) { + if (translate != 0d) { + y = (y-translate)*100d; + } + + xy.add(new StickyAxisAnnotation( + title, + (float) y, + StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + } + + doAnnotations( + new RiverAnnotation(title, xy), + aaf, theme, visible); + return; + } + + // Otherwise add points. + XYSeries series = new StyledXYSeries(title, theme); + + if (translate != 0d) { + StyledSeriesBuilder.addPointsQW(series, data, -translate, 100d); + addAxisSeries(series, YAXIS.W.idx, visible); + } + else { + StyledSeriesBuilder.addPoints(series, data, true); + addAxisSeries(series, YAXIS.W.idx, visible); + } + + if (visible && theme.parseShowPointLabel() + && data != null && data.length != 0) { + + double[] xs = data[0]; + double[] ys = data[1]; + for (int i = 0; i < xs.length; i++) { + double x = xs[i]; + double y = ys[i]; + + if (translate != 0d) { + y = (y-translate)*100d; + } + + addPointTextAnnotation(title, x, y, theme); + } + } + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* 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 org.apache.log4j.Logger; - -import org.jfree.data.xy.XYSeries; - -import org.w3c.dom.Document; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; - -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.WQCKms; -import org.dive4elements.river.artifacts.model.WQKms; -import org.dive4elements.river.exports.process.Processor; -import org.dive4elements.river.exports.process.WOutProcessor; - -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StyledXYSeries; - - - -/** - * An OutGenerator that generates discharge longitudinal section curves. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class DischargeLongitudinalSectionGenerator -extends LongitudinalSectionGenerator -implements FacetTypes -{ - private static Logger logger = - Logger.getLogger(DischargeLongitudinalSectionGenerator.class); - - - public DischargeLongitudinalSectionGenerator() { - super(); - } - - - @Override - public void doOut( - ArtifactAndFacet artifactFacet, - Document attr, - boolean visible - ) { - logger.debug("DischargeLongitudinalSectionGenerator.doOut"); - - String name = artifactFacet.getFacetName(); - - if (name == null) { - return; - } - - Facet facet = artifactFacet.getFacet(); - - if (name.contains(DISCHARGE_LONGITUDINAL_Q)) { - doQOut( - (WQKms) artifactFacet.getData(context), - artifactFacet, - attr, - visible); - } - else if (name.equals(DISCHARGE_LONGITUDINAL_C)) { - doCorrectedWOut( - (WQCKms) artifactFacet.getData(context), - facet, - attr, - visible); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations((RiverAnnotation) artifactFacet.getData(context), - artifactFacet, attr, visible); - } - else if (FacetTypes.IS.MANUALPOINTS(name)) { - doPoints(artifactFacet.getData(context), - artifactFacet, - attr, visible, YAXIS.W.idx); - } - else if (name.equals(STATIC_WQKMS_Q)) { - doQOut( - (WQKms) artifactFacet.getData(context), - artifactFacet, - attr, - visible); - } - else { - Processor processor = new WOutProcessor(); - if (processor.canHandle(name)) { - processor.doOut(this, artifactFacet, attr, visible, YAXIS.W.idx); - } - else { - logger.warn("Unknown facet name: " + name); - } - } - } - - - /** - * Adds a new series for the corrected W curve. - * - * @param wqckms The object that contains the corrected W values. - * @param theme The theme that contains styling information. - */ - protected void doCorrectedWOut( - WQCKms wqckms, - Facet facet, - Document theme, - boolean visible - ) { - logger.debug("DischargeLongitudinalSectionGenerator.doCorrectedWOut"); - - int size = wqckms.size(); - - if (size > 0) { - XYSeries series = new StyledXYSeries( - facet.getDescription(), - theme); - - for (int i = 0; i < size; i++) { - series.add(wqckms.getKm(i), wqckms.getC(i)); - } - - addAxisSeries(series, YAXIS.W.idx, visible); - } - - if (wqckms.guessWaterIncreasing()) { - setInverted(true); - } - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeLongitudinalSectionInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* 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; - - -/** - * A ChartInfoGenerator that generates meta information for specific discharge - * longitudinal section curves. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class DischargeLongitudinalSectionInfoGenerator -extends ChartInfoGenerator -{ - public DischargeLongitudinalSectionInfoGenerator() { - super(new DischargeLongitudinalSectionGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,8 +18,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; @@ -29,7 +27,6 @@ import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JRException; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.common.utils.Config; @@ -73,16 +70,10 @@ /** The storage that contains all WQKms objects for the different facets. */ protected List<WQDay> data; - - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("DurationCurveExporter.init"); - - super.init(request, out, context); - - this.data = new ArrayList<WQDay>(); + public DurationCurveExporter() { + data = new ArrayList<WQDay>(); } - @Override protected void addData(Object d) { if (d instanceof CalculationResult) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -14,6 +14,7 @@ import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import java.awt.Font; import java.awt.geom.Point2D; @@ -24,7 +25,6 @@ import org.jfree.chart.plot.XYPlot; import org.jfree.data.Range; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; /** @@ -173,7 +173,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactFacet.getFacetName(); @@ -238,7 +238,7 @@ protected void doWOut( WQDay wqdays, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("DurationCurveGenerator.doWOut"); @@ -257,10 +257,10 @@ } protected void doPointOut( - Point2D point, + Point2D point, ArtifactAndFacet aandf, - Document theme, - boolean visible + ThemeDocument theme, + boolean visible ){ logger.debug("DurationCurveGenerator.doPointOut"); @@ -281,7 +281,7 @@ protected void doQOut( WQDay wqdays, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("DurationCurveGenerator.doQOut"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -13,14 +13,10 @@ import java.util.ArrayList; import java.util.List; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; - import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.FlowVelocityData; @@ -58,13 +54,10 @@ protected List<FlowVelocityData[]> data; - - public void init(Document request, OutputStream out, CallContext cc) { - super.init(request, out, cc); + public FlowVelocityExporter() { data = new ArrayList<FlowVelocityData[]>(); } - @Override protected void addData(Object d) { if (d instanceof CalculationResult) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/FlowVelocityGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -14,8 +14,6 @@ import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; @@ -33,6 +31,7 @@ import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; @@ -209,7 +208,7 @@ */ public void doOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactAndFacet.getFacetName(); @@ -370,7 +369,7 @@ private void doBedQualityLoadDiameter( BedloadDiameterResult data, ArtifactAndFacet aandf, - Document attr, + ThemeDocument attr, boolean visible) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), attr); StyledSeriesBuilder.addPoints(series, data.getDiameterData(), true); @@ -382,7 +381,7 @@ private void doBedQualityTopLayerOut( BedDiameterResult data, ArtifactAndFacet aandf, - Document attr, + ThemeDocument attr, boolean visible) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), attr); StyledSeriesBuilder.addPoints(series, data.getDiameterSubData(), true); @@ -393,7 +392,7 @@ private void doBedQualitySubLayerOut( BedDiameterResult data, ArtifactAndFacet aandf, - Document attr, + ThemeDocument attr, boolean visible ) { logger.debug("Do beddiametersubout"); @@ -416,7 +415,7 @@ protected void doMainChannelOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("FlowVelocityGenerator.doMainChannelOut"); @@ -433,7 +432,7 @@ protected void doVPointOut ( Object data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("FlowVelocityGenerator.doVPointOut"); @@ -456,7 +455,7 @@ protected void doTotalChannelOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("FlowVelocityGenerator.doTotalChannelOut"); @@ -486,10 +485,10 @@ protected void doQOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { - logger.debug("FlowVelocityGenerator.doTauOut"); + logger.debug("FlowVelocityGenerator.doQOut"); XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); @@ -509,7 +508,7 @@ protected void doTauOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("FlowVelocityGenerator.doTauOut"); @@ -543,10 +542,10 @@ * @param visible whether or not visible. */ protected void doArea( - Object o, + Object o, ArtifactAndFacet aandf, - Document theme, - boolean visible + ThemeDocument theme, + boolean visible ) { logger.debug("FlowVelocityGenerator.doArea"); logger.warn("TODO: Implement FlowVelocityGenerator.doArea"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,8 +18,6 @@ import java.util.HashMap; import java.util.Locale; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; import au.com.bytecode.opencsv.CSVWriter; @@ -31,7 +29,6 @@ import org.dive4elements.artifacts.common.utils.Config; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.D4EArtifact; @@ -77,14 +74,10 @@ protected List<WQTimerange[]> data; - - public void init(Document request, OutputStream out, CallContext cc) { - super.init(request, out, cc); - + public HistoricalDischargeCurveExporter() { data = new ArrayList<WQTimerange[]>(); } - @Override protected void addData(Object d) { logger.debug("Add data of class: " + d.getClass()); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -25,6 +25,7 @@ import org.dive4elements.river.jfree.StyledTimeSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import org.jfree.chart.plot.XYPlot; @@ -36,8 +37,6 @@ import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; -import org.w3c.dom.Document; - /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> @@ -127,7 +126,7 @@ } @Override - public void doOut(ArtifactAndFacet artifactFacet, Document theme, + public void doOut(ArtifactAndFacet artifactFacet, ThemeDocument theme, boolean visible) { String name = artifactFacet.getFacetName(); logger.debug("HistoricalDischargeCurveGenerator.doOut: " + name); @@ -169,7 +168,7 @@ } protected void doHistoricalDischargeOutQ(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { logger.debug("doHistoricalDischargeOut(): description = " + desc); WQTimerange wqt = (WQTimerange) data; @@ -181,7 +180,7 @@ } protected void doHistoricalDischargeOutW(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { logger.debug("doHistoricalDischargeOut(): description = " + desc); WQTimerange wqt = (WQTimerange) data; @@ -193,7 +192,7 @@ } protected void doHistoricalDischargeDifferenceOutQ(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; @@ -205,7 +204,7 @@ } protected void doHistoricalDischargeDifferenceOutW(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); HistoricalWQTimerange wqt = (HistoricalWQTimerange) data; @@ -223,7 +222,7 @@ * looks like a "step chart". */ protected TimeSeriesCollection newTimeSeriesCollection( - Timerange[] timeranges, double[] values, Document theme, String desc) { + Timerange[] timeranges, double[] values, ThemeDocument theme, String desc) { logger.debug("Create new TimeSeriesCollection for: " + desc); TimeSeriesCollection tsc = new TimeSeriesCollection(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeWQCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeWQCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeWQCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,7 +10,6 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.river.artifacts.D4EArtifact; @@ -22,6 +21,7 @@ import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledValueMarker; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; @@ -105,7 +105,7 @@ } @Override - public void doOut(ArtifactAndFacet artifactFacet, Document theme, + public void doOut(ArtifactAndFacet artifactFacet, ThemeDocument theme, boolean visible) { String name = artifactFacet.getFacetName(); logger.debug("HistoricalDischargeWQCurveGenerator.doOut: " + name); @@ -124,7 +124,9 @@ artifactFacet.getData(context), artifactFacet.getFacetDescription(), theme, visible); } - else if (name.equals(HISTORICAL_DISCHARGE_WQ_CURVE)) { + else if (name.equals(HISTORICAL_DISCHARGE_WQ_CURVE) || + name.equals(DISCHARGE_CURVE) || + name.equals(GAUGE_DISCHARGE_CURVE)) { doHistoricalDischargeCurveOut( (D4EArtifact) artifactFacet.getArtifact(), artifactFacet.getData(context), @@ -148,19 +150,19 @@ } protected void doHistoricalDischargeOutQ(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { double value = Double.valueOf(data.toString()); addDomainMarker(new StyledValueMarker(value, theme), visible); } protected void doHistoricalDischargeOutW(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { double value = Double.valueOf(data.toString()); addValueMarker(new StyledValueMarker(value, theme), visible); } protected void doHistoricalDischargeCurveOut(D4EArtifact artifact, - Object data, String desc, Document theme, boolean visible) { + Object data, String desc, ThemeDocument theme, boolean visible) { XYSeries series = new StyledXYSeries(desc, theme); StyledSeriesBuilder.addPointsQW(series, (WQKms) data); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper.java Fri Sep 27 17:36:50 2013 +0200 @@ -48,12 +48,10 @@ protected ChartGenerator generator; - public InfoGeneratorHelper(ChartGenerator generator) { this.generator = generator; } - /** * Triggers the creation of the chart info document. * diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/InfoGeneratorHelper2.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,409 @@ +/* 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.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; + +import java.util.Date; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import org.jfree.chart.ChartRenderingInfo; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.DateAxis; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.ValueAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.Range; +import org.jfree.data.xy.XYDataset; + +import org.dive4elements.artifacts.common.ArtifactNamespaceContext; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; + +import org.dive4elements.river.jfree.Bounds; + + +/** + * This class helps generating chart info documents. + */ +public class InfoGeneratorHelper2 { + + /** Private logging instance. */ + private static final Logger logger = + Logger.getLogger(InfoGeneratorHelper2.class); + + protected ChartGenerator2 generator; + + public InfoGeneratorHelper2(ChartGenerator2 generator) { + this.generator = generator; + } + + /** + * Triggers the creation of the chart info document. + * + * @param chart The JFreeChart chart. + * @param info An info object that has been created while chart creation. + * + * @return the info document. + */ + public Document createInfoDocument( + JFreeChart chart, + ChartRenderingInfo info) + { + logger.debug("InfoGeneratorHelper.createInfoDocument"); + + Document doc = XMLUtils.newDocument(); + + ElementCreator cr = new ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element chartinfo = cr.create("chartinfo"); + + chartinfo.appendChild(createAxesElements(cr, chart)); + chartinfo.appendChild(createTransformationElements(cr, chart, info)); + + doc.appendChild(chartinfo); + + return doc; + } + + + /** + * This method create a axes element that contains all domain and range + * axes of the given chart. + * + * @param cr The ElementCreator. + * @param chart The chart that provides range information of its axes. + * + * @return an element with axes information. + */ + protected Element createAxesElements( + ElementCreator cr, + JFreeChart chart) + { + logger.debug("InfoGeneratorHelper.createRangeElements"); + + Element axes = cr.create("axes"); + + XYPlot plot = (XYPlot) chart.getPlot(); + + int dAxisCount = plot.getDomainAxisCount(); + for (int i = 0; i < dAxisCount; i++) { + ValueAxis axis = plot.getDomainAxis(i); + XYDataset data = plot.getDataset(i); + + if (axis != null) { + Element e = createAxisElement(cr, axis, data, "domain", i); + axes.appendChild(e); + } + } + + int rAxisCount = plot.getRangeAxisCount(); + for (int i = 0; i < rAxisCount; i++) { + ValueAxis axis = plot.getRangeAxis(i); + XYDataset data = plot.getDataset(i); + + if (axis == null || data == null) { + logger.warn("Axis or dataset is empty at pos: " + i); + continue; + } + + Element e = createAxisElement(cr, axis, data, "range", i); + axes.appendChild(e); + } + + return axes; + } + + + /** + * This method create a axis element for a given <i>axis</i> and + * <i>type</i>. Type can be one of 'domain' or 'range'. + * + * @param cr The ElementCreator + * @param axis The axis that provides range information. + * @param dataset The dataset for min/max determination. + * @param type The axis type ('domain' or 'range'). + * @param pos The position in the chart. + * + * @return An element that contains range information of a given axis. + */ + protected Element createAxisElement( + ElementCreator cr, + ValueAxis axis, + XYDataset dataset, + String type, + int pos) + { + logger.debug("createAxisElement " + pos); + logger.debug("Axis is from type: " + axis.getClass()); + + Element e = cr.create(type); + cr.addAttr(e, "pos", String.valueOf(pos), true); + + if (axis instanceof DateAxis) { + prepareDateAxisElement( + e, cr, (DateAxis) axis, dataset, type, pos); + } + else { + prepareNumberAxisElement( + e, cr, (NumberAxis) axis, dataset, type, pos); + } + + return e; + } + + + protected Element prepareNumberAxisElement( + Element e, + ElementCreator cr, + NumberAxis axis, + XYDataset dataset, + String type, + int pos + ) { + Range range = axis.getRange(); + + cr.addAttr(e, "from", String.valueOf(range.getLowerBound()), true); + cr.addAttr(e, "to", String.valueOf(range.getUpperBound()), true); + cr.addAttr(e, "axistype", "number", true); + + Range[] rs = generator.getRangesForAxis(pos); + Range r = null; + + if (type.equals("range")) { + r = rs[1]; + } + else { + r = rs[0]; + } + + cr.addAttr(e, "min", String.valueOf(r.getLowerBound()), true); + cr.addAttr(e, "max", String.valueOf(r.getUpperBound()), true); + + return e; + } + + + protected Element prepareDateAxisElement( + Element e, + ElementCreator cr, + DateAxis axis, + XYDataset dataset, + String type, + int pos + ) { + Date from = axis.getMinimumDate(); + Date to = axis.getMaximumDate(); + + Bounds bounds = null; + if (type.equals("range")) { + bounds = generator.getYBounds(pos); + } + else { + bounds = generator.getXBounds(pos); + } + + cr.addAttr(e, "axistype", "date", true); + cr.addAttr(e, "from", String.valueOf(from.getTime()), true); + cr.addAttr(e, "to", String.valueOf(to.getTime()), true); + + cr.addAttr(e, "min", bounds.getLower().toString(), true); + cr.addAttr(e, "max", bounds.getUpper().toString(), true); + + return e; + } + + + /** + * This method appends the values of a transformation matrix to transform + * image pixel coordinates into chart coordinates. + * + * @param cr The ElementCreator. + * @param chart The chart object. + * @param info The ChartRenderingInfo that is filled while chart creation. + * + * @return an element that contains one or more transformation matrix. + */ + protected Element createTransformationElements( + ElementCreator cr, + JFreeChart chart, + ChartRenderingInfo info) + { + logger.debug("InfoGeneratorHelper.createTransformationElements"); + + Element tf = cr.create("transformation-matrix"); + + Rectangle2D dataArea = info.getPlotInfo().getDataArea(); + + XYPlot plot = (XYPlot) chart.getPlot(); + ValueAxis xAxis = plot.getDomainAxis(); + + if (xAxis == null) { + logger.error("There is no x axis in the chart!"); + return null; + } + + for (int i = 0, num = plot.getRangeAxisCount(); i < num; i++) { + ValueAxis yAxis = plot.getRangeAxis(i); + + if (yAxis == null) { + logger.warn("No y axis at pos " + i + " existing."); + continue; + } + + Element matrix = createTransformationElement( + cr, xAxis, yAxis, dataArea, i); + + tf.appendChild(matrix); + } + + return tf; + } + + + /** + * Creates an element that contains values used to transform coordinates + * of a coordinate system A into a coordinate system B. + * + * @param cr The ElementCreator. + * @param xAxis The x axis of the target coordinate system. + * @param yAxis The y axis of the target coordinate system. + * @param dataArea The pixel coordinates of the chart image. + * @param pos The dataset position. + * + * @return an element that contains transformation matrix values. + */ + protected Element createTransformationElement( + ElementCreator cr, + ValueAxis xAxis, + ValueAxis yAxis, + Rectangle2D dataArea, + int pos) + { + double[] tm = createTransformationMatrix(dataArea, xAxis, yAxis); + + Element matrix = cr.create("matrix"); + + cr.addAttr(matrix, "pos", String.valueOf(pos), true); + cr.addAttr(matrix, "sx", String.valueOf(tm[0]), true); + cr.addAttr(matrix, "sy", String.valueOf(tm[1]), true); + cr.addAttr(matrix, "tx", String.valueOf(tm[2]), true); + cr.addAttr(matrix, "ty", String.valueOf(tm[3]), true); + + if (xAxis instanceof DateAxis) { + cr.addAttr(matrix, "xtype", "date", true); + } + else { + cr.addAttr(matrix, "xtype", "number", true); + } + + if (yAxis instanceof DateAxis) { + cr.addAttr(matrix, "ytype", "date", true); + } + else { + cr.addAttr(matrix, "ytype", "number", true); + } + + return matrix; + } + + + /** + * This method determines a transformation matrix to transform pixel + * coordinates of the chart image into chart coordinates. + * + * @param dataArea The rectangle that contains the data points of the chart. + * @param xAxis The x axis. + * @param yAxis The y axis. + * + * @return a double array as follows: [sx, sy, tx, ty]. + */ + protected static double[] createTransformationMatrix( + Rectangle2D dataArea, + ValueAxis xAxis, + ValueAxis yAxis) + { + logger.debug("InfoGeneratorHelper.createTransformationMatrix"); + + double offsetX = dataArea.getX(); + double width = dataArea.getWidth(); + double offsetY = dataArea.getY(); + double height = dataArea.getHeight(); + + Range xRange = getRangeFromAxis(xAxis); + Range yRange = getRangeFromAxis(yAxis); + + double lowerX = xRange.getLowerBound(); + double upperX = xRange.getUpperBound(); + double lowerY = yRange.getLowerBound(); + double upperY = yRange.getUpperBound(); + + if (xAxis.isInverted()) { + logger.info("X-Axis is inverted!"); + + double tmp = upperX; + upperX = lowerX; + lowerX = tmp; + } + + double dMoveX = upperX - lowerX; + double fMoveX = width * lowerX; + double dMoveY = lowerY - upperY; + double fMoveY = height * upperY; + + AffineTransform t1 = AffineTransform.getTranslateInstance( + offsetX - ( fMoveX / dMoveX ), + offsetY - ( fMoveY / dMoveY ) ); + + AffineTransform t2 = AffineTransform.getScaleInstance( + width / (upperX - lowerX), + height / (lowerY - upperY)); + + t1.concatenate(t2); + + try { + t1.invert(); + + double[] c = new double[6]; + t1.getMatrix(c); + + return new double[] { c[0], c[3], c[4], c[5] }; + } + catch (NoninvertibleTransformException e) { + // do nothing + logger.warn("Matrix is not invertible."); + } + + return new double[] { 1d, 1d, 0d, 0d }; + } + + + protected static Range getRangeFromAxis(ValueAxis axis) { + if (axis instanceof DateAxis) { + DateAxis dAxis = (DateAxis) axis; + Date min = dAxis.getMinimumDate(); + Date max = dAxis.getMaximumDate(); + + return new Range(min.getTime(), max.getTime()); + } + else { + return axis.getRange(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/IsKmUpEvaluator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/IsKmUpEvaluator.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,32 @@ +/* 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 org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.access.RiverAccess; +import org.dive4elements.river.artifacts.model.RiverFactory; +import org.dive4elements.river.model.River; + +public class IsKmUpEvaluator +implements DiagramAttributes.Evaluator +{ + public IsKmUpEvaluator() { + } + + @Override + public Object evaluate(D4EArtifact artifact, CallContext context) { + RiverAccess access = new RiverAccess(artifact); + River river = RiverFactory.getRiver(access.getRiver()); + return river == null + ? Boolean.FALSE + : river.getKmUp(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -20,20 +20,20 @@ import org.dive4elements.river.exports.process.Processor; import org.dive4elements.river.exports.process.BedDiffHeightYearProcessor; import org.dive4elements.river.exports.process.BedDiffYearProcessor; -import org.dive4elements.river.exports.process.BedheightProcessor; +import org.dive4elements.river.exports.process.BedHeightSoundingProcessor; +import org.dive4elements.river.exports.process.QOutProcessor; import org.dive4elements.river.exports.process.WOutProcessor; +import org.dive4elements.river.exports.process.AnnotationProcessor; -import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import org.apache.log4j.Logger; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; /** @@ -321,7 +321,7 @@ @Override public void doOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String name = artifactAndFacet.getFacetName(); @@ -339,14 +339,19 @@ return; } - WOutProcessor wProcessor = new WOutProcessor(); - Processor bedp = new BedheightProcessor(); + Processor wProcessor = new WOutProcessor(); + Processor qProcessor = new QOutProcessor(); + Processor bedp = new BedHeightSoundingProcessor(); Processor bdyProcessor = new BedDiffYearProcessor(); Processor bdhyProcessor = new BedDiffHeightYearProcessor(); + Processor annotationProcessor = new AnnotationProcessor(); if (wProcessor.canHandle(name)) { wProcessor.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx); } + if (qProcessor.canHandle(name)) { + qProcessor.doOut(this, artifactAndFacet, attr, visible, YAXIS.Q.idx); + } else if (bedp.canHandle(name)) { bedp.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx); } @@ -356,26 +361,8 @@ else if (bdhyProcessor.canHandle(name)) { bdhyProcessor.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx); } - else if (name.equals(LONGITUDINAL_Q)) { - doQOut( - (WQKms) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (name.equals(STATIC_WQKMS_Q)) { - doQOut( - (WQKms) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); + else if (annotationProcessor.canHandle(name)) { + annotationProcessor.doOut(this, artifactAndFacet, attr, visible, 0); } else if (name.equals(W_DIFFERENCES)) { doWDifferencesOut( @@ -411,7 +398,7 @@ protected void doWDifferencesOut( WKms wkms, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("WDifferencesCurveGenerator.doWDifferencesOut"); @@ -434,68 +421,6 @@ StyledSeriesBuilder.addPoints(series, wkms); addAxisSeries(series, YAXIS.D.idx, visible); - if (DataUtil.guessWaterIncreasing(wkms.allWs())) { - setInverted(true); - } - } - - - /** - * Process the output for Q facets in a longitudinal section curve. - * - * @param wqkms An array of WQKms values. - * @param aandf The facet and artifact. This facet does NOT support any data objects. Use - * D4EArtifact.getNativeFacet() instead to retrieve a Facet which supports - * data. - * @param theme The theme that contains styling information. - * @param visible The visibility of the curve. - */ - protected void doQOut( - WQKms wqkms, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - logger.debug("LongitudinalSectionGenerator.doQOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); - - addAxisSeries(series, YAXIS.Q.idx, visible); - - if (needInvertAxis(wqkms)) { - setInverted(true); - } - } - - /** - * This method determines - taking JFreeCharts auto x value ordering into - * account - if the x axis need to be inverted. Waterlines in these charts - * should decrease. - * - * @param wkms The data object that stores the x and y values used for this - * chart. - */ - public boolean needInvertAxis(WKms wkms) { - boolean wsUp = wkms.guessWaterIncreasing(); - boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms()); - boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp); - - int size = wkms.size(); - - if (logger.isDebugEnabled()) { - logger.debug("(Wkms)Values : " + size); - if (size > 0) { - logger.debug("Start km: " + wkms.getKm(0)); - logger.debug("End km: " + wkms.getKm(size-1)); - } - logger.debug("wsUp: " + wsUp); - logger.debug("kmUp: " + kmUp); - logger.debug("inv: " + inv); - } - - return inv; } @@ -536,7 +461,7 @@ protected void doArea( Object o, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("LongitudinalSectionGenerator.doArea"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator2.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,92 @@ +/* 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 org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.river.artifacts.access.RangeAccess; +import org.dive4elements.river.jfree.Bounds; +import org.dive4elements.river.jfree.DoubleBounds; +import org.dive4elements.river.themes.ThemeDocument; + +public class LongitudinalSectionGenerator2 extends DiagramGenerator +{ + public static final String I18N_CHART_SHORT_SUBTITLE = + "chart.longitudinal.section.shortsubtitle"; + + public static final String I18N_CHART_LOCATION_SUBTITLE = + "chart.longitudinal.section.locsubtitle"; + + @Override + public String getDefaultChartSubtitle() { + double[] dist = getRange(); + + if (dist == null || dist.length != 2 || + Double.isNaN(dist[0]) || Double.isNaN(dist[1])) { + Object [] args = new Object[] {getRiverName()}; + return msg(I18N_CHART_SHORT_SUBTITLE, "", args); + } + + if (Math.abs(dist[0] - dist[1]) < 1E-5) { + Object [] args = new Object[] {getRiverName(), dist[1]}; + return msg(I18N_CHART_LOCATION_SUBTITLE, "", args); + } + + return super.getDefaultChartSubtitle(); + } + + /* We override doOut here to save the startkm and endkm in the + * context. Some facets will deliver different data because of + * that setting. It is mainly used in MINFO where it causes + * adaptive smoothing on the data if you are zoomed out do + * reduce the static in the curve. */ + @Override + public void doOut( + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible + ) { + /* Aheinecke (25.09.2013): I do not understand why this has to be + * done so difficult and if it really must be done for every + * facet. At least it has to be done _before_ the super class + * actually does the output and accesses the facet data. + */ + D4EArtifact artifact = (D4EArtifact)bundle.getArtifact(); + + if (getXBounds(0) != null && getDomainAxisRange() != null) { + Bounds bounds = + calculateZoom(getXBounds(0), getDomainAxisRange()); + context.putContextValue("startkm", bounds.getLower()); + context.putContextValue("endkm", bounds.getUpper()); + } + else if (getXBounds(0) != null && getDomainAxisRange() == null) { + context.putContextValue("startkm", getXBounds(0).getLower()); + context.putContextValue("endkm", getXBounds(0).getUpper()); + } + else if (getXBounds(0) == null && getDomainAxisRange() == null) { + RangeAccess access = new RangeAccess(artifact); + if (access.hasFrom() && access.hasTo()) { + context.putContextValue("startkm", access.getFrom()); + context.putContextValue("endkm", access.getTo()); + } + } + else if (getXBounds(0) == null && getDomainAxisRange() != null){ + RangeAccess access = new RangeAccess(artifact); + if (access.hasFrom() && access.hasTo()) { + Bounds b = new DoubleBounds(access.getFrom(), access.getTo()); + Bounds bounds = + calculateZoom(b, getDomainAxisRange()); + context.putContextValue("startkm", bounds.getLower()); + context.putContextValue("endkm", bounds.getUpper()); + } + } + super.doOut(bundle, theme, visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* 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; - - -/** - * A ChartInfoGenerator that generates meta information for specific - * longitudinal section curves. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class LongitudinalSectionInfoGenerator -extends ChartInfoGenerator -{ - public LongitudinalSectionInfoGenerator() { - super(new LongitudinalSectionGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/MapGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/MapGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/MapGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -24,9 +24,9 @@ import org.dive4elements.river.artifacts.model.map.WSPLGENLayerFacet; import org.dive4elements.river.artifacts.states.WaterlevelGroundDifferences; import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.ArtifactMapfileGenerator; import org.dive4elements.river.utils.GeometryUtils; -import org.dive4elements.river.utils.ThemeUtil; import java.io.File; import java.io.FileNotFoundException; @@ -65,12 +65,18 @@ protected String srid; - + protected String outName; @Override - public void init(Document request, OutputStream out, CallContext context) { + public void setup(Object config) { + logger.debug("MapGenerator.setup"); + } + + @Override + public void init(String outName, Document request, OutputStream out, CallContext context) { logger.debug("MapGenerator.init"); + this.outName = outName; this.request = request; this.out = out; this.context = context; @@ -96,7 +102,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible) { String name = artifactFacet.getFacetName(); @@ -120,9 +126,11 @@ setInitialExtent(extent); createWSPLGENLayer(flys, wms, attr); } - else if (FLOODMAP_USERSHAPE.equals(name)) { - createUserShapeLayer(flys, wms); - } + // FIXME: Already generated by HWSBarrierState + // wms has a wrong SRID which would break that layer + //else if (FLOODMAP_USERSHAPE.equals(name)) { + // createUserShapeLayer(flys, wms); + //} else { logger.debug("doOut: createDatabaseLayer for facet name: " + name); createDatabaseLayer(flys, wms, attr); @@ -135,9 +143,9 @@ protected void createWSPLGENLayer( - D4EArtifact flys, + D4EArtifact flys, WMSLayerFacet wms, - Document attr + ThemeDocument attr ) { try { if(wms instanceof WSPLGENLayerFacet) { @@ -158,7 +166,8 @@ mfg.createUeskLayer( flys, (WSPLGENLayerFacet) wms, - ThemeUtil.createDynamicMapserverStyle(attr, from, to, step, context.getMeta()), + attr.createDynamicMapserverStyle( + from, to, step, context.getMeta()), context); } else { @@ -188,9 +197,9 @@ protected void createDatabaseLayer( - D4EArtifact flys, + D4EArtifact flys, WMSLayerFacet wms, - Document attr + ThemeDocument attr ) { logger.debug("createDatabaseLayer for facet: " + wms.getName()); @@ -209,7 +218,7 @@ mfg.createDatabaseLayer( flys, (WMSDBLayerFacet) wms, - ThemeUtil.createMapserverStyle(attr)); + attr.createMapserverStyle()); } else { logger.warn("Cannot create DB layer from: " + wms.getClass()); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -13,14 +13,10 @@ import java.util.ArrayList; import java.util.List; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; - import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.MiddleBedHeightData; @@ -64,13 +60,10 @@ protected List<MiddleBedHeightData[]> data; - - public void init(Document request, OutputStream out, CallContext cc) { - super.init(request, out, cc); + public MiddleBedHeightExporter() { data = new ArrayList<MiddleBedHeightData[]>(); } - @Override protected void addData(Object d) { if (d instanceof CalculationResult) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,295 +0,0 @@ -/* 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 org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; -import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.MiddleBedHeightData; -import org.dive4elements.river.exports.process.BedheightProcessor; -import org.dive4elements.river.exports.process.Processor; -import org.dive4elements.river.exports.process.WOutProcessor; -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.RiverUtils; - -import org.apache.log4j.Logger; -import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - -// TODO Move class to org.dive4elements.river.exports.minfo -/** - * An OutGenerator that generates middle bed height charts. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class MiddleBedHeightGenerator -extends XYChartGenerator -implements FacetTypes -{ - public enum YAXIS { - H(0), W(1), P(2); - protected int idx; - private YAXIS(int c) { - idx = c; - } - } - - /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(MiddleBedHeightGenerator.class); - - /** Key to look up internationalized String for annotations label. */ - public static final String I18N_ANNOTATIONS_LABEL = - "chart.bedheight_middle.annotations.label"; - - public static final String I18N_CHART_TITLE = - "chart.bedheight_middle.section.title"; - - public static final String I18N_CHART_SUBTITLE = - "chart.bedheight_middle.section.subtitle"; - - public static final String I18N_CHART_SHORT_SUBTITLE = - "chart.bedheight_middle.section.shortsubtitle"; - - public static final String I18N_XAXIS_LABEL = - "chart.bedheight_middle.section.xaxis.label"; - - public static final String I18N_YAXIS_LABEL = - "chart.bedheight_middle.section.yaxis.label"; - - public static final String I18N_CHART_TITLE_DEFAULT = "Mittlere Sohlhöhe"; - public static final String I18N_XAXIS_LABEL_DEFAULT = "km"; - public static final String I18N_YAXIS_LABEL_DEFAULT = "mittlere Sohlhöhen [müNN]"; - public static final String I18N_W_YAXIS_LABEL = - "chart.longitudinal.section.yaxis.label"; - public static final String I18N_W_YAXIS_LABEL_DEFAULT = "W [NN + m]"; - public static final String I18N_P_YAXIS_LABEL_DEFAULT = "Gepeilte Breite [m]"; - public static final String I18N_P_YAXIS_LABEL = - "chart.bedheight_middle.sounding.yaxis.label"; - - @Override - protected YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } - - - /** - * Returns the default title for this chart. - * - * @return the default title for this chart. - */ - @Override - public String getDefaultChartTitle() { - Object[] args = new Object[] { - getRiverName() - }; - - return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, args); - } - - - /** - * Get internationalized label for the x axis. - */ - @Override - protected String getDefaultXAxisLabel() { - D4EArtifact flys = (D4EArtifact) master; - - return msg( - I18N_XAXIS_LABEL, - I18N_XAXIS_LABEL_DEFAULT, - new Object[] { RiverUtils.getRiver(flys).getName() }); - } - - - @Override - protected String getDefaultYAxisLabel(int index) { - String label = "default"; - - if (index == YAXIS.H.idx) { - label = getHAxisLabel(); - } - else if (index == YAXIS.W.idx) { - D4EArtifact flys = (D4EArtifact) master; - String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); - - label = msg( - I18N_W_YAXIS_LABEL, - I18N_W_YAXIS_LABEL_DEFAULT, - new Object[] { unit }); - } - else if (index == YAXIS.P.idx) { - label = msg(I18N_P_YAXIS_LABEL, I18N_P_YAXIS_LABEL_DEFAULT); - } - - return label; - } - - - /** - * Get internationalized label for the y axis. - */ - protected String getHAxisLabel() { - D4EArtifact flys = (D4EArtifact) master; - - String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); - - return msg(I18N_YAXIS_LABEL, - I18N_YAXIS_LABEL_DEFAULT, - new Object[] { unit }); - } - - - /** - * Produce output. - * @param artifactAndFacet current facet. - * @param attr theme for facet - */ - @Override - public void doOut( - ArtifactAndFacet artifactAndFacet, - Document attr, - boolean visible - ) { - String name = artifactAndFacet.getFacetName(); - - logger.debug("MiddleBedHeightGenerator.doOut: " + name); - - if (name == null) { - logger.error("No facet name for doOut(). No output generated!"); - return; - } - - Facet facet = artifactAndFacet.getFacet(); - - if (facet == null) { - return; - } - - Processor woutp = new WOutProcessor(); - Processor bedp = new BedheightProcessor(); - WOutProcessor processor = new WOutProcessor(); - if (processor.canHandle(name)) { - processor.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx); - } - if (name.equals(MIDDLE_BED_HEIGHT_SINGLE) || name.equals(MIDDLE_BED_HEIGHT_EPOCH)) { - doHeightOut( - (MiddleBedHeightData) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (name.equals(MIDDLE_BED_HEIGHT_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (FacetTypes.IS.AREA(name)) { - doArea( - artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (FacetTypes.IS.MANUALPOINTS(name)) { - doPoints( - artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible, - YAXIS.H.idx); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (bedp.canHandle(name)) { - bedp.doOut(this, artifactAndFacet, attr, visible, YAXIS.P.idx); - } - else if (woutp.canHandle(name)) { - woutp.doOut(this, artifactAndFacet, attr, visible, YAXIS.W.idx); - } - else { - logger.warn("Unknown facet name: " + name); - } - } - - - /** - * @param data A data object - * @param aandf The artifact and facet. This facet does NOT support any data objects. Use - * D4EArtifact.getNativeFacet() instead to retrieve a Facet which supports - * data. - * @param theme The theme that contains styling information. - * @param visible The visibility of the curve. - */ - protected void doHeightOut( - MiddleBedHeightData data, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - logger.debug("MiddleBedHeightGenerator.doMainChannelOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addPoints(series, data.getMiddleHeightsPoints(), false, 0.110d); - - addAxisSeries(series, YAXIS.H.idx, visible); - } - - - /** Look up the axis identifier for a given facet type. */ - public int axisIdxForFacet(String facetName) { - if (FacetTypes.IS.H(facetName)) { - return YAXIS.H.idx; - } - else if (FacetTypes.IS.W(facetName)) { - return YAXIS.W.idx; - } - else { - logger.warn("Could not find axis for facet " + facetName); - return YAXIS.H.idx; - } - } - - - /** - * Do Area out. - * @param theme styling information. - * @param visible whether or not visible. - */ - protected void doArea( - Object o, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - logger.debug("FlowVelocityGenerator.doArea"); - logger.warn("TODO: Implement FlowVelocityGenerator.doArea"); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/MiddleBedHeightInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* 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; - - -/** - * A ChartInfoGenerator that generates meta information for specific - * middle bed height curves. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class MiddleBedHeightInfoGenerator -extends ChartInfoGenerator -{ - public MiddleBedHeightInfoGenerator() { - super(new MiddleBedHeightGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/OutGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/OutGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/OutGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,6 +18,7 @@ import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.themes.ThemeDocument; /** @@ -28,15 +29,21 @@ public interface OutGenerator { /** + * Pre-initialize generator from configuration. + */ + void setup(Object config); + + /** * Initializes the OutGenerator with meta information which are necessary * for the output generation. * + * @param outName The name of the out to serve. * @param request The incomding request document. * @param out The output stream. * @param context The CallContext that provides further information and * objects used for the output generation. */ - void init(Document request, OutputStream out, CallContext context); + void init(String outName, Document request, OutputStream out, CallContext context); /** * This method is used to tell the OutGenerator which artifact is the master @@ -63,7 +70,7 @@ * producing the output. * @param visible Specifies, if this output should be visible or not. */ - void doOut(ArtifactAndFacet bundle, Document attr, boolean visible); + void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible); /** * Writes the collected output of all artifacts specified in the diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/OutputHelper.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/OutputHelper.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/OutputHelper.java Fri Sep 27 17:36:50 2013 +0200 @@ -40,6 +40,7 @@ import org.dive4elements.river.artifacts.model.ManagedDomFacet; import org.dive4elements.river.artifacts.model.ManagedFacet; import org.dive4elements.river.themes.Theme; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.themes.ThemeFactory; public class OutputHelper { @@ -76,6 +77,8 @@ ThemeList themeList = new ThemeList(attributes); + ThemeDocument themeDoc = new ThemeDocument(attributes); + List<ArtifactAndFacet> dataProviders = doBlackboardPass(themeList, context, outName); @@ -109,7 +112,7 @@ if (outName.equals("sq_overview")) { generator.doOut( dataProviders.get(i), - attributes, + themeDoc, theme.getActive() == 1); } else { @@ -141,7 +144,7 @@ * * @return an attribute in form of a document. */ - protected Document getFacetThemeFromAttribute( + protected ThemeDocument getFacetThemeFromAttribute( String uuid, String outName, String facet, @@ -219,7 +222,7 @@ Document doc = XMLUtils.newDocument(); doc.appendChild(doc.importNode(theme, true)); - return doc; + return new ThemeDocument(doc); } /** * Adds the theme of a facet to a CollectionItem's attribute. diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,7 +10,6 @@ import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.common.utils.Config; @@ -46,8 +45,6 @@ import org.apache.log4j.Logger; -import org.w3c.dom.Document; - /** * (CSV)Exporter for Reference Curves. */ @@ -91,17 +88,10 @@ protected boolean endAtGauge = false; - - @Override - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("ReferenceCurveExporter.init"); - - super.init(request, out, context); - + public ReferenceCurveExporter() { this.data = new ArrayList<WWQQ[]>(); } - /** * Genereate data in csv format. */ diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -15,6 +15,7 @@ import org.dive4elements.river.artifacts.model.WWAxisTypes; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; import java.awt.geom.Point2D; @@ -25,7 +26,6 @@ import org.jfree.chart.axis.TickUnits; import org.jfree.chart.axis.ValueAxis; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; /** * An OutGenerator that generates reference curves. @@ -137,7 +137,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document theme, + ThemeDocument theme, boolean visible ) { String name = artifactFacet.getFacetName(); @@ -187,9 +187,9 @@ /** Register DataSeries with (maybe transformed) points. */ public void doReferenceOut( - Object data, - Document theme, - boolean visible + Object data, + ThemeDocument theme, + boolean visible ) { WW ww = (WW)data; @@ -216,10 +216,10 @@ // TODO resolve duplicate in DurationCurveGenerator protected void doPointOut( - Point2D point, + Point2D point, ArtifactAndFacet aandf, - Document theme, - boolean visible + ThemeDocument theme, + boolean visible ){ logger.debug("ReferenceCurveGenerator.doPointOut"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ReportGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/ReportGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ReportGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -24,6 +24,7 @@ import org.dive4elements.river.artifacts.model.Calculation; import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.themes.ThemeDocument; import org.w3c.dom.Document; @@ -35,13 +36,20 @@ protected Document result; protected OutputStream out; protected CallContext context; + protected String outName; public ReportGenerator() { } @Override - public void init(Document request, OutputStream out, CallContext context) { + public void setup(Object config) { + logger.debug("ReportGenerator.setup"); + } + + @Override + public void init(String outName, Document request, OutputStream out, CallContext context) { logger.debug("init"); + this.outName = outName; this.out = out; this.context = context; result = null; @@ -60,7 +68,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document attr, + ThemeDocument attr, boolean visible ) { logger.debug("doOut"); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/ShapeExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/ShapeExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ShapeExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -14,6 +14,7 @@ import org.dive4elements.artifacts.common.utils.FileTools; import org.dive4elements.artifacts.common.utils.XMLUtils; import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.themes.ThemeDocument; import org.w3c.dom.Document; @@ -28,9 +29,16 @@ private D4EArtifactCollection collection; private String facet; private File dir; + private String outName; @Override - public void init(Document request, OutputStream out, CallContext context) { + public void setup(Object config) { + logger.debug("ShapeExporter.setup"); + } + + @Override + public void init(String outName, Document request, OutputStream out, CallContext context) { + this.outName = outName; this.request = request; this.out = out; this.context = context; @@ -47,7 +55,7 @@ } @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { + public void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible) { String name = bundle.getFacetName(); if (!isFacetValid(name)) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/StyledSeriesBuilder.java Fri Sep 27 17:36:50 2013 +0200 @@ -40,14 +40,63 @@ /** + * Add points to series, create gaps if certain distance between + * points is met and scale the Y value. + * + * @param series Series to add points to. + * @param points Points to add to series, points[0] to 1st dim, points[1] + * to 2nd dim. + * @param skipNANs if true, skip NAN values in points parameter. Otherwise, + * the NaNs lead to gaps in graph. + * @param distance if two consecutive entries in points[0] are more + * than distance apart, create a NaN value to skip in display. + * Still, create a line segment. + * @param factor Factor by which to scale the y value (points[1]). + */ + public static void addPointsFactorY(XYSeries series, + double[][] points, + boolean skipNANs, + double distance, + double factor + ) { + if (points == null || points.length <= 1) { + return; + } + double [] xPoints = points[0]; + double [] yPoints = points[1]; + for (int i = 0; i < xPoints.length; i++) { + if (skipNANs && + (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) { + logger.warn ("Skipping NaN in StyledSeriesBuilder."); + continue; + } + // Create gap if distance >= distance. + if (i != 0 && Math.abs(xPoints[i-1] - xPoints[i]) >= distance) { + // Create at least a small segment for last point. + if (!Double.isNaN(yPoints[i-1])) { + series.add(xPoints[i-1]+0.99d*(distance)/2.d, yPoints[i-1]*factor, false); + } + + if (!Double.isNaN(yPoints[i-1]) && !Double.isNaN(yPoints[i])) { + series.add((xPoints[i-1]+xPoints[i])/2.d, Double.NaN, false); + } + } + series.add(xPoints[i], yPoints[i]*factor, false); + } + } + + + /** * Add points to series, create gaps if certain distance between points is met. * * @param series Series to add points to. * @param points Points to add to series, points[0] to 1st dim, points[1] * to 2nd dim. - * @param skipNANs if true, skip NAN values in points parameter. + * @param skipNANs if true, skip NAN values in points parameter. Otherwise, + * the NaNs lead to gaps in graph. * @param distance if two consecutive entries in points[0] are more * than distance apart, create a NaN value to skip in display. + * Still, create a line segment. */ public static void addPoints(XYSeries series, double[][] points, boolean skipNANs, double distance) { if (points == null || points.length <= 1) { @@ -63,6 +112,11 @@ } // Create gap if distance >= distance. if (i != 0 && Math.abs(xPoints[i-1] - xPoints[i]) >= distance) { + // Create at least a small segment for last point. + if (!Double.isNaN(yPoints[i-1])) { + series.add(xPoints[i-1]+0.99d*(distance)/2.d, yPoints[i-1], false); + } + if (!Double.isNaN(yPoints[i-1]) && !Double.isNaN(yPoints[i])) { series.add((xPoints[i-1]+xPoints[i])/2.d, Double.NaN, false); } @@ -250,6 +304,27 @@ * W values and scaling it with wScale. * * @param series Series to add points to. + * @param qws to add to series. + * @param wAdd Value to add to each Q while adding to series. + * @param wScale multiply with + */ + public static void addPointsQW(XYSeries series, double[][] qws, double wTrans, double wScale) { + if (qws == null || qws.length == 0) { + return; + } + + double x[] = qws[0]; + double y[] = qws[1]; + + for (int i = 0; i < x.length; i++) { + series.add(x[i], wScale * (y[i] + wTrans), false); + } + } + /** + * Add points to series (q to 1st dim, w to 2nd dim), adding wTrans to the + * W values and scaling it with wScale. + * + * @param series Series to add points to. * @param wqkms WQKms to add to series. * @param wAdd Value to add to each Q while adding to series. * @param wScale multiply with diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/SyncNumberAxis.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/SyncNumberAxis.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/SyncNumberAxis.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,6 +18,7 @@ /** * Axis which is to be registered with other axis and tries * to clone its range. The cloned range is transformed. + * Keeps in sync via AxisChangedEvents. */ public class SyncNumberAxis extends IdentifiableNumberAxis implements AxisChangeListener diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,6 +16,8 @@ import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledTimeSeries; import org.dive4elements.river.jfree.TimeBounds; +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.themes.ThemeDocument; import java.awt.Color; import java.awt.Font; @@ -51,133 +53,13 @@ import org.jfree.ui.Layer; import org.json.JSONArray; import org.json.JSONException; -import org.w3c.dom.Document; /** + * Generator for diagrams with time on x axis. * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ -public abstract class TimeseriesChartGenerator extends ChartGenerator { - - - /** - * Inner class TimeseriesAxisDataset stores TimeSeriesCollection. - */ - public class TimeseriesAxisDataset implements AxisDataset { - - protected int axisSymbol; - - protected List<TimeSeriesCollection> datasets; - - protected Range range; - - protected int plotAxisIndex; - - public TimeseriesAxisDataset(int axisSymbol) { - this.axisSymbol = axisSymbol; - this.datasets = new ArrayList<TimeSeriesCollection>(); - } - - - @Override - public void addDataset(XYDataset dataset) { - if (!(dataset instanceof TimeSeriesCollection)) { - logger.warn("Skip non TimeSeriesCollection dataset."); - return; - } - - TimeSeriesCollection tsc = (TimeSeriesCollection) dataset; - - datasets.add(tsc); - mergeRanges(tsc); - } - - - @Override - public XYDataset[] getDatasets() { - return datasets.toArray(new XYDataset[datasets.size()]); - } - - - @Override - public boolean isEmpty() { - return datasets.isEmpty(); - } - - - @Override - public void setRange(Range range) { - this.range = range; - } - - - @Override - public Range getRange() { - return range; - } - - - @Override - public void setPlotAxisIndex(int plotAxisIndex) { - this.plotAxisIndex = plotAxisIndex; - } - - - @Override - public int getPlotAxisIndex() { - return plotAxisIndex; - } - - - @Override - public boolean isArea(XYDataset dataset) { - logger.warn("This AxisDataset doesn't support Areas yet!"); - return false; - } - - - protected void mergeRanges(TimeSeriesCollection dataset) { - logger.debug("Range before merging: " + range); - Range subRange = null; - - // Determine min/max of range axis. - for (int i = 0; i < dataset.getSeriesCount(); i++) { - if (dataset.getSeries(i).getItemCount() == 0) { - continue; - } - double min = Double.MAX_VALUE; - double max = -Double.MAX_VALUE; - TimeSeries series = dataset.getSeries(i); - for (int j = 0; j < series.getItemCount(); j++) { - double tmp = series.getValue(j).doubleValue(); - min = tmp < min ? tmp : min; - max = tmp > max ? tmp : max; - } - if (subRange != null) { - subRange = new Range( - min < subRange.getLowerBound() ? - min : subRange.getLowerBound(), - max > subRange.getUpperBound() ? - max : subRange.getUpperBound()); - } - else { - subRange = new Range(min, max); - } - } - - // Avoid merging NaNs, as they take min/max place forever. - if (subRange == null || - Double.isNaN(subRange.getLowerBound()) || - Double.isNaN(subRange.getUpperBound())) { - return; - } - if (range == null) { - range = subRange; - return; - } - range = Range.combine(range, subRange); - } - - } // end of TimeseriesAxisDataset class +public abstract class TimeseriesChartGenerator +extends ChartGenerator { protected List<Marker> domainMarker; @@ -388,14 +270,14 @@ /** - * This method creates new instances of TimeseriesAxisDataset. + * This method creates new instances of AxisDataset. * - * @param idx The symbol for the new TimeseriesAxisDataset. + * @param idx The symbol for the new AxisDataset. */ @Override protected AxisDataset createAxisDataset(int idx) { logger.debug("Create a new AxisDataset for index: " + idx); - return new TimeseriesAxisDataset(idx); + return new AxisDataset(idx); } @@ -691,7 +573,7 @@ protected void doPoints( Object o, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible, int axisIndex ) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* 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 org.apache.log4j.Logger; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; - -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.WKms; - -import org.dive4elements.river.exports.process.BedDiffYearProcessor; -import org.dive4elements.river.exports.process.BedDiffHeightYearProcessor; -import org.dive4elements.river.exports.process.BedheightProcessor; -import org.dive4elements.river.exports.process.Processor; - -import org.jfree.chart.JFreeChart; -import org.jfree.chart.plot.XYPlot; -import org.w3c.dom.Document; - - -/** - * An OutGenerator that generates w differences curves. - */ -public class WDifferencesCurveGenerator -extends LongitudinalSectionGenerator -implements FacetTypes -{ - /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(WDifferencesCurveGenerator.class); - - public enum YAXIS { - W(0), - D(1), - Q(2); - protected int idx; - private YAXIS(int c) { - idx = c; - } - } - - /** Key for internationalized title of WDiff charts. */ - public final static String I18N_WDIFF_TITLE = "chart.w_differences.title"; - - /** Default for internationalized title (when no translation found). */ - public final static String I18N_WDIFF_TITLE_DEFAULT = "Differences"; - - public final static String I18N_WDIFF_SUBTITLE = - "chart.w_differences.subtitle"; - - - @Override - protected YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } - - - /** - * Get internationalized title for chart. - * @return internationalized Chart title. - */ - @Override - public String getDefaultChartTitle() { - return msg(I18N_WDIFF_TITLE, I18N_WDIFF_TITLE_DEFAULT); - } - - - @Override - protected String getDefaultChartSubtitle() { - return getRiverName(); - } - - - /** - * Gets key to look up internationalized String for the charts subtitle. - * @return key to look up translated subtitle. - */ - @Override - protected String getChartSubtitleKey() { - return I18N_WDIFF_SUBTITLE; - } - - - /** Handle additional facets (beddifferences). */ - @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { - super.doOut(bundle, attr, visible); - - String name = bundle.getFacetName(); - logger.debug("doOut: " + name); - - if (name == null) { - logger.error("No facet name for doOut(). No output generated!"); - return; - } - - Facet facet = bundle.getFacet(); - - if (facet == null) { - return; - } - - Processor bedp = new BedheightProcessor(); - Processor bdyProcessor = new BedDiffYearProcessor(); - Processor bdhyProcessor = new BedDiffHeightYearProcessor(); - - if (bedp.canHandle(name)) { - bedp.doOut(this, bundle, attr, visible, YAXIS.W.idx); - } - else if (bdyProcessor.canHandle(name)) { - bdyProcessor.doOut(this, bundle, attr, visible, YAXIS.W.idx); - } - else if (bdhyProcessor.canHandle(name)) { - bdhyProcessor.doOut(this, bundle, attr, visible, YAXIS.W.idx); - } - else { - logger.warn("WDifferencesCurveGenerator.doOut: unknown facet type " + name); - } - } - - - /** - * Sets the zero base line visible. - */ - @Override - public JFreeChart generateChart() { - JFreeChart chart = super.generateChart(); - if (chart != null && chart.getPlot() != null) { - XYPlot plot = (XYPlot) chart.getPlot(); - plot.setRangeZeroBaselineVisible(true); - } - return chart; - } - - - /** - * Get name of series (displayed in legend). - * @return name of the series. - */ - protected String getSeriesName(WKms wqkms, String mode) { - String name = wqkms.getName(); - String prefix = (name != null && name.indexOf(mode) >= 0) - ? null - : mode; - - return (prefix != null && prefix.length() > 0) - ? prefix + "(" + name +")" - : name; - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesCurveInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -/* 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; - - -/** - * A ChartInfoGenerator that generates meta information for specific - * w differences. - */ -public class WDifferencesCurveInfoGenerator -extends ChartInfoGenerator -{ - public WDifferencesCurveInfoGenerator() { - super(new WDifferencesCurveGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/WDifferencesExporter.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; @@ -30,7 +28,6 @@ import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JRException; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.common.utils.Config; @@ -68,16 +65,10 @@ /** The storage that contains all WKms objects for the different facets. */ protected List<WKms[]> data; - - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("WDifferencesExporter.init"); - - super.init(request, out, context); - - this.data = new ArrayList<WKms[]>(); + public WDifferencesExporter() { + data = new ArrayList<WKms[]>(); } - /** * Genereate data in csv format. */ diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/WaterlevelExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/WaterlevelExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/WaterlevelExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -21,8 +21,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; import au.com.bytecode.opencsv.CSVWriter; @@ -35,7 +33,6 @@ import net.sf.jasperreports.engine.JRException; import org.dive4elements.artifacts.Artifact; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.common.utils.Config; @@ -145,15 +142,10 @@ /** The storage that contains official fixings if available.*/ protected List<WQKms> officalFixings; - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("WaterlevelExporter.init"); - - super.init(request, out, context); - - this.data = new ArrayList<WQKms[]>(); + public WaterlevelExporter() { + data = new ArrayList<WQKms[]>(); } - @Override public void generate() throws IOException @@ -594,12 +586,11 @@ writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), - qf.format(wqkm[1]), + qf.format(RiverUtils.roundQ(wqkm[1])), RiverUtils.getLocationDescription(flys, wqkm[2]) }); } - /** Write an csv-row at gauge location. */ private void writeRow6(CSVWriter writer, double wqkm[], String wOrQDesc, D4EArtifact flys, String gaugeName) { @@ -610,7 +601,7 @@ writer.writeNext(new String[] { kmf.format(wqkm[2]), wf.format(wqkm[0]), - qf.format(wqkm[1]), + qf.format(RiverUtils.roundQ(wqkm[1])), wOrQDesc, RiverUtils.getLocationDescription(flys, wqkm[2]), gaugeName @@ -913,12 +904,14 @@ Locale locale = Resources.getLocale(meta); DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + NumberFormat kmf = getKmFormatter(); source.addMetaData("date", df.format(new Date())); RangeAccess rangeAccess = new RangeAccess(flys); double[] kms = rangeAccess.getKmRange(); - source.addMetaData("range", kms[0] + " - " + kms[kms.length-1]); + source.addMetaData("range", + kmf.format(kms[0]) + " - " + kmf.format(kms[kms.length-1])); source.addMetaData("gauge", RiverUtils.getGaugename(flys)); @@ -969,7 +962,7 @@ source.addData(new String[] { kmf.format(result[2]), wf.format(result[0]), - qf.format(result[1]), + qf.format(RiverUtils.roundQ(result[1])), desc, RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b @@ -981,7 +974,7 @@ source.addData(new String[] { kmf.format(result[2]), wf.format(result[0]), - qf.format(result[1]), + qf.format(RiverUtils.roundQ(result[1])), desc, RiverUtils.getLocationDescription(flys, result[2]), result[2] >= a && result[2] <= b diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -38,7 +38,6 @@ import org.jfree.data.xy.XYSeriesCollection; import org.json.JSONArray; import org.json.JSONException; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.river.jfree.Bounds; @@ -47,6 +46,9 @@ import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.jfree.AnnotationHelper; +import org.dive4elements.river.themes.ThemeDocument; /** @@ -66,115 +68,6 @@ */ public abstract class XYChartGenerator extends ChartGenerator { - public class XYAxisDataset implements AxisDataset { - /** Symbolic integer, but also coding the priority (0 goes first). */ - protected int axisSymbol; - - /** List of assigned datasets (in order). */ - protected List<XYDataset> datasets; - - /** Range to use to include all given datasets. */ - protected Range range; - - /** Index of axis in plot. */ - protected int plotAxisIndex; - - /** Create AxisDataset. */ - public XYAxisDataset(int symb) { - this.axisSymbol = symb; - datasets = new ArrayList<XYDataset>(); - } - - /** Merge (or create given range with range so far (if any). */ - private void mergeRanges(Range subRange) { - // Avoid merging NaNs, as they take min/max place forever. - if (subRange == null || - Double.isNaN(subRange.getLowerBound()) || - Double.isNaN(subRange.getUpperBound())) { - return; - } - if (range == null) { - range = subRange; - return; - } - range = Range.combine(range, subRange); - } - - - /** Add a dataset to internal list for this axis. */ - @Override - public void addDataset(XYDataset dataset) { - datasets.add(dataset); - includeYRange(((XYSeriesCollection) dataset).getSeries(0)); - } - - /** Add a dataset, include its range. */ - public void addDataset(XYSeries series) { - addDataset(new XYSeriesCollection(series)); - } - - - /** Set Range for this axis. */ - @Override - public void setRange(Range range) { - this.range = range; - } - - - /** Get Range for this axis. */ - @Override - public Range getRange() { - return range; - } - - - /** Get Array of Datasets. */ - @Override - public XYDataset[] getDatasets() { - return datasets.toArray(new XYDataset[datasets.size()]); - } - - - /** Add a Dataset that describes an area. */ - public void addArea(StyledAreaSeriesCollection series) { - this.datasets.add(series); - List<?> allSeries = series.getSeries(); - /* We do not include the bounds/ranges, if the area includes - * points at "infinity"/BIG_DOUBLE_VALUE, the charts extents are - * expanded to include these very small/big value. - * This is especially used when showing "area above axis". */ - } - - /** True if to be rendered as area. */ - @Override - public boolean isArea(XYDataset series) { - return (series instanceof StyledAreaSeriesCollection); - } - - /** Adjust range to include given dataset. */ - public void includeYRange(XYSeries dataset) { - mergeRanges(new Range(dataset.getMinY(), dataset.getMaxY())); - } - - /** True if no datasets given. */ - @Override - public boolean isEmpty() { - return this.datasets.isEmpty(); - } - - /** Set the 'real' axis index that this axis is mapped to. */ - @Override - public void setPlotAxisIndex(int axisIndex) { - this.plotAxisIndex = axisIndex; - } - - /** Get the 'real' axis index that this axis is mapped to. */ - @Override - public int getPlotAxisIndex() { - return this.plotAxisIndex; - } - } // class AxisDataset - /** Enumerator over existing axes. */ @Override protected abstract YAxisWalker getYAxisWalker(); @@ -258,7 +151,8 @@ //debugAxis(plot); // These have to go after the autozoom. - addAnnotationsToRenderer(plot); + AnnotationHelper.addAnnotationsToRenderer(annotations, plot, + getChartSettings(), datasets); // Add a logo (maybe). addLogo(plot); @@ -415,8 +309,8 @@ @Override protected AxisDataset createAxisDataset(int idx) { - logger.debug("Create new XYAxisDataset for index: " + idx); - return new XYAxisDataset(idx); + logger.debug("Create new AxisDataset for index: " + idx); + return new AxisDataset(idx); } @@ -481,7 +375,7 @@ return; } - XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); + AxisDataset axisDataset = (AxisDataset) getAxisDataset(index); if (visible) { axisDataset.addArea(area); @@ -510,13 +404,6 @@ addAxisDataset(new XYSeriesCollection(series), index, visible); - XYAxisDataset axisDataset = (XYAxisDataset) getAxisDataset(index); - - if (!visible) { - // Do this also when not visible to have axis scaled by default such - // that every data-point could be seen (except for annotations). - axisDataset.includeYRange(series); - } } @@ -991,7 +878,7 @@ protected void doPoints( Object o, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible, int axisIndex ) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -17,7 +17,6 @@ import org.jfree.chart.plot.XYPlot; import org.jfree.chart.title.TextTitle; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; @@ -33,8 +32,8 @@ import org.dive4elements.river.jfree.JFreeUtil; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; -import org.dive4elements.river.utils.ThemeUtil; /** @@ -76,7 +75,7 @@ /** First, ask parent to add data, then handle extreme_wq_curve(_base) data.*/ @Override - public boolean prepareChartData(ArtifactAndFacet aaf, Document theme, boolean visible) { + public boolean prepareChartData(ArtifactAndFacet aaf, ThemeDocument theme, boolean visible) { if (super.prepareChartData(aaf, theme, visible)) { return true; } @@ -104,7 +103,7 @@ } /** Do Extreme Curve nonextrapolated points out. */ - protected void doExtremeCurveBaseOut(ArtifactAndFacet aaf, Document theme, boolean visible) { + protected void doExtremeCurveBaseOut(ArtifactAndFacet aaf, ThemeDocument theme, boolean visible) { logger.debug("doExtremeCurveBaseOut"); ExtremeCurveFacet facet = (ExtremeCurveFacet) aaf.getFacet(); Curve curve = (Curve) facet.getData(aaf.getArtifact(), context); @@ -136,7 +135,7 @@ /** Do Extreme Curve out */ - protected void doExtremeCurveOut(ArtifactAndFacet aaf, Document theme, boolean visible) { + protected void doExtremeCurveOut(ArtifactAndFacet aaf, ThemeDocument theme, boolean visible) { logger.debug("doExtremeCurveOut"); ExtremeCurveFacet facet = (ExtremeCurveFacet) aaf.getFacet(); Curve curve = (Curve) facet.getData(aaf.getArtifact(), context); @@ -159,7 +158,7 @@ maxQ); // end // Add marker from where on its extrapolated. - if (ThemeUtil.parseShowExtraMark(theme)) { + if (theme.parseShowExtraMark()) { double[] qs = curve.getQs(); double extrapolateFrom = qs[qs.length-1]; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/DeltaWtExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/DeltaWtExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/DeltaWtExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,7 +10,6 @@ import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.model.CalculationResult; @@ -39,8 +38,6 @@ import org.apache.log4j.Logger; -import org.w3c.dom.Document; - /** Exports fixation analysis deltaw(t) computation results to csv. */ public class DeltaWtExporter extends AbstractExporter @@ -101,10 +98,7 @@ protected List<KMIndex<QWD[]>> referenceEvents; - @Override - public void init(Document request, OutputStream out, CallContext context) { - log.debug("DeltaWtExporter.init"); - super.init(request, out, context); + public DeltaWtExporter() { analysisPeriods = new ArrayList<KMIndex<AnalysisPeriod []>>(); referenceEvents = new ArrayList<KMIndex<QWD[]>>(); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixATExport.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixATExport.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixATExport.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,6 +16,7 @@ import org.dive4elements.river.artifacts.access.FixAccess; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; import org.dive4elements.river.artifacts.math.fitting.Function; @@ -37,7 +38,6 @@ import org.apache.log4j.Logger; -import org.w3c.dom.Document; import org.w3c.dom.NodeList; /** Export result of fixation analysis. */ @@ -52,7 +52,7 @@ @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { + public void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible) { logger.debug("AT Export doOut()."); Object data = bundle.getData(context); if (data instanceof CalculationResult) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixChartGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixChartGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixChartGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -33,8 +33,8 @@ "/art:action/art:attributes/art:currentKm/@art:km"; @Override - public void init(Document request, OutputStream out, CallContext context) { - super.init(request, out, context); + public void init(String outName, Document request, OutputStream out, CallContext context) { + super.init(outName, request, out, context); Double currentKm = getCurrentKmFromRequest(request); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDeltaWtGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDeltaWtGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDeltaWtGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -23,7 +23,7 @@ import org.dive4elements.river.jfree.StyledDomainMarker; import org.dive4elements.river.jfree.StyledTimeSeries; import org.dive4elements.river.jfree.StyledValueMarker; -import org.dive4elements.river.utils.ThemeUtil; +import org.dive4elements.river.themes.ThemeDocument; import java.io.OutputStream; import java.text.NumberFormat; @@ -35,13 +35,14 @@ import org.apache.log4j.Logger; import org.jfree.chart.annotations.XYTextAnnotation; -import org.jfree.data.time.Day; import org.jfree.data.time.RegularTimePeriod; import org.jfree.data.time.FixedMillisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.w3c.dom.Document; +import gnu.trove.TLongHashSet; + /** * Generator for Delta W(t) charts. @@ -80,7 +81,10 @@ } - private D4EArtifact artifact = null; + private D4EArtifact artifact; + + // Used to make the dates collision free. + private TLongHashSet uniqueDates = new TLongHashSet(); @Override @@ -156,7 +160,7 @@ @Override public void doOut( ArtifactAndFacet artifactFacet, - Document theme, + ThemeDocument theme, boolean visible ) { String name = artifactFacet.getFacetName(); @@ -226,11 +230,11 @@ protected void doReferencePeriodsOut( - D4EArtifact artifact, - Object data, - String desc, - Document theme, - boolean visible) + D4EArtifact artifact, + Object data, + String desc, + ThemeDocument theme, + boolean visible) { logger.debug("doReferencePeriodsOut()"); @@ -248,13 +252,19 @@ } } + private long uniqueDate(long date) { + return uniqueDates.add(date) + ? date + : uniqueDate(date+30L*1000L); // add 30secs. + } + protected void doSectorAverageOut( - D4EArtifact artifact, - Object data, - String desc, - Document theme, - boolean visible) + D4EArtifact artifact, + Object data, + String desc, + ThemeDocument theme, + boolean visible) { logger.debug("doSectorAverageOut(): description = " + desc); @@ -270,16 +280,16 @@ // Draw a line spanning the analysis time. series.add(rtp, value); - rtp = new Day(qwd.dateRange.getFrom()); + rtp = new FixedMillisecond(qwd.dateRange.getFrom()); series.addOrUpdate(rtp, value); - rtp = new Day(qwd.dateRange.getTo()); + rtp = new FixedMillisecond(qwd.dateRange.getTo()); series.addOrUpdate(rtp, value); tsc.addSeries(series); addAxisDataset(tsc, 0, visible); - if (visible && ThemeUtil.parseShowLineLabel(theme)) { + if (visible && theme.parseShowLineLabel()) { List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( "\u0394 W(t) [cm] " + (float)Math.round(qwd.qwd.getDeltaW() * 10000) / 10000, @@ -298,7 +308,7 @@ D4EArtifact artifact, Object data, String desc, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("doAnalysisEventsOut: desc = " + desc); @@ -308,7 +318,7 @@ } - protected void doQWDEventsOut(QWD qwd, String desc, Document theme, boolean visible) + protected void doQWDEventsOut(QWD qwd, String desc, ThemeDocument theme, boolean visible) { TimeSeriesCollection tsc = new TimeSeriesCollection(); @@ -324,7 +334,8 @@ int idxInterpol = 0; int idxRegular = 0; - RegularTimePeriod rtp = new FixedMillisecond(qwd.getDate()); + long time = uniqueDate(qwd.getDate().getTime()); + RegularTimePeriod rtp = new FixedMillisecond(time); double value = qwd.getDeltaW(); boolean interpolate = qwd.getInterpolated(); if (interpolate) { @@ -358,11 +369,11 @@ * @param annoIdxMap map of index in qwds to series/data item indices in tsc. */ protected void doQWDTextAnnotations(Map<Integer, int[]> annoIdxMap, - TimeSeriesCollection tsc, QWD qwd, Document theme, + TimeSeriesCollection tsc, QWD qwd, ThemeDocument theme, boolean visible) { logger.debug("doQWDTextAnnotation()"); - if (!visible || !ThemeUtil.parseShowPointLabel(theme)) { + if (!visible || !theme.parseShowPointLabel()) { logger.debug("doQWDTextAnnotation: annotation not visible"); return; } @@ -390,11 +401,11 @@ protected void doReferenceEventsOut( - D4EArtifact artifact, - Object data, - String desc, - Document theme, - boolean visible + D4EArtifact artifact, + Object data, + String desc, + ThemeDocument theme, + boolean visible ) { logger.debug("doReferenceEventsOut: desc = " + desc); @@ -404,11 +415,11 @@ protected void doDeviationOut( - D4EArtifact artifact, - Object data, - String desc, - Document theme, - boolean visible + D4EArtifact artifact, + Object data, + String desc, + ThemeDocument theme, + boolean visible ) { logger.debug("doDeviationOut: desc = " + desc); @@ -427,10 +438,10 @@ protected void doAnalysisPeriodsOut( D4EArtifact artifact, - Object data, - String desc, - Document theme, - boolean visible) + Object data, + String desc, + ThemeDocument theme, + boolean visible) { DateRange[] ranges = (DateRange[]) data; if (ranges == null || !visible) { @@ -451,8 +462,8 @@ @Override - public void init(Document request, OutputStream out, CallContext context) { - super.init(request, out, context); + public void init(String outName, Document request, OutputStream out, CallContext context) { + super.init(outName, request, out, context); Double currentKm = FixChartGenerator.getCurrentKmFromRequest(request); @@ -462,7 +473,9 @@ context.putContextValue("currentKm", currentKm); - StyledValueMarker marker = new StyledValueMarker(0, request); + // XXX: This looks hackish! + StyledValueMarker marker = + new StyledValueMarker(0, new ThemeDocument(request)); valueMarker.add(marker); } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDerivedCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDerivedCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDerivedCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,7 +9,6 @@ package org.dive4elements.river.exports.fixings; import org.apache.log4j.Logger; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.river.artifacts.model.FacetTypes; @@ -19,6 +18,7 @@ import org.dive4elements.river.exports.ChartGenerator; import org.dive4elements.river.jfree.JFreeUtil; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; /** * Generator for fixation derived function curve. @@ -65,7 +65,7 @@ @Override - public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + public void doOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doOut"); if (FacetTypes.IS.MANUALPOINTS(aaf.getFacetName())) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,319 +0,0 @@ -/* 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.fixings; - -import java.awt.BasicStroke; -import java.awt.Color; - -import org.apache.log4j.Logger; -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.river.artifacts.D4EArtifact; -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.artifacts.model.fixings.AnalysisPeriod; -import org.dive4elements.river.artifacts.model.fixings.QWD; -import org.dive4elements.river.exports.ChartGenerator; -import org.dive4elements.river.exports.StyledSeriesBuilder; -import org.dive4elements.river.exports.process.KMIndexProcessor; -import org.dive4elements.river.exports.process.Processor; -import org.dive4elements.river.exports.process.WOutProcessor; -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StyledAreaSeriesCollection; -import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; -import org.dive4elements.river.utils.KMIndex; -import org.dive4elements.river.utils.RiverUtils; -import org.jfree.chart.plot.Marker; -import org.jfree.chart.plot.ValueMarker; -import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - -public class FixLongitudinalSectionGenerator -extends FixChartGenerator -implements FacetTypes -{ - private static Logger logger = - Logger.getLogger(FixLongitudinalSectionGenerator.class); - - public static final String I18N_CHART_TITLE = - "chart.fixings.longitudinalsection.title"; - - public static final String I18N_CHART_SUBTITLE = - "chart.fixings.longitudinalsection.subtitle"; - - public static final String I18N_XAXIS_LABEL = - "chart.fixings.longitudinalsection.xaxis.label"; - - public static final String I18N_CHART_TITLE_DEFAULT = - "Fixierungsanalyse"; - - public static final String I18N_XAXIS_LABEL_DEFAULT = - "[km]"; - - public static final String I18N_DW_YAXIS_LABEL_DEFAULT = - "delta W [cm]"; - - public static final String I18N_DW_YAXIS_LABEL = - "chart.fixings.longitudinalsection.yaxis.label"; - - public static final String I18N_W_YAXIS_LABEL = - "chart.longitudinal.section.yaxis.label"; - - public static final String I18N_Q_YAXIS_LABEL = - "chart.longitudinal.section.yaxis.second.label"; - - public static final String I18N_W_YAXIS_LABEL_DEFAULT = "W [NN + m]"; - public static final String I18N_Q_YAXIS_LABEL_DEFAULT = "Q [m\u00b3/s]"; - - public static enum YAXIS { - dW(0), W(1), Q(2); - public int idx; - private YAXIS(int c) { - idx = c; - } - } - - @Override - public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { - String name = aaf.getFacetName(); - logger.debug("FixLongitudinalSectionGenerator: doOut: " + name); - - Processor processor = new KMIndexProcessor(); - Processor wProcessor = new WOutProcessor(); - if (name.contains(FIX_SECTOR_AVERAGE_LS_DEVIATION)) { - doSectorAverageDeviationOut(aaf, doc, visible); - } - else if (processor.canHandle(name)) { - processor.doOut(this, aaf, doc, visible, YAXIS.dW.idx); - } - else if (wProcessor.canHandle(name)) { - wProcessor.doOut(this, aaf, doc, visible, YAXIS.W.idx); - } - else if (name.equals(STATIC_WQKMS_Q)) { - doQOut( - (WQKms) aaf.getData(context), - aaf, - doc, - visible); - } - else if (name.equals(FIX_DEVIATION_LS)) { - doReferenceDeviationOut(aaf, doc, visible); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) aaf.getData(context), - aaf, - doc, - visible); - } - else if (FacetTypes.IS.MANUALPOINTS(name)) { - doPoints (aaf.getData(context), - aaf, - doc, visible, YAXIS.dW.idx); - } - else { - logger.warn("Unknown facet name " + name); - } - } - - /** - * Process the output for Q facets in a longitudinal section curve. - * - * @param wqkms An array of WQKms values. - * @param aandf The facet and artifact. This facet does NOT support any data objects. Use - * D4EArtifact.getNativeFacet() instead to retrieve a Facet which supports - * data. - * @param theme The theme that contains styling information. - * @param visible The visibility of the curve. - */ - protected void doQOut( - WQKms wqkms, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - logger.debug("LongitudinalSectionGenerator.doQOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); - - addAxisSeries(series, YAXIS.Q.idx, visible); - - if (needInvertAxis(wqkms)) { - setInverted(true); - } - } - - /** - * This method determines - taking JFreeCharts auto x value ordering into - * account - if the x axis need to be inverted. Waterlines in these charts - * should decrease. - * - * @param wkms The data object that stores the x and y values used for this - * chart. - */ - public boolean needInvertAxis(WKms wkms) { - boolean wsUp = wkms.guessWaterIncreasing(); - boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms()); - boolean inv = (wsUp && kmUp) || (!wsUp && !kmUp); - - int size = wkms.size(); - - if (logger.isDebugEnabled()) { - logger.debug("(Wkms)Values : " + size); - if (size > 0) { - logger.debug("Start km: " + wkms.getKm(0)); - logger.debug("End km: " + wkms.getKm(size-1)); - } - logger.debug("wsUp: " + wsUp); - logger.debug("kmUp: " + kmUp); - logger.debug("inv: " + inv); - } - - return inv; - } - - @SuppressWarnings("unchecked") - protected void doSectorAverageDeviationOut( - ArtifactAndFacet aaf, - Document doc, - boolean visible) - { - logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex()); - - int index = aaf.getFacet().getIndex(); - int sectorNdx = index & 3; - - KMIndex<AnalysisPeriod> kms = - (KMIndex<AnalysisPeriod>)aaf.getData(context); - - if(kms == null) { - return; - } - - StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); - XYSeries upper = - new StyledXYSeries(aaf.getFacetDescription(), false, doc); - XYSeries lower = - new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); - - for (KMIndex.Entry<AnalysisPeriod> entry: kms) { - double km = entry.getKm(); - AnalysisPeriod ap = entry.getValue(); - QWD qwd = ap.getQSectorAverages()[sectorNdx]; - double dev = ap.getQSectorStdDev(sectorNdx); - logger.debug("std-dev: " + dev); - if (qwd == null) { - continue; - } - double deltaW = qwd.getDeltaW(); - double up = deltaW + dev; - double lo = deltaW - dev; - upper.add(km, up); - lower.add(km, lo); - } - area.addSeries(upper); - area.addSeries(lower); - - addAreaSeries(area, 0, visible); - } - - - @SuppressWarnings("unchecked") - protected void doReferenceDeviationOut( - ArtifactAndFacet aaf, - Document doc, - boolean visible) - { - logger.debug("doReferenceOut"); - - KMIndex<double[]> kms = - (KMIndex<double[]>)aaf.getData(context); - - if(kms == null) { - return; - } - - StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); - XYSeries upper = - new StyledXYSeries(aaf.getFacetDescription(), false, doc); - XYSeries lower = - new StyledXYSeries(aaf.getFacetDescription() + " ", false, doc); - - - for (KMIndex.Entry<double[]> entry: kms) { - double km = entry.getKm(); - double[] devArray = entry.getValue(); - if (devArray == null) { - continue; - } - double dev = devArray[0]; - double up = dev; - double lo = -dev; - upper.add(km, up, false); - lower.add(km, lo, false); - } - area.addSeries(upper); - area.addSeries(lower); - - Marker marker = new ValueMarker(0); - marker.setStroke(new BasicStroke(2)); - marker.setPaint(Color.BLACK); - addValueMarker(marker); - addAreaSeries(area, 0, visible); - } - - @Override - protected String getDefaultChartTitle() { - return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); - } - - @Override - protected String getDefaultXAxisLabel() { - return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); - } - - @Override - protected String getDefaultYAxisLabel(int pos) { - if (pos == YAXIS.dW.idx) { - return msg(I18N_DW_YAXIS_LABEL, I18N_DW_YAXIS_LABEL_DEFAULT); - } - else if (pos == YAXIS.W.idx) { - D4EArtifact flys = (D4EArtifact) master; - String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); - return msg( - I18N_W_YAXIS_LABEL, - I18N_W_YAXIS_LABEL_DEFAULT, - new Object[] { unit }); - } - else if (pos == YAXIS.Q.idx) { - return msg(I18N_Q_YAXIS_LABEL, I18N_Q_YAXIS_LABEL_DEFAULT); - } - return ""; - } - - @Override - protected ChartGenerator.YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixLongitudinalSectionInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -/* 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.fixings; - -import org.dive4elements.river.exports.ChartInfoGenerator; - -public class FixLongitudinalSectionInfoGenerator extends ChartInfoGenerator { - - public FixLongitudinalSectionInfoGenerator() { - super(new FixLongitudinalSectionGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -27,7 +27,6 @@ import org.jfree.ui.RectangleAnchor; import org.jfree.ui.RectangleInsets; import org.jfree.ui.TextAnchor; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; @@ -57,8 +56,8 @@ import org.dive4elements.river.jfree.StyledXYSeries; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; -import org.dive4elements.river.utils.ThemeUtil; /** * Generator for WQ fixing charts. @@ -175,7 +174,7 @@ } @Override - public void doOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + public void doOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doOut: " + aaf.getFacetName()); if (!prepareChartData(aaf, doc, visible)) { logger.warn("Unknown facet, name " + aaf.getFacetName()); @@ -186,7 +185,7 @@ * Return true if data could be handled, * to be overridden to add more handled data. */ - public boolean prepareChartData(ArtifactAndFacet aaf, Document doc, boolean visible) { + public boolean prepareChartData(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { String name = aaf.getFacetName(); this.artifact = (D4EArtifact) aaf.getArtifact(); @@ -257,7 +256,7 @@ /** Add sector average points to chart. */ - protected void doSectorAverageOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doSectorAverageOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doSectorAverageOut"); QWDDateRange qwdd = (QWDDateRange) aaf.getData(context); @@ -272,7 +271,7 @@ } /** Add analysis event points to chart. */ - protected void doAnalysisEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doAnalysisEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doAnalysisEventsOut"); QWD qwd = (QWD)aaf.getData(context); @@ -292,7 +291,7 @@ textAnnos.add(anno); addAxisSeries(series, YAXIS.W.idx, visible); - if(visible && ThemeUtil.parseShowPointLabel(doc)) { + if(visible && doc.parseShowPointLabel()) { RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, doc); flysAnno.setTextAnnotations(textAnnos); addAnnotations(flysAnno); @@ -305,42 +304,42 @@ /** Add reference event points to chart. */ - protected void doReferenceEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doReferenceEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doReferenceEventsOut"); QWI qwd = (QWI)aaf.getData(context); - if(qwd != null) { - XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); - List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); - - DateFormat dateFormat = DateFormat.getDateInstance( - DateFormat.SHORT); - - series.add(qwd.getQ(), qwd.getW()); + if (qwd == null) { + logger.debug("doReferenceEventsOut: qwds == null"); + return; + } - XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( - dateFormat.format(qwd.getDate()), - qwd.getQ(), - qwd.getW()); - textAnnos.add(anno); + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, true, doc); + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); - addAxisSeries(series, YAXIS.W.idx, visible); - if(visible && ThemeUtil.parseShowPointLabel(doc)) { - RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, doc); - flysAnno.setTextAnnotations(textAnnos); - addAnnotations(flysAnno); - } - } - else { - logger.debug("doReferenceEventsOut: qwds == null"); + DateFormat dateFormat = DateFormat.getDateInstance( + DateFormat.SHORT); + + series.add(qwd.getQ(), qwd.getW(), false); + + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + dateFormat.format(qwd.getDate()), + qwd.getQ(), + qwd.getW()); + textAnnos.add(anno); + + addAxisSeries(series, YAXIS.W.idx, visible); + if(visible && doc.parseShowPointLabel()) { + RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, doc); + flysAnno.setTextAnnotations(textAnnos); + addAnnotations(flysAnno); } } private void addPointFromWQKms(WQKms wqkms, - String title, - Document theme, - boolean visible + String title, + ThemeDocument theme, + boolean visible ) { XYSeries series = new StyledXYSeries(title, theme); Double ckm = (Double) context.getContextValue(CURRENT_KM); @@ -351,9 +350,9 @@ double[] kms = wqkms.getKms(); for (int i = 0 ; i< kms.length; i++) { if (Math.abs(kms[i] - ckm) <= EPSILON) { - series.add(wqkms.getQ(i), wqkms.getW(i)); + series.add(wqkms.getQ(i), wqkms.getW(i), false); addAxisSeries(series, YAXIS.W.idx, visible); - if(visible && ThemeUtil.parseShowPointLabel(theme)) { + if(visible && theme.parseShowPointLabel()) { List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( title, @@ -369,7 +368,7 @@ } } - protected void doEventsOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doEventsOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doEventsOut"); // Find W/Q at km. addPointFromWQKms((WQKms) aaf.getData(context), @@ -377,7 +376,7 @@ } - protected void doWQCurveOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doWQCurveOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doWQCurveOut"); FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet(); @@ -428,7 +427,7 @@ } } - protected void doOutlierOut(ArtifactAndFacet aaf, Document doc, boolean visible) { + protected void doOutlierOut(ArtifactAndFacet aaf, ThemeDocument doc, boolean visible) { logger.debug("doOutlierOut"); QWI[] qws = (QWI[])aaf.getData(context); @@ -437,7 +436,7 @@ /** Add markers for q sectors. */ - protected void doQSectorOut(ArtifactAndFacet aaf, Document theme, boolean visible) { + protected void doQSectorOut(ArtifactAndFacet aaf, ThemeDocument theme, boolean visible) { logger.debug("doQSectorOut"); if (!visible) { return; @@ -465,8 +464,8 @@ Marker m = new ValueMarker(qsector.getValue()); m.setPaint(Color.black); - float[] dashes = ThemeUtil.parseLineStyle(theme); - int size = ThemeUtil.parseLineWidth(theme); + float[] dashes = theme.parseLineStyle(); + int size = theme.parseLineWidth(); BasicStroke stroke; if (dashes.length <= 1) { stroke = new BasicStroke(size); @@ -481,12 +480,12 @@ } m.setStroke(stroke); - if (ThemeUtil.parseShowLineLabel(theme)) { + if (theme.parseShowLineLabel()) { m.setLabel(qsector.getName()); - m.setPaint(ThemeUtil.parseTextColor(theme)); - m.setLabelFont(ThemeUtil.parseTextFont(theme)); + m.setPaint(theme.parseTextColor()); + m.setLabelFont(theme.parseTextFont()); } - Color paint = ThemeUtil.parseLineColorField(theme); + Color paint = theme.parseLineColorField(); if (paint != null) { m.setPaint(paint); } @@ -504,10 +503,10 @@ * @param theme theme to use. */ protected void doWAnnotations( - Object wqkms, + Object wqkms, ArtifactAndFacet aandf, - Document theme, - boolean visible + ThemeDocument theme, + boolean visible ) { Facet facet = aandf.getFacet(); @@ -549,7 +548,7 @@ WINFOArtifact artifact, Object o, String description, - Document theme, + ThemeDocument theme, boolean visible) { WQKms wqkms = (WQKms) o; @@ -583,7 +582,7 @@ protected void doWQOut( Object wqkms, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { logger.debug("FixWQCurveGenerator: doWQOut"); @@ -598,7 +597,7 @@ logger.debug("FixWQCurveGenerator: doWQOut: double[][]"); double [][] data = (double [][]) wqkms; - XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, true, theme); StyledSeriesBuilder.addPoints(series, data, true); addAxisSeries(series, YAXIS.W.idx, visible); @@ -609,14 +608,18 @@ protected void addQWSeries( QWI [] qws, ArtifactAndFacet aaf, - Document theme, + ThemeDocument theme, boolean visible ) { if (qws == null) { return; } - XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + XYSeries series = new StyledXYSeries( + aaf.getFacetDescription(), + false, true, + theme); + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(qws.length); @@ -624,7 +627,7 @@ DateFormat.SHORT); for (QWI qw: qws) { - series.add(qw.getQ(), qw.getW()); + series.add(qw.getQ(), qw.getW(), false); XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( dateFormat.format(qw.getDate()), @@ -634,7 +637,7 @@ } addAxisSeries(series, YAXIS.W.idx, visible); - if (visible && ThemeUtil.parseShowPointLabel(theme)) { + if (visible && theme.parseShowPointLabel()) { RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme); flysAnno.setTextAnnotations(textAnnos); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/fixings/ParametersExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/ParametersExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/ParametersExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,8 +10,6 @@ import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; - import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.Parameters; @@ -31,8 +29,6 @@ import org.apache.log4j.Logger; -import org.w3c.dom.Document; - public class ParametersExporter extends AbstractExporter { @@ -40,10 +36,7 @@ protected List<Parameters> parametersList; - @Override - public void init(Document request, OutputStream out, CallContext context) { - log.debug("ParametersExporter.init"); - super.init(request, out, context); + public ParametersExporter() { parametersList = new ArrayList<Parameters>(); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* 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.minfo; - -import org.apache.log4j.Logger; -import org.w3c.dom.Document; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.minfo.BedDifferencesResult; -import org.dive4elements.river.exports.process.BedDiffHeightYearProcessor; -import org.dive4elements.river.exports.process.KMIndexProcessor; -import org.dive4elements.river.exports.process.Processor; -import org.dive4elements.river.jfree.RiverAnnotation; - - -public class BedDiffHeightYearGenerator -extends BedDiffBaseGenerator -implements FacetTypes -{ - public enum YAXIS { - D(0), dW(1); - - protected int idx; - - private YAXIS(int c) { - idx = c; - } - } - - /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(BedDiffHeightYearGenerator.class); - - public static final String I18N_CHART_TITLE = "chart.beddifference.height.title"; - public static final String I18N_XAXIS_LABEL = "chart.beddifference.height.xaxis.label"; - public static final String I18N_YAXIS_LABEL = "chart.beddifference.height.yaxis.label"; - - public static final String I18N_CHART_TITLE_DEFAULT = "Sohlenhöhen Differenz"; - public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km"; - public static final String I18N_YAXIS_LABEL_DEFAULT = "delta S [cm / Jahr]"; - public static final String I18N_DW_YAXIS_LABEL_DEFAULT = - "delta W [cm]"; - public static final String I18N_DW_YAXIS_LABEL = - "chart.fixings.longitudinalsection.yaxis.label"; - - @Override - protected YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } - - @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { - String name = bundle.getFacetName(); - - logger.debug("doOut: " + name); - - if (name == null) { - logger.error("No facet name for doOut(). No output generated!"); - return; - } - - Facet facet = bundle.getFacet(); - - if (facet == null) { - return; - } - - if (bundle.getData(context) instanceof BedDifferencesResult) { - setContextBounds(bundle); - } - - Processor processor = new KMIndexProcessor(); - Processor bdyProcessor = new BedDiffHeightYearProcessor(); - if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) bundle.getData(context), - bundle, - attr, - visible); - } - else if (processor.canHandle(name)) { - processor.doOut(this, bundle, attr, visible, YAXIS.dW.idx); - } - else if (bdyProcessor.canHandle(name)) { - bdyProcessor.doOut(this, bundle, attr, visible, YAXIS.D.idx); - } - else { - logger.warn("Unknown facet name " + name); - } - } - - - @Override - protected String getDefaultChartTitle() { - return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); - } - - @Override - protected String getDefaultXAxisLabel() { - return msg(I18N_XAXIS_LABEL, - I18N_XAXIS_LABEL_DEFAULT, - new Object[] { getRiverName() }); - } - - @Override - protected String getDefaultYAxisLabel(int pos) { - if (pos == YAXIS.D.idx) { - return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); - } - else if (pos == YAXIS.dW.idx) { - return msg(I18N_DW_YAXIS_LABEL, I18N_DW_YAXIS_LABEL_DEFAULT); - } - return "default"; - } -} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffHeightYearInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* 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.minfo; - -import org.dive4elements.river.exports.ChartInfoGenerator; - - -public class BedDiffHeightYearInfoGenerator -extends ChartInfoGenerator -{ - public BedDiffHeightYearInfoGenerator() { - super (new BedDiffHeightYearGenerator()); - } -} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffYearInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDiffYearInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* 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.minfo; - -import org.dive4elements.river.exports.ChartInfoGenerator; - - -public class BedDiffYearInfoGenerator -extends ChartInfoGenerator -{ - public BedDiffYearInfoGenerator() { - super(new BedDifferenceYearGenerator()); - } -} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceEpochGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,7 +10,6 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; @@ -28,7 +27,7 @@ import org.dive4elements.river.jfree.DoubleBounds; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.RiverUtils; @@ -47,7 +46,7 @@ } /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(BedQualityGenerator.class); + private static Logger logger = Logger.getLogger(BedDifferenceEpochGenerator.class); public static final String I18N_CHART_TITLE = "chart.beddifference.epoch.title"; public static final String I18N_XAXIS_LABEL = "chart.beddifference.xaxis.label"; @@ -86,7 +85,7 @@ } @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { + public void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible) { String name = bundle.getFacetName(); logger.debug("doOut: " + name); @@ -215,7 +214,7 @@ } protected void doBedDifferenceEpochOut(BedDiffEpochResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { + ArtifactAndFacet aandf, ThemeDocument theme, boolean visible) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); StyledSeriesBuilder.addPoints(series, data.getDifferencesData(), true); @@ -226,7 +225,7 @@ private void doBedDifferenceHeightsOut( BedDiffEpochResult data, ArtifactAndFacet bundle, - Document attr, + ThemeDocument attr, boolean visible, int idx) { logger.debug("doBedDifferenceHeightOut()"); @@ -245,7 +244,7 @@ protected void doWDifferencesOut( WKms wkms, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { if (wkms == null) { @@ -257,8 +256,9 @@ StyledSeriesBuilder.addPoints(series, wkms); addAxisSeries(series, YAXIS.D.idx, visible); - if (DataUtil.guessWaterIncreasing(wkms.allWs())) { + if (wkms.guessWaterIncreasing()) { setInverted(true); } } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -27,7 +27,6 @@ import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JRException; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.access.BedDifferencesAccess; @@ -40,11 +39,8 @@ import org.dive4elements.river.utils.Formatter; import org.dive4elements.river.utils.RiverUtils; -import org.w3c.dom.Document; - import au.com.bytecode.opencsv.CSVWriter; - public class BedDifferenceExporter extends AbstractExporter { @@ -70,10 +66,7 @@ private BedDifferencesResult[] results; - @Override - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("init"); - super.init(request, out, context); + public BedDifferenceExporter() { results = new BedDifferencesResult[0]; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceYearGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedDifferenceYearGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ -/* 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.minfo; - -import org.apache.log4j.Logger; -import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; -import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.WKms; -import org.dive4elements.river.artifacts.model.minfo.BedDiffYearResult; -import org.dive4elements.river.artifacts.model.minfo.BedDifferencesResult; -import org.dive4elements.river.artifacts.model.minfo.MorphologicWidth; -import org.dive4elements.river.exports.StyledSeriesBuilder; -import org.dive4elements.river.exports.process.BedDiffYearProcessor; -import org.dive4elements.river.exports.process.BedDiffHeightYearProcessor; -import org.dive4elements.river.exports.process.KMIndexProcessor; -import org.dive4elements.river.exports.process.Processor; -import org.dive4elements.river.exports.process.WOutProcessor; -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; -import org.dive4elements.river.utils.RiverUtils; - - -public class BedDifferenceYearGenerator -extends BedDiffBaseGenerator -implements FacetTypes -{ - public enum YAXIS { - D(0), M(1), H(2), dW(3), W(4); - - protected int idx; - - private YAXIS(int c) { - idx = c; - } - } - - /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(BedDifferenceYearGenerator.class); - - public static final String I18N_CHART_TITLE = "chart.beddifference.year.title"; - public static final String I18N_XAXIS_LABEL = "chart.beddifference.xaxis.label"; - public static final String I18N_YAXIS_LABEL = "chart.beddifference.yaxis.label.diff"; - public static final String I18N_SECOND_YAXIS_LABEL = "chart.beddifference.yaxis.label.morph"; - public static final String I18N_THIRD_YAXIS_LABEL = "chart.beddifference.yaxis.label.heights"; - - public static final String I18N_CHART_TITLE_DEFAULT = "Sohlenhöhen Differenz"; - public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km"; - public static final String I18N_YAXIS_LABEL_DEFAULT = "delta S [m]"; - public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Breite [m]"; - public static final String I18N_THIRD_YAXIS_LABEL_DEFAULT = "Höhe [m]"; - public static final String I18N_DW_YAXIS_LABEL_DEFAULT = - "delta W [cm]"; - public static final String I18N_DW_YAXIS_LABEL = - "chart.fixings.longitudinalsection.yaxis.label"; - private static final String I18N_W_YAXIS_LABEL = - "chart.longitudinal.section.yaxis.label"; - private static final String I18N_W_YAXIS_LABEL_DEFAULT = "W [NN + m]"; - - @Override - protected YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } - - - @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { - String name = bundle.getFacetName(); - - logger.debug("doOut: " + name); - - if (name == null) { - logger.error("No facet name for doOut(). No output generated!"); - return; - } - - Facet facet = bundle.getFacet(); - - if (facet == null) { - return; - } - - if (bundle.getData(context) instanceof BedDifferencesResult) { - setContextBounds(bundle); - } - - Processor processor = new KMIndexProcessor(); - Processor woutp = new WOutProcessor(); - Processor bdhyProcessor = new BedDiffHeightYearProcessor(); - Processor bdyProcessor = new BedDiffYearProcessor(); - if (name.equals(BED_DIFFERENCE_MORPH_WIDTH)) { - doBedDifferenceMorphWidthOut( - (BedDiffYearResult) bundle.getData(context), - bundle, attr, visible); - } - else if (name.equals(MORPHOLOGIC_WIDTH)) { - doMorphologicWidthOut( - (MorphologicWidth)bundle.getData(context), - bundle, - attr, - visible, - 0); - } - else if (processor.canHandle(name)) { - processor.doOut(this, bundle, attr, visible, YAXIS.dW.idx); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) bundle.getData(context), - bundle, - attr, - visible); - } - else if (bdyProcessor.canHandle(name)) { - bdyProcessor.doOut(this, bundle, attr, visible, YAXIS.H.idx); - } - else if (bdhyProcessor.canHandle(name)) { - bdhyProcessor.doOut(this, bundle, attr, visible, YAXIS.D.idx); - } - else if (woutp.canHandle(name)) { - woutp.doOut(this, bundle, attr, visible, YAXIS.W.idx); - } - else if (name.equals(W_DIFFERENCES)) { - doWDifferencesOut( - (WKms) bundle.getData(context), - bundle, - attr, - visible); - } - else { - logger.warn("Unknown facet name " + name); - } - } - - private void doMorphologicWidthOut( - MorphologicWidth data, - ArtifactAndFacet bundle, - Document attr, - boolean visible, - int i) { - XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), attr); - StyledSeriesBuilder.addPoints(series, data.getAsArray(), true); - - addAxisSeries(series, YAXIS.M.idx, visible); - } - - - @Override - protected String getDefaultChartTitle() { - return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); - } - - @Override - protected String getDefaultXAxisLabel() { - return msg(I18N_XAXIS_LABEL, - I18N_XAXIS_LABEL_DEFAULT, - new Object[] { getRiverName() }); - } - - @Override - protected String getDefaultYAxisLabel(int pos) { - String label = "default"; - D4EArtifact flys = (D4EArtifact) master; - if (pos == YAXIS.D.idx) { - label = msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); - } - else if (pos == YAXIS.M.idx) { - label = msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT); - } - else if (pos == YAXIS.H.idx) { - label = msg(I18N_THIRD_YAXIS_LABEL, - I18N_THIRD_YAXIS_LABEL_DEFAULT, - new Object[] - { RiverUtils.getRiver(flys).getWstUnit().getName() }); - } - else if (pos == YAXIS.dW.idx) { - label = msg(I18N_DW_YAXIS_LABEL, I18N_DW_YAXIS_LABEL_DEFAULT); - } - else if (pos == YAXIS.W.idx) { - return msg(I18N_W_YAXIS_LABEL, I18N_W_YAXIS_LABEL_DEFAULT, - new Object[] - { RiverUtils.getRiver(flys).getWstUnit().getName() }); - } - - return label; - } - - - protected void doBedDifferenceMorphWidthOut(BedDiffYearResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("doBedDifferencesMorphWidthOut()"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getMorphWidthData(), true); - - addAxisSeries(series, YAXIS.M.idx, visible); - } - - protected void doWDifferencesOut( - WKms wkms, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - if (wkms == null) { - logger.warn("No data to add to WDifferencesChart."); - return; - } - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, wkms); - - addAxisSeries(series, YAXIS.D.idx, visible); - if (DataUtil.guessWaterIncreasing(wkms.allWs())) { - setInverted(true); - } - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -19,10 +19,8 @@ import java.util.List; import org.apache.log4j.Logger; -import org.w3c.dom.Document; import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.minfo.BedDiameterResult; import org.dive4elements.river.artifacts.model.minfo.BedParametersResult; @@ -56,10 +54,7 @@ private BedQualityResult[] results; - @Override - public void init(Document request, OutputStream out, CallContext context) { - logger.debug("BedQualityExporter.init"); - super.init(request, out, context); + public BedQualityExporter() { results = new BedQualityResult[0]; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,311 +0,0 @@ -/* 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.minfo; - -import org.apache.log4j.Logger; -import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Facet; -import org.dive4elements.river.artifacts.model.FacetTypes; -import org.dive4elements.river.artifacts.model.minfo.BedDiameterData; -import org.dive4elements.river.artifacts.model.minfo.BedDiameterResult; -import org.dive4elements.river.artifacts.model.minfo.BedParametersResult; -import org.dive4elements.river.artifacts.model.minfo.BedloadDiameterResult; -import org.dive4elements.river.exports.StyledSeriesBuilder; -import org.dive4elements.river.exports.XYChartGenerator; -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StyledXYSeries; - - -/** - * An OutGenerator that generates bed quality charts. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class BedQualityGenerator extends XYChartGenerator implements FacetTypes { - - public enum YAXIS { - W(0), P(1), D(2); - - protected int idx; - - private YAXIS(int c) { - idx = c; - } - } - - /** The logger that is used in this generator. */ - private static Logger logger = Logger.getLogger(BedQualityGenerator.class); - - public static final String I18N_CHART_TITLE = "chart.bedquality.title"; - public static final String I18N_XAXIS_LABEL = "chart.bedquality.xaxis.label"; - public static final String I18N_YAXIS_LABEL = "chart.bedquality.yaxis.label"; - public static final String I18N_SECOND_YAXIS_LABEL = "chart.bedquality.yaxis.label.porosity"; - public static final String I18N_THIRD_YAXIS_LABEL = "chart.bedquality.yaxis.label.diameter"; - - public static final String I18N_CHART_TITLE_DEFAULT = "Sohlen Längsschnitt"; - public static final String I18N_XAXIS_LABEL_DEFAULT = "Fluss-Km"; - public static final String I18N_YAXIS_LABEL_DEFAULT = "Durchmesser [mm]"; - public static final String I18N_SECOND_YAXIS_LABEL_DEFAULT = "Porosität [%]"; - public static final String I18N_THIRD_YAXIS_LABEL_DEFAULT = "Dichte [t/m^3]"; - - @Override - protected YAxisWalker getYAxisWalker() { - return new YAxisWalker() { - - @Override - public int length() { - return YAXIS.values().length; - } - - @Override - public String getId(int idx) { - YAXIS[] yaxes = YAXIS.values(); - return yaxes[idx].toString(); - } - }; - } - - /** - * Returns the default title for this chart. - * - * @return the default title for this chart. - */ - @Override - public String getDefaultChartTitle() { - return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); - } - - /** - * Get internationalized label for the x axis. - */ - @Override - protected String getDefaultXAxisLabel() { - return msg(I18N_XAXIS_LABEL, - I18N_XAXIS_LABEL_DEFAULT, - new Object[] {getRiverName()}); - } - - @Override - protected String getDefaultYAxisLabel(int index) { - String label = "default"; - - if (index == YAXIS.W.idx) { - label = getWAxisLabel(); - } - else if (index == YAXIS.P.idx) { - label = getPAxisLabel(); - } - else if (index == YAXIS.D.idx) { - label = getDAxisLabel(); - } - - return label; - } - - /** - * Get internationalized label for the y axis displaying the diameter. - */ - protected String getWAxisLabel() { - return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL_DEFAULT); - } - - /** - * Get internationalized label for the y axis displaying the porosity. - */ - protected String getPAxisLabel() { - return msg(I18N_SECOND_YAXIS_LABEL, I18N_SECOND_YAXIS_LABEL_DEFAULT); - } - - /** - * Get internationalized label for the y axis displaying the density. - */ - protected String getDAxisLabel() { - return msg(I18N_THIRD_YAXIS_LABEL, I18N_THIRD_YAXIS_LABEL_DEFAULT); - } - - /** - * Produce output. - * - * @param artifactAndFacet - * current facet. - * @param attr - * theme for facet - */ - public void doOut(ArtifactAndFacet artifactAndFacet, Document attr, - boolean visible) { - String name = artifactAndFacet.getFacetName(); - - logger.debug("BedQualityGenerator.doOut: " + name); - - if (name == null) { - logger.error("No facet name for doOut(). No output generated!"); - return; - } - - Facet facet = artifactAndFacet.getFacet(); - - if (facet == null) { - return; - } - - // TODO BED_QUALITY_BED_DIAMETER_TOPLAYER - if (name.equals(BED_QUALITY_BED_DIAMETER_TOPLAYER)) { - doBedDiameterTopLayerOut( - (BedDiameterResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_QUALITY_BED_DIAMETER_SUBLAYER)) { - doBedDiameterSubLayerOut( - (BedDiameterResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - // TODO BED_QUALITY_BED_DIAMETER_SUBLAYER - else if (name.equals(BED_QUALITY_BEDLOAD_DIAMETER)) { - doBedLoadDiameterOut( - (BedloadDiameterResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_QUALITY_POROSITY_TOPLAYER)) { - doPorosityTopLayerOut( - (BedParametersResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_QUALITY_POROSITY_SUBLAYER)) { - doPorositySubLayerOut( - (BedParametersResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER)) { - doDensityTopLayerOut( - (BedParametersResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER)) { - doDensitySubLayerOut( - (BedParametersResult) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(BED_DIAMETER_DATA_TOP) || - name.equals(BED_DIAMETER_DATA_SUB) || - name.equals(BEDLOAD_DIAMETER_DATA)) { - doBedDiameterDataOut( - (BedDiameterData) artifactAndFacet.getData(context), - artifactAndFacet, attr, visible); - } - else if (name.equals(LONGITUDINAL_ANNOTATION)) { - doAnnotations( - (RiverAnnotation) artifactAndFacet.getData(context), - artifactAndFacet, - attr, - visible); - } - else if (FacetTypes.IS.MANUALPOINTS(name)) { - doPoints(artifactAndFacet.getData(context), artifactAndFacet, attr, - visible, YAXIS.W.idx); - } - else { - logger.warn("Unknown facet name: " + name); - return; - } - } - - private void doBedDiameterDataOut( - BedDiameterData data, - ArtifactAndFacet aandf, - Document theme, - boolean visible - ) { - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getDiameterData(), true); - - addAxisSeries(series, YAXIS.W.idx, visible); - } - - protected void doBedDiameterTopLayerOut(BedDiameterResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doBedDiameterTopLayerOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getDiameterCapData(), true); - - addAxisSeries(series, YAXIS.W.idx, visible); - } - - protected void doBedDiameterSubLayerOut(BedDiameterResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doBedDiameterSubLayerOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getDiameterSubData(), true); - - addAxisSeries(series, YAXIS.W.idx, visible); - } - - protected void doBedLoadDiameterOut(BedloadDiameterResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doBedLoadDiameterOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getDiameterData(), true); - - addAxisSeries(series, YAXIS.W.idx, visible); - } - - protected void doPorosityTopLayerOut(BedParametersResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doPorosityTopLayerOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addPoints(series, data.getPorosityCapData(), - true); - - addAxisSeries(series, YAXIS.P.idx, visible); - } - - protected void doPorositySubLayerOut(BedParametersResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doPorositySubLayerOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addPoints(series, data.getPorositySubData(), - true); - - addAxisSeries(series, YAXIS.P.idx, visible); - } - - protected void doDensityTopLayerOut(BedParametersResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doDensityOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addPoints(series, data.getDensityCapData(), - true); - - addAxisSeries(series, YAXIS.D.idx, visible); - } - - protected void doDensitySubLayerOut(BedParametersResult data, - ArtifactAndFacet aandf, Document theme, boolean visible) { - logger.debug("BedQuality.doDensityOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - - StyledSeriesBuilder.addPoints(series, data.getDensitySubData(), - true); - - addAxisSeries(series, YAXIS.D.idx, visible); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/BedQualityInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* 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.minfo; - -import org.dive4elements.river.exports.ChartInfoGenerator; - - -/** - * A ChartInfoGenerator that generates meta information for specific computed - * bed quality curves. - * - * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> - */ -public class BedQualityInfoGenerator extends ChartInfoGenerator { - - public BedQualityInfoGenerator() { - super(new BedQualityGenerator()); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -17,12 +17,8 @@ import java.text.NumberFormat; -import org.w3c.dom.Document; - import org.apache.log4j.Logger; -import org.dive4elements.artifacts.CallContext; - import org.dive4elements.river.artifacts.model.CalculationResult; import org.dive4elements.river.artifacts.model.minfo.SedimentLoad; import org.dive4elements.river.artifacts.model.minfo.SedimentLoadFraction; @@ -35,7 +31,8 @@ import au.com.bytecode.opencsv.CSVWriter; -/** Do CSV export for sediment load calculations (will also be shown in +/** + * Do CSV export for sediment load calculations (will also be shown in * client). */ public class SedimentLoadExporter extends AbstractExporter @@ -62,6 +59,9 @@ public static final String CSV_SUSP_SAND = "export.sedimentload_ls.csv.header.suspsand"; + public static final String CSV_SUSP_SAND_BB = + "export.sedimentload_ls.csv.header.suspsandbb"; + public static final String CSV_SUSP_SEDIMENT = "export.sedimentload_ls.csv.header.suspsediment"; @@ -74,48 +74,64 @@ /** Empty constructor. */ public SedimentLoadExporter() { - } - - /** Trivial init. */ - @Override - public void init(Document request, OutputStream out, CallContext context) { - super.init(request, out, context); - logger.debug("init"); results = new SedimentLoadResult[0]; } - /** Process all stored data and write csv. */ @Override protected void writeCSVData(CSVWriter writer) throws IOException { writeCSVHeader(writer); for (SedimentLoadResult result: results) { + String years = (result.getEndYear() == 0) + ? result.getStartYear() + " " + : result.getStartYear() + "-" + result.getEndYear(); SedimentLoad load = result.getLoad(); // Put load.getName()+load.getDescription()}); somewhere? for (double km: new TreeSet<Double>(load.getKms())) { SedimentLoadFraction fraction = load.getFraction(km); - writeRecord(writer, km, result.getStartYear(), result.getEndYear(), fraction); + writeRecord(writer, km, years, fraction); } } } + + /** Return space when val is NaN, apply NumberFormat otherwise. */ + private String numberToString(NumberFormat valf, double val) { + if (Double.isNaN(val)) { + return " "; + } + return valf.format(val); + } + + /** Return space when val is NaN or zero, apply NumberFormat otherwise. */ + private String nonZeroToString(NumberFormat valf, double val) { + if (Double.isNaN(val) || val == 0d) { + return " "; + } + return valf.format(val); + } + /** Write a line. */ - private void writeRecord(CSVWriter writer, double km, int fromYear, int toYear, SedimentLoadFraction fraction) { + private void writeRecord( + CSVWriter writer, + double km, + String years, + SedimentLoadFraction fraction + ) { // year, total, susp sed, susp sandbed suspsand, sand, finemiddle, coarse - String years = (toYear == 0) ? fromYear+"" : fromYear + "-" + toYear; NumberFormat kmf = Formatter.getCalculationKm(context.getMeta()); NumberFormat valf = Formatter.getFormatter(context.getMeta(), 0, 2); writer.writeNext(new String[] { kmf.format(km), years, - valf.format(fraction.getTotal()), - valf.format(fraction.getSand()), - valf.format(fraction.getFineMiddle()), - valf.format(fraction.getCoarse()), - valf.format(fraction.getSuspSand()), - //valf.format(fraction.getSuspSandBed()), - valf.format(fraction.getSuspSediment()) + numberToString(valf, fraction.getSuspSediment()), + numberToString(valf, fraction.getSuspSand()), + numberToString(valf, fraction.getSuspSandBed()), + numberToString(valf, fraction.getSand()), + numberToString(valf, fraction.getFineMiddle()), + numberToString(valf, fraction.getCoarse()), + nonZeroToString(valf, fraction.getTotal()) }); } @@ -125,15 +141,15 @@ List<String> header = new LinkedList<String>(); if (results != null) { - header.add(msg(CSV_KM, "km")); - header.add(msg(CSV_YEAR, "Jahr")); - header.add(msg(CSV_TOTAL, "Gesamt")); - header.add(msg(CSV_SAND, "Sand")); - header.add(msg(CSV_FINEMIDDLE,"Fein")); - header.add(msg(CSV_COARSE, "Grob")); - header.add(msg(CSV_SUSP_SAND, "Su.Sand")); + header.add(msg(CSV_KM, "km")); + header.add(msg(CSV_YEAR, "Jahr")); header.add(msg(CSV_SUSP_SEDIMENT, "Schwebst.")); - //header.add("Susp.Sand Bett"); + header.add(msg(CSV_SUSP_SAND, "Susp.Sand")); + header.add(msg(CSV_SUSP_SAND_BB, "Susp.Sand(BB)")); + header.add(msg(CSV_SAND, "Sand")); + header.add(msg(CSV_FINEMIDDLE, "Kies(f+m)")); + header.add(msg(CSV_COARSE, "Kies(g)")); + header.add(msg(CSV_TOTAL, "Gesamt")); } writer.writeNext(header.toArray(new String[header.size()])); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -13,7 +13,6 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; @@ -33,7 +32,7 @@ import org.dive4elements.river.jfree.DoubleBounds; import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; +import org.dive4elements.river.themes.ThemeDocument; /** Generator for Longitudinal Sections of SedimentLoad-Calculations. */ @@ -94,7 +93,7 @@ } @Override - public void doOut(ArtifactAndFacet bundle, Document attr, boolean visible) { + public void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible) { String name = bundle.getFacetName(); logger.debug("doOut: " + name); @@ -259,7 +258,7 @@ } protected void doSedimentLoadOut(double[][] data, - ArtifactAndFacet aandf, Document theme, boolean visible) { + ArtifactAndFacet aandf, ThemeDocument theme, boolean visible) { // Allow for gaps (NaNs). XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), false, theme); @@ -269,7 +268,7 @@ } protected void doSedimentLoadUnknownOut(SedimentLoad load, - ArtifactAndFacet aandf, Document theme, boolean visible) { + ArtifactAndFacet aandf, ThemeDocument theme, boolean visible) { Set<Double> kms = load.getKms(); double[][] data = new double[2][kms.size()]; @@ -289,7 +288,7 @@ protected void doFlowVelocityMainOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); @@ -301,7 +300,7 @@ protected void doFlowVelocityTotalOut( FlowVelocityData data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { if (data == null) { @@ -318,7 +317,7 @@ protected void doBedDifferenceYearOut( BedDiffYearResult data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); @@ -330,7 +329,7 @@ protected void doBedDifferenceEpochOut( BedDiffEpochResult data, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); @@ -342,7 +341,7 @@ protected void doWDifferencesOut( WKms wkms, ArtifactAndFacet aandf, - Document theme, + ThemeDocument theme, boolean visible ) { if (wkms == null) { @@ -355,7 +354,7 @@ StyledSeriesBuilder.addPoints(series, wkms); addAxisSeries(series, YAXIS.D.idx, visible); - if (DataUtil.guessWaterIncreasing(wkms.allWs())) { + if (wkms.guessWaterIncreasing()) { setInverted(true); } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSInfoGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/minfo/SedimentLoadLSInfoGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -/* 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.minfo; - -import org.dive4elements.river.exports.ChartInfoGenerator; - - -public class SedimentLoadLSInfoGenerator -extends ChartInfoGenerator -{ - public SedimentLoadLSInfoGenerator() { - super(new SedimentLoadLSGenerator()); - } -} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/AnnotationProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/AnnotationProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,86 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.themes.ThemeDocument; + +/** + * Add data to chart/generator. + * + */ +public class AnnotationProcessor extends DefaultProcessor { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(AnnotationProcessor.class); + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + if (!visible) { + // Nothing to do + return; + } + CallContext context = generator.getCallContext(); + if (!(bundle.getData(context) instanceof RiverAnnotation)) { + // Just a bit defensive should not happen + logger.error("Incompatible facet in doOut"); + return; + } + RiverAnnotation ra = (RiverAnnotation)bundle.getData(context); + ra.setTheme(theme); + ra.setLabel(bundle.getFacetDescription()); + generator.addAnnotations(ra); + } + + @Override + public void doOut( + XYChartGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int index) + { + if (!visible) { + // Nothing to do + return; + } + CallContext context = generator.getCallContext(); + if (!(bundle.getData(context) instanceof RiverAnnotation)) { + // Just a bit defensive should not happen + logger.error("Incompatible facet in doOut"); + return; + } + RiverAnnotation ra = (RiverAnnotation)bundle.getData(context); + ra.setTheme(theme); + ra.setLabel(bundle.getFacetDescription()); + generator.addAnnotations(ra); + } + + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + return facetType.equals(FacetTypes.LONGITUDINAL_ANNOTATION) || + facetType.equals(FacetTypes.MIDDLE_BED_HEIGHT_ANNOTATION) || + facetType.equals(FacetTypes.FLOW_VELOCITY_ANNOTATION); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,154 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; + + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.river.artifacts.geom.Lines; +import org.dive4elements.river.artifacts.model.WKms; +import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.artifacts.model.AreaFacet; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledAreaSeriesCollection; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.jfree.data.xy.XYSeries; + +public class AreaProcessor extends DefaultProcessor { + + private static final Logger logger = Logger.getLogger(ManualPointsProcessor.class); + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + String seriesName = bundle.getFacetDescription(); + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); + + logger.debug("Area Processor processing: " + seriesName); + + AreaFacet.Data data = (AreaFacet.Data) bundle.getData(context); + + XYSeries up = null; + XYSeries down = null; + + if (data.getUpperData() != null) { + up = new StyledXYSeries(seriesName, false, theme); + if (data.getUpperData() instanceof WQKms) { + if (FacetTypes.IS.Q(data.getRootFacetName())) { + StyledSeriesBuilder.addPointsKmQ(up, (WQKms) data.getUpperData()); + } + else { + StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData()); + } + } + else if (data.getUpperData() instanceof double[][]) { + StyledSeriesBuilder.addPoints(up, (double [][]) data.getUpperData(), false); + } + else if (data.getUpperData() instanceof WKms) { + StyledSeriesBuilder.addPoints(up, (WKms) data.getUpperData()); + } + else if (data.getUpperData() instanceof Lines.LineData) { + StyledSeriesBuilder.addPoints(up, ((Lines.LineData) data.getUpperData()).points, false); + } + else { + logger.error("Do not know how to deal with (up) area info from: " + + data.getUpperData()); + } + } + + // TODO Depending on style, the area (e.g. 20m^2) should be added as annotation. + + if (data.getLowerData() != null) { + // TODO: Sort this out: when the two series have the same name, + // the renderer (or anything in between) will not work correctly. + down = new StyledXYSeries(seriesName + " ", false, theme); + if (data.getLowerData() instanceof WQKms) { + if (FacetTypes.IS.Q(data.getRootFacetName())) { + StyledSeriesBuilder.addPointsKmQ(down, (WQKms) data.getLowerData()); + } + else { + StyledSeriesBuilder.addPoints(down, (WQKms) data.getLowerData()); + } + } + else if (data.getLowerData() instanceof double[][]) { + StyledSeriesBuilder.addPoints(down, (double[][]) data.getLowerData(), false); + } + else if (data.getLowerData() instanceof WKms) { + StyledSeriesBuilder.addPoints(down, (WKms) data.getLowerData()); + } + else if (data.getLowerData() instanceof Lines.LineData) { + StyledSeriesBuilder.addPoints(down, ((Lines.LineData) data.getLowerData()).points, false); + } + else { + logger.error("Do not know how to deal with (down) area info from: " + + data.getLowerData()); + } + } + + if (up == null && down != null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE); + down.setKey(seriesName); + area.addSeries(down); + area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(down)); + } + else if (up != null && down == null) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.UNDER); + area.addSeries(up); + area.addSeries(StyledSeriesBuilder.createGroundAtInfinity(up)); + } + else if (up != null && down != null) { + if (data.doPaintBetween()) { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); + } + else { + area.setMode(StyledAreaSeriesCollection.FILL_MODE.ABOVE); + } + area.addSeries(up); + area.addSeries(down); + } + + /* Decide axis name based on facet name */ + generator.addAreaSeries(area, + axisNameForFacet(data.getRootFacetName()), visible); + } + + /** Look up the axis identifier for a given facet type. */ + private String axisNameForFacet(String facetName) { + if (FacetTypes.IS.W(facetName)) { + return "W"; + } + else if (FacetTypes.IS.Q(facetName)) { + return "Q"; + } + else { + logger.warn("Could not find axis for facet " + facetName); + return "W"; + } + } + + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + return FacetTypes.IS.AREA(facetType); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,39 +10,70 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.minfo.BedDiffYearResult; import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.exports.DiagramGenerator; import org.dive4elements.river.exports.XYChartGenerator; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; -public class BedDiffHeightYearProcessor implements Processor, FacetTypes { +public class BedDiffHeightYearProcessor +extends DefaultProcessor implements FacetTypes { private final static Logger logger = Logger.getLogger(BedDiffHeightYearProcessor.class); + protected static double GAP_TOLERANCE = 0.101d; + + public static final String I18N_AXIS_LABEL = + "chart.beddifference.height.yaxis.label"; + public static final String I18N_AXIS_LABEL_DEFAULT = + "delta S [cm / Jahr]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + if (data instanceof BedDiffYearResult) { + BedDiffYearResult bData = (BedDiffYearResult) data; + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, bData.getHeightPerYearData(), false, GAP_TOLERANCE); + + generator.addAxisSeries(series, axisName, visible); + return; + } + // Should not happen if canHandle is correct + logger.error("Can't process " + data.getClass().getName() + " objects"); + } + @Override public void doOut( XYChartGenerator generator, - ArtifactAndFacet aandf, - Document theme, + ArtifactAndFacet bundle, + ThemeDocument theme, boolean visible, int index ) { CallContext context = generator.getCallContext(); - Object data = aandf.getData(context); + Object data = bundle.getData(context); if (data instanceof BedDiffYearResult) { - doBedDifferenceYearOut( - generator, - (BedDiffYearResult) data, - aandf, theme, visible, index); + BedDiffYearResult bData = (BedDiffYearResult) data; + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, bData.getHeightPerYearData(), false, GAP_TOLERANCE); + + generator.addAxisSeries(series, index, visible); return; } + // Should not happen if canHandle is correct logger.error("Can't process " + data.getClass().getName() + " objects"); } @@ -56,15 +87,23 @@ protected void doBedDifferenceYearOut(XYChartGenerator generator, BedDiffYearResult data, - ArtifactAndFacet aandf, - Document theme, + ArtifactAndFacet bundle, + ThemeDocument theme, boolean visible, int axidx) { - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), theme); - StyledSeriesBuilder.addPoints(series, data.getHeightPerYearData(), true); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + StyledSeriesBuilder.addPoints(series, data.getHeightPerYearData(), false, GAP_TOLERANCE); generator.addAxisSeries(series, axidx, visible); } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } + } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,7 +10,6 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.CallContext; @@ -18,33 +17,85 @@ import org.dive4elements.river.artifacts.model.minfo.BedDiffYearResult; import org.dive4elements.river.exports.StyledSeriesBuilder; import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.exports.DiagramGenerator; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; -public class BedDiffYearProcessor implements Processor, FacetTypes { +public class BedDiffYearProcessor +extends DefaultProcessor implements FacetTypes { private final static Logger logger = Logger.getLogger(BedDiffYearProcessor.class); + protected static double GAP_TOLERANCE = 0.101d; + + public static final String I18N_AXIS_LABEL = + "chart.beddifference.yaxis.label.diff"; + public static final String I18N_AXIS_LABEL_DEFAULT = + "delta S [cm]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + if (data instanceof BedDiffYearResult) { + String facetType = bundle.getFacetName(); + BedDiffYearResult bData = (BedDiffYearResult) data; + + double[][] points; + if (BED_DIFFERENCE_YEAR_HEIGHT1.equals(facetType)) { + points = bData.getHeights1Data(); + } else { + points = bData.getHeights2Data(); + } + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + StyledSeriesBuilder.addPointsFactorY(series, + points, + false, + GAP_TOLERANCE, + 100d); + + generator.addAxisSeries(series, axisName, visible); + + return; + } + logger.error("Can't process " + data.getClass().getName() + " objects"); + } + @Override public void doOut( XYChartGenerator generator, - ArtifactAndFacet aandf, - Document theme, + ArtifactAndFacet bundle, + ThemeDocument theme, boolean visible, int axidx ) { CallContext context = generator.getCallContext(); - Object data = aandf.getData(context); + Object data = bundle.getData(context); if (data instanceof BedDiffYearResult) { - String facetType = aandf.getFacetName(); - int index = - (BED_DIFFERENCE_YEAR_HEIGHT1.equals(facetType) - || BED_DIFFERENCE_YEAR_HEIGHT1_FILTERED.equals(facetType))?0:1; - doBedDifferenceHeightsOut( - generator, - (BedDiffYearResult) data, - aandf, theme, visible, index, axidx); + String facetType = bundle.getFacetName(); + BedDiffYearResult bData = (BedDiffYearResult) data; + + double[][] points; + if (BED_DIFFERENCE_YEAR_HEIGHT1.equals(facetType)) { + points = bData.getHeights1Data(); + } else { + points = bData.getHeights2Data(); + } + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + StyledSeriesBuilder.addPointsFactorY(series, + points, + false, + GAP_TOLERANCE, + 100d); + + generator.addAxisSeries(series, axidx, visible); + return; } logger.error("Can't process " + data.getClass().getName() + " objects"); @@ -59,25 +110,11 @@ || BED_DIFFERENCE_YEAR_HEIGHT2_FILTERED.equals(facetType); } - private void doBedDifferenceHeightsOut( - XYChartGenerator generator, - BedDiffYearResult data, - ArtifactAndFacet bundle, - Document attr, - boolean visible, - int idx, - int axidx) { - logger.debug("doBedDifferenceHeightsOut()"); - - XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), attr); - if (idx == 0) { - StyledSeriesBuilder.addPoints(series, data.getHeights1Data(), true); - } - else { - StyledSeriesBuilder.addPoints(series, data.getHeights2Data(), true); - } - - generator.addAxisSeries(series, axidx, visible); + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedHeightSoundingProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedHeightSoundingProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,114 @@ +/* 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.process; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.minfo.BedHeightSingle; +import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.model.BedHeightSingleValue; +import org.dive4elements.river.themes.ThemeDocument; + +public class BedHeightSoundingProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(BedHeightSoundingProcessor.class); + + private final static String BEDHEIGHT = "bedheight"; + + public static final String I18N_AXIS_LABEL_DEFAULT + = "Gepeilte Breite [m]"; + public static final String I18N_AXIS_LABEL = + "chart.bedheight_middle.sounding.yaxis.label"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + if (data instanceof BedHeightSingle) { + BedHeightSingle bData = (BedHeightSingle)data; + double[] width = bData.getMorphWidths(); + double[] stations = bData.getStations().toNativeArray(); + + logger.debug("doBedheightSingleOut"); + + for (int i = 0; i < width.length; i++) { + series.add(stations[i], width[i], false); + } + } else if (data instanceof List<?>) { + List<BedHeightSingleValue> bData = (List<BedHeightSingleValue>)data; + + logger.debug("doBedheightSingleValueOut"); + + for(BedHeightSingleValue bvalue: bData) { + series.add(bvalue.getStation(), bvalue.getSoundingWidth()); + } + } + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public void doOut( + XYChartGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int index + ) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + if (data instanceof BedHeightSingle) { + BedHeightSingle bData = (BedHeightSingle)data; + double[] width = bData.getMorphWidths(); + double[] stations = bData.getStations().toNativeArray(); + + logger.debug("doBedheightSingleOut"); + + for (int i = 0; i < width.length; i++) { + series.add(stations[i], width[i], false); + } + } else if (data instanceof List<?>) { + List<BedHeightSingleValue> bData = (List<BedHeightSingleValue>)data; + + logger.debug("doBedheightSingleValueOut"); + + for(BedHeightSingleValue bvalue: bData) { + series.add(bvalue.getStation(), bvalue.getSoundingWidth()); + } + } + generator.addAxisSeries(series, index, visible); + } + + @Override + public boolean canHandle(String facettype) { + return BEDHEIGHT.equals(facettype); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDensityProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDensityProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,72 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.minfo.BedParametersResult; + +public class BedQualityDensityProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(BedQualityDensityProcessor.class); + + public static final String I18N_AXIS_LABEL_DEFAULT = + "Dichte [t/m^3]"; + public static final String I18N_AXIS_LABEL = + "chart.bedquality.yaxis.label.density"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + Object data = bundle.getData(context); + String facetName = bundle.getFacetName(); + double [][] points; + + if (facetName.equals(FacetTypes.BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER)) { + points = ((BedParametersResult) data).getDensityCapData(); + } else if (facetName.equals(FacetTypes.BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER)) { + points = ((BedParametersResult) data).getDensitySubData(); + } else { + logger.error("Unknown facet name: " + facetName); + return; + } + StyledSeriesBuilder.addPoints(series, points, true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.BED_QUALITY_SEDIMENT_DENSITY_SUBLAYER) || + facettype.equals(FacetTypes.BED_QUALITY_SEDIMENT_DENSITY_TOPLAYER); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDiameterProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDiameterProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,85 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.minfo.BedDiameterData; +import org.dive4elements.river.artifacts.model.minfo.BedDiameterResult; +import org.dive4elements.river.artifacts.model.minfo.BedloadDiameterResult; + +public class BedQualityDiameterProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(BedQualityDiameterProcessor.class); + + public static final String I18N_AXIS_LABEL_DEFAULT = + "Durchmesser [mm]"; + public static final String I18N_AXIS_LABEL = + "chart.bedquality.yaxis.label.diameter"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + Object data = bundle.getData(context); + String facetName = bundle.getFacetName(); + double [][] points; + + if (facetName.equals(FacetTypes.BED_QUALITY_BED_DIAMETER_TOPLAYER)) { + points = ((BedDiameterResult) data).getDiameterCapData(); + } else if (facetName.equals(FacetTypes.BED_QUALITY_BED_DIAMETER_SUBLAYER)) { + points = ((BedDiameterResult) data).getDiameterSubData(); + } else if (facetName.equals(FacetTypes.BED_QUALITY_BEDLOAD_DIAMETER)) { + points = ((BedloadDiameterResult) data).getDiameterData(); + } else if (facetName.equals(FacetTypes.BED_DIAMETER_DATA_TOP) || + facetName.equals(FacetTypes.BED_DIAMETER_DATA_SUB) || + facetName.equals(FacetTypes.BEDLOAD_DIAMETER_DATA)) { + points = ((BedDiameterData) data).getDiameterData(); + } else { + logger.error("Unknown facet name: " + facetName); + return; + } + StyledSeriesBuilder.addPoints(series, points, true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.BED_QUALITY_BED_DIAMETER_TOPLAYER) || + facettype.equals(FacetTypes.BED_QUALITY_BED_DIAMETER_SUBLAYER) || + facettype.equals(FacetTypes.BED_QUALITY_BEDLOAD_DIAMETER) || + facettype.equals(FacetTypes.BED_DIAMETER_DATA_TOP) || + facettype.equals(FacetTypes.BED_DIAMETER_DATA_SUB) || + facettype.equals(FacetTypes.BEDLOAD_DIAMETER_DATA); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} + diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityPorosityProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityPorosityProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,74 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.minfo.BedParametersResult; + +public class BedQualityPorosityProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(BedQualityPorosityProcessor.class); + + public static final String I18N_AXIS_LABEL_DEFAULT = + "Porosität [%]"; + public static final String I18N_AXIS_LABEL = + "chart.bedquality.yaxis.label.porosity"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + Object data = bundle.getData(context); + String facetName = bundle.getFacetName(); + double [][] points; + + if (facetName.equals(FacetTypes.BED_QUALITY_POROSITY_TOPLAYER)) { + points = ((BedParametersResult) data).getPorosityCapData(); + } else if (facetName.equals(FacetTypes.BED_QUALITY_BED_DIAMETER_SUBLAYER)) { + points = ((BedParametersResult) data).getPorositySubData(); + } else { + logger.error("Unknown facet name: " + facetName); + return; + } + StyledSeriesBuilder.addPoints(series, points, true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.BED_QUALITY_POROSITY_TOPLAYER) || + facettype.equals(FacetTypes.BED_QUALITY_POROSITY_SUBLAYER); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} + + diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedWidthProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedWidthProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,71 @@ +/* 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.minfo.BedDiffYearResult; +import org.dive4elements.river.artifacts.model.minfo.MorphologicWidth; + +public class BedWidthProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(BedWidthProcessor.class); + + public static final String I18N_AXIS_LABEL_DEFAULT = + "Breite [m]"; + public static final String I18N_AXIS_LABEL = + "chart.beddifference.yaxis.label.morph"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + Object data = bundle.getData(context); + + if (data instanceof BedDiffYearResult) { + BedDiffYearResult bData = (BedDiffYearResult) data; + StyledSeriesBuilder.addPoints(series, bData.getMorphWidthData(), true); + } else if (data instanceof MorphologicWidth) { + MorphologicWidth bData = (MorphologicWidth) data; + StyledSeriesBuilder.addPoints(series, bData.getAsArray(), true); + } else { + logger.error("Unknown data for facet: " + bundle.getFacetName()); + } + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.BED_DIFFERENCE_MORPH_WIDTH) || + facettype.equals(FacetTypes.MORPHOLOGIC_WIDTH); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/BedheightProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedheightProcessor.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* 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.process; - -import java.util.List; - -import org.apache.log4j.Logger; -import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; - -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifacts.CallContext; -import org.dive4elements.river.artifacts.model.minfo.BedHeightSingle; -import org.dive4elements.river.exports.XYChartGenerator; -import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.model.BedHeightSingleValue; - -public class BedheightProcessor implements Processor { - - private final static Logger logger = - Logger.getLogger(BedheightProcessor.class); - - private final static String BEDHEIGHT = "bedheight"; - - @Override - public void doOut( - XYChartGenerator generator, - ArtifactAndFacet aandf, - Document theme, - boolean visible, - int index - ) { - CallContext context = generator.getCallContext(); - Object data = aandf.getData(context); - if (data instanceof BedHeightSingle) { - doBedheightSingleOut(generator, aandf, theme, index, visible, - (BedHeightSingle)data); - } - else if (data instanceof List<?>) { - doBedheightSingeValuesOut(generator, aandf, theme, index, visible, - (List<BedHeightSingleValue>)data); - } - logger.error("Can't process " + data.getClass().getName() + " objects"); - } - - private void doBedheightSingeValuesOut(XYChartGenerator generator, - ArtifactAndFacet aandf, Document theme, int index, boolean visible, - List<BedHeightSingleValue> data) { - logger.debug("doBedheightSingleOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), - theme); - for(BedHeightSingleValue bvalue: data) { - series.add(bvalue.getStation(), bvalue.getSoundingWidth()); - } - generator.addAxisSeries(series, index, visible); - } - - @Override - public boolean canHandle(String facettype) { - return BEDHEIGHT.equals(facettype); - } - - public void doBedheightSingleOut(XYChartGenerator generator, - ArtifactAndFacet aandf, Document theme, int index, boolean visible, - BedHeightSingle data) { - double[] width = data.getMorphWidths(); - double[] stations = data.getStations().toNativeArray(); - - logger.debug("doBedheightSingleOut"); - - XYSeries series = new StyledXYSeries(aandf.getFacetDescription(), - theme); - - for (int i = 0; i < width.length; i++) { - series.add(stations[i], width[i], false); - } - - generator.addAxisSeries(series, index, visible); - } -} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/DefaultProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DefaultProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,74 @@ +/* Copyright (C) 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.process; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.themes.ThemeDocument; + +/** Dummy implementation for the Processor interface. + */ +public class DefaultProcessor implements Processor { + + protected String axisName; + + public void setAxisName(String axisName) { + this.axisName = axisName; + } + + public String getAxisName() { + return axisName; + } + + /** + * Processes data to generate e.g. a chart. + * + * @param generator XYChartGenerator to add output on. + * @param bundle The artifact and facet + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + * @param index The index of the curve + */ + @Override + public void doOut( + XYChartGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int index) { + return; + } + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + return; + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return null; + } + + + /** + * Returns true if the Processor class is able to generate output for a facet type + * + * @param facettype Name of the facet type + * @return true if the facettype can be processed + */ + @Override + public boolean canHandle(String facettype) { + return false; + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,263 @@ +/* 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.process; + +import org.apache.log4j.Logger; + +import java.awt.BasicStroke; +import java.awt.Color; + +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +import org.jfree.chart.plot.Marker; +import org.jfree.chart.plot.ValueMarker; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.fixings.AnalysisPeriod; +import org.dive4elements.river.artifacts.model.fixings.QWD; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.jfree.StyledAreaSeriesCollection; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.utils.KMIndex; + +public class DeltaWProcessor extends DefaultProcessor { + /* This is basically a collection of different processors. The + * historic reason for this is that they have in common that they + * work on deltaW data from the fixing analysis. */ + + private static final Logger logger = Logger.getLogger(DeltaWProcessor.class); + + public static final String I18N_DW_YAXIS_LABEL_DEFAULT = + "delta W [cm]"; + + public static final String I18N_DW_YAXIS_LABEL = + "chart.fixings.longitudinalsection.yaxis.label"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + String facettype = bundle.getFacetName(); + if (!visible) { + return; + } + logger.debug("Doing out for: " + bundle.getFacetName()); + if (facettype.equals(FacetTypes.FIX_REFERENCE_EVENTS_LS)) { + doReferenceEventsOut(generator, bundle, theme, visible); + } else if (facettype.equals(FacetTypes.FIX_ANALYSIS_EVENTS_LS)) { + doAnalysisEventsOut(generator, bundle, theme, visible); + } else if (facettype.startsWith(FacetTypes.FIX_SECTOR_AVERAGE_LS_DEVIATION)) { + doSectorAverageDeviationOut(generator, bundle, theme, visible); + } else if (facettype.equals(FacetTypes.FIX_DEVIATION_LS)) { + doReferenceDeviationOut(generator, bundle, theme, visible); + } else if (facettype.startsWith(FacetTypes.FIX_SECTOR_AVERAGE_LS)) { + doSectorAverageOut(generator, bundle, theme, visible); + } else { + logger.error("Could not handle: " + facettype); + } + } + + @Override + public boolean canHandle(String facettype) { + if (facettype == null) { + return false; + } + + if (facettype.startsWith(FacetTypes.FIX_SECTOR_AVERAGE_LS) + || facettype.equals(FacetTypes.FIX_REFERENCE_EVENTS_LS) + || facettype.equals(FacetTypes.FIX_ANALYSIS_EVENTS_LS) + || facettype.equals(FacetTypes.FIX_DEVIATION_LS)) { + return true; + } + return false; + } + + private void doSectorAverageOut(DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument doc, boolean visible) { + CallContext context = generator.getCallContext(); + int index = bundle.getFacet().getIndex(); + int sectorNdx = index & 3; + + KMIndex<AnalysisPeriod> kms = + (KMIndex<AnalysisPeriod>)bundle.getData(context); + + if(kms == null) { + return; + } + + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), doc); + + for (KMIndex.Entry<AnalysisPeriod> entry: kms) { + double km = entry.getKm(); + AnalysisPeriod ap = entry.getValue(); + QWD qwd = ap.getQSectorAverages()[sectorNdx]; + if (qwd == null) { + continue; + } + double deltaW = qwd.getDeltaW(); + series.add(km, deltaW); + } + + generator.addAxisSeries(series, axisName, visible); + } + + private void doReferenceEventsOut(DiagramGenerator generator, + ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { + CallContext context = generator.getCallContext(); + + KMIndex<QWD> kms = + (KMIndex<QWD>)bundle.getData(context); + + if(kms == null) { + return; + } + + XYSeriesCollection col = new XYSeriesCollection(); + + StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, + doc); + + for (KMIndex.Entry<QWD> entry: kms) { + double km = entry.getKm(); + QWD qwd = entry.getValue(); + + series.add(km, qwd.getDeltaW()); + } + col.addSeries(series); + + generator.addAxisDataset(col, axisName, visible); + } + + private void doAnalysisEventsOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument doc, + boolean visible) { + CallContext context = generator.getCallContext(); + + KMIndex<QWD> kms = + (KMIndex<QWD>)bundle.getData(context); + + if(kms == null) { + return; + } + + XYSeriesCollection col = new XYSeriesCollection(); + + StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, doc); + + for (KMIndex.Entry<QWD> entry: kms) { + double km = entry.getKm(); + QWD qwd = entry.getValue(); + + series.add(km, qwd.getDeltaW()); + } + col.addSeries(series); + + generator.addAxisDataset(col, axisName, visible); + } + + protected void doSectorAverageDeviationOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument doc, + boolean visible) { + CallContext context = generator.getCallContext(); + + int index = bundle.getFacet().getIndex(); + int sectorNdx = index & 3; + + KMIndex<AnalysisPeriod> kms = + (KMIndex<AnalysisPeriod>)bundle.getData(context); + + if(kms == null) { + return; + } + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); + XYSeries upper = + new StyledXYSeries(bundle.getFacetDescription(), false, doc); + XYSeries lower = + new StyledXYSeries(bundle.getFacetDescription() + " ", false, doc); + + for (KMIndex.Entry<AnalysisPeriod> entry: kms) { + double km = entry.getKm(); + AnalysisPeriod ap = entry.getValue(); + QWD qwd = ap.getQSectorAverages()[sectorNdx]; + double dev = ap.getQSectorStdDev(sectorNdx); + if (qwd == null) { + continue; + } + double deltaW = qwd.getDeltaW(); + double up = deltaW + dev; + double lo = deltaW - dev; + upper.add(km, up); + lower.add(km, lo); + } + area.addSeries(upper); + area.addSeries(lower); + + generator.addAreaSeries(area, axisName, visible); + } + + protected void doReferenceDeviationOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument doc, + boolean visible) { + CallContext context = generator.getCallContext(); + + KMIndex<double[]> kms = + (KMIndex<double[]>)bundle.getData(context); + + if(kms == null) { + return; + } + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(doc); + XYSeries upper = + new StyledXYSeries(bundle.getFacetDescription(), false, doc); + XYSeries lower = + new StyledXYSeries(bundle.getFacetDescription() + " ", false, doc); + + for (KMIndex.Entry<double[]> entry: kms) { + double km = entry.getKm(); + double[] devArray = entry.getValue(); + if (devArray == null) { + continue; + } + double dev = devArray[0]; + double up = dev; + double lo = -dev; + upper.add(km, up, false); + lower.add(km, lo, false); + } + area.addSeries(upper); + area.addSeries(lower); + + Marker marker = new ValueMarker(0); + marker.setStroke(new BasicStroke(2)); + marker.setPaint(Color.BLACK); + generator.addValueMarker(marker); + generator.addAreaSeries(area, axisName, visible); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg(I18N_DW_YAXIS_LABEL, I18N_DW_YAXIS_LABEL_DEFAULT); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/DischargeProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DischargeProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,201 @@ +/* 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.process; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.exports.DischargeCurveGenerator; +import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; +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.jfree.chart.annotations.XYTextAnnotation; + + +/** Helper for data handling in discharge diagrams. */ +public class DischargeProcessor +extends DefaultProcessor implements FacetTypes { + + private final static Logger logger = + Logger.getLogger(DischargeProcessor.class); + + /** Station for which the diagram is shown. */ + private double km; + + /** Tolerance for comparison of kilometers. */ + public static final double KM_EPSILON = 0.001d; + + + /** This processor needs to be constructed with a given km. */ + private DischargeProcessor() { + km = Double.NaN; + } + + + public DischargeProcessor(double km) { + this.km = km; + } + + + /** Process data, add it to plot. */ + @Override + public void doOut( + XYChartGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int axisIndex + ) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + if (false && data instanceof WQKms) { + doWQKmsPointOut( + generator, (WQKms) data, bundle, theme, visible, axisIndex); + return; + } + else if (data instanceof RiverAnnotation) { + doRiverAnnotationOut( + generator, (RiverAnnotation) data, bundle, theme, visible); + return; + } + else if (data instanceof double[][]) { + doMarksOut( + generator, (double[][]) data, bundle, theme, visible); + return; + } + else { + logger.error("Can't process " + + data.getClass().getName() + " objects of facet " + + bundle.getFacetName()); + } + } + + + /** True if this processor knows how to deal with facetType. */ + @Override + public boolean canHandle(String facetType) { + return /*STATIC_WQKMS_W.equals(facetType) + ||*/ COMPUTED_DISCHARGE_MAINVALUES_Q.equals(facetType) + || MAINVALUES_Q.equals(facetType) + || COMPUTED_DISCHARGE_MAINVALUES_W.equals(facetType) + || MAINVALUES_W.equals(facetType) + || STATIC_W_INTERPOL.equals(facetType); + } + + + /** The station of the current calculation/view. */ + protected double getKm() { + return km; + } + + + /** Handle WQKms data by finding w/q values at given km. */ + protected void doWQKmsPointOut(XYChartGenerator generator, + WQKms wqkms, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int axidx + ) { + logger.debug("doWQKmsPointOut"); + String title = bundle.getFacetDescription(); + XYSeries series = new StyledXYSeries( + title, + theme); + + double[] kms = wqkms.getKms(); + + for (int i = 0 ; i< kms.length; i++) { + if (Math.abs(kms[i] - getKm()) <= KM_EPSILON) { + series.add(wqkms.getQ(i), wqkms.getW(i)); + generator.addAxisSeries(series, axidx, visible); + if(visible && theme.parseShowPointLabel()) { + List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( + title, + wqkms.getQ(i), + // TODO add a percentage to the extend of W axis + wqkms.getW(i)); + textAnnos.add(anno); + RiverAnnotation flysAnno = new RiverAnnotation(null, null, null, theme); + flysAnno.setTextAnnotations(textAnnos); + generator.addAnnotations(flysAnno); + } + return; + } + } + + logger.warn("No WQ found for km " + getKm()); + } + + protected void doRiverAnnotationOut(XYChartGenerator generator, + RiverAnnotation annotations, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible + ) { + if (!(generator instanceof DischargeCurveGenerator)) { + logger.error("DischargeProcessor can only be used in " + + " in DischargeCurveGenerator-classes."); + return; + } + logger.debug("doRiverAnnotationOut"); + DischargeCurveGenerator dGenerator = + (DischargeCurveGenerator) generator; + + dGenerator.translateRiverAnnotation(annotations); + dGenerator.doAnnotations( + annotations, + bundle, theme, visible); + } + + + /** + * Put Sticky Axis Markers to Y-axis for each value. + * @param data [[-,y1],[-,y2],...] ('x'-coordinates ignored) + */ + protected void doMarksOut(XYChartGenerator generator, + double[][] data, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible + ) { + logger.debug("doMarksOut"); + + if (!visible) { + return; + } + + // TODO subtract gauge null point if at gauge. + String title = bundle.getFacetDescription(); + List<StickyAxisAnnotation> yMarks = new ArrayList<StickyAxisAnnotation>(); + + for (double yPos: data[1]) { + yMarks.add(new StickyAxisAnnotation( + title, + (float) yPos, + StickyAxisAnnotation.SimpleAxis.Y_AXIS)); + } + + generator.doAnnotations(new RiverAnnotation(title, yMarks), + bundle, theme, visible); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,90 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.model.FlowVelocityMeasurementValue.FastFlowVelocityMeasurementValue; +import org.dive4elements.river.artifacts.model.FlowVelocityData; + +public class FlowVelocityProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(FlowVelocityProcessor.class); + + public static final String I18N_AXIS_LABEL = + "chart.flow_velocity.section.yaxis.label"; + public static final String I18N_AXIS_LABEL_DEFAULT = + "Geschwindigkeit v [m/s]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + String facetName = bundle.getFacetName(); + Object data = bundle.getData(context); + if (data == null) { + // Check has been here before so we keep it for security reasons + // this should never happen though. + logger.error("Data is null for facet: " + facetName); + return; + } + double [][] points; + + if (facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL) || + facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL_FILTERED)) { + FlowVelocityData fData = (FlowVelocityData) data; + points = fData.getTotalChannelPoints(); + } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL) || + facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL_FILTERED)) { + FlowVelocityData fData = (FlowVelocityData) data; + points = fData.getMainChannelPoints(); // I hate facets! + } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MEASUREMENT)) { + FastFlowVelocityMeasurementValue fData = + (FastFlowVelocityMeasurementValue) data; + points = new double[][] {{fData.getStation()},{fData.getV()}}; + } else { + logger.error("Unknown facet name: " + facetName); + return; + } + StyledSeriesBuilder.addPoints(series, points, true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL_FILTERED) || + facettype.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL) || + facettype.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL_FILTERED) || + facettype.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL) || + facettype.equals(FacetTypes.FLOW_VELOCITY_MEASUREMENT); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/KMIndexProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/KMIndexProcessor.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/KMIndexProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,7 +11,6 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.CallContext; @@ -20,24 +19,25 @@ import org.dive4elements.river.artifacts.model.fixings.QWD; import org.dive4elements.river.exports.XYChartGenerator; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.KMIndex; -public class KMIndexProcessor implements Processor { +public class KMIndexProcessor extends DefaultProcessor { private static final Logger logger = Logger.getLogger(KMIndexProcessor.class); @Override - public void doOut(XYChartGenerator generator, ArtifactAndFacet aandf, - Document theme, boolean visible, int index) { - String facettype = aandf.getFacetName(); + public void doOut(XYChartGenerator generator, ArtifactAndFacet bundle, + ThemeDocument theme, boolean visible, int index) { + String facettype = bundle.getFacetName(); if (facettype.contains(FacetTypes.FIX_SECTOR_AVERAGE_LS)) { - doSectorAverageOut(generator, aandf, theme, visible, index); + doSectorAverageOut(generator, bundle, theme, visible, index); } else if (facettype.equals(FacetTypes.FIX_REFERENCE_EVENTS_LS)) { - doReferenceEventsOut(generator, aandf, theme, visible, index); + doReferenceEventsOut(generator, bundle, theme, visible, index); } else if (facettype.equals(FacetTypes.FIX_ANALYSIS_EVENTS_LS)) { - doAnalysisEventsOut(generator, aandf, theme, visible, index); + doAnalysisEventsOut(generator, bundle, theme, visible, index); } } @@ -57,23 +57,23 @@ return false; } - private void doSectorAverageOut(XYChartGenerator generator, ArtifactAndFacet aaf, - Document doc, boolean visible, int idx) { - logger.debug("doSectorAverageOut" + aaf.getFacet().getIndex()); + private void doSectorAverageOut(XYChartGenerator generator, ArtifactAndFacet bundle, + ThemeDocument doc, boolean visible, int idx) { + logger.debug("doSectorAverageOut" + bundle.getFacet().getIndex()); CallContext context = generator.getCallContext(); - int index = aaf.getFacet().getIndex(); + int index = bundle.getFacet().getIndex(); int sectorNdx = index & 3; @SuppressWarnings("unchecked") KMIndex<AnalysisPeriod> kms = - (KMIndex<AnalysisPeriod>)aaf.getData(context); + (KMIndex<AnalysisPeriod>)bundle.getData(context); if(kms == null) { return; } - XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), doc); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), doc); for (KMIndex.Entry<AnalysisPeriod> entry: kms) { double km = entry.getKm(); @@ -90,14 +90,14 @@ } private void doReferenceEventsOut(XYChartGenerator generator, - ArtifactAndFacet aaf, Document doc, boolean visible, int idx) { + ArtifactAndFacet bundle, ThemeDocument doc, boolean visible, int idx) { logger.debug("doReferenceEventOut"); CallContext context = generator.getCallContext(); @SuppressWarnings("unchecked") KMIndex<QWD> kms = - (KMIndex<QWD>)aaf.getData(context); + (KMIndex<QWD>)bundle.getData(context); if(kms == null) { return; @@ -105,7 +105,7 @@ XYSeriesCollection col = new XYSeriesCollection(); - StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, + StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, doc); for (KMIndex.Entry<QWD> entry: kms) { @@ -120,14 +120,14 @@ } private void doAnalysisEventsOut(XYChartGenerator generator, - ArtifactAndFacet aaf, Document doc, boolean visible, int idx) { + ArtifactAndFacet bundle, ThemeDocument doc, boolean visible, int idx) { logger.debug("doAnalysisEventsOut"); CallContext context = generator.getCallContext(); @SuppressWarnings("unchecked") KMIndex<QWD> kms = - (KMIndex<QWD>)aaf.getData(context); + (KMIndex<QWD>)bundle.getData(context); if(kms == null) { return; @@ -135,7 +135,7 @@ XYSeriesCollection col = new XYSeriesCollection(); - StyledXYSeries series = new StyledXYSeries(aaf.getFacetDescription(), false, doc); + StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, doc); for (KMIndex.Entry<QWD> entry: kms) { double km = entry.getKm(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/ManualPointsProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/ManualPointsProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,87 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; + +import java.util.List; +import java.util.ArrayList; + +import org.json.JSONArray; +import org.json.JSONException; + +import org.jfree.data.xy.XYSeries; +import org.jfree.chart.annotations.XYTextAnnotation; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +public class ManualPointsProcessor extends DefaultProcessor { + + private static final Logger logger = Logger.getLogger(ManualPointsProcessor.class); + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + String seriesName = bundle.getFacetDescription(); + XYSeries series = new StyledXYSeries(seriesName, theme); + String jsonData = (String) bundle.getData(context); + + // Add text annotations for single points. + List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); + + try { + JSONArray points = new JSONArray(jsonData); + for (int i = 0, P = points.length(); i < P; i++) { + JSONArray array = points.getJSONArray(i); + double x = array.getDouble(0); + double y = array.getDouble(1); + String name = array.getString(2); + boolean act = array.getBoolean(3); + if (!act) { + continue; + } + //logger.debug(" x " + x + " y " + y ); + series.add(x, y, false); + xy.add(new CollisionFreeXYTextAnnotation(name, x, y)); + } + } + catch(JSONException e){ + logger.error("Could not decode json."); + } + + RiverAnnotation annotation = new RiverAnnotation(null, null, null, theme); + annotation.setTextAnnotations(xy); + + if (visible) { + generator.addAnnotations(annotation); + } + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + return FacetTypes.IS.MANUALPOINTS(facetType); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/MiddleBedHeightProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/MiddleBedHeightProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,79 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; + +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; + +import org.dive4elements.river.artifacts.model.MiddleBedHeightData; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.utils.RiverUtils; +import org.dive4elements.river.jfree.StyledXYSeries; + +public class MiddleBedHeightProcessor extends DefaultProcessor { + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(WOutProcessor.class); + + public static final String I18N_AXIS_LABEL = + "chart.bedheight_middle.section.yaxis.label"; + + public static final String I18N_AXIS_LABEL_DEFAULT = + "mittlere Sohlhöhen [müNN]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + logger.debug("Processing: " + bundle.getFacetName()); + MiddleBedHeightData data = + (MiddleBedHeightData) bundle.getData(context); + + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + + StyledSeriesBuilder.addPoints(series, data.getMiddleHeightsPoints(), + false, 0.110d); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + D4EArtifact flys = (D4EArtifact) generator.getMaster(); + + String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); + + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT, + new Object[] { unit }); + } + + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + return facetType.equals(FacetTypes.MIDDLE_BED_HEIGHT_EPOCH) || + facetType.equals(FacetTypes.MIDDLE_BED_HEIGHT_SINGLE); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/Processor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/Processor.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/Processor.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,10 +8,10 @@ package org.dive4elements.river.exports.process; -import org.w3c.dom.Document; - import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.exports.DiagramGenerator; /** * A processor is intended to generate an output e.g. curve in a chart diagramm from @@ -20,22 +20,58 @@ * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a> */ public interface Processor { + /** + * Set the axis for this processor. + * This should be done before doOut is called for the first time. + * + * @param axisName The name of the Axis this processor should use. + */ + public void setAxisName(String axisName); + + /** + * Get the axis for this processor. + * + * @return The name of the axis that is used. + */ + public String getAxisName(); + + /** + * Get the axis label for this processor. + * + * @return The label of the axis. + */ + public String getAxisLabel(DiagramGenerator generator); /** * Processes data to generate e.g. a chart. * * @param generator XYChartGenerator to add output on. - * @param aandf The artifact and facet - * @param theme The theme that contains styling information. - * @param visible The visibility of the curve. - * @param index The index of the curve + * @param bundle The artifact and facet + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. */ public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible); + + /** + * Processes data to generate e.g. a chart. + * + * @param generator DiagramGenerator to add output on. + * @param bundle The artifact and facet + * @param theme The theme that contains styling information. + * @param visible The visibility of the curve. + * @param index The index of the curve + */ + @Deprecated + public void doOut( XYChartGenerator generator, - ArtifactAndFacet aandf, - Document theme, - boolean visible, - int index); + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int index); /** * Returns true if the Processor class is able to generate output for a facet type diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/QOutProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/QOutProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,110 @@ +/* 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.WQKms; +import org.dive4elements.river.artifacts.model.FlowVelocityData; + +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +/** + * Add data to chart/generator. + * + * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a> + */ +public class QOutProcessor extends DefaultProcessor { + + public static final String I18N_LONGITUDINAL_LABEL = + "chart.longitudinal.section.yaxis.second.label"; + + public static final String + I18N_LONGITUDINAL_LABEL_DEFAULT = "Q [m\u00b3/s]"; + + /** Private logger. */ + private static final Logger logger = + Logger.getLogger(QOutProcessor.class); + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + String facetName = bundle.getFacetName(); + + if (facetName.equals(FacetTypes.FLOW_VELOCITY_DISCHARGE)) { + FlowVelocityData fData = (FlowVelocityData) data; + StyledSeriesBuilder.addPoints(series, fData.getQPoints(), true); + } else { + WQKms wqkms = (WQKms) data; + StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); + } + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public void doOut( + XYChartGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible, + int index) + { + CallContext context = generator.getCallContext(); + WQKms wqkms = (WQKms) bundle.getData(context); + + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + + StyledSeriesBuilder.addStepPointsKmQ(series, wqkms); + + generator.addAxisSeries(series, index, visible); + + /* Check if the diagram should be inverted*/ + generator.setInverted(wqkms.guessRTLData()); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg(I18N_LONGITUDINAL_LABEL, + I18N_LONGITUDINAL_LABEL_DEFAULT); + } + + /** + * Returns true if facettype is q-type. + */ + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + + if (facetType.equals(FacetTypes.STATIC_WQKMS_Q) + || facetType.equals(FacetTypes.LONGITUDINAL_Q) + || facetType.startsWith(FacetTypes.DISCHARGE_LONGITUDINAL_Q) + || facetType.startsWith(FacetTypes.FLOW_VELOCITY_DISCHARGE)) { + return true; + } + return false; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,95 @@ +/* Copyright (C) 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.process; + +import java.util.Set; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.access.SedimentLoadAccess; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.minfo.SedimentLoad; +import org.dive4elements.river.artifacts.model.minfo.SedimentLoadFraction; + +public class SedimentLoadProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(SedimentLoadProcessor.class); + + public static final String I18N_YAXIS_LABEL_1 = + "chart.sedimentload.ls.yaxis.label.tpera"; + public static final String I18N_YAXIS_LABEL_2 = + "chart.sedimentload.ls.yaxis.label.m3pera"; + public static final String I18N_YAXIS_LABEL_DEFAULT_1 = "[t/a]"; + public static final String I18N_YAXIS_LABEL_DEFAULT_2 = "[m\u00b3/a]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + logger.debug("doOut " + bundle.getFacetName()); + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + Object data = bundle.getData(context); + String facetName = bundle.getFacetName(); + double [][] points; + + if (FacetTypes.IS.SEDIMENT_LOAD(facetName)) { + points = (double[][]) data; + } else if (FacetTypes.IS.SEDIMENT_LOAD_UNKNOWN(facetName)) { + SedimentLoad load = (SedimentLoad) data; + Set<Double> kms = load.getKms(); + points = new double[2][kms.size()]; + int counter = 0; + for (Double km: kms) { + SedimentLoadFraction fraction = load.getFraction(km); + points[0][counter] = km; + points[1][counter] = fraction.getUnknown(); + counter++; + } + } else { + logger.error("Unknown facet name: " + facetName); + return; + } + StyledSeriesBuilder.addPoints(series, points, true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return FacetTypes.IS.SEDIMENT_LOAD(facettype) || + FacetTypes.IS.SEDIMENT_LOAD_UNKNOWN(facettype); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + SedimentLoadAccess slaccess = + new SedimentLoadAccess((D4EArtifact) generator.getMaster()); + String unit = slaccess.getUnit(); + if (unit != null && unit.equals("m3_per_a")) { + return generator.msg(I18N_YAXIS_LABEL_2, I18N_YAXIS_LABEL_DEFAULT_2); + } + else { + return generator.msg(I18N_YAXIS_LABEL_1, I18N_YAXIS_LABEL_DEFAULT_1); + } + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/ShearStressProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/ShearStressProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,64 @@ +/* Copyright (C) 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.process; + +import org.apache.log4j.Logger; +import org.jfree.data.xy.XYSeries; + +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +import org.dive4elements.river.artifacts.model.FlowVelocityData; + +public class ShearStressProcessor extends DefaultProcessor { + + private final static Logger logger = + Logger.getLogger(ShearStressProcessor.class); + + public static final String I18N_AXIS_LABEL = + "chart.flow_velocity.section.yaxis.third.label"; + public static final String I18N_AXIS_LABEL_DEFAULT = + "Schubspannung Tau [N]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), + theme); + String facetName = bundle.getFacetName(); + FlowVelocityData data = (FlowVelocityData) bundle.getData(context); + + StyledSeriesBuilder.addPoints(series, data.getTauPoints(), true); + + generator.addAxisSeries(series, axisName, visible); + } + + @Override + public boolean canHandle(String facettype) { + return facettype.equals(FacetTypes.FLOW_VELOCITY_TAU) || + facettype.equals(FacetTypes.FLOW_VELOCITY_TAU_FILTERED); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT); + } +} + diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/WDiffProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/WDiffProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,36 @@ +/* Copyright (C) 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.process; + +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.exports.DiagramGenerator; + +public class WDiffProcessor extends WOutProcessor { + + public final static String I18N_WDIFF_YAXIS_LABEL = + "chart.w_differences.yaxis.label"; + + public final static String I18N_WDIFF_YAXIS_LABEL_DEFAULT = "m"; + + @Override + public boolean canHandle(String facetType) { + if (facetType == null) { + return false; + } + return facetType.equals(FacetTypes.W_DIFFERENCES); + } + + + @Override + public String getAxisLabel(DiagramGenerator generator) { + return generator.msg(I18N_WDIFF_YAXIS_LABEL, + I18N_WDIFF_YAXIS_LABEL_DEFAULT); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,55 +10,116 @@ import org.apache.log4j.Logger; import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.WKms; +import org.dive4elements.river.artifacts.model.WQCKms; import org.dive4elements.river.exports.StyledSeriesBuilder; import org.dive4elements.river.exports.XYChartGenerator; +import org.dive4elements.river.exports.DiagramGenerator; import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.StyledXYSeries; -import org.dive4elements.river.utils.DataUtil; -import org.dive4elements.river.utils.ThemeUtil; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.utils.RiverUtils; /** * Add data to chart/generator. * * @author <a href="mailto:bjoern.ricks@intevation.de">Björn Ricks</a> */ -public class WOutProcessor implements Processor { +public class WOutProcessor extends DefaultProcessor { /** Private logger. */ private static final Logger logger = Logger.getLogger(WOutProcessor.class); + public static final String I18N_AXIS_LABEL = + "chart.longitudinal.section.yaxis.label"; + + public static final String I18N_AXIS_LABEL_DEFAULT = "W [NN + m]"; + + @Override + public void doOut( + DiagramGenerator generator, + ArtifactAndFacet bundle, + ThemeDocument theme, + boolean visible) { + CallContext context = generator.getCallContext(); + Object data = bundle.getData(context); + WKms wkms = (WKms) data; + + logger.debug("Processing facet: " + bundle.getFacetName()); + + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + + if (bundle.getFacetName().equals(FacetTypes.DISCHARGE_LONGITUDINAL_C)) { + // Add corrected values + WQCKms wqckms = (WQCKms) data; + int size = wqckms.size(); + for (int i = 0; i < size; i++) { + series.add(wqckms.getKm(i), wqckms.getC(i), false); + } + } else { + StyledSeriesBuilder.addPoints(series, wkms); + } + generator.addAxisSeries(series, axisName, visible); + + // If a "band around the curve shall be drawn, add according area. + double bandWidth = theme.parseBandWidth(); + if (bandWidth > 0 ) { + XYSeries seriesDown = new StyledXYSeries( + "band " + bundle.getFacetDescription(), false, theme); + XYSeries seriesUp = new StyledXYSeries( + bundle.getFacetDescription()+"+/-"+bandWidth, false, theme); + StyledSeriesBuilder.addUpperBand(seriesUp, wkms, bandWidth); + StyledSeriesBuilder.addLowerBand(seriesDown, wkms, bandWidth); + + StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); + area.addSeries(seriesUp); + area.addSeries(seriesDown); + area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); + generator.addAreaSeries(area, axisName, visible); + } + + if (bundle.getFacetName().equals(FacetTypes.LONGITUDINAL_W) || + bundle.getFacetName().equals(FacetTypes.DISCHARGE_LONGITUDINAL_W) || + bundle.getFacetName().equals(FacetTypes.STATIC_WQKMS_W) || + bundle.getFacetName().equals(FacetTypes.DISCHARGE_LONGITUDINAL_C)) { + /* Only use W values to check if the diagram should be inverted + * see flys/issue1290 for details */ + logger.debug("Check for RTL data: "+ wkms.guessRTLData()); + generator.setInverted(wkms.guessRTLData()); + } + } + @Override public void doOut( XYChartGenerator generator, - ArtifactAndFacet aaf, - Document theme, + ArtifactAndFacet bundle, + ThemeDocument theme, boolean visible, int index) { CallContext context = generator.getCallContext(); - WKms wkms = (WKms) aaf.getData(context); + WKms wkms = (WKms) bundle.getData(context); logger.debug("doOut"); - XYSeries series = new StyledXYSeries(aaf.getFacetDescription(), theme); + XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); StyledSeriesBuilder.addPoints(series, wkms); generator.addAxisSeries(series, index, visible); // If a "band around the curve shall be drawn, add according area. - double bandWidth = ThemeUtil.parseBandWidth(theme); + double bandWidth = theme.parseBandWidth(); if (bandWidth > 0 ) { XYSeries seriesDown = new StyledXYSeries( - "band " + aaf.getFacetDescription(), false, theme); + "band " + bundle.getFacetDescription(), false, theme); XYSeries seriesUp = new StyledXYSeries( - aaf.getFacetDescription()+"+/-"+bandWidth, false, theme); + bundle.getFacetDescription()+"+/-"+bandWidth, false, theme); StyledSeriesBuilder.addUpperBand(seriesUp, wkms, bandWidth); StyledSeriesBuilder.addLowerBand(seriesDown, wkms, bandWidth); @@ -69,18 +130,27 @@ generator.addAreaSeries(area, index, visible); } - if (aaf.getFacetName().equals(FacetTypes.LONGITUDINAL_W) || - aaf.getFacetName().equals(FacetTypes.DISCHARGE_LONGITUDINAL_W) || - aaf.getFacetName().equals(FacetTypes.STATIC_WQKMS_W)) { + if (bundle.getFacetName().equals(FacetTypes.LONGITUDINAL_W) || + bundle.getFacetName().equals(FacetTypes.DISCHARGE_LONGITUDINAL_W) || + bundle.getFacetName().equals(FacetTypes.STATIC_WQKMS_W)) { /* Only use W values to check if the diagram should be inverted * see flys/issue1290 for details */ - invertAxis(generator, wkms); + generator.setInverted(wkms.guessRTLData()); } } - /** - * Returns true if facettype is longitutinal_section.w . - */ + @Override + public String getAxisLabel(DiagramGenerator generator) { + D4EArtifact flys = (D4EArtifact) generator.getMaster(); + + String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); + + return generator.msg( + I18N_AXIS_LABEL, + I18N_AXIS_LABEL_DEFAULT, + new Object[] { unit }); + } + @Override public boolean canHandle(String facetType) { if (facetType == null) { @@ -92,41 +162,11 @@ || facetType.equals(FacetTypes.HEIGHTMARKS_POINTS) || facetType.equals(FacetTypes.STATIC_WQKMS) || facetType.equals(FacetTypes.STATIC_WQKMS_W) - || facetType.equals(FacetTypes.DISCHARGE_LONGITUDINAL_W)) - { + || facetType.equals(FacetTypes.DISCHARGE_LONGITUDINAL_W) + || facetType.equals(FacetTypes.DISCHARGE_LONGITUDINAL_C)) { return true; } return false; } - - /** - * This method determines - taking JFreeCharts auto x value ordering into - * account - if the x axis need to be inverted. Waterlines in these charts - * should decrease. - * - * @param wkms The data object that stores the x and y values used for this - * chart. - */ - public void invertAxis(XYChartGenerator generator, WKms wkms) { - boolean wsUp = wkms.guessWaterIncreasing(); - boolean kmUp = DataUtil.guessWaterIncreasing(wkms.allKms()); - int size = wkms.size(); - boolean inv = ((wsUp && kmUp) || (!wsUp && !kmUp)) && size > 1; - - if (logger.isDebugEnabled()) { - logger.debug("(Wkms)Values : " + size); - if (size > 0) { - logger.debug("Start km: " + wkms.getKm(0)); - logger.debug("End km: " + wkms.getKm(size-1)); - } - logger.debug("wsUp: " + wsUp); - logger.debug("kmUp: " + kmUp); - if (size == 1) { - logger.debug("InvertAxis not inverting because we have just one km"); - } - logger.debug("inv: " + inv); - } - generator.setInverted(inv); - } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/sq/SQOverviewGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQOverviewGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQOverviewGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -38,6 +38,7 @@ import org.dive4elements.river.exports.ChartGenerator; import org.dive4elements.river.exports.OutGenerator; import org.dive4elements.river.exports.OutputHelper; +import org.dive4elements.river.themes.ThemeDocument; public class SQOverviewGenerator implements OutGenerator @@ -61,6 +62,13 @@ protected List<JFreeChart> charts; + protected String outName; + + @Override + public void setup(Object config) { + logger.debug("SQOverviewGenerator.setup"); + } + /** * Produce output. * @param artifactAndFacet current facet and artifact. @@ -69,11 +77,13 @@ @Override public void doOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { logger.debug("doOut()"); + // TODO: Why not using outName for this. + String name = artifactAndFacet.getData(context).toString(); if(name != null) { logger.debug("name: " + name); @@ -93,7 +103,7 @@ try { Document cAttr = getAttribute(context, collectionAttribute, name); - g.init(request, out, context); + g.init(name, request, out, context); helper.doOut(g, name, name, cAttr, context); JFreeChart chart = g.generateChart(); @@ -110,7 +120,8 @@ } @Override - public void init(Document request, OutputStream out, CallContext context) { + public void init(String outName, Document request, OutputStream out, CallContext context) { + this.outName = outName; this.request = request; this.out = out; this.context = context; @@ -152,6 +163,7 @@ if (i > 1) { vertPos = (size[1] / 3) * (i / 2); } + // TODO: Dispose Graphics object! result.createGraphics().drawImage(img, horPos, vertPos, null); } ImageIO.write(result, "png", out); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationExporter.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationExporter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationExporter.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,8 +16,7 @@ import java.util.Date; import java.util.Locale; import java.text.DateFormat; - -import org.w3c.dom.Document; +import java.text.NumberFormat; import net.sf.jasperreports.engine.JasperExportManager; import net.sf.jasperreports.engine.JasperFillManager; @@ -26,7 +25,6 @@ import au.com.bytecode.opencsv.CSVWriter; -import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.model.CalculationResult; @@ -99,8 +97,11 @@ public static final String CSV_C_FERGUSON = "export.sqrelation.csv.header.c.ferguson"; - public static final String CSV_VARIANCE = - "export.sqrelation.csv.header.variance"; + public static final String CSV_QMAX = + "export.sqrelation.csv.header.qmax"; + + public static final String CSV_SD = + "export.sqrelation.csv.header.sd"; public static final String PDF_TITLE= "export.sqrelation.pdf.title"; @@ -113,13 +114,10 @@ protected List<SQResult []> data; - - public void init(Document request, OutputStream out, CallContext cc) { - super.init(request, out, cc); + public SQRelationExporter() { data = new ArrayList<SQResult []>(); } - @Override protected void addData(Object d) { if (d instanceof CalculationResult) { @@ -136,9 +134,13 @@ msg(CSV_PARAMETER, CSV_PARAMETER), msg(CSV_COEFF_A , CSV_COEFF_A), msg(CSV_COEFF_B , CSV_COEFF_B), + msg(CSV_SD, CSV_SD), + msg(CSV_QMAX, CSV_QMAX), + msg(CSV_COEFF_R, CSV_COEFF_R), msg(CSV_N_TOTAL , CSV_N_TOTAL), msg(CSV_N_OUTLIERS, CSV_N_OUTLIERS), - msg(CSV_VARIANCE , CSV_VARIANCE) + msg(CSV_C_DUAN, CSV_C_DUAN), + msg(CSV_C_FERGUSON, CSV_C_FERGUSON) }); } @@ -160,6 +162,12 @@ ).format(result.getKm()); List<String[]> retval = new ArrayList<String[]>(); + NumberFormat sqAFormatter = Formatter.getSQRelationA(context); + NumberFormat sqBFormatter = Formatter.getSQRelationB(context); + NumberFormat fThreeFormatter = Formatter.getFormatter(context, 3, 3); + NumberFormat fTwoFormatter = Formatter.getFormatter(context, 2, 2); + NumberFormat fZeroFormatter = Formatter.getFormatter(context, 0, 0); + for (int i = 0; i < SQResult.NUMBER_FRACTIONS; ++i) { SQFractionResult fraction = result.getFraction(i); @@ -171,10 +179,17 @@ continue; } - String a, b, sd, o, t; - a = Formatter.getSQRelationA(context).format(parameters.getValue(0, "a")); - b = Formatter.getSQRelationB(context).format(parameters.getValue(0, "b")); - sd = Formatter.getVariance(context).format(Math.sqrt(parameters.getValue(0, "std_dev"))); + String a, b, sd, o, t, max_q, c_ferguson, c_duan, r2; + a = sqAFormatter.format(parameters.getValue(0, "a")); + b = sqBFormatter.format(parameters.getValue(0, "b")); + + /* The std_dev parameter contains the standard error actually */ + sd = fThreeFormatter.format(parameters.getValue(0, "std_dev")); + max_q = fZeroFormatter.format(parameters.getValue(0, "max_q")); + c_ferguson = fTwoFormatter.format(parameters.getValue(0, "c_ferguson")); + c_duan = fTwoFormatter.format(parameters.getValue(0, "c_duan")); + r2 = fTwoFormatter.format(parameters.getValue(0, "r2")); + o = String.valueOf(fraction.totalNumOutliers()); t = String.valueOf(fraction.numMeasurements() + o); @@ -184,9 +199,13 @@ name, a, b, - t, - o, - sd + sd, // 4 + max_q, // 5 + r2, // 6 + t, // 7 + o, // 8 + c_duan, // 9 + c_ferguson // 10 }); } return retval; @@ -229,12 +248,26 @@ source.addMetaData("outliertest", Resources.getMsg(meta, access.getOutlierMethod(), access.getOutlierMethod())); - source.addMetaData("outliers", access.getOutliers().toString()); + source.addMetaData("outliers", Formatter.getRawFormatter(context).format( + access.getOutliers())); source.addMetaData("calculation", Resources.getMsg( locale, PDF_HEADER_MODE, "SQRelation")); + + String measurementStationName = access.getMeasurementStationName(); + + if (measurementStationName != null) { + source.addMetaData("msName", measurementStationName); + } + + String measurementStationGaugeName = access.getMeasurementStationGaugeName(); + + if (measurementStationGaugeName != null) { + source.addMetaData("msGauge", measurementStationGaugeName); + } + } @Override diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/sq/SQRelationGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,6 +11,10 @@ import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.river.artifacts.D4EArtifact; + +import org.dive4elements.river.artifacts.access.SQRelationAccess; + import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.sq.SQ; @@ -20,6 +24,7 @@ import org.dive4elements.river.jfree.JFreeUtil; import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; import org.apache.log4j.Logger; @@ -28,7 +33,6 @@ import org.jfree.data.xy.XYSeries; -import org.w3c.dom.Document; /** * An OutGenerator that generates charts for MINFO sq relation. @@ -54,6 +58,11 @@ public static final String I18N_YAXIS_LABEL = "chart.sq_relation.yaxis.label"; + public static final String I18N_SUBTITLE = + "chart.computed.discharge.curve.subtitle"; + + /** Needed to access data to create subtitle. */ + protected D4EArtifact artifact; /** The logger that is used in this generator. */ private static Logger logger = Logger.getLogger(SQRelationGenerator.class); @@ -75,6 +84,23 @@ }; } + /** + * Returns the default subtitle for this chart. + * + * @return the default subtitle for this chart. + */ + @Override + protected String getDefaultChartSubtitle() { + SQRelationAccess sqAccess = new SQRelationAccess(artifact); + Object[] args = null; + args = new Object[] { + sqAccess.getRiver(), + sqAccess.getLocation() + }; + return msg(I18N_SUBTITLE, "", args); + } + + @Override public String getDefaultChartTitle() { @@ -109,11 +135,13 @@ @Override public void doOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { logger.debug("doOut"); + this.artifact = (D4EArtifact) artifactAndFacet.getArtifact(); + Facet facet = artifactAndFacet.getFacet(); String name = facet != null ? facet.getName() : null; @@ -144,7 +172,7 @@ protected void doSQCurveOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String desc = artifactAndFacet.getFacetDescription(); @@ -180,7 +208,7 @@ protected void doSQOut( ArtifactAndFacet artifactAndFacet, - Document attr, + ThemeDocument attr, boolean visible ) { String desc = artifactAndFacet.getFacetDescription(); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/AnnotationHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/AnnotationHelper.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,365 @@ +/* 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.jfree; + +import org.dive4elements.river.themes.ThemeDocument; + +import java.util.List; +import java.util.Map; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; + +import org.jfree.ui.TextAnchor; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.annotations.XYLineAnnotation; + +import org.dive4elements.river.themes.LineStyle; +import org.dive4elements.river.themes.TextStyle; +import org.dive4elements.river.exports.ChartSettings; +import org.dive4elements.river.exports.LegendSection; +import org.dive4elements.river.exports.ChartArea; + +import org.apache.log4j.Logger; + +/** Annotation helper class, handles plotting of annotations. */ +public class AnnotationHelper { + private static final Logger logger = Logger.getLogger(AnnotationHelper.class); + + protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f; + + /* arr this would be better in chartsettings */ + public static final int DEFAULT_FONT_SIZE = 12; + public static final String DEFAULT_FONT_NAME = "Tahoma"; + + /** + * Add annotations (Sticky, Text and hyk zones) to a plot. + * @param annotations Annotations to add + * @param plot Plot to add annotations to. + * @param settings ChartSettings object for settings. + */ + public static void addAnnotationsToRenderer(List<RiverAnnotation> annotations, + XYPlot plot, ChartSettings settings, Map<Integer, AxisDataset> datasets) { + logger.debug("addAnnotationsToRenderer"); + + if (annotations == null || annotations.isEmpty()) { + logger.debug("addAnnotationsToRenderer: no annotations."); + return; + } + + // OPTMIMIZE: Pre-calculate positions + ChartArea area = new ChartArea( + plot.getDomainAxis(0).getRange(), + plot.getRangeAxis().getRange()); + + // Walk over all Annotation sets. + for (RiverAnnotation fa: annotations) { + + // Access text styling, if any. + ThemeDocument theme = fa.getTheme(); + TextStyle textStyle = null; + LineStyle lineStyle = null; + + // Get Themeing information and add legend item. + if (theme != null) { + textStyle = theme.parseComplexTextStyle(); + lineStyle = theme.parseComplexLineStyle(); + if (fa.getLabel() != null) { + // Legend handling, maybe misplaced? + LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + + Color color = theme.parseLineColorField(); + if (color == null) { + color = Color.BLACK; + } + + LegendItem newItem = new LegendItem(fa.getLabel(), color); + LegendSection ls = (settings != null ? + settings.getLegendSection() : null); + newItem.setLabelFont (new Font( + DEFAULT_FONT_NAME, + Font.PLAIN, + ls != null ? ls.getFontSize() : null) + ); + + lic.add(newItem); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } + else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // The 'Sticky' Annotations (at axis, with line and text). + for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) { + addStickyAnnotation( + sta, plot, area, lineStyle, textStyle, theme, + datasets.get(new Integer(sta.getAxisSymbol()))); + } + + // Other Text Annotations (e.g. labels of (manual) points). + for (XYTextAnnotation ta: fa.getTextAnnotations()) { + // Style the text. + if (textStyle != null) { + textStyle.apply(ta); + } + ta.setY(area.above(0.05d, ta.getY())); + plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); + } + } + } + + /** + * Add a text and a line annotation. + * @param area convenience to determine positions in plot. + * @param theme (optional) theme document + */ + public static void addStickyAnnotation( + StickyAxisAnnotation annotation, + XYPlot plot, + ChartArea area, + LineStyle lineStyle, + TextStyle textStyle, + ThemeDocument theme, + AxisDataset dataset + ) { + // OPTIMIZE pre-calculate area-related values + final float TEXT_OFF = 0.03f; + + XYLineAnnotation lineAnnotation = null; + XYTextAnnotation textAnnotation = null; + + int rendererIndex = 0; + + if (annotation.atX()) { + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF)); + // OPTIMIZE externalize the calculation involving PI. + //textAnnotation.setRotationAngle(270f*Math.PI/180f); + lineAnnotation = createGroundStickAnnotation( + area, annotation.getPos(), lineStyle); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + } + else { + // Do the more complicated case where we stick to the Y-Axis. + // There is one nasty case (duration curves, where annotations + // might stick to the second y-axis). + if (dataset == null) { + logger.warn("Annotation should stick to unfindable y-axis: " + + annotation.getAxisSymbol()); + rendererIndex = 0; + } + else { + rendererIndex = dataset.getPlotAxisIndex(); + } + + // Stick to the "right" (opposed to left) Y-Axis. + if (rendererIndex != 0) { + // OPTIMIZE: Pass a different area to this function, + // do the adding to renderer outside (let this + // function return the annotations). + // Note that this path is travelled rarely. + ChartArea area2 = new ChartArea(plot.getDomainAxis(), plot.getRangeAxis(rendererIndex)); + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), area2.ofRight(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT); + lineAnnotation = createRightStickAnnotation( + area2, annotation.getPos(), lineStyle); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (theme.parseShowVerticalLine()) { + XYLineAnnotation hitLineAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.X_AXIS, + annotation.getHitPoint(), annotation.getPos(),// annotation.getHitPoint(), + area2, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + if (theme.parseShowHorizontalLine()) { + XYLineAnnotation lineBackAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.Y_AXIS2, + annotation.getPos(), annotation.getHitPoint(), + area2, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + } + } + else { // Stick to the left y-axis. + textAnnotation = new CollisionFreeXYTextAnnotation( + annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (theme.parseShowHorizontalLine()) { + XYLineAnnotation hitLineAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.Y_AXIS, + annotation.getPos(), annotation.getHitPoint(), + area, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(hitLineAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + if (theme.parseShowVerticalLine()) { + XYLineAnnotation lineBackAnnotation = + createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis.X_AXIS, + annotation.getHitPoint(), annotation.getPos(), + area, lineStyle); + plot.getRenderer(rendererIndex).addAnnotation(lineBackAnnotation, + org.jfree.ui.Layer.BACKGROUND); + } + } + } + } + + // Style the text. + if (textStyle != null) { + textStyle.apply(textAnnotation); + } + + // Add the Annotations to renderer. + plot.getRenderer(rendererIndex).addAnnotation(textAnnotation, + org.jfree.ui.Layer.FOREGROUND); + plot.getRenderer(rendererIndex).addAnnotation(lineAnnotation, + org.jfree.ui.Layer.FOREGROUND); + } + + /** + * Create annotation that sticks to "ground" (X) axis. + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + public static XYLineAnnotation createGroundStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + pos, area.atGround(), + pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET), + new BasicStroke(lineStyle.getWidth()),lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + pos, area.atGround(), + pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET)); + } + } + + + /** + * Create annotation that sticks to the second Y axis ("right"). + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + public static XYLineAnnotation createRightStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos, + area.atRight(), pos, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + area.atRight(), pos, + area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos); + } + } + /** + * Create annotation that sticks to the first Y axis ("left"). + * @param area helper to calculate coordinates + * @param pos one-dimensional position (distance from axis) + * @param lineStyle the line style to use for the line. + */ + public static XYLineAnnotation createLeftStickAnnotation( + ChartArea area, float pos, LineStyle lineStyle + ) { + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + area.atLeft(), pos, + area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + area.atLeft(), pos, + area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos); + } + } + + + /** + * Create a line from a axis to a given point. + * @param axis The "simple" axis. + * @param fromD1 from-location in first dimension. + * @param toD2 to-location in second dimension. + * @param area helper to calculate offsets. + * @param lineStyle optional line style. + */ + public static XYLineAnnotation createStickyLineAnnotation( + StickyAxisAnnotation.SimpleAxis axis, float fromD1, float toD2, + ChartArea area, LineStyle lineStyle + ) { + double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d; + switch(axis) { + case X_AXIS: + anchorX1 = fromD1; + anchorX2 = fromD1; + anchorY1 = area.atGround(); + anchorY2 = toD2; + break; + case Y_AXIS: + anchorX1 = area.atLeft(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + case Y_AXIS2: + anchorX1 = area.atRight(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + } + // Style the line. + if (lineStyle != null) { + return new XYLineAnnotation( + anchorX1, anchorY1, + anchorX2, anchorY2, + new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + } + else { + return new XYLineAnnotation( + anchorX1, anchorY1, + anchorX2, anchorY2); + } + } + +}; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,127 @@ +/* Copyright (C) 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * XYDatasethis file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUXYDatasetELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.jfree; + +import java.util.List; +import java.util.ArrayList; + +import org.jfree.data.Range; +import org.jfree.data.RangeInfo; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.data.time.TimeSeriesCollection; + +import org.apache.log4j.Logger; + +/** + * Axis datasets. + */ +public class AxisDataset +{ + private static Logger logger = Logger.getLogger(AxisDataset.class); + + /** Symbolic integer, but also coding the priority (0 goes first). */ + protected int axisSymbol; + + /** List of assigned datasets (in order). */ + protected List<XYDataset> datasets; + + /** Range to use to include all given datasets. */ + protected Range range; + + /** Index of axis in plot. */ + protected int plotAxisIndex; + + protected boolean rangeDirty; + + /** Create AxisDataset. */ + public AxisDataset(int symb) { + axisSymbol = symb; + datasets = new ArrayList<XYDataset>(); + } + + /** Add a dataset to internal list for this axis. */ + public void addDataset(XYDataset dataset) { + datasets.add(dataset); + rangeDirty = true; + } + + /** Add a dataset. */ + public void addDataset(XYSeries series) { + addDataset(new XYSeriesCollection(series)); + } + + public void setRange(Range val) { + range = val; + } + + /** Get Range for the range axis of this dataset. */ + public Range getRange() { + if (range != null && !rangeDirty) { + return range; + } + /* Calculate the min / max of all series */ + for (XYDataset dataset: datasets) { + Range newRange = null; + if (dataset instanceof StyledAreaSeriesCollection) { + /* We do not include areas in the range calculation because + * they are used with very large / small values to draw areas + * with axis boundaries */ + continue; + } else if (dataset instanceof RangeInfo) { + /* The usual case for most series */ + newRange = ((RangeInfo) dataset).getRangeBounds(false); + } else if (dataset instanceof TimeSeriesCollection) { + /* Lalala <3 Jfreechart's class hirarchy */ + newRange = ((TimeSeriesCollection) dataset).getRangeBounds(false); + } + + /* Now we only expand as we also only add new data */ + if (range == null) { + range = newRange; + } else { + range = Range.combine(range, newRange); + } + } + rangeDirty = false; + return range; + } + + /** Get Array of Datasets. */ + public XYDataset[] getDatasets() { + return datasets.toArray(new XYDataset[datasets.size()]); + } + + /** True if to be rendered as area. */ + public boolean isArea(XYDataset series) { + return (series instanceof StyledAreaSeriesCollection); + } + + /** True if no datasets given. */ + public boolean isEmpty() { + return datasets.isEmpty(); + } + + /** Set the 'real' axis index that this axis is mapped to. */ + public void setPlotAxisIndex(int axisIndex) { + plotAxisIndex = axisIndex; + } + + /** Get the 'real' axis index that this axis is mapped to. */ + public int getPlotAxisIndex() { + return plotAxisIndex; + } + + /** Add a Dataset that describes an area. */ + public void addArea(StyledAreaSeriesCollection series) { + addDataset(series); + } + +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/JFreeUtil.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/JFreeUtil.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/JFreeUtil.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,9 +16,9 @@ import org.apache.log4j.Logger; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.EntityCollection; -import org.w3c.dom.Document; import org.dive4elements.river.artifacts.math.Function; +import org.dive4elements.river.themes.ThemeDocument; public class JFreeUtil { @@ -107,7 +107,7 @@ public static StyledXYSeries sampleFunction2D( Function func, - Document theme, + ThemeDocument theme, String seriesKey, int samples, double start, @@ -127,7 +127,7 @@ public static StyledXYSeries sampleFunction2DPositive( Function func, - Document theme, + ThemeDocument theme, String seriesKey, int samples, double start, diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/RiverAnnotation.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/RiverAnnotation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/RiverAnnotation.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,12 +9,12 @@ package org.dive4elements.river.jfree; import org.dive4elements.river.artifacts.model.HYKFactory; +import org.dive4elements.river.themes.ThemeDocument; import java.util.Collections; import java.util.List; import org.jfree.chart.annotations.XYTextAnnotation; -import org.w3c.dom.Document; /** * List of Text- Annotations (Sticky to one axis or in space) @@ -32,7 +32,7 @@ protected List<HYKFactory.Zone> boxes; /** Styling information. */ - protected Document theme; + protected ThemeDocument theme; /** Chart-legend information. */ protected String label; @@ -53,7 +53,7 @@ /** Create annotations, parameter might be null. */ public RiverAnnotation(String label, List<StickyAxisAnnotation> annotations, - List<HYKFactory.Zone> bAnnotations, Document theme + List<HYKFactory.Zone> bAnnotations, ThemeDocument theme ) { this.label = label; this.axisTextAnnotations = (annotations != null) @@ -92,11 +92,11 @@ return boxes; } - public void setTheme(Document theme) { + public void setTheme(ThemeDocument theme) { this.theme = theme; } - public Document getTheme() { + public ThemeDocument getTheme() { return theme; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StickyAxisAnnotation.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StickyAxisAnnotation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StickyAxisAnnotation.java Fri Sep 27 17:36:50 2013 +0200 @@ -70,7 +70,7 @@ * Constructor with given explicit axis and axisSymbol * @param text the text to display. * @param pos the position at which to draw the text and mark. - * @param stickAxis the axis at which to stick (and to which 'pos' is + * @param stickAxis the axis at which to stick (and to which 'pos' is * relative). */ public StickyAxisAnnotation(String text, float pos, SimpleAxis stickAxis, diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Fri Sep 27 17:36:50 2013 +0200 @@ -13,11 +13,8 @@ import java.awt.Stroke; import org.jfree.data.xy.XYSeriesCollection; -import org.w3c.dom.Document; -import org.dive4elements.river.themes.ThemeAccess; -import org.dive4elements.river.utils.ThemeUtil; - +import org.dive4elements.river.themes.ThemeDocument; /** * One or more dataseries to draw a polygon (either "open up/downwards", or @@ -36,13 +33,13 @@ protected FILL_MODE mode; /** The theme-document with attributes about actual visual representation. */ - protected Document theme; + protected ThemeDocument theme; /** * @param theme the theme-document. */ - public StyledAreaSeriesCollection(Document theme) { + public StyledAreaSeriesCollection(ThemeDocument theme) { this.theme = theme; this.mode = FILL_MODE.BETWEEN; } @@ -73,7 +70,7 @@ applyShowShape(renderer); applyOutlineColor(renderer); applyOutlineStyle(renderer); - applyShowArea(renderer); + applyShowAreaLabel(renderer); if (mode == FILL_MODE.UNDER) { renderer.setAreaCalculationMode(StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA); } @@ -85,16 +82,15 @@ } // Apply text style. - new ThemeAccess(theme).parseTextStyle().apply(renderer); + theme.parseComplexTextStyle().apply(renderer); return renderer; } protected void applyFillColor(StableXYDifferenceRenderer renderer) { - Color paint = ThemeUtil.parseColor( - ThemeUtil.getAreaBackgroundColorString(theme)); + Color paint = theme.parseAreaBackgroundColor(); - int transparency = ThemeUtil.parseAreaTransparency(theme); + int transparency = theme.parseAreaTransparency(); if (transparency > 0 && paint != null) { paint = new Color( paint.getRed(), @@ -121,34 +117,35 @@ protected void applyShowShape(StableXYDifferenceRenderer renderer) { - boolean show = ThemeUtil.parseAreaShowBorder(theme); + boolean show = theme.parseAreaShowBorder(); renderer.setDrawOutline(show); } protected void applyShowLine(StableXYDifferenceRenderer renderer) { - boolean show = ThemeUtil.parseShowLine(theme); + boolean show = theme.parseShowLine(); renderer.setShapesVisible(show); } protected void applyOutlineColor(StableXYDifferenceRenderer renderer) { - Color c = ThemeUtil.parseLineColorField(theme); + Color c = theme.parseLineColorField(); renderer.setOutlinePaint(c); } protected void applyOutlineWidth(StableXYDifferenceRenderer renderer) { - int size = ThemeUtil.parseLineWidth(theme); + // int size = theme.parseLineWidth(); + // XXX: Why is this not set? } /** Inform renderer whether it should draw a label. */ - protected void applyShowArea(StableXYDifferenceRenderer renderer) { - renderer.setLabelArea(ThemeUtil.parseShowArea(theme)); + protected void applyShowAreaLabel(StableXYDifferenceRenderer renderer) { + renderer.setLabelArea(theme.parseShowAreaLabel()); } protected void applyOutlineStyle(StableXYDifferenceRenderer renderer) { - float[] dashes = ThemeUtil.parseLineStyle(theme); - int size = ThemeUtil.parseLineWidth(theme); + float[] dashes = theme.parseLineStyle(); + int size = theme.parseLineWidth(); Stroke stroke = null; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,9 +11,8 @@ import java.awt.Color; import org.jfree.chart.plot.IntervalMarker; -import org.w3c.dom.Document; -import org.dive4elements.river.utils.ThemeUtil; +import org.dive4elements.river.themes.ThemeDocument; /** * Marker that represents a highlighted interval. @@ -26,19 +25,17 @@ private final Color backgroundColor, backgroundColor2; - public StyledDomainMarker(double start, double end, Document theme) { + public StyledDomainMarker(double start, double end, ThemeDocument theme) { super(start, end); - backgroundColor = ThemeUtil.parseColor( - ThemeUtil.getAreaBackgroundColorString(theme)); + backgroundColor = theme.parseAreaBackgroundColor(); backgroundColor2 = new Color( 255 - backgroundColor.getRed(), 255 - backgroundColor.getGreen(), 255 - backgroundColor.getBlue()); useSecondColor(false); - int alpha = 100 - ThemeUtil.parseInteger( - ThemeUtil.getAreaTransparencyString(theme), 50); + int alpha = 100 - theme.parseAreaTransparency(50); setAlpha(alpha / 100.0f); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StyledTimeSeries.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledTimeSeries.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledTimeSeries.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,8 +9,7 @@ package org.dive4elements.river.jfree; import org.apache.log4j.Logger; - -import org.w3c.dom.Document; +import org.dive4elements.river.themes.ThemeDocument; import org.jfree.data.time.TimeSeries; @@ -27,7 +26,7 @@ protected Style style; - public StyledTimeSeries(String key, Document theme) { + public StyledTimeSeries(String key, ThemeDocument theme) { super(key); setStyle(new XYStyle(theme)); } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StyledValueMarker.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledValueMarker.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledValueMarker.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,13 +8,12 @@ package org.dive4elements.river.jfree; -import org.dive4elements.river.utils.ThemeUtil; +import org.dive4elements.river.themes.ThemeDocument; import java.awt.BasicStroke; import java.awt.Color; import org.jfree.chart.plot.ValueMarker; -import org.w3c.dom.Document; /** * Marker that represents a single value. @@ -24,16 +23,16 @@ private static final long serialVersionUID = -3607777705307785140L; - public StyledValueMarker(double value, Document theme) { + public StyledValueMarker(double value, ThemeDocument theme) { super(value); - Color color = ThemeUtil.parseAreaBackgroundColor(theme); + Color color = theme.parseAreaBackgroundColor(); if(color == null) { color = Color.BLACK; } this.setPaint(color); - int size = ThemeUtil.parsePointWidth(theme); + int size = theme.parsePointWidth(); setStroke(new BasicStroke(size)); } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Fri Sep 27 17:36:50 2013 +0200 @@ -11,8 +11,7 @@ import java.util.List; import org.apache.log4j.Logger; - -import org.w3c.dom.Document; +import org.dive4elements.river.themes.ThemeDocument; import org.jfree.data.xy.XYDataItem; import org.jfree.data.xy.XYSeries; @@ -30,13 +29,13 @@ protected String label; - public StyledXYSeries(String key, Document theme) { + public StyledXYSeries(String key, ThemeDocument theme) { this(key, true, theme); this.label = key.toString(); } - public StyledXYSeries(String key, Document theme, XYSeries unstyledSeries) { + public StyledXYSeries(String key, ThemeDocument theme, XYSeries unstyledSeries) { this(key, theme); add(unstyledSeries); } @@ -47,12 +46,24 @@ * to one extrema which can cause problems in certain * algorithms. */ - public StyledXYSeries(String key, boolean sorted, Document theme) { + public StyledXYSeries(String key, boolean sorted, ThemeDocument theme) { super(key, sorted); setStyle(new XYStyle(theme)); this.label = key.toString(); } + public StyledXYSeries( + String key, + boolean sorted, + boolean allowDuplicateXValues, + ThemeDocument theme + ) { + super(key, sorted, allowDuplicateXValues); + setStyle(new XYStyle(theme)); + this.label = key.toString(); + } + + @Override public void setStyle(Style style) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/jfree/XYStyle.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/XYStyle.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/XYStyle.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,7 +8,7 @@ package org.dive4elements.river.jfree; -import org.dive4elements.river.utils.ThemeUtil; +import org.dive4elements.river.themes.ThemeDocument; import java.awt.BasicStroke; import java.awt.Color; @@ -16,7 +16,6 @@ import org.apache.log4j.Logger; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.w3c.dom.Document; /** @@ -27,14 +26,13 @@ private static Logger logger = Logger.getLogger(XYStyle.class); - protected Document theme; + protected ThemeDocument theme; protected XYLineAndShapeRenderer renderer; - public XYStyle(Document theme) { + public XYStyle(ThemeDocument theme) { this.theme = theme; - this.renderer = null; } @@ -43,7 +41,11 @@ * whether to draw lines and/or points. */ @Override - public XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx){ + public XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx) { + if (theme == null) { + // Hurray we already applied nothing :) + return r; + } this.renderer = r; applyLineColor(r, idx); applyLineSize(r, idx); @@ -76,7 +78,7 @@ /** Set line color to renderer. */ protected void applyLineColor(XYLineAndShapeRenderer r, int idx) { - Color c = ThemeUtil.parseLineColorField(theme); + Color c = theme.parseLineColorField(); if(c != null) { logger.debug("applyLineColor " + c.toString()); r.setSeriesPaint(idx, c); @@ -92,10 +94,10 @@ if (!(r instanceof EnhancedLineAndShapeRenderer)) { return; } - boolean showLabelLine = ThemeUtil.parseShowLineLabel(theme); - boolean anyLabel = showLabelLine || ThemeUtil.parseShowWidth(theme) || - ThemeUtil.parseShowLevel(theme) || - ThemeUtil.parseShowMiddleHeight(theme); + boolean showLabelLine = theme.parseShowLineLabel(); + boolean anyLabel = showLabelLine || theme.parseShowWidth() || + theme.parseShowLevel() || + theme.parseShowMiddleHeight(); ((EnhancedLineAndShapeRenderer)r).setShowLineLabel(anyLabel, idx); } @@ -105,7 +107,7 @@ if (!(r instanceof EnhancedLineAndShapeRenderer)) { return; } - boolean showLabelLine = ThemeUtil.parseLabelShowBackground(theme); + boolean showLabelLine = theme.parseLabelShowBackground(); ((EnhancedLineAndShapeRenderer)r).setShowLineLabelBG(idx, showLabelLine); } @@ -116,7 +118,7 @@ return; } ((EnhancedLineAndShapeRenderer)r).setLineLabelFont( - ThemeUtil.parseTextFont(theme), idx); + theme.parseTextFont(), idx); } /** Tell the renderer which color to use for @@ -126,7 +128,7 @@ return; } ((EnhancedLineAndShapeRenderer)r).setLineLabelTextColor( - idx, ThemeUtil.parseTextColor(theme)); + idx, theme.parseTextColor()); } /** Tell the renderer which color to use for bg of @@ -136,12 +138,12 @@ return; } ((EnhancedLineAndShapeRenderer)r).setLineLabelBGColor(idx, - ThemeUtil.parseTextBackground(theme)); + theme.parseTextBackground()); } /** Set stroke of series. */ protected void applyLineSize(XYLineAndShapeRenderer r, int idx) { - int size = ThemeUtil.parseLineWidth(theme); + int size = theme.parseLineWidth(); r.setSeriesStroke( idx, new BasicStroke(size)); @@ -150,8 +152,8 @@ /** Set stroke strength of series. */ protected void applyLineType(XYLineAndShapeRenderer r, int idx) { - int size = ThemeUtil.parseLineWidth(theme); - float[] dashes = ThemeUtil.parseLineStyle(theme); + int size = theme.parseLineWidth(); + float[] dashes = theme.parseLineStyle(); // Do not apply the dashed style. if (dashes.length <= 1) { @@ -170,7 +172,7 @@ protected void applyPointSize(XYLineAndShapeRenderer r, int idx) { - int size = ThemeUtil.parsePointWidth(theme); + int size = theme.parsePointWidth(); int dim = 2 * size; r.setSeriesShape(idx, new Ellipse2D.Double(-size, -size, dim, dim)); @@ -178,7 +180,7 @@ protected void applyPointColor(XYLineAndShapeRenderer r, int idx) { - Color c = ThemeUtil.parsePointColor(theme); + Color c = theme.parsePointColor(); if (c != null) { r.setSeriesFillPaint(idx, c); @@ -192,7 +194,7 @@ * Sets form and visibility of points. */ protected void applyShowPoints(XYLineAndShapeRenderer r, int idx) { - boolean show = ThemeUtil.parseShowPoints(theme); + boolean show = theme.parseShowPoints(); r.setSeriesShapesVisible(idx, show); r.setDrawOutlines(true); @@ -200,7 +202,7 @@ protected void applyShowLine(XYLineAndShapeRenderer r, int idx) { - boolean show = ThemeUtil.parseShowLine(theme); + boolean show = theme.parseShowLine(); r.setSeriesLinesVisible(idx, show); } @@ -210,7 +212,7 @@ return; } - boolean visible = ThemeUtil.parseShowMinimum(theme); + boolean visible = theme.parseShowMinimum(); EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r; er.setIsMinimumShapeVisisble(idx, visible); @@ -222,7 +224,7 @@ return; } - boolean visible = ThemeUtil.parseShowMaximum(theme); + boolean visible = theme.parseShowMaximum(); EnhancedLineAndShapeRenderer er = (EnhancedLineAndShapeRenderer) r; er.setIsMaximumShapeVisible(idx, visible); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/themes/TextStyle.java --- a/artifacts/src/main/java/org/dive4elements/river/themes/TextStyle.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/TextStyle.java Fri Sep 27 17:36:50 2013 +0200 @@ -37,12 +37,16 @@ } public void apply(XYTextAnnotation ta) { - ta.setPaint(textColor); - ta.setFont(font); - if (this.showBg) { + if (textColor != null) { + ta.setPaint(textColor); + } + if (font != null) { + ta.setFont(font); + } + if (showBg) { ta.setBackgroundPaint(bgColor); } - if (this.isVertical) { + if (isVertical) { ta.setRotationAngle(270f*Math.PI/180f); } else { @@ -57,4 +61,4 @@ renderer.setLabelBGColor(bgColor); } } -} \ No newline at end of file +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/themes/ThemeAccess.java --- a/artifacts/src/main/java/org/dive4elements/river/themes/ThemeAccess.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* 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.themes; - -import org.dive4elements.river.utils.ThemeUtil; - -import java.awt.Color; -import java.awt.Font; - -import org.w3c.dom.Document; - - -public class ThemeAccess -{ - protected Document theme; - - protected Integer lineWidth; - - protected Color lineColor; - protected Color textColor; - protected Font font; - protected String textOrientation; - protected Color textBackground; - protected Boolean showTextBackground; - protected Color pointColor; - - - public ThemeAccess(Document theme) { - this.theme = theme; - } - - - public int parseLineWidth() { - if (lineWidth == null) { - lineWidth = ThemeUtil.parseLineWidth(theme); - } - return lineWidth; - } - - - public Color parseLineColorField() { - if (lineColor == null) { - lineColor = ThemeUtil.parseLineColorField(theme); - if (lineColor == null) { - lineColor = Color.BLACK; - } - } - return lineColor; - } - - - public Color parseTextColor() { - if (textColor == null) { - textColor = ThemeUtil.parseTextColor(theme); - if (textColor == null) { - textColor = Color.BLACK; - } - } - return textColor; - } - - - public Font parseTextFont() { - if (font == null) { - font = ThemeUtil.parseTextFont(theme); - if (font == null) { - font = new Font("Arial", Font.BOLD, 10); - } - } - return font; - } - - - public String parseTextOrientation() { - if (textOrientation == null) { - textOrientation = ThemeUtil.parseTextOrientation(theme); - } - return textOrientation; - } - - - public Color parseTextBackground() { - if (textBackground == null) { - textBackground = ThemeUtil.parseTextBackground(theme); - if (textBackground == null) { - textBackground = Color.WHITE; - } - } - return textBackground; - } - - public boolean parseLabelShowBackground() { - if (showTextBackground == null) { - showTextBackground = ThemeUtil.parseLabelShowBackground(theme); - } - return showTextBackground; - } - - - public Color parsePointColor() { - if (pointColor == null) { - pointColor = ThemeUtil.parsePointColor(theme); - - if (pointColor == null) { - return parseLineColorField(); - } - } - - return pointColor; - } - - - public LineStyle parseLineStyle() { - return new LineStyle(parseLineColorField(), Integer.valueOf(parseLineWidth())); - } - - public TextStyle parseTextStyle() { - return new TextStyle( - parseTextColor(), - parseTextFont(), - parseTextBackground(), - parseLabelShowBackground(), - !parseTextOrientation().equals("horizontal")); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,745 @@ +/* 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.themes; + +import java.awt.Color; +import java.awt.Font; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.river.artifacts.model.MapserverStyle; +import org.dive4elements.river.artifacts.model.MapserverStyle.Clazz; +import org.dive4elements.river.artifacts.model.MapserverStyle.Expression; +import org.dive4elements.river.artifacts.model.MapserverStyle.Label; +import org.dive4elements.river.artifacts.model.MapserverStyle.Style; +import org.dive4elements.river.artifacts.resources.Resources; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class ThemeDocument +{ + private static Logger logger = Logger.getLogger(ThemeDocument.class); + + private static final String MSG_ISOBATH_CLASS = "floodmap.isobath.class"; + + private static final String MSG_ISOBATH_LASTCLASS = "floodmap.isobath.lastclass"; + + public final static String FILL_COLOR = "fillcolor"; + + public final static String LINE_COLOR = "linecolor"; + + public final static String AREA_LINE_COLOR = "areabordercolor"; + + public static final String LINE_SIZE = "linesize"; + + public static final String LINE_STYLE = "linetype"; + + public static final String POINT_SIZE = "pointsize"; + + public static final String POINT_COLOR = "pointcolor"; + + public final static String SHOW_BORDER = "showborder"; + + public final static String AREA_SHOW_BORDER = "showborder"; + + public final static String SHOW_POINTS = "showpoints"; + + public final static String SHOW_LINE = "showlines"; + + public final static String SHOW_VERTICAL_LINE = "showverticalline"; + + public final static String SHOW_HORIZONTAL_LINE = "showhorizontalline"; + + public final static String SHOW_LINE_LABEL = "showlinelabel"; + + public final static String SHOW_POINT_LABEL = "showpointlabel"; + + public final static String SHOW_WIDTH = "showwidth"; + + public final static String SHOW_LEVEL = "showlevel"; + + public final static String TRANSPARENCY = "transparency"; + + public final static String AREA_TRANSPARENCY = "areatransparency"; + + public final static String SHOW_AREA = "showarea"; + + public final static String SHOW_AREA_LABEL = "showarealabel"; + + public final static String SHOW_MIDDLE_HEIGHT = "showmiddleheight"; + + public final static String LABEL_FONT_COLOR = "labelfontcolor"; + + public final static String LABEL_FONT_SIZE = "labelfontsize"; + + public final static String LABEL_FONT_FACE = "labelfontface"; + + public final static String LABEL_FONT_STYLE = "labelfontstyle"; + + public final static String TEXT_ORIENTATION = "textorientation"; + + public final static String LABEL_BGCOLOR = "labelbgcolor"; + + public final static String LABEL_SHOW_BACKGROUND = "labelshowbg"; + + public final static String BACKGROUND_COLOR = "backgroundcolor"; + + public final static String AREA_BACKGROUND_COLOR = "areabgcolor"; + + public final static String SYMBOL = "symbol"; + + public final static String SHOW_MINIMUM = "showminimum"; + + public final static String SHOW_MAXIMUM = "showmaximum"; + + public final static String WSPLGEN_STARTCOLOR = "startcolor"; + + public final static String WSPLGEN_ENDCOLOR = "endcolor"; + + public final static String WSPLGEN_NUMCLASSES = "numclasses"; + + public final static String BANDWIDTH = "bandwidth"; + + public final static String SHOWEXTRAMARK = "showextramark"; + + + private Document document; + + private Map<String, String> values; + + public ThemeDocument() { + } + + public ThemeDocument(Document document) { + this.document = document; + values = extractValues(document); + } + + public Document getDocument() { + return document; + } + + private String getValue(String key) { + return values.get(key); + } + + private static Map<String, String> extractValues(Document document) { + Map<String, String> values = new HashMap<String, String>(); + if (document == null) { + logger.error("Invalid null document given."); + return values; + } + + NodeList fields = document.getElementsByTagName("field"); + for (int i = 0, N = fields.getLength(); i < N; ++i) { + Element field = (Element)fields.item(i); + String name = field.getAttribute("name"); + String value = field.getAttribute("default"); + if (!name.isEmpty() && !value.isEmpty()) { + values.put(name, value); + } + } + if (logger.isDebugEnabled()) { + logger.debug("Theme values: " + values); + } + return values; + } + + /** Parse string to be boolean with default if empty or unrecognized. */ + private static boolean parseBoolean(String value, boolean defaultsTo) { + if (value == null) { + return defaultsTo; + } + if (value.equals("false")) { + return false; + } + if (value.equals("true")) { + return true; + } + return defaultsTo; + } + + + /** + * Attempt converting \param value to an integer, in failing cases, + * return \param defaultsTo. + * @param value String to be converted to integer. + * @param defaultsTo Default to return if conversion failed. + * @return \param value as integer or defaultsto if conversion failed. + */ + private static int parseInteger(String value, int defaultsTo) { + if (value == null) { + return defaultsTo; + } + + try { + return Integer.parseInt(value); + } + catch (NumberFormatException nfe) { + // do nothing + } + + return defaultsTo; + } + + + /** + * Attempt converting \param value to a double, in failing cases, + * return \param defaultsTo. + * @param value String to be converted to double. + * @param defaultsTo Default to return if conversion failed. + * @return \param value as integer or defaultsto if conversion failed. + */ + private static double parseDouble(String value, double defaultsTo) { + if (value == null) { + return defaultsTo; + } + + try { + return Double.parseDouble(value); + } + catch (NumberFormatException nfe) { + // do nothing + } + + return defaultsTo; + } + + public boolean parseShowLineLabel() { + String show = getValue(SHOW_LINE_LABEL); + return parseBoolean(show, false); + } + + public boolean parseShowWidth() { + String show = getValue(SHOW_WIDTH); + return parseBoolean(show, false); + } + + public boolean parseShowLevel() { + String show = getValue(SHOW_LEVEL); + return parseBoolean(show, false); + } + + public String parseTextOrientation() { + String o = getValue(TEXT_ORIENTATION); + + return o != null && "true".equals(o) + ? "horizontal" + : "vertical"; + } + + public boolean parseShowMiddleHeight() { + String show = getValue(SHOW_MIDDLE_HEIGHT); + return parseBoolean(show, false); + } + + public boolean parseLabelShowBackground() { + String show = getValue(LABEL_SHOW_BACKGROUND); + return parseBoolean(show, false); + } + + public Font parseTextFont() { + String font = getValue(LABEL_FONT_FACE); + if (font == null) { + return null; + } + + int size = parseTextSize(); + int style = parseTextStyle(); + Font f = new Font(font, style, size); + return f; + } + + public Color parseTextColor() { + return parseRGB(getTextColorString()); + } + + private String getTextColorString() { + return getValue(LABEL_FONT_COLOR); + } + + public Color parseTextBackground() { + String color = getLabelBackgroundColorString(); + return color != null + ? parseRGB(color) + : Color.WHITE; + } + + private String getLabelBackgroundColorString() { + return getValue(LABEL_BGCOLOR); + } + + public int parseLineWidth() { + String size = getValue(LINE_SIZE); + if (size == null) { + return 0; + } + + try { + return Integer.parseInt(size); + } + catch (NumberFormatException nfe) { + logger.warn("Unable to set line size from string: '" + size + "'"); + } + return 0; + } + + public float [] parseLineStyle() { + String dash = getValue(LINE_STYLE); + + float[] def = {10}; + if (dash == null) { + return def; + } + + String[] pattern = dash.split(","); + if(pattern.length == 1) { + return def; + } + + try { + float[] dashes = new float[pattern.length]; + for (int i = 0; i < pattern.length; i++) { + dashes[i] = Float.parseFloat(pattern[i]); + } + return dashes; + } + catch (NumberFormatException nfe) { + logger.warn("Unable to set dash from string: '" + dash + "'"); + return def; + } + } + + public int parsePointWidth() { + String width = getValue(POINT_SIZE); + return parseInteger(width, 3); + } + + public Color parsePointColor() { + String color = getValue(POINT_COLOR); + return parseColor(color); + } + + public boolean parseShowPoints() { + String show = getValue(SHOW_POINTS); + return parseBoolean(show, false); + } + + public boolean parseShowLine() { + String show = getValue(SHOW_LINE); + return parseBoolean(show, true); + } + + public int parseTextStyle() { + String style = getValue(LABEL_FONT_STYLE); + if (style == null) { + return Font.PLAIN; + } + + if (style.equals("italic")) { + return Font.ITALIC; + } + if (style.equals("bold")) { + return Font.BOLD; + } + return Font.PLAIN; + } + + public TextStyle parseComplexTextStyle() { + return new TextStyle( + parseTextColor(), + parseTextFont(), + parseTextBackground(), + parseLabelShowBackground(), + !parseTextOrientation().equals("horizontal")); + } + + public LineStyle parseComplexLineStyle() { + return new LineStyle( + parseLineColorField(), + Integer.valueOf(parseLineWidth())); + } + + public boolean parseShowVerticalLine() { + String show = getValue(SHOW_VERTICAL_LINE); + return parseBoolean(show, true); + } + + public boolean parseShowHorizontalLine() { + String show = getValue(SHOW_HORIZONTAL_LINE); + return parseBoolean(show, true); + } + + public double parseBandWidth() { + String bandWidth = getValue(BANDWIDTH); + return parseDouble(bandWidth, 0); + } + + private static Color parseColor(String colorString) { + if (colorString == null) { + return null; + } + if (colorString.indexOf("#") == 0) { + return parseHexColor(colorString); + } + if (colorString.indexOf(",") >= 0) { + return parseRGB(colorString); + } + + return null; + } + + + /** + * Parse a string like "#00CC22" and return the corresponding color. + * + * @param hex The hex color value. + * + * @return a Color or null, if <i>hex</i> is empty. + */ + private static Color parseHexColor(String hex) { + return hex != null + ? Color.decode(hex) + : null; + } + + + public boolean parseShowArea() { + String show = getValue(SHOW_AREA); + return parseBoolean(show, false); + } + + public boolean parseShowAreaLabel() { + String show = getValue(SHOW_AREA_LABEL); + return parseBoolean(show, false); + } + + public boolean parseShowPointLabel() { + String show = getValue(SHOW_POINT_LABEL); + return parseBoolean(show, false); + } + + public boolean parseShowExtraMark() { + String show = getValue(SHOWEXTRAMARK); + return parseBoolean(show, false); + } + + public int parseTextSize() { + String size = getValue(LABEL_FONT_SIZE); + if (size == null) { + return 10; + } + + try { + return Integer.parseInt(size); + } + catch (NumberFormatException nfe) { + // Do nothing + } + return 10; + } + + /** + * Parse a string like "103, 100, 0" and return a corresping color. + * @param rgbtext Color as string representation, e.g. "255,0,20". + * @return Color, null in case of issues. + */ + public static Color parseRGB(String rgbtext) { + if (rgbtext == null) { + return null; + } + String rgb[] = rgbtext.split(","); + try { + return new Color( + Integer.parseInt(rgb[0].trim()), + Integer.parseInt(rgb[1].trim()), + Integer.parseInt(rgb[2].trim())); + } + catch (NumberFormatException nfe) { + // Do nothing + } + return null; + } + + private String getLineColorString() { + return getValue(LINE_COLOR); + } + + + /** Get show border as string. */ + private String getShowBorderString() { + return getValue(SHOW_BORDER); + } + + + /** Get fill color as string. */ + private String getFillColorString() { + return getValue(FILL_COLOR); + } + + private String getSymbol() { + return getValue(SYMBOL); + } + + private String getTransparencyString() { + return getValue(TRANSPARENCY); + } + + + private String getAreaTransparencyString() { + return getValue(AREA_TRANSPARENCY); + } + + + private String getShowMinimum() { + return getValue(SHOW_MINIMUM); + } + + + private String getShowMaximum() { + return getValue(SHOW_MAXIMUM); + } + + /** + * Gets color from color field. + * @param theme the theme document. + * @return color. + */ + public Color parseFillColorField() { + return parseRGB(getFillColorString()); + } + + public boolean parseShowBorder() { + return parseBoolean(getShowBorderString(), false); + } + + public int parseTransparency() { + return parseInteger(getTransparencyString(), 50); + } + + + /** + * Gets color from color field. + * @return color. + */ + public Color parseLineColorField() { + String lineColorStr = getLineColorString(); + if (logger.isDebugEnabled()) { + logger.debug("parseLineColorField: lineColorStr = " + + (lineColorStr == null + ? "null" + : lineColorStr)); + } + return parseColor(lineColorStr); + } + + + public Color parseAreaLineColorField() { + String lineColorStr = getAreaLineColorString(); + if (logger.isDebugEnabled()) { + logger.debug("parseLineColorField: lineColorStr = " + + (lineColorStr == null + ? "null" + : lineColorStr)); + } + return parseColor(lineColorStr); + } + + + private String getAreaLineColorString() { + return getValue(AREA_LINE_COLOR); + } + + + public boolean parseShowMinimum() { + return parseBoolean(getShowMinimum(), false); + } + + + public boolean parseShowMaximum() { + return parseBoolean(getShowMaximum(), false); + } + + + /** + * Creates a MapserverStyle from the given XML theme. + * This method uses a start- and endcolor to interpolate a + * given number of color classes for the MapserverStyle. + * @param theme + * @return String representation of the MapserverStyle + */ + public String createDynamicMapserverStyle( + float from, + float to, + float step, + CallMeta meta + ) { + MapserverStyle ms = new MapserverStyle(); + + String strStartColor = getValue(WSPLGEN_STARTCOLOR); + Color startColor = strStartColor != null + ? parseColor(strStartColor) + : new Color(178, 201, 215); + String strEndColor = getValue(WSPLGEN_ENDCOLOR); + Color endColor = strEndColor != null + ? parseColor(strEndColor) + : new Color(2, 27, 42); + + to = to != 0 ? to : 9999; + step = step != 0 ? step : to; + + int numClasses = (int)((to - from) / step); + + float rd = (endColor.getRed() - startColor.getRed()) / (float)numClasses; + float gd = (endColor.getGreen() - startColor.getGreen()) / (float)numClasses; + float bd = (endColor.getBlue() - startColor.getBlue()) / (float)numClasses; + + if (numClasses > 1) { + // Desktop Flys always added a last "and larger class" + numClasses += 1; + } + + for (int n = 0; n < numClasses; n++) { + StringBuilder newColor = new StringBuilder(); + newColor.append(startColor.getRed() + Math.round(n * rd)); + newColor.append(' '); + newColor.append(startColor.getGreen() + Math.round(n * gd)); + newColor.append(' '); + newColor.append(startColor.getBlue() + Math.round(n * bd)); + + String expr = createWSPLGENClassExpression(from + n * step, step, n + 1, numClasses); + String name = createWSPLGENClassName(from + n * step, step, n + 1, numClasses, meta); + + Clazz c = new Clazz(name); + Style s = new Style(); + s.setColor(newColor.toString()); + s.setSize(5); + + c.addItem(new Expression("(" + expr + ")")); + c.addItem(s); + + ms.addClazz(c); + } + + return ms.toString(); + } + + + protected static String createWSPLGENClassExpression(float val, float step, int idx, int maxIdx) { + if (idx < maxIdx) { + return "[DIFF] >= " + val + " AND [DIFF] < " + (val + step); + } + else { + return "[DIFF] >= " + val; + } + } + + /** + * Creates a class name for the mapfile style that visualizes a floodmap. + * The class names are used in the map's legend. + * + * @param val Current isobath value. + * @param step Difference between to class values. + * @param idx Current class index that is being processed. + * @param maxIdx Highest class index. + * @param meta Caller meta object used to determine locale. + * @return + */ + protected static String createWSPLGENClassName( + float val, + float step, + int idx, + int maxIdx, + CallMeta meta + ) { + assert meta != null : "CallMeta instance is null"; + + if (idx < maxIdx) { + return Resources.getMsg(meta, MSG_ISOBATH_CLASS, + new Object[] {val, val + step}); + } + return Resources.getMsg(meta, MSG_ISOBATH_LASTCLASS, + new Object[] {val}); + } + + + public String createMapserverStyle() { + String symbol = getSymbol(); + String backcolor = getLabelBackgroundColorString(); + String linecolor = getLineColorString(); + if (linecolor == null) { + logger.warn("createMapserverStyle: linecolor String is empty"); + linecolor = "0,128,255"; + } + + int linewidth = parseLineWidth(); + + MapserverStyle ms = new MapserverStyle(); + + Clazz c = new Clazz(" "); + + Style s = new Style(); + s.setOutlineColor(linecolor.replace(",", " ")); + + if (backcolor != null) { + s.setColor(backcolor.replace(",", " ")); + } + + s.setSize(linewidth); + s.setSymbol(symbol); + c.addItem(s); + + String textcolor = getTextColorString(); + int textsize = parseTextSize(); + + if (textcolor != null && textsize > 0) { + Label l = new Label(); + l.setColor(textcolor.replace(",", " ")); + l.setSize(textsize); + c.addItem(l); + } + + ms.addClazz(c); + + return ms.toString(); + } + + + private String getAreaBackgroundColorString() { + return getValue(AREA_BACKGROUND_COLOR); + } + + + public Color parseAreaBackgroundColor() { + return parseColor(getAreaBackgroundColorString()); + } + + + public int parseAreaTransparency() { + return parseAreaTransparency(50); + } + + public int parseAreaTransparency(int alpha) { + return parseInteger(getAreaTransparencyString(), alpha); + } + + + public boolean parseAreaShowBorder() { + return parseBoolean(getAreaShowBorderString(), false); + } + + + private String getAreaShowBorderString() { + return getValue(AREA_SHOW_BORDER); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/themes/ThemeMapping.java --- a/artifacts/src/main/java/org/dive4elements/river/themes/ThemeMapping.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeMapping.java Fri Sep 27 17:36:50 2013 +0200 @@ -133,7 +133,8 @@ } // Test. - if (artifact.getDataAsString(parts[0]).equals(parts[1])) { + String artData = artifact.getDataAsString(parts[0]); + if (artData != null && artData.equals(parts[1])) { logger.debug("Matches master Attribute."); return true; } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/ArtifactMapfileGenerator.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/ArtifactMapfileGenerator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/ArtifactMapfileGenerator.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,12 +10,13 @@ import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.access.RiverAccess; +import org.dive4elements.river.artifacts.access.DGMAccess; import org.dive4elements.river.artifacts.model.LayerInfo; import org.dive4elements.river.artifacts.model.map.WMSDBLayerFacet; import org.dive4elements.river.artifacts.model.map.WMSLayerFacet; import org.dive4elements.river.artifacts.model.map.WSPLGENLayerFacet; import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.states.FloodMapState; import java.io.File; import java.io.FileNotFoundException; @@ -32,6 +33,12 @@ private static Logger logger = Logger.getLogger(ArtifactMapfileGenerator.class); + public static final String FLOODMAP_UESK_KEY = + "floodmap.uesk"; + + public static final String FLOODMAP_UESK_DEF = + "Floodmap: {0}-km {1,number,####} - {2,number,####} - {3}"; + @Override protected String getVelocityLogfile() { return RiverUtils.getXPathString(RiverUtils.XPATH_FLOODMAP_VELOCITY_LOGFILE); @@ -77,18 +84,33 @@ { logger.debug("createUeskLayer"); + String identifier = flys.identifier(); + + DGMAccess access = new DGMAccess(flys); + LayerInfo layerinfo = new LayerInfo(); - layerinfo.setName(MS_WSPLGEN_PREFIX + flys.identifier()); + layerinfo.setName(MS_WSPLGEN_PREFIX + identifier); layerinfo.setType("POLYGON"); - layerinfo.setDirectory(flys.identifier()); + layerinfo.setDirectory(identifier); layerinfo.setData(WSPLGEN_RESULT_SHAPE); - layerinfo.setTitle(Resources.getMsg(Resources.getLocale(context.getMeta()), - "floodmap.uesk", - "Floodmap")); + + String river = access.getRiver(); + + double from = access.hasFrom() ? access.getFrom() : 0d; + double to = access.hasTo() ? access.getTo() : 0d; + + String title = Resources.format( + context.getMeta(), + FLOODMAP_UESK_KEY, + FLOODMAP_UESK_DEF, + river, + from, to, + identifier); + + layerinfo.setTitle(title); + layerinfo.setStyle(style); - RiverAccess access = new RiverAccess(flys); - String river = access.getRiver(); - layerinfo.setSrid(RiverUtils.getRiverDGMSrid(river)); + layerinfo.setSrid(String.valueOf(access.getDGM().getSrid())); String name = MS_LAYER_PREFIX + wms.getName(); @@ -99,7 +121,7 @@ } try { - File dir = new File(getShapefileBaseDir(), flys.identifier()); + File dir = new File(getShapefileBaseDir(), identifier); writeLayer(layerinfo, new File(dir, name), template); } catch (FileNotFoundException fnfe) { @@ -135,11 +157,11 @@ ShapefileReader sfr = new ShapefileReader(sf, true, false, null); ShapefileHeader sfh = sfr.getHeader(); - String group = uuid + MS_USERSHAPE_PREFIX; + String group = MS_USERSHAPE_PREFIX + uuid; String groupTitle = "I18N_USER_SHAPE_TITLE"; LayerInfo info = new LayerInfo(); - info.setName(MS_USERSHAPE_PREFIX + uuid); + info.setName(MS_LAYER_PREFIX + FloodMapState.WSPLGEN_USER_RGD + uuid); if (sfh.getShapeType().isLineType()) { info.setType("LINE"); } @@ -156,7 +178,11 @@ info.setGroupTitle(groupTitle); info.setSrid(wms.getSrid()); - String nameUser = MS_LAYER_PREFIX + wms.getName(); + //String nameUser = MS_LAYER_PREFIX + wms.getName(); + // TODO: This rewrites the user-rgd mapfile fragment generated by + // HWSBarrierState. Otherwise we would have to fragments with same + // layer name. Should be refactored... + String nameUser = MS_LAYER_PREFIX + "user-rgd"; Template tpl = getTemplateByName(SHP_LAYER_TEMPLATE); if (tpl == null) { @@ -225,13 +251,12 @@ } @Override - protected String getMapfilePath() { - return RiverUtils.getXPathString(RiverUtils.XPATH_FLOODMAP_MAPFILE_PATH); - } + protected String getMapfilePath() { + return RiverUtils.getXPathString(RiverUtils.XPATH_FLOODMAP_MAPFILE_PATH); + } @Override - protected String getMapfileTemplate() { - return RiverUtils.getXPathString(RiverUtils.XPATH_FLOODMAP_MAPFILE_TEMPLATE); - } - + protected String getMapfileTemplate() { + return RiverUtils.getXPathString(RiverUtils.XPATH_FLOODMAP_MAPFILE_TEMPLATE); + } } diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/BatchLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/BatchLoader.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,116 @@ +/* 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.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.hibernate.SQLQuery; +import org.hibernate.Session; + +/** To reduce the number of SQL queries send to the backend + * (mainly by the fixings overviews) we execute them in batches of ids + * and store the results in a small cache. + * TODO: It currently relies on dynamic SQL. + * Is there a way to use Hibernate with java.sql.Array + * in cross database compatible manner? + */ +public abstract class BatchLoader<T> { + + private static Logger log = Logger.getLogger(BatchLoader.class); + + public static final int BATCH_SIZE = 100; + + private Map<Integer, T> loaded; + private List<Integer> rest; + private Session session; + private String sqlTemplate; + + public BatchLoader( + List<Integer> columns, + Session session, + String sqlTemplate + ) { + rest = new ArrayList<Integer>(columns.size()); + loaded = new HashMap<Integer, T>(); + this.session = session; + this.sqlTemplate = sqlTemplate; + + // Insert in reverse order to minize searching. + for (int i = columns.size()-1; i >= 0; --i) { + rest.add(columns.get(i)); + } + } + + /** Searches for id and fill a batch to load containing the found id. */ + private List<Integer> prepareBatch(int id) { + List<Integer> batch = new ArrayList<Integer>(BATCH_SIZE); + + boolean found = false; + + for (int i = rest.size()-1; batch.size() < BATCH_SIZE && i >= 0; --i) { + Integer cid = rest.get(i); + if (cid == id) { + found = true; + batch.add(cid); + rest.remove(i); + } + else if ((found && batch.size() < BATCH_SIZE) + || (!found && batch.size() < BATCH_SIZE-1)) { + batch.add(cid); + rest.remove(i); + } + } + + return batch; + } + + /** Converts id to a list of comma separated ints. */ + private static String idsAsString(List<Integer> ids) { + StringBuilder sb = new StringBuilder(); + for (Iterator<Integer> i = ids.iterator(); i.hasNext();) { + sb.append(i.next()); + if (i.hasNext()) { + sb.append(','); + } + } + return sb.toString(); + } + + /** Get data for id. */ + public T get(int id) { + T already = loaded.get(id); + if (already != null) { + return already; + } + + List<Integer> batch = prepareBatch(id); + if (batch.isEmpty()) { + return null; + } + String sql = sqlTemplate.replace("$IDS", idsAsString(batch)); + if (log.isDebugEnabled()) { + log.debug(sql + " " + sql.length()); + } + fill(session.createSQLQuery(sql)); + return get(id); + } + + /** Call this from fill() to store data in the cache. */ + protected void cache(int key, T data) { + loaded.put(key, data); + } + + /** Override this to fill the cache */ + protected abstract void fill(SQLQuery query); +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/CompareUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/CompareUtil.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,25 @@ +/* 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.utils; + +/** Utils to deal with Comparisons. */ +public class CompareUtil +{ + /** Singleton. */ + private CompareUtil() { + } + + /** Return true if a and b are either both null or equal(). */ + public static <T> boolean areSame(T a, T b) { + if (a == null) return b == null; + if (b == null) return false; + return a.equals(b); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/DataUtil.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/DataUtil.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/DataUtil.java Fri Sep 27 17:36:50 2013 +0200 @@ -14,11 +14,20 @@ public class DataUtil { - public static boolean guessWaterIncreasing(TDoubleArrayList data) { - return guessWaterIncreasing(data, 0.05f); + public static boolean guessDataIncreasing(TDoubleArrayList data) { + return guessDataIncreasing(data, 0.05f); } - public static boolean guessWaterIncreasing(TDoubleArrayList data, float factor) { + /** Guess if data1 and data2 both grow in the same direction */ + public static boolean guessSameDirectionData(TDoubleArrayList data1, + TDoubleArrayList data2) { + boolean d1dir = DataUtil.guessDataIncreasing(data1, 0.05f); + boolean d2dir = DataUtil.guessDataIncreasing(data2, 0.05f); + int size = data1.size(); + return ((d1dir && d2dir) || (!d1dir && !d2dir)) && size > 1; + } + + public static boolean guessDataIncreasing(TDoubleArrayList data, float factor) { int N = data.size(); if (N < 2) return false; diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/Formatter.java Fri Sep 27 17:36:50 2013 +0200 @@ -94,11 +94,15 @@ // SQ Relation public static final int SQ_RELATION_KM_MIN_DIGITS = 2; public static final int SQ_RELATION_KM_MAX_DIGITS = 2; - public static final int SQ_RELATION_A_MAX_DIGITS = 7; - public static final int SQ_RELATION_A_MIN_DIGITS = 7; + public static final int SQ_RELATION_A_MAX_DIGITS = 2; + public static final int SQ_RELATION_A_MIN_DIGITS = 2; public static final int SQ_RELATION_B_MAX_DIGITS = 3; public static final int SQ_RELATION_B_MIN_DIGITS = 3; + // OTHER + public static final int CSV_DIAGRAM_DATA_MAX_DIGITS = 3; + public static final int CSV_DIAGRAM_DATA_MIN_DIGITS = 3; + /** * Creates a localized NumberFormatter with given range of decimal digits. * @param m CallMeta to find the locale. @@ -191,6 +195,18 @@ WATERLEVEL_KM_MAX_DIGITS); } + /** + * Returns the number formatter for data exported from diagram (not from + * calculation. + * + * @return the number formatter for csv data from diagra. + */ + public static NumberFormat getCSVFormatter(CallContext context) { + return getFormatter( + context, + CSV_DIAGRAM_DATA_MIN_DIGITS, + CSV_DIAGRAM_DATA_MAX_DIGITS); + } public static NumberFormat getWaterlevelW(CallMeta meta) { return getFormatter( @@ -442,7 +458,7 @@ } public static NumberFormat getSQRelationA(CallContext context) { - return getFormatter( + return getScientificFormater( context, SQ_RELATION_A_MIN_DIGITS, SQ_RELATION_A_MAX_DIGITS); diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/Pair.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/Pair.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/Pair.java Fri Sep 27 17:36:50 2013 +0200 @@ -21,8 +21,7 @@ private A a; private B b; - @SuppressWarnings("unused") - private Pair() { + public Pair() { } public Pair(A a, B b) { diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/RiverUtils.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/RiverUtils.java Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/RiverUtils.java Fri Sep 27 17:36:50 2013 +0200 @@ -10,6 +10,7 @@ import org.dive4elements.artifactdatabase.state.State; import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.ArtifactNamespaceContext; import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.common.utils.Config; import org.dive4elements.artifacts.common.utils.XMLUtils; @@ -80,9 +81,6 @@ public static final String XPATH_FLOODMAP_RIVER_PROJECTION = "/artifact-database/floodmap/river[@name=$name]/srid/@value"; - public static final String XPATH_FLOODMAP_DGM_PROJECTION = - "/artifact-database/floodmap/river[@name=$name]/dgm-srid/@value"; - public static final String XPATH_FLOODMAP_SHAPEFILE_DIR = "/artifact-database/floodmap/shapefile-path/@value"; @@ -104,6 +102,11 @@ public static final String XPATH_FLOODMAP_MAPSERVER_TEMPLATE_PATH = "/artifact-database/floodmap/mapserver/templates/@path"; + public static final String CURRENT_KM = "currentKm"; + + public static final String XPATH_CHART_CURRENTKM = + "/art:action/art:attributes/art:currentKm/@art:km"; + private RiverUtils() { } @@ -427,24 +430,6 @@ variables); } - public static String getRiverDGMSrid(String rivername) { - Map<String, String> variables = new HashMap<String, String>(1); - variables.put("name", rivername); - - Document cfg = Config.getConfig(); - - String dgm = (String) XMLUtils.xpath( - cfg, - XPATH_FLOODMAP_DGM_PROJECTION, - XPathConstants.STRING, - null, - variables); - if (logger.isDebugEnabled()) { - logger.debug("Use EPSG:" + dgm + " for DGM"); - } - return dgm; - } - /** * Return the (first) Gauge corresponding to the given location(s) of * the artifact. @@ -491,10 +476,14 @@ public static Gauge getReferenceGauge(D4EArtifact flys) { Long officialNumber = flys.getDataAsLong("reference_gauge"); + String river = getRivername(flys); - return officialNumber != null - ? Gauge.getGaugeByOfficialNumber(officialNumber) - : null; + if (officialNumber != null && river != null) { + return Gauge.getGaugeByOfficialNumber(officialNumber, river); + } else if (officialNumber != null) { + return Gauge.getGaugeByOfficialNumber(officialNumber); + } + return null; } @@ -925,5 +914,40 @@ return river.determineGauges(dist[0], dist[1]); } + + /** Round a Q in the AT format style **/ + public static double roundQ(double q) { + if (q < 10d) q = Math.rint((q*1000d)) / 1000d; + else if (q < 100d) q = Math.rint((q*100d)) / 100d; + else if (q < 1000d) q = Math.rint((q*10d)) / 10d; + else if (q >= 1000d) q = Math.rint(q); + return q; + } + + /** Parses the request and checks if it contains a currentKM setting. + * If this is the case the currentKM is added to the context.*/ + public static void setKMFromRequestInContext(Document request, + CallContext context) { + Double dKm; + String km = XMLUtils.xpathString( + request, + XPATH_CHART_CURRENTKM, + ArtifactNamespaceContext.INSTANCE); + + if (km == null) { + return; + } + + try { + dKm = Double.valueOf(km); + } catch (NumberFormatException nfe) { + return; + } + + if (logger.isDebugEnabled()) { + logger.debug("currentKm = " + dKm); + } + context.putContextValue(CURRENT_KM, dKm); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/ThemeUtil.java --- a/artifacts/src/main/java/org/dive4elements/river/utils/ThemeUtil.java Fri Sep 13 18:29:01 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,827 +0,0 @@ -/* 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.utils; - -import org.dive4elements.artifacts.CallMeta; -import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.river.artifacts.model.MapserverStyle; -import org.dive4elements.river.artifacts.model.MapserverStyle.Clazz; -import org.dive4elements.river.artifacts.model.MapserverStyle.Expression; -import org.dive4elements.river.artifacts.model.MapserverStyle.Label; -import org.dive4elements.river.artifacts.model.MapserverStyle.Style; -import org.dive4elements.river.artifacts.resources.Resources; - -import java.awt.Color; -import java.awt.Font; - -import org.apache.log4j.Logger; -import org.w3c.dom.Document; - - -/** - * Utility to deal with themes and their representations. - */ -public class ThemeUtil { - - /** Private logger. */ - private static Logger logger = - Logger.getLogger(ThemeUtil.class); - - private static final String MSG_ISOBATH_CLASS = "floodmap.isobath.class"; - - private static final String MSG_ISOBATH_LASTCLASS = "floodmap.isobath.lastclass"; - - public final static String XPATH_FILL_COLOR = - "/theme/field[@name='fillcolor']/@default"; - - public final static String XPATH_LINE_COLOR = - "/theme/field[@name='linecolor']/@default"; - - public final static String XPATH_AREA_LINE_COLOR = - "/theme/field[@name='areabordercolor']/@default"; - - public static final String XPATH_LINE_SIZE = - "/theme/field[@name='linesize']/@default"; - - public static final String XPATH_LINE_STYLE = - "/theme/field[@name='linetype']/@default"; - - public static final String XPATH_POINT_SIZE = - "/theme/field[@name='pointsize']/@default"; - - public static final String XPATH_POINT_COLOR = - "/theme/field[@name='pointcolor']/@default"; - - public final static String XPATH_SHOW_BORDER = - "/theme/field[@name='showborder']/@default"; - - public final static String XPATH_AREA_SHOW_BORDER = - "/theme/field[@name='showborder']/@default"; - - public final static String XPATH_SHOW_POINTS = - "/theme/field[@name='showpoints']/@default"; - - public final static String XPATH_SHOW_LINE = - "/theme/field[@name='showlines']/@default"; - - public final static String XPATH_SHOW_VERTICAL_LINE = - "/theme/field[@name='showverticalline']/@default"; - - public final static String XPATH_SHOW_HORIZONTAL_LINE = - "/theme/field[@name='showhorizontalline']/@default"; - - public final static String XPATH_SHOW_LINE_LABEL = - "/theme/field[@name='showlinelabel']/@default"; - - public final static String XPATH_SHOW_POINT_LABEL = - "/theme/field[@name='showpointlabel']/@default"; - - public final static String XPATH_SHOW_WIDTH = - "/theme/field[@name='showwidth']/@default"; - - public final static String XPATH_SHOW_LEVEL = - "/theme/field[@name='showlevel']/@default"; - - public final static String XPATH_TRANSPARENCY = - "/theme/field[@name='transparency']/@default"; - - public final static String XPATH_AREA_TRANSPARENCY = - "/theme/field[@name='areatransparency']/@default"; - - public final static String XPATH_SHOW_AREA = - "/theme/field[@name='showarea']/@default"; - - public final static String XPATH_SHOW_MIDDLE_HEIGHT = - "/theme/field[@name='showmiddleheight']/@default"; - - public final static String XPATH_LABEL_FONT_COLOR = - "/theme/field[@name='labelfontcolor']/@default"; - - public final static String XPATH_LABEL_FONT_SIZE = - "/theme/field[@name='labelfontsize']/@default"; - - public final static String XPATH_LABEL_FONT_FACE = - "/theme/field[@name='labelfontface']/@default"; - - public final static String XPATH_LABEL_FONT_STYLE = - "/theme/field[@name='labelfontstyle']/@default"; - - public final static String XPATH_TEXT_ORIENTATION = - "/theme/field[@name='textorientation']/@default"; - - public final static String XPATH_LABEL_BGCOLOR = - "/theme/field[@name='labelbgcolor']/@default"; - - public final static String XPATH_LABEL_SHOW_BACKGROUND = - "/theme/field[@name='labelshowbg']/@default"; - - public final static String XPATH_BACKGROUND_COLOR = - "/theme/field[@name='backgroundcolor']/@default"; - - public final static String XPATH_AREA_BACKGROUND_COLOR = - "/theme/field[@name='areabgcolor']/@default"; - - public final static String XPATH_SYMBOL = - "/theme/field[@name='symbol']/@default"; - - public final static String XPATH_SHOW_MINIMUM = - "/theme/field[@name='showminimum']/@default"; - - public final static String XPATH_SHOW_MAXIMUM = - "/theme/field[@name='showmaximum']/@default"; - - public final static String XPATH_WSPLGEN_FIELDS = - "/theme[@name='WSPLGEN']/field"; - - public final static String XPATH_WSPLGEN_STARTCOLOR = - "/theme/field[@name='startcolor']/@default"; - - public final static String XPATH_WSPLGEN_ENDCOLOR = - "/theme/field[@name='endcolor']/@default"; - - public final static String XPATH_WSPLGEN_NUMCLASSES = - "/theme/field[@name='numclasses']/@default"; - - /** XPATH to bandwidth field. */ - public final static String XPATH_BANDWIDTH = - "/theme/field[@name='bandwidth']/@default"; - - /** XPATH to find showextramark field. */ - public final static String XPATH_SHOWEXTRAMARK = - "/theme/field[@name='showextramark']/@default"; - - /** Parse string to be boolean with default if empty or unrecognized. */ - public static boolean parseBoolean(String value, boolean defaultsTo) { - if (value == null || value.length() == 0) { - return defaultsTo; - } - if (value.equals("false")) { - return false; - } - else if (value.equals("true")) { - return true; - } - else { - return defaultsTo; - } - } - - - /** - * Attempt converting \param value to an integer, in failing cases, - * return \param defaultsTo. - * @param value String to be converted to integer. - * @param defaultsTo Default to return if conversion failed. - * @return \param value as integer or defaultsto if conversion failed. - */ - public static int parseInteger(String value, int defaultsTo) { - if (value == null || value.length() == 0) { - return defaultsTo; - } - - try { - return Integer.parseInt(value); - } - catch (NumberFormatException nfe) { - // do nothing - } - - return defaultsTo; - } - - - /** - * Attempt converting \param value to a double, in failing cases, - * return \param defaultsTo. - * @param value String to be converted to double. - * @param defaultsTo Default to return if conversion failed. - * @return \param value as integer or defaultsto if conversion failed. - */ - public static double parseDouble(String value, double defaultsTo) { - if (value == null || value.length() == 0) { - return defaultsTo; - } - - try { - return Double.parseDouble(value); - } - catch (NumberFormatException nfe) { - // do nothing - } - - return defaultsTo; - } - - - /** - * Parses line width, defaulting to 0. - * @param theme the theme - */ - public static int parseLineWidth(Document theme) { - String size = XMLUtils.xpathString(theme, XPATH_LINE_SIZE, null); - if (size == null || size.length() == 0) { - return 0; - } - - try { - return Integer.parseInt(size); - } - catch (NumberFormatException nfe) { - logger.warn("Unable to set line size from string: '" + size + "'"); - } - return 0; - } - - - /** - * Parse band width, defaulting to 0. - * @param theme the theme. - */ - public static double parseBandWidth(Document theme) { - String bandWidth = XMLUtils.xpathString(theme, XPATH_BANDWIDTH, null); - - return parseDouble(bandWidth, 0); - } - - - public static int parsePointWidth(Document theme) { - String width = XMLUtils.xpathString(theme, XPATH_POINT_SIZE, null); - - return parseInteger(width, 3); - } - - - public static Color parsePointColor(Document theme) { - String color = XMLUtils.xpathString(theme, XPATH_POINT_COLOR, null); - logger.debug("parsePointColor(): color = " + color); - return parseColor(color); - } - - - /** - * Parses the line style, defaulting to '10'. - * @param theme The theme. - */ - public static float[] parseLineStyle(Document theme) { - String dash = XMLUtils.xpathString(theme, XPATH_LINE_STYLE, null); - - float[] def = {10}; - if (dash == null || dash.length() == 0) { - return def; - } - - String[] pattern = dash.split(","); - if(pattern.length == 1) { - return def; - } - - try { - float[] dashes = new float[pattern.length]; - for (int i = 0; i < pattern.length; i++) { - dashes[i] = Float.parseFloat(pattern[i]); - } - return dashes; - } - catch(NumberFormatException nfe) { - logger.warn("Unable to set dash from string: '" + dash + "'"); - return def; - } - } - - - /** - * Parses text size, defaulting to 10. - * @param theme The theme. - */ - public static int parseTextSize(Document theme, String path) { - String size = XMLUtils.xpathString(theme, path, null); - if (size == null || size.length() == 0) { - return 10; - } - - try { - return Integer.parseInt(size); - } - catch (NumberFormatException nfe) { - } - return 10; - } - - - public static int parseTextSize(Document theme) { - return parseTextSize(theme, XPATH_LABEL_FONT_SIZE); - } - - - /** - * Parses the attribute 'showextramark', defaults to false. - * @param theme The theme. - */ - public static boolean parseShowExtraMark(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOWEXTRAMARK, null); - return parseBoolean(show, false); - } - - /** - * Parses the attribute 'showpoints', defaults to false. - * @param theme The theme. - */ - public static boolean parseShowPoints(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_POINTS, null); - return parseBoolean(show, false); - } - - /** - * Parses the attribute 'showmiddleheight', defaults to false. - * @param theme The theme. - */ - public static boolean parseShowMiddleHeight(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_MIDDLE_HEIGHT, null); - return parseBoolean(show, false); - } - - /** - * Parses the attribute 'showarea', defaults to false. - * @param theme The theme. - */ - public static boolean parseShowArea(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_AREA, null); - return parseBoolean(show, false); - } - - /** - * Parses the attribute 'showverticalline', defaults to true. - * @param theme The theme. - */ - public static boolean parseShowVerticalLine(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_VERTICAL_LINE, null); - return parseBoolean(show, true); - } - - /** - * Parses the attribute 'showhorizontalline', defaults to true. - * @param theme The theme. - */ - public static boolean parseShowHorizontalLine(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_HORIZONTAL_LINE, null); - return parseBoolean(show, true); - } - - /** - * Parses the attribute 'showlines', defaults to true. - * @param theme The theme. - */ - public static boolean parseShowLine(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_LINE, null); - return parseBoolean(show, true); - } - - /** - * Parses the attribute 'showlinelabel', defaults to true. - * @param theme The theme. - */ - public static boolean parseShowLineLabel(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_LINE_LABEL, null); - return parseBoolean(show, false); - } - - public static boolean parseShowPointLabel(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_POINT_LABEL, null); - return parseBoolean(show, false); - } - - /** - * Parses text color. - * @param theme The theme. - */ - public static Color parseTextColor(Document theme) { - return parseRGB(getTextColorString(theme)); - } - - - /** - * Parses the font. - * @param theme The theme. - */ - public static Font parseTextFont(Document theme) { - String font = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_FACE, null); - if (font == null || font.length() == 0) { - return null; - } - - int size = parseTextSize(theme); - int style = parseTextStyle(theme); - Font f = new Font (font, style, size); - return f; - } - - - /** - * Parses the text style, defaults to 'Font.PLAIN'. - * @param theme The theme. - */ - public static int parseTextStyle(Document theme, String path) { - String style = XMLUtils.xpathString(theme, path, null); - if (style == null || style.length() == 0) { - return Font.PLAIN; - } - - if (style.equals("italic")) { - return Font.ITALIC; - } - else if (style.equals("bold")) { - return Font.BOLD; - } - else { - return Font.PLAIN; - } - } - - - public static int parseTextStyle(Document theme) { - return parseTextStyle(theme, XPATH_LABEL_FONT_STYLE); - } - - - public static boolean parseShowWidth(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_WIDTH, null); - return parseBoolean(show, false); - } - - - public static boolean parseShowLevel(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_SHOW_LEVEL, null); - return parseBoolean(show, false); - } - - /** - * Parses the textorientation, defaults to 'vertical'. - * @param theme The theme. - */ - public static String parseTextOrientation(Document theme) { - String o = XMLUtils.xpathString(theme, XPATH_TEXT_ORIENTATION, null); - if ("true".equals(o)) { - return "horizontal"; - } - else { - return "vertical"; - } - } - - - /** - * Parses the text background color, defaults to white. - * @param theme The theme. - */ - public static Color parseTextBackground(Document theme) { - String color = getLabelBackgroundColorString(theme); - if (color == null || color.length() == 0) { - return Color.WHITE; - } - return parseRGB(color); - } - - - /** - * Parses the attribute whether to show background or not, defaults to - * false. - * @param theme The theme. - */ - public static boolean parseLabelShowBackground(Document theme) { - String show = XMLUtils.xpathString(theme, XPATH_LABEL_SHOW_BACKGROUND, null); - return parseBoolean(show, false); - } - - - public static Color parseColor(String colorString) { - if (colorString == null || colorString.length() == 0) { - return null; - } - else if (colorString.indexOf("#") == 0) { - return parseHexColor(colorString); - } - else if (colorString.indexOf(",") >= 0) { - return parseRGB(colorString); - } - - return null; - } - - - /** - * Parse a string like "#00CC22" and return the corresponding color. - * - * @param hex The hex color value. - * - * @return a Color or null, if <i>hex</i> is empty. - */ - public static Color parseHexColor(String hex) { - if (hex == null) { - return null; - } - - return Color.decode(hex); - } - - /** - * Parse a string like "103, 100, 0" and return a corresping color. - * @param rgbtext Color as string representation, e.g. "255,0,20". - * @return Color, null in case of issues. - */ - public static Color parseRGB(String rgbtext) { - if (rgbtext == null) { - return null; - } - String rgb[] = rgbtext.split(","); - Color c = null; - try { - c = new Color( - Integer.parseInt(rgb[0].trim()), - Integer.parseInt(rgb[1].trim()), - Integer.parseInt(rgb[2].trim())); - } - catch (NumberFormatException nfe) { - c = null; - } - return c; - } - - - public static String getLineColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_LINE_COLOR, null); - } - - - /** Get show border as string. */ - public static String getShowBorderString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_SHOW_BORDER, null); - } - - - /** Get fill color as string. */ - public static String getFillColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_FILL_COLOR, null); - } - - - public static String getLabelBackgroundColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_LABEL_BGCOLOR, null); - } - - - public static String getBackgroundColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_BACKGROUND_COLOR, null); - } - - - public static String getTextColorString(Document theme) { - String textColor = XMLUtils.xpathString(theme, XPATH_LABEL_FONT_COLOR, null); - return textColor; - } - - - public static String getSymbol(Document theme) { - return XMLUtils.xpathString(theme, XPATH_SYMBOL, null); - } - - - public static String getTransparencyString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_TRANSPARENCY, null); - } - - - public static String getAreaTransparencyString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_AREA_TRANSPARENCY, null); - } - - - public static String getShowMinimum(Document theme) { - return XMLUtils.xpathString(theme, XPATH_SHOW_MINIMUM, null); - } - - - public static String getShowMaximum(Document theme) { - return XMLUtils.xpathString(theme, XPATH_SHOW_MAXIMUM, null); - } - - - /** - * Gets color from color field. - * @param theme the theme document. - * @return color. - */ - public static Color parseFillColorField(Document theme) { - return parseRGB(getFillColorString(theme)); - } - - - public static boolean parseShowBorder(Document theme) { - return parseBoolean(getShowBorderString(theme), false); - } - - - public static int parseTransparency(Document theme) { - return parseInteger(getTransparencyString(theme), 50); - } - - - /** - * Gets color from color field. - * @param theme the theme document. - * @return color. - */ - public static Color parseLineColorField(Document theme) { - String lineColorStr = getLineColorString(theme); - logger.debug("parseLineColorField: lineColorStr = " + - (lineColorStr == null ? "null" : lineColorStr)); - return parseColor(lineColorStr); - } - - - public static Color parseAreaLineColorField(Document theme) { - String lineColorStr = getAreaLineColorString(theme); - logger.debug("parseLineColorField: lineColorStr = " + - (lineColorStr == null ? "null" : lineColorStr)); - return parseColor(lineColorStr); - } - - - private static String getAreaLineColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_AREA_LINE_COLOR, null); - } - - - public static boolean parseShowMinimum(Document theme) { - return parseBoolean(getShowMinimum(theme), false); - } - - - public static boolean parseShowMaximum(Document theme) { - return parseBoolean(getShowMaximum(theme), false); - } - - - /** - * Creates a MapserverStyle from the given XML theme. - * This method uses a start- and endcolor to interpolate a - * given number of color classes for the MapserverStyle. - * @param theme - * @return String representation of the MapserverStyle - */ - public static String createDynamicMapserverStyle(Document theme, - float from, float to, float step, CallMeta meta) - { - MapserverStyle ms = new MapserverStyle(); - - String strStartColor = XMLUtils.xpathString(theme, XPATH_WSPLGEN_STARTCOLOR, null); - Color startColor = strStartColor != null ? parseColor(strStartColor) : new Color(178, 201, 215); - String strEndColor = XMLUtils.xpathString(theme, XPATH_WSPLGEN_ENDCOLOR, null); - Color endColor = strEndColor != null? parseColor(strEndColor) : new Color(2, 27, 42); - - to = to != 0 ? to : 9999; - step = step != 0 ? step : to; - - int numClasses = (int)((to - from) / step); - - float rd = (endColor.getRed() - startColor.getRed()) / (float)numClasses; - float gd = (endColor.getGreen() - startColor.getGreen()) / (float)numClasses; - float bd = (endColor.getBlue() - startColor.getBlue()) / (float)numClasses; - - if (numClasses > 1) { - // Desktop Flys always added a last "and larger class" - numClasses += 1; - } - - for (int n = 0; n < numClasses; n++) { - StringBuilder newColor = new StringBuilder(); - newColor.append(startColor.getRed() + Math.round(n * rd)); - newColor.append(' '); - newColor.append(startColor.getGreen() + Math.round(n * gd)); - newColor.append(' '); - newColor.append(startColor.getBlue() + Math.round(n * bd)); - - String expr = createWSPLGENClassExpression(from + n * step, step, n + 1, numClasses); - String name = createWSPLGENClassName(from + n * step, step, n + 1, numClasses, meta); - - Clazz c = new Clazz(name); - Style s = new Style(); - s.setColor(newColor.toString()); - s.setSize(5); - - c.addItem(new Expression("(" + expr + ")")); - c.addItem(s); - - ms.addClazz(c); - } - - return ms.toString(); - } - - - protected static String createWSPLGENClassExpression(float val, float step, int idx, int maxIdx) { - if (idx < maxIdx) { - return "[DIFF] >= " + val + " AND [DIFF] < " + (val + step); - } - else { - return "[DIFF] >= " + val; - } - } - - /** - * Creates a class name for the mapfile style that visualizes a floodmap. - * The class names are used in the map's legend. - * - * @param val Current isobath value. - * @param step Difference between to class values. - * @param idx Current class index that is being processed. - * @param maxIdx Highest class index. - * @param meta Caller meta object used to determine locale. - * @return - */ - protected static String createWSPLGENClassName(float val, float step, int idx, int maxIdx, CallMeta meta) { - assert meta != null : "CallMeta instance is null"; - - if (idx < maxIdx) { - return Resources.getMsg(meta, MSG_ISOBATH_CLASS, - new Object[] {val, val + step}); - } - else { - return Resources.getMsg(meta, MSG_ISOBATH_LASTCLASS, - new Object[] {val}); - } - } - - - public static String createMapserverStyle(Document theme) { - String symbol = getSymbol(theme); - String backcolor = getLabelBackgroundColorString(theme); - String linecolor = getLineColorString(theme); - if (linecolor == null || "".equals(linecolor)) { - logger.warn("createMapserverStyle: linecolor String is empty"); - linecolor = "0,128,255"; - } - - int linewidth = parseLineWidth(theme); - - MapserverStyle ms = new MapserverStyle(); - - Clazz c = new Clazz(" "); - - Style s = new Style(); - s.setOutlineColor(linecolor.replace(",", " ")); - - if (backcolor != null && backcolor.length() > 0) { - s.setColor(backcolor.replace(",", " ")); - } - - s.setSize(linewidth); - s.setSymbol(symbol); - c.addItem(s); - - String textcolor = getTextColorString(theme); - int textsize = parseTextSize(theme); - - if (textcolor != null && textcolor.length() > 0 && textsize > 0) { - Label l = new Label(); - l.setColor(textcolor.replace(",", " ")); - l.setSize(textsize); - c.addItem(l); - } - - ms.addClazz(c); - - return ms.toString(); - } - - - public static String getAreaBackgroundColorString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_AREA_BACKGROUND_COLOR, null); - } - - - public static Color parseAreaBackgroundColor(Document theme) { - return parseColor(getAreaBackgroundColorString(theme)); - } - - - public static int parseAreaTransparency(Document theme) { - return parseInteger(getAreaTransparencyString(theme), 50); - } - - - public static boolean parseAreaShowBorder(Document theme) { - return parseBoolean(getAreaShowBorderString(theme), false); - } - - - private static String getAreaShowBorderString(Document theme) { - return XMLUtils.xpathString(theme, XPATH_AREA_SHOW_BORDER, null); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/java/org/dive4elements/river/utils/UniqueDateFormatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/UniqueDateFormatter.java Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,59 @@ +/* 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.utils; + +import java.text.DateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; + +public class UniqueDateFormatter { + + private static Logger log = Logger.getLogger(UniqueDateFormatter.class); + + private DateFormat df; + private DateFormat lf; + private Map<String, int[]> collisions; + + public UniqueDateFormatter( + DateFormat df, + DateFormat lf, + Collection<Date> dates + ) { + this.df = df; + this.lf = lf; + collisions = build(dates); + } + + private Map<String, int []> build(Collection<Date> dates) { + Map<String, int []> collisions = new HashMap<String, int[]>(); + for (Date d: dates) { + String s = df.format(d); + int [] count = collisions.get(s); + if (count == null) { + collisions.put(s, count = new int[1]); + } + if (++count[0] > 1) { + log.debug("date collsion found: " + d); + } + } + return collisions; + } + + public String format(Date date) { + String s = df.format(date); + int [] count = collisions.get(s); + return count == null || count[0] < 2 + ? s + : lf.format(date); + } +} diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/resources/datacage-sql/org-h2-driver.properties --- a/artifacts/src/main/resources/datacage-sql/org-h2-driver.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/resources/datacage-sql/org-h2-driver.properties Fri Sep 27 17:36:50 2013 +0200 @@ -17,7 +17,7 @@ insert.out = INSERT INTO outs (id, artifact_id, name, description, out_type) VALUES (?, ?, ?, ?, ?) facet.id.nextval = SELECT NEXTVAL('FACETS_ID_SEQ') insert.facet = INSERT INTO facets (id, out_id, name, num, state, description) VALUES (?, ?, ?, ?, ?, ?) -update.artifact.state = UPDATE artifacts SET state = ? WHERE gid = ? +update.artifact.state = UPDATE artifacts SET state = ? WHERE id = ? update.collection.name = UPDATE collections SET name = ? WHERE gid = ? delete.artifact.from.collection = DELETE FROM collection_items WHERE collection_id = ? AND artifact_id = ? diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/resources/messages.properties --- a/artifacts/src/main/resources/messages.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/resources/messages.properties Fri Sep 27 17:36:50 2013 +0200 @@ -141,7 +141,7 @@ floodplain.inactive = Inactiv outlier.method.grubbs=Grubbs -outlier.method.std-dev=Standard deviation +outlier.method.std-dev=Residual standard error river = River calculation_mode = Calculation Mode @@ -152,6 +152,7 @@ chart.longitudinal.section.title = W-Longitudinal Section chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.locsubtitle = {0} km {1,number,#.###} chart.longitudinal.section.xaxis.label = {0}-km chart.longitudinal.section.yaxis.label = W [{0}] chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] @@ -171,7 +172,7 @@ chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} chart.computed.discharge.curve.yaxis.label = W [{0}] chart.computed.discharge.curve.curve.label = Discharge Curve {0} km {1} -chart.computed.discharge.curve.gauge = Discharge curve at gauge {0} (km {1}) +chart.computed.discharge.curve.gauge = current DC {0} {1} - {2} chart.duration.curve.title = Duration Curve chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] @@ -197,7 +198,7 @@ chart.reference.curve.y.axis.in.m = Target Station(s) [NN + m] chart.w_differences.title = Differences -chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.subtitle = {0} chart.w_differences.yaxis.label = m chart.w_differences.yaxis.second.label = W [NN + m] @@ -287,7 +288,7 @@ bedquality.toplayer = 0.0m - 0.3m bedquality.sublayer = 0.1m - 0.5m facet.bedheight.diff.year = Bedheight Difference {0} -facet.bedheight.diff.morph = sounding Width {0} +facet.bedheight.diff.morph = sounding Width facet.bedheight.diff.height1 = Original Height Minuend {0} facet.bedheight.diff.height2 = Original Height Subtrahend {0} facet.bedheight.diff.absolute = Bedheight Difference/Year {0} @@ -310,7 +311,7 @@ chart.beddifference.height.yaxis.label = Difference [cm/year] chart.beddifference.epoch.title = Bedheight Difference chart.beddifference.xaxis.label = {0}-km -chart.beddifference.yaxis.label.diff = Difference [m] +chart.beddifference.yaxis.label.diff = Difference [cm] chart.beddifference.yaxis.label.height = Absolute Height [{0}] chart.beddifference.year.title = Bedheight Difference chart.beddifference.yaxis.label.morph = Width [m] @@ -391,6 +392,7 @@ export.sedimentload_ls.csv.header.sand = sand export.sedimentload_ls.csv.header.suspsand = susp. sand export.sedimentload_ls.csv.header.suspsediment = susp. sediment +export.sedimentload_ls.csv.header.suspsandbb = susp. sand (BB) export.sedimentload_ls.csv.header.total = total export.sqrelation.csv.header.parameter = Parameter export.sqrelation.csv.header.station = Station @@ -403,9 +405,10 @@ export.sqrelation.csv.header.coeff.r = r^2 export.sqrelation.csv.header.n.total = n total export.sqrelation.csv.header.n.outliers = n outliers -export.sqrelation.csv.header.c.duan = C (DUAN) -export.sqrelation.csv.header.c.ferguson = C (FERGUSON) -export.sqrelation.csv.header.variance = Standard variance +export.sqrelation.csv.header.c.duan = C (Duan) +export.sqrelation.csv.header.c.ferguson = C (Ferguson) +export.sqrelation.csv.header.sd = Standard error +export.sqrelation.csv.header.qmax = Q max,measured export.sqrelation.pdf.file = /jasper/sqrelation_en.jasper export.sqrelation.pdf.mode = Load Discharge Relation export.minfo.bedquality.km = km @@ -424,7 +427,7 @@ floodmap.wmsbackground = Background Map floodmap.riveraxis = River Axis -floodmap.uesk = Floodmap: {0}-km {1,number,####} - {2,number,####} +floodmap.uesk = Floodmap: {0}-km {1,number,####} - {2,number,####} - {3} floodmap.barriers = Digitized Objects floodmap.kms = Kilometrage floodmap.qps = Crosssection Tracks diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/resources/messages_de.properties --- a/artifacts/src/main/resources/messages_de.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Fri Sep 27 17:36:50 2013 +0200 @@ -142,7 +142,7 @@ floodplain.inactive = Inaktiv outlier.method.grubbs=Grubbs -outlier.method.std-dev=Standardabweichung +outlier.method.std-dev=Standardfehler der Residuen river = Fluss calculation_mode = Berechnungsart @@ -158,6 +158,7 @@ chart.longitudinal.section.title = W-L\u00e4ngsschnitt chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###} chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.locsubtitle = {0} km {1,number,#.###} chart.longitudinal.section.xaxis.label = {0}-km chart.longitudinal.section.yaxis.label = W [{0}] chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] @@ -171,7 +172,7 @@ chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} chart.computed.discharge.curve.yaxis.label = W [{0}] chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1} -chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1}) +chart.computed.discharge.curve.gauge = aktuelle AT {0} {1} - {2} chart.duration.curve.title = Dauerlinie chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] @@ -207,7 +208,7 @@ chart.normalized.reference.curve.title = Reduzierte Bezugslinie chart.w_differences.title = Differenzen -chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.subtitle = {0} chart.w_differences.yaxis.label = m chart.w_differences.yaxis.second.label = W [NN + m] @@ -287,7 +288,7 @@ bedquality.toplayer = 0,0m - 0,3m bedquality.sublayer = 0,1m - 0,5m facet.bedheight.diff.year = Sohlh\u00f6hendifferenz {0} -facet.bedheight.diff.morph = gepeilte Breite {0} +facet.bedheight.diff.morph = gepeilte Breite facet.bedheight.diff.height1 = H\u00f6he Minuend {0} facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0} facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0} @@ -310,7 +311,7 @@ chart.beddifference.height.yaxis.label = Differenz [cm/Jahr] chart.beddifference.epoch.title = Sohlh\u00f6hendifferenz chart.beddifference.xaxis.label = {0}-km -chart.beddifference.yaxis.label.diff = Differenz [m] +chart.beddifference.yaxis.label.diff = Differenz [cm] chart.beddifference.yaxis.label.height = Absolute H\u00f6he [m] chart.beddifference.year.title = Sohlh\u00f6hendifferenz chart.beddifference.yaxis.label.morph = Breite [m] @@ -386,12 +387,13 @@ export.bedheight_middle.csv.header.locations = Streckendaten export.sedimentload_ls.csv.header.km = km export.sedimentload_ls.csv.header.year = Jahr -export.sedimentload_ls.csv.header.coarse = Grob -export.sedimentload_ls.csv.header.finemiddle = Fein +export.sedimentload_ls.csv.header.coarse = Kies(g) +export.sedimentload_ls.csv.header.finemiddle = Kies(f+m) export.sedimentload_ls.csv.header.sand = Sand -export.sedimentload_ls.csv.header.suspsand = susp. Sand -export.sedimentload_ls.csv.header.suspsediment = susp. Sediment -export.sedimentload_ls.csv.header.total = Total +export.sedimentload_ls.csv.header.suspsand = susp.Sand +export.sedimentload_ls.csv.header.suspsandbb = susp.Sand(BB) +export.sedimentload_ls.csv.header.suspsediment = Schwebst. +export.sedimentload_ls.csv.header.total = Gesamt export.sqrelation.csv.header.parameter = Parameter export.sqrelation.csv.header.station = Station export.sqrelation.csv.header.km = Fluss-Km @@ -401,11 +403,12 @@ export.sqrelation.csv.header.coeff.b = b export.sqrelation.csv.header.coeff.q = Q export.sqrelation.csv.header.coeff.r = r^2 -export.sqrelation.csv.header.n.total = n gesamt +export.sqrelation.csv.header.n.total = n Gesamt export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer -export.sqrelation.csv.header.c.duan = C (DUAN) -export.sqrelation.csv.header.c.ferguson = C (FERGUSON) -export.sqrelation.csv.header.variance = Standardabweichung +export.sqrelation.csv.header.c.duan = C (Duan) +export.sqrelation.csv.header.c.ferguson = C (Ferguson) +export.sqrelation.csv.header.sd = Standardfehler +export.sqrelation.csv.header.qmax = Q max,gemessen export.sqrelation.pdf.file = /jasper/sqrelation.jasper export.sqrelation.pdf.mode = Transport-Abfluss Beziehung export.minfo.bedquality.km = km @@ -424,7 +427,7 @@ floodmap.wmsbackground = Hintergrundkarte floodmap.riveraxis = Flussachse -floodmap.uesk = \u00dcSG: {0}-km {1,number,####} - {2,number,####} +floodmap.uesk = \u00dcSG: {0}-km {1,number,####} - {2,number,####} - {3} floodmap.barriers = Digitalisierte Objekte floodmap.kms = Kilometrierung floodmap.qps = Querprofilspuren diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/resources/messages_de_DE.properties --- a/artifacts/src/main/resources/messages_de_DE.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/resources/messages_de_DE.properties Fri Sep 27 17:36:50 2013 +0200 @@ -141,7 +141,7 @@ floodplain.inactive = Inaktiv outlier.method.grubbs=Grubbs -outlier.method.std-dev=Standardabweichung +outlier.method.std-dev=Standardfehler der Residuen river = Fluss calculation_mode = Berechnungsart @@ -157,6 +157,7 @@ chart.longitudinal.section.title = W-L\u00e4ngsschnitt chart.longitudinal.section.subtitle = Bereich: {0}-km {1,number,#.###} - {2,number,#.###} chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.locsubtitle = {0} km {1,number,#.###} chart.longitudinal.section.xaxis.label = {0}-km chart.longitudinal.section.yaxis.label = W [{0}] chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] @@ -170,7 +171,7 @@ chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} chart.computed.discharge.curve.yaxis.label = W [{0}] chart.computed.discharge.curve.curve.label = Abflusskurve {0} km {1} -chart.computed.discharge.curve.gauge = Abflusskurve an Pegel {0} (km {1}) +chart.computed.discharge.curve.gauge = aktuelle AT {0} {1} - {2} chart.duration.curve.title = Dauerlinie chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Unterschreitungsdauer [Tage] @@ -205,7 +206,7 @@ chart.normalized.reference.curve.title = Reduzierte Bezugslinie chart.w_differences.title = Differenzen -chart.w_differences.subtitle = Strecke: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.subtitle = {0} chart.w_differences.yaxis.label = m chart.w_differences.yaxis.second.label = W [NN + m] @@ -286,7 +287,7 @@ bedquality.sublayer = 0,1m - 0,5m facet.bedheight.diff.year = Sohlh\u00f6hendifferenz {0} facet.bedheight.diff.year.raw = Sohlh\u00f6hendifferenz {0} (Rohdaten) -facet.bedheight.diff.morph = gepeilte Breite {0} +facet.bedheight.diff.morph = gepeilte Breite facet.bedheight.diff.height1 = H\u00f6he Minuend {0} facet.bedheight.diff.height2 = H\u00f6he Subtrahend {0} facet.bedheight.diff.absolute = Sohlh\u00f6hendifferenz/Jahr {0} @@ -308,7 +309,7 @@ chart.beddifference.height.yaxis.label = Differenz [cm/Jahr] chart.beddifference.epoch.title = Sohlh\u00f6hendifferenz chart.beddifference.xaxis.label = {0}-km -chart.beddifference.yaxis.label.diff = Differenz [m] +chart.beddifference.yaxis.label.diff = Differenz [cm] chart.beddifference.yaxis.label.height = Absolute H\u00f6he [{0}] chart.beddifference.year.title = Sohlh\u00f6hendifferenz chart.beddifference.yaxis.label.morph = Breite [m] @@ -383,12 +384,13 @@ export.bedheight_middle.csv.header.locations = Streckendaten export.sedimentload_ls.csv.header.km = km export.sedimentload_ls.csv.header.year = Jahr -export.sedimentload_ls.csv.header.coarse = Grob -export.sedimentload_ls.csv.header.finemiddle = Fein +export.sedimentload_ls.csv.header.coarse = Kies(g) +export.sedimentload_ls.csv.header.finemiddle = Kies(f+m) export.sedimentload_ls.csv.header.sand = Sand -export.sedimentload_ls.csv.header.suspsand = susp. Sand -export.sedimentload_ls.csv.header.suspsediment = susp. Sediment -export.sedimentload_ls.csv.header.total = Total +export.sedimentload_ls.csv.header.suspsand = susp.Sand +export.sedimentload_ls.csv.header.suspsandbb = susp.Sand(BB) +export.sedimentload_ls.csv.header.suspsediment = Schwebst. +export.sedimentload_ls.csv.header.total = Gesamt export.sqrelation.csv.header.parameter = Parameter export.sqrelation.csv.header.station = Station export.sqrelation.csv.header.km = Fluss-Km @@ -398,11 +400,12 @@ export.sqrelation.csv.header.coeff.b = b export.sqrelation.csv.header.coeff.q = Q export.sqrelation.csv.header.coeff.r = r^2 -export.sqrelation.csv.header.n.total = n gesamt +export.sqrelation.csv.header.n.total = n Gesamt export.sqrelation.csv.header.n.outliers = n Ausrei\u00dfer -export.sqrelation.csv.header.c.duan = C (DUAN) -export.sqrelation.csv.header.c.ferguson = C (FERGUSON) -export.sqrelation.csv.header.variance = Standardabweichung +export.sqrelation.csv.header.c.duan = C (Duan) +export.sqrelation.csv.header.c.ferguson = C (Ferguson) +export.sqrelation.csv.header.sd = Standardfehler +export.sqrelation.csv.header.qmax = Q max,gemessen export.sqrelation.pdf.file = /jasper/sqrelation.jasper export.sqrelation.pdf.mode = Transport-Abfluss Beziehung export.minfo.bedquality.km = km @@ -421,7 +424,7 @@ floodmap.wmsbackground = Hintergrundkarte floodmap.riveraxis = Flussachse -floodmap.uesk = \u00dcSG: {0}-km {1,number,####} - {2,number,####} +floodmap.uesk = \u00dcSG: {0}-km {1,number,####} - {2,number,####} - {3} floodmap.barriers = Digitalisierte Objekte floodmap.kms = Kilometrierung floodmap.qps = Querprofilspuren diff -r 28748bb1b676 -r 7fabae60428b artifacts/src/main/resources/messages_en.properties --- a/artifacts/src/main/resources/messages_en.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/artifacts/src/main/resources/messages_en.properties Fri Sep 27 17:36:50 2013 +0200 @@ -141,7 +141,7 @@ floodplain.inactive = Inactiv outlier.method.grubbs=Grubbs -outlier.method.std-dev=Standard deviation +outlier.method.std-dev=Residual standard error river = River calculation_mode = Calculation Mode @@ -157,6 +157,7 @@ chart.longitudinal.section.title = W-Longitudinal Section chart.longitudinal.section.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} chart.longitudinal.section.shortsubtitle = {0} +chart.longitudinal.section.locsubtitle = {0} km {1,number,#.###} chart.longitudinal.section.xaxis.label = {0}-km chart.longitudinal.section.yaxis.label = W [{0}] chart.longitudinal.section.yaxis.second.label = Q [m\u00b3/s] @@ -171,6 +172,7 @@ chart.computed.discharge.curve.subtitle = {0}-km: {1,number,#.###} chart.computed.discharge.curve.yaxis.label = W [{0}] chart.computed.discharge.curve.curve.label = Discharge Curve {0} km {1} +chart.computed.discharge.curve.gauge = current DC {0} {1} - {2} chart.duration.curve.title = Duration Curve chart.duration.curve.subtitle = {0}-km: {1,number,#.###} chart.duration.curve.xaxis.label = Duration of Non-Exceedence [Days] @@ -209,7 +211,7 @@ chart.normalized.reference.curve.title = Reduced Reference Curve chart.w_differences.title = Differences -chart.w_differences.subtitle = Range: {0}-km {1,number,#.###} - {2,number,#.###} +chart.w_differences.subtitle = {0} chart.w_differences.yaxis.label = m chart.w_differences.yaxis.second.label = W [NN + m] @@ -290,7 +292,7 @@ bedquality.toplayer = 0.0m - 0.3m bedquality.sublayer = 0.1m - 0.5m facet.bedheight.diff.year = Bedheight Difference {0} -facet.bedheight.diff.morph = sounding Width {0} +facet.bedheight.diff.morph = sounding Width facet.bedheight.diff.height1 = Original Height Minuend {0} facet.bedheight.diff.height2 = Original Height Subtrahend {0} facet.bedheight.diff.absolute = Bedheight Difference/Year {0} @@ -313,7 +315,7 @@ chart.beddifference.height.yaxis.label = Difference [cm/year] chart.beddifference.epoch.title = Bedheight Difference chart.beddifference.xaxis.label = {0}-km -chart.beddifference.yaxis.label.diff = Difference [m] +chart.beddifference.yaxis.label.diff = Difference [cm] chart.beddifference.yaxis.label.height = Absolute Height [m] chart.beddifference.year.title = Bedheight Difference chart.beddifference.yaxis.label.morph = Width [m] @@ -391,6 +393,7 @@ export.sedimentload_ls.csv.header.coarse = coarse export.sedimentload_ls.csv.header.finemiddle = finemiddle export.sedimentload_ls.csv.header.sand = sand +export.sedimentload_ls.csv.header.suspsandbb = susp. sand (BB) export.sedimentload_ls.csv.header.suspsand = susp. sand export.sedimentload_ls.csv.header.suspsediment = susp. sediment export.sedimentload_ls.csv.header.total = total @@ -405,9 +408,10 @@ export.sqrelation.csv.header.coeff.r = r^2 export.sqrelation.csv.header.n.total = n total export.sqrelation.csv.header.n.outliers = n outliers -export.sqrelation.csv.header.c.duan = C (DUAN) -export.sqrelation.csv.header.c.ferguson = C (FERGUSON) -export.sqrelation.csv.header.variance = Standard variance +export.sqrelation.csv.header.c.duan = C (Duan) +export.sqrelation.csv.header.c.ferguson = C (Ferguson) +export.sqrelation.csv.header.sd = Standard error +export.sqrelation.csv.header.qmax = Q max,measured export.sqrelation.pdf.file = /jasper/sqrelation_en.jasper export.sqrelation.pdf.mode = Load Discharge Relation export.minfo.bedquality.km = km @@ -426,7 +430,7 @@ floodmap.wmsbackground = Background Map floodmap.riveraxis = River Axis -floodmap.uesk = Floodmap: {0}-km {1,number,####} - {2,number,####} +floodmap.uesk = Floodmap: {0}-km {1,number,####} - {2,number,####} - {3} floodmap.barriers = Digitized Objects floodmap.kms = Kilometrage floodmap.qps = Crosssection Tracks diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java --- a/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java Fri Sep 27 17:36:50 2013 +0200 @@ -941,6 +941,7 @@ WstParser wstParser = new WstParser(); wstParser.parse(wstFile); wst = wstParser.getWst(); + wst.setKmUp(wst.guessWaterLevelIncreasing()); } public void parseGauges() throws IOException { @@ -1222,9 +1223,15 @@ } public void storeWst() { - if (!Config.INSTANCE.skipWst()) { + if (wst != null && !Config.INSTANCE.skipWst()) { River river = getPeer(); wst.storeDependencies(river); + + // The flow direction of the main wst and the corresponding + // waterlevels determine if the river is 'km_up'. + Session session = ImporterSession.getInstance().getDatabaseSession(); + river.setKmUp(wst.getKmUp()); + session.save(river); } } diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/importer/ImportWst.java --- a/backend/src/main/java/org/dive4elements/river/importer/ImportWst.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/importer/ImportWst.java Fri Sep 27 17:36:50 2013 +0200 @@ -46,6 +46,8 @@ protected ImportWstColumnFactory columnFactory; + protected boolean kmUp; + /** Wst as in db. */ protected Wst peer; @@ -80,6 +82,13 @@ this.kind = kind; } + public boolean getKmUp() { + return kmUp; + } + + public void setKmUp(boolean kmUp) { + this.kmUp = kmUp; + } public void setDescription(String description) { this.description = description; @@ -120,7 +129,7 @@ public void storeDependencies(River river) { log.info("store '" + description + "'"); - Wst wst = getPeer(river); + getPeer(river); for (ImportWstColumn column: columns) { column.storeDependencies(river); @@ -130,6 +139,19 @@ session.flush(); } + public boolean guessWaterLevelIncreasing() { + int up = 0; + for (ImportWstColumn column: columns) { + if (column.guessWaterLevelIncreasing()) ++up; + } + return up > columns.size() - up; + } + + public void fixRangesOrder() { + for (ImportWstColumn column: columns) { + column.fixRangesOrder(); + } + } /** Get corresponding mapped wst (from database). */ public Wst getPeer(River river) { diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/importer/ImportWstColumn.java --- a/backend/src/main/java/org/dive4elements/river/importer/ImportWstColumn.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/importer/ImportWstColumn.java Fri Sep 27 17:36:50 2013 +0200 @@ -18,6 +18,7 @@ import java.util.List; import java.util.ArrayList; +import java.util.Random; import java.math.BigDecimal; @@ -129,7 +130,7 @@ public void storeDependencies(River river) { log.info("store column '" + name + "'"); - WstColumn column = getPeer(river); + getPeer(river); for (ImportWstColumnQRange columnQRange: columnQRanges) { columnQRange.getPeer(river); @@ -148,6 +149,36 @@ this.timeInterval = timeInterval; } + public boolean guessWaterLevelIncreasing() { + + int N = columnValues.size(); + + if (N < 2) { + return true; + } + + Random r = new Random(); + int up = 0; + + int S = N < 50 ? N : (int)(0.1f * N)+1; + for (int s = 0; s < S; ++s) { + int i1, i2; + do { + i1 = r.nextInt(N-1); + i2 = r.nextInt(N-1); + } while (i1 == i2); + ImportWstColumnValue b = columnValues.get(i1); + ImportWstColumnValue a = columnValues.get(i2); + if (b.getPosition().compareTo(a.getPosition()) < 0) { + ImportWstColumnValue t = a; a = b; b = t; + } + + if (a.getW().compareTo(b.getW()) < 0) ++up; + } + + return up > S - up; + } + /** Get corresponding mapped wst-column (from database). */ public WstColumn getPeer(River river) { if (peer == null) { @@ -169,7 +200,7 @@ List<WstColumn> columns = query.list(); if (columns.isEmpty()) { - log.debug("source: " + source); + log.debug("source: " + source); peer = new WstColumn( w, name, description, source, position, ti); session.save(peer); diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/model/CrossSection.java --- a/backend/src/main/java/org/dive4elements/river/model/CrossSection.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/CrossSection.java Fri Sep 27 17:36:50 2013 +0200 @@ -69,7 +69,7 @@ "JOIN cross_sections cs ON cs_ranges.cross_section_id = cs.id " + "LEFT OUTER JOIN time_intervals ON cs.time_interval_id = time_intervals.id " + "WHERE :km BETWEEN minkm AND maxkm " + - "ORDER BY stop_time desc, start_time asc, :km - minkm"; + "ORDER BY stop_time desc, start_time desc, :km - minkm"; // Order by time interval missing. private Integer id; @@ -241,11 +241,19 @@ List<Integer> results = sqlQuery.list(); - for (Integer result: results) { + if (results.size() >= 1) { + Integer result = results.get(0); if (result == getId()) { return true; } } + else { + logger.warn("No CS found that could be master."); + } + + // TODO If there is none, might need a fallback. + // Formerly this was the most current CS (issue1157). + return false; } } diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/model/Gauge.java --- a/backend/src/main/java/org/dive4elements/river/model/Gauge.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/Gauge.java Fri Sep 27 17:36:50 2013 +0200 @@ -223,7 +223,6 @@ this.mainValues = mainValues; } - public static Gauge getGaugeByOfficialNumber(long number) { Session session = SessionHolder.HOLDER.get(); @@ -237,6 +236,21 @@ return results.isEmpty() ? null : results.get(0); } + public static Gauge getGaugeByOfficialNumber(long number, String river_name) { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from Gauge as gau " + + "where gau.officialNumber=:number and gau.river.name=:river_name"); + + query.setParameter("number", number); + query.setParameter("river_name", river_name); + + List<Gauge> results = query.list(); + + return results.isEmpty() ? null : results.get(0); + } + public DischargeTable fetchMasterDischargeTable() { for (DischargeTable dt: dischargeTables) { diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java --- a/backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java Fri Sep 27 17:36:50 2013 +0200 @@ -8,6 +8,8 @@ package org.dive4elements.river.model; +import java.util.List; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -18,6 +20,10 @@ import javax.persistence.SequenceGenerator; import javax.persistence.Table; +import org.hibernate.Session; +import org.hibernate.Query; + +import org.dive4elements.river.backend.SessionHolder; @Entity @Table(name = "measurement_station") @@ -176,4 +182,17 @@ public void setDescription(String description) { this.description = description; } + + public static List<MeasurementStation> getStationsAtKM(String river, Double river_km) + { + Session session = SessionHolder.HOLDER.get(); + + Query query = session.createQuery( + "from MeasurementStation as ms " + + "where ms.river.name = :river_name and ms.station = :river_km"); + query.setParameter("river_name", river); + query.setParameter("river_km", river_km); + + return query.list(); + } } diff -r 28748bb1b676 -r 7fabae60428b backend/src/main/java/org/dive4elements/river/utils/EpsilonComparator.java --- a/backend/src/main/java/org/dive4elements/river/utils/EpsilonComparator.java Fri Sep 13 18:29:01 2013 +0200 +++ b/backend/src/main/java/org/dive4elements/river/utils/EpsilonComparator.java Fri Sep 27 17:36:50 2013 +0200 @@ -9,9 +9,10 @@ package org.dive4elements.river.utils; import java.util.Comparator; +import java.io.Serializable; /** Comparator with some tolerance (epsilon). */ -public class EpsilonComparator implements Comparator<Double> +public class EpsilonComparator implements Comparator<Double>, Serializable { public static final double EPSILON = 1e-4; diff -r 28748bb1b676 -r 7fabae60428b contrib/make_flys_release/issue_overview.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/make_flys_release/issue_overview.sh Fri Sep 27 17:36:50 2013 +0200 @@ -0,0 +1,31 @@ +#!/bin/sh + +# Use this on an exported query from roundup +# Known issue: Tiles with more then three , in them fail. +# Yes (ah) I do not know how to correctly handle the csv quoting... + +echo "-------------" +echo "Unter anderem wurden folgende issues bearbeitet und können getestet werden:" + +sed 's/"\(.*\),\(.*\)"/"\1§\2"/g' "$1" | \ +sed 's/"\(.*\),\(.*\)"/"\1§\2"/g' | \ +sed 's/"\(.*\),\(.*\)"/\1§\2/g' | \ +gawk -F, '$5 > 5 { +print "- flys/issue"$2 " ("$1")" +print "[https://roundup-intern.intevation.de/flys/issue"$2"]" +print "" +}' | sed 's/§/,/g' + + +echo "-------------" +echo "Desweiteren gab es fortschritte in folgenden Issues:" +echo "" +sed 's/"\(.*\),\(.*\)"/"\1§\2"/g' "$1" | \ +sed 's/"\(.*\),\(.*\)"/"\1§\2"/g' | \ +sed 's/"\(.*\),\(.*\)"/\1§\2/g' | \ +gawk -F, '$5 <= 5 && $5 > 0 { +print "- flys/issue"$2 " ("$1")" +print "[https://roundup-intern.intevation.de/flys/issue"$2"]" +print "" +}' | sed 's/§/,/g' + diff -r 28748bb1b676 -r 7fabae60428b contrib/make_flys_release/make_release.sh --- a/contrib/make_flys_release/make_release.sh Fri Sep 13 18:29:01 2013 +0200 +++ b/contrib/make_flys_release/make_release.sh Fri Sep 27 17:36:50 2013 +0200 @@ -86,7 +86,7 @@ BACKENDUSER=${BACKENDUSER:-flys_dami} BACKENDPASS=${BACKENDPASS:-flys_dami} INITSQLS=${INITSQLS:-} -DGM_PATH=${DGM_PATH:-/opt/river/gewaesser} +DGM_PATH=${DGM_PATH:-/vol1/projects/Geospatial/flys-3.0/testdaten/dami_dgms/} LOG_DIR=/var/log/flys OPTS=`getopt -o ?w:,t,o \ diff -r 28748bb1b676 -r 7fabae60428b etl/src/main/java/org/dive4elements/river/etl/aft/River.java --- a/etl/src/main/java/org/dive4elements/river/etl/aft/River.java Fri Sep 13 18:29:01 2013 +0200 +++ b/etl/src/main/java/org/dive4elements/river/etl/aft/River.java Fri Sep 27 17:36:50 2013 +0200 @@ -15,9 +15,11 @@ import java.sql.SQLException; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; import org.apache.log4j.Logger; @@ -80,6 +82,7 @@ ConnectedStatements aftStatements = context.getAftStatements(); String riverName = getName(); + String lowerRiverName = riverName.toLowerCase(); Map<Long, DIPSGauge> aftDIPSGauges = new HashMap<Long, DIPSGauge>(); @@ -113,7 +116,7 @@ continue; } String gaugeRiver = dipsGauge.getRiverName(); - if (!gaugeRiver.equalsIgnoreCase(riverName)) { + if (!lowerRiverName.contains(gaugeRiver.toLowerCase())) { log.warn( "DIPS: MESSSTELLE '" + name + "' is assigned to river '" + gaugeRiver + @@ -136,11 +139,25 @@ .clearParameters() .setInt("river_id", id1).executeQuery(); + TreeMap<Double, String> station2gaugeName = new TreeMap<Double, String>( + new Comparator<Double>() { + @Override + public int compare(Double a, Double b) { + double diff = a - b; + if (diff < -0.0001) return -1; + if (diff > 0.0001) return +1; + return 0; + } + }); + try { while (gaugesRs.next()) { int gaugeId = gaugesRs.getInt("id"); String name = gaugesRs.getString("name"); long number = gaugesRs.getLong("official_number"); + double station = gaugesRs.getDouble("station"); + station2gaugeName.put(station, name); + if (gaugesRs.wasNull()) { log.warn("FLYS: Gauge '" + name + "' has no official number. Ignored."); @@ -163,7 +180,8 @@ gaugesRs.close(); } - boolean modified = createGauges(context, aftDIPSGauges); + boolean modified = createGauges( + context, aftDIPSGauges, station2gaugeName); modified |= updateGauges(context, updateGauges); @@ -364,7 +382,8 @@ protected boolean createGauges( SyncContext context, - Map<Long, DIPSGauge> gauges + Map<Long, DIPSGauge> gauges, + Map<Double, String> station2gaugeName ) throws SQLException { @@ -385,6 +404,14 @@ log.info("Gauge '" + gauge.getAftName() + "' not in FLYS but in AFT/DIPS. -> Create"); + String flysGaugeName = station2gaugeName.get(gauge.getStation()); + if (flysGaugeName != null) { + log.warn("FLYS: AFT gauge " + gauge.getName() + + " has same station as FLYS gauge " + flysGaugeName + + " -> ignored."); + continue; + } + if (!gauge.hasDatums()) { log.warn("DIPS: Gauge '" + gauge.getAftName() + "' has no datum. Ignored."); diff -r 28748bb1b676 -r 7fabae60428b etl/src/main/java/org/dive4elements/river/etl/aft/Rivers.java --- a/etl/src/main/java/org/dive4elements/river/etl/aft/Rivers.java Fri Sep 13 18:29:01 2013 +0200 +++ b/etl/src/main/java/org/dive4elements/river/etl/aft/Rivers.java Fri Sep 27 17:36:50 2013 +0200 @@ -14,9 +14,7 @@ import java.sql.SQLException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.log4j.Logger; @@ -27,6 +25,24 @@ public Rivers() { } + private static List<River> findFLYSRivers( + List<River> flysRivers, + String needle + ) { + List<River> rivers = new ArrayList<River>(); + + needle = needle.toLowerCase(); + + for (River river: flysRivers) { + String name = river.getName().toLowerCase(); + if (name.contains(needle)) { + rivers.add(river); + } + } + + return rivers; + } + public boolean sync(SyncContext context) throws SQLException { log.info("sync: rivers"); @@ -34,7 +50,7 @@ ConnectedStatements flysStatements = context.getFlysStatements(); ConnectedStatements aftStatements = context.getAftStatements(); - Map<String, River> flysRivers = new HashMap<String, River>(); + List<River> flysRivers = new ArrayList<River>(); ResultSet flysRs = flysStatements .getStatement("select.rivers").executeQuery(); @@ -45,7 +61,7 @@ String name = flysRs.getString("name"); double from = flysRs.getDouble("min_km"); double to = flysRs.getDouble("max_km"); - flysRivers.put(name.toLowerCase(), new River(id, name, from, to)); + flysRivers.add(new River(id, name, from, to)); } } finally { @@ -60,9 +76,8 @@ try { while (aftRs.next()) { String name = aftRs.getString("NAME"); - River river = flysRivers.get(name.toLowerCase()); - if (river != null) { - int id2 = aftRs.getInt("GEWAESSER_NR"); + int id2 = aftRs.getInt("GEWAESSER_NR"); + for (River river: findFLYSRivers(flysRivers, name)) { river.setId2(id2); commonRivers.add(river); } @@ -72,8 +87,15 @@ aftRs.close(); } + boolean modified = false; - boolean modified = false; + if (log.isDebugEnabled()) { + log.debug("Rivers found in FLYS and AFT:"); + for (River river: commonRivers) { + log.debug(" " + river.getName()); + } + log.debug("---"); + } for (River river: commonRivers) { modified |= river.sync(context); diff -r 28748bb1b676 -r 7fabae60428b etl/src/main/java/org/dive4elements/river/etl/aft/SyncContext.java --- a/etl/src/main/java/org/dive4elements/river/etl/aft/SyncContext.java Fri Sep 13 18:29:01 2013 +0200 +++ b/etl/src/main/java/org/dive4elements/river/etl/aft/SyncContext.java Fri Sep 27 17:36:50 2013 +0200 @@ -119,6 +119,10 @@ double station = gauge.getStation(); if (station >= from && station <= to) { result.put(entry.getKey(), gauge); + } else { + log.warn("DIPS: Skipping Gauge: " + gauge.getName() + + " because it is at Station: " + station + + " and the river is limited to: " + from + " - " + to); } } diff -r 28748bb1b676 -r 7fabae60428b etl/src/main/resources/sql/flys-common.properties --- a/etl/src/main/resources/sql/flys-common.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/etl/src/main/resources/sql/flys-common.properties Fri Sep 27 17:36:50 2013 +0200 @@ -7,7 +7,7 @@ WHERE w.kind = 0 \ GROUP BY r.id, r.name select.gauges = \ - SELECT id, name, official_number \ + SELECT id, name, official_number, station \ FROM gauges \ WHERE river_id = :river_id next.gauge.id = \ diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Fri Sep 27 17:36:50 2013 +0200 @@ -934,6 +934,18 @@ String delta_w(); + String delta_w_cm(); + + String delta_w_cma(); + + String wlevel(); + + String yields(); + + String years(); + + String epochs(); + // Capabilities Information Panel String addwmsInputTitle(); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Fri Sep 27 17:36:50 2013 +0200 @@ -369,7 +369,7 @@ error_gc_doc_not_valid = Capabilities document is not valid. error_malformed_url = The URL you have entered is not valid. error_no_dgm_selected = No DEM selected. -error_invalid_dgm_selected = You have selected an invalid DEM. +error_invalid_dgm_selected = An error occured while selecting the DEM. error_bad_dgm_range = You have selected a DEM with an invalid range. error_bad_dgm_river = You have selected a DEM for a wrong river. error_dialog_not_valid = One or more values are not valid. @@ -496,7 +496,13 @@ measurements = Measurements floodmarks = Flood Marks pegel_had_measurement_points = HAD Discharge-Measurement points -delta_w = Delta W +delta_w = Waterleveldifferences +delta_w_cm = cm +delta_w_cma = cm/a +wlevel = Waterlevels +yields = sedimentyields +years = years +epochs = epochs # No translation for the pegelonline wms service layer names. gauge_points = Pegelpunkte (WSV) gauge_level = Aktueller Wasserstand (WSV) diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Fri Sep 27 17:36:50 2013 +0200 @@ -369,7 +369,7 @@ error_gc_doc_not_valid = Das Capabilities Dokument ist nicht valide. error_malformed_url = Die eingegebene URL ist ung\u00fcltig. error_no_dgm_selected = Sie haben kein DGM gew\u00e4hlt. -error_invalid_dgm_selected = Sie haben ein falsches DGM gew\u00e4hlt. +error_invalid_dgm_selected = Bei der Auswahl des DGMs ist ein Fehler aufgetreten. error_bad_dgm_range = Das gew\u00e4hlte DGM passt nicht zur gew\u00e4hlten Berechnungsstrecke. error_bad_dgm_river = Das gew\u00e4hlte DGM passt nicht zum gew\u00e4hlten Fluss. error_dialog_not_valid = Eine oder mehrere Daten sind nicht korrekt. @@ -501,7 +501,13 @@ measurements = Messungen floodmarks = HW-Marken pegel_had_measurement_points = HAD Abflussmessstellen (WMS) -delta_w = W Differenzen +delta_w = Wasserspiegeldifferenzen +delta_w_cm = cm +delta_w_cma = cm/a +wlevel = Wasserspiegellagen +yields = Frachten +years = Einzeljahre +epochs = Epochen gauge_points = Pegelmessstelle (WMS) gauge_level = Wasserstand (WMS) gauge_names = Pegelname (WMS) diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Fri Sep 27 17:36:50 2013 +0200 @@ -367,7 +367,7 @@ error_gc_doc_not_valid = Capabilities document is not valid. error_malformed_url = The URL you have entered is not valid. error_no_dgm_selected = No DEM selected. -error_invalid_dgm_selected = You have selected an invalid DEM. +error_invalid_dgm_selected = An error occured while selecting the DEM. error_bad_dgm_range = You have selected a DEM with an invalid range. error_bad_dgm_river = You have selected a DEM for a wrong river. error_dialog_not_valid = One or more values are not valid. @@ -480,7 +480,13 @@ bedheights = Bedheights morph_width = morphologic Width datacage = Datacage -delta_w = Delta W +delta_w = Waterleveldifferences +delta_w_cm = cm +delta_w_cma = cm/a +wlevel = Waterlevels +yields = sedimentyields +years = years +epochs = epochs startcolor = Colorrange start color endcolor = Colorrange end color diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoService.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoService.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoService.java Fri Sep 27 17:36:50 2013 +0200 @@ -28,7 +28,8 @@ */ DischargeInfoObject[] getDischargeInfo( String locale, - long gauge) + long gauge, + String river) throws ServerException; } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoServiceAsync.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoServiceAsync.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DischargeInfoServiceAsync.java Fri Sep 27 17:36:50 2013 +0200 @@ -21,6 +21,7 @@ void getDischargeInfo( String locale, long gauge, + String river, AsyncCallback<DischargeInfoObject[]> cb); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DistancePanel.java Fri Sep 27 17:36:50 2013 +0200 @@ -57,6 +57,7 @@ import java.util.List; +/** Panel to allow input of distance for calculation range. */ public class DistancePanel extends AbstractUIProvider implements BlurHandler, FilterHandler { diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ExportPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ExportPanel.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ExportPanel.java Fri Sep 27 17:36:50 2013 +0200 @@ -120,6 +120,7 @@ imgUrl += MSG.downloadWST(); } else if (facet.equals("csv")) { + url += "&encoding=windows-1252"; imgUrl += MSG.downloadCSV(); } else { diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/GaugeTimeRangePanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/GaugeTimeRangePanel.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/GaugeTimeRangePanel.java Fri Sep 27 17:36:50 2013 +0200 @@ -105,7 +105,8 @@ Config config = Config.getInstance(); String url = config.getServerUrl(); - yearTable.setDataSource(new DischargeInfoDataSource(url, gauge)); + String river = artifact.getArtifactDescription().getRiver(); + yearTable.setDataSource(new DischargeInfoDataSource(url, gauge, river)); helperContainer.addMember(createHelperPanel()); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/LocationDistancePanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/LocationDistancePanel.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/LocationDistancePanel.java Fri Sep 27 17:36:50 2013 +0200 @@ -963,17 +963,19 @@ double step = getStep(); if (from < min || from > max) { - String tmp = MESSAGES.error_validate_lower_range(); + String tmp = MESSAGES.error_validate_range(); tmp = tmp.replace("$1", nf.format(from)); tmp = tmp.replace("$2", nf.format(min)); + tmp = tmp.replace("$3", nf.format(max)); errors.add(tmp); from = min; } if (to < min || to > max) { - String tmp = MESSAGES.error_validate_upper_range(); + String tmp = MESSAGES.error_validate_range(); tmp = tmp.replace("$1", nf.format(to)); - tmp = tmp.replace("$2", nf.format(max)); + tmp = tmp.replace("$2", nf.format(min)); + tmp = tmp.replace("$3", nf.format(max)); errors.add(tmp); to = max; } diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/RiverInfoPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/RiverInfoPanel.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/RiverInfoPanel.java Fri Sep 27 17:36:50 2013 +0200 @@ -102,8 +102,6 @@ DynamicForm infoLink = WikiLinks.linkDynamicForm(this.flys, wikiBaseUrl + url, MSG.gauge_river_info_link()); infoLink.setTop(5); - LinkItem item = (LinkItem)infoLink.getField("saml"); - item.setTextBoxStyle("font-size: large;"); add(infoLink); } diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WikiLinks.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WikiLinks.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WikiLinks.java Fri Sep 27 17:36:50 2013 +0200 @@ -50,31 +50,32 @@ if (currentUser != null) { String saml = currentUser.getSamlXMLBase64(); - final DynamicForm form = new DynamicForm(); - form.setMethod(FormMethod.POST); - form.setTarget("_blank"); - form.setAction(quotedUrl); - form.setCanSubmit(true); - LinkItem item = new LinkItem("saml"); - item.setShowTitle(false); - item.setLinkTitle(quotedText); - item.setValue(SafeHtmlUtils.htmlEscape(saml)); - item.addClickHandler(new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - form.submitForm(); - } - }); - form.setFields(item); - return form; + if (saml != null) { + final DynamicForm form = new DynamicForm(); + form.setMethod(FormMethod.POST); + form.setTarget("_blank"); + form.setAction(quotedUrl); + form.setCanSubmit(true); + LinkItem item = new LinkItem("saml"); + item.setTextBoxStyle("font-size: large;"); + item.setShowTitle(false); + item.setLinkTitle(quotedText); + item.setValue(SafeHtmlUtils.htmlEscape(saml)); + item.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + form.submitForm(); + } + }); + form.setFields(item); + return form; + } } - else { - DynamicForm form = new DynamicForm(); - LinkItem item = new LinkItem(quotedText); - item.setShowTitle(false); - item.setTarget(quotedUrl); - return form; - } + DynamicForm form = new DynamicForm(); + LinkItem item = new LinkItem(quotedText); + item.setShowTitle(false); + item.setTarget(quotedUrl); + return form; } public static DynamicForm dynamicForm(FLYS flys, String url) { @@ -83,26 +84,26 @@ if (currentUser != null) { String saml = currentUser.getSamlXMLBase64(); - saml = SafeHtmlUtils.htmlEscape(saml); - GWT.log("saml=" + saml); - DynamicForm form = new DynamicForm(); - form.setID("wikiDynamicForm"); - form.setMethod(FormMethod.POST); - form.setTarget("_blank"); - form.setAction(quotedUrl); - form.setCanSubmit(true); - HiddenItem item = new HiddenItem("saml"); - item.setDefaultValue(saml); - item.setValue(saml); - form.setFields(item); - //form.setValue("saml", saml); - return form; + if (saml != null) { + saml = SafeHtmlUtils.htmlEscape(saml); + GWT.log("saml=" + saml); + DynamicForm form = new DynamicForm(); + form.setID("wikiDynamicForm"); + form.setMethod(FormMethod.POST); + form.setTarget("_blank"); + form.setAction(quotedUrl); + form.setCanSubmit(true); + HiddenItem item = new HiddenItem("saml"); + item.setDefaultValue(saml); + item.setValue(saml); + form.setFields(item); + //form.setValue("saml", saml); + return form; + } } - else { - DynamicForm form = new DynamicForm(); - form.setTarget("_blank"); - form.setAction(quotedUrl); - return form; - } + DynamicForm form = new DynamicForm(); + form.setTarget("_blank"); + form.setAction(quotedUrl); + return form; } } diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartOutputTab.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartOutputTab.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartOutputTab.java Fri Sep 27 17:36:50 2013 +0200 @@ -652,6 +652,18 @@ } + /** Get link to export image in given dimension, format and encoding. */ + public String getExportUrl( + int width, int height, String format, String encoding) { + String url = getImgUrl(width, height); + url += "&format=" + format; + url += "&export=true"; + url += "&encoding=" + encoding; + + return url; + } + + /** Get link to export image in given dimension and format. */ public String getExportUrl(int width, int height, String format) { String url = getImgUrl(width, height); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartToolbar.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartToolbar.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/chart/ChartToolbar.java Fri Sep 27 17:36:50 2013 +0200 @@ -156,7 +156,7 @@ downloadCSV = new ImgLink( baseUrl + MSG.downloadCSV(), - chartTab.getExportUrl(-1, -1, "csv"), + chartTab.getExportUrl(-1, -1, "csv", "windows-1252"), 20, 20); downloadCSV.setTooltip(MSG.downloadCSVTooltip()); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/client/ui/range/DischargeInfoDataSource.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/range/DischargeInfoDataSource.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/range/DischargeInfoDataSource.java Fri Sep 27 17:36:50 2013 +0200 @@ -20,7 +20,7 @@ public static final String XPATH_DISCHARGE_DEFAULT = "/discharges/discharge"; - public DischargeInfoDataSource(String url, long gauge) { + public DischargeInfoDataSource(String url, long gauge, String river) { setDataFormat(DSDataFormat.XML); setRecordXPath(XPATH_DISCHARGE_DEFAULT); @@ -37,15 +37,16 @@ "end", FieldType.TEXT, "end"); setFields(desc, bfgid, start, end); - setDataURL(getServiceURL(url, gauge)); + setDataURL(getServiceURL(url, gauge, river)); } - protected String getServiceURL(String server, long gauge) { + protected String getServiceURL(String server, long gauge, String river) { String url = GWT.getModuleBaseURL(); url += "dischargeinfoxml"; url += "?server=" + server; url += "&gauge=" + String.valueOf(gauge); + url += "&river=" + river; return url; } diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/CSVExportServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/CSVExportServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/CSVExportServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -77,7 +77,7 @@ try { InputStream in = client.collectionOut(requestDoc, uuid, "export"); Reader reader = new InputStreamReader (in, "UTF-8"); - CSVReader csvReader = new CSVReader (reader); + CSVReader csvReader = new CSVReader (reader, ';'); List<String[]> lines = new ArrayList<String[]>(); String[] line = null; diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/ChartOutputServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/ChartOutputServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/ChartOutputServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -29,8 +29,10 @@ /** * This service is used to request a chart from the artifact server. The - * response is directed directly to the output stream, so the image that is - * retrieved is displayed in the UI afterwards. + * response is directed directly to the output stream. This can be used + * to stream an image that is displayed in the UI afterwards. + * + * Note that a chart output can also be a csv file. * * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ @@ -41,6 +43,7 @@ Logger.getLogger(ChartOutputServiceImpl.class); + /** Handle a get, collectionOut. */ public void doGet(HttpServletRequest req, HttpServletResponse resp) { logger.info("ChartOutputServiceImpl.doGet"); @@ -49,9 +52,10 @@ String url = getServletContext().getInitParameter("server-url"); - String uuid = req.getParameter("uuid"); - String type = req.getParameter("type"); - String locale = req.getParameter("locale"); + String uuid = req.getParameter("uuid"); + String type = req.getParameter("type"); + String locale = req.getParameter("locale"); + String encoding = req.getParameter("encoding"); prepareHeader(req, resp); @@ -60,6 +64,16 @@ ChartServiceHelper.getChartAttributes(prepareChartAttributes(req))); HttpClient client = new HttpClientImpl(url, locale); + + if (encoding != null) { + try { + client.setOutEncoding( + java.nio.charset.Charset.forName(encoding)); + } + catch(java.nio.charset.UnsupportedCharsetException e) { + logger.warn("Unsupported encoding: " + encoding); + } + } client.collectionOut(request, uuid, "chart", out); out.close(); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -48,9 +48,11 @@ public static final String XPATH_DISTANCES = "art:discharges/art:discharge"; + @Override public DischargeInfoObject[] getDischargeInfo( String locale, - long gauge) + long gauge, + String river) throws ServerException { logger.info("DichargeInfoServiceImpl.getDischargeInfo"); @@ -67,6 +69,10 @@ Element gaugeEl = ec.create("gauge"); gaugeEl.setTextContent(String.valueOf(gauge)); + Element riverEl = ec.create("river"); + riverEl.setTextContent(river); + + gaugeEl.appendChild(riverEl); doc.appendChild(gaugeEl); HttpClient client = new HttpClientImpl(url, locale); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoXML.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoXML.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DischargeInfoXML.java Fri Sep 27 17:36:50 2013 +0200 @@ -50,6 +50,8 @@ String gauge = req.getParameter("gauge"); + String river = req.getParameter("river"); + Document doc = XMLUtils.newDocument(); XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( @@ -60,6 +62,12 @@ Element gaugeEl = ec.create("gauge"); gaugeEl.setTextContent(gauge); + if (river != null && !river.isEmpty()) { + Element riverEl = ec.create("river"); + riverEl.setTextContent(river); + gaugeEl.appendChild(riverEl); + } + doc.appendChild(gaugeEl); HttpClient client = new HttpClientImpl(url); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/ExportServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/ExportServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/ExportServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -55,6 +55,7 @@ String locale = req.getParameter("locale"); String km = req.getParameter("km"); String fn = name + "." + type; + String enc = req.getParameter("encoding"); resp.setHeader("Content-Disposition", "attachment;filename=" + fn); @@ -74,6 +75,18 @@ Document request = ClientProtocolUtils.newOutCollectionDocument( uuid, mode, type, attr); HttpClient client = new HttpClientImpl(url, locale); + + // Set out encoding if specified. + if (enc != null) { + try { + client.setOutEncoding( + java.nio.charset.Charset.forName(enc)); + } + catch(java.nio.charset.UnsupportedCharsetException e) { + logger.warn("Unsupported encoding: " + enc); + } + } + client.collectionOut(request, uuid, mode, out); out.close(); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/FixingsOverviewServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/FixingsOverviewServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/FixingsOverviewServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -33,8 +33,6 @@ import java.util.ArrayList; import java.util.List; -import javax.xml.xpath.XPathConstants; - import org.apache.log4j.Logger; import org.w3c.dom.Document; @@ -58,9 +56,6 @@ protected static final String XPATH_RFROM = "/fixings/river/@from"; protected static final String XPATH_RTO = "/fixings/river/@to"; - protected static final String XPATH_EVENT = "/fixings/events/event"; - - @Override public FixingsOverviewInfo generateOverview( String locale, @@ -193,18 +188,16 @@ protected List<FixEvent> getFixEvents(Document doc) { List<FixEvent> list = new ArrayList<FixEvent>(); - NodeList events = (NodeList) XMLUtils.xpath( - doc, - XPATH_EVENT, - XPathConstants.NODESET, - null); + NodeList events = doc.getElementsByTagName("event"); - if (events == null || events.getLength() == 0) { + int E = events.getLength(); + + if (E == 0) { log.warn("No events in Overview!"); return list; } - for (int i = 0, E = events.getLength(); i < E; i++) { + for (int i = 0; i < E; i++) { Element n = (Element)events.item(i); List<Sector> sectors = getSectors(n); String cid = n.getAttribute("cid"); @@ -218,13 +211,15 @@ protected List<Sector> getSectors(Element event) { NodeList sectors = event.getElementsByTagName("sector"); - if (sectors.getLength() == 0) { + int S = sectors.getLength(); + + if (S == 0) { log.warn("No Sectors in Event!"); return null; } - List<Sector> list = new ArrayList<Sector>(); - for (int i = 0, S = sectors.getLength(); i < S; i++) { + List<Sector> list = new ArrayList<Sector>(S); + for (int i = 0; i < S; i++) { Element n = (Element)sectors.item(i); int cls = -1; double from = -1; diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java Fri Sep 27 17:36:50 2013 +0200 @@ -427,6 +427,7 @@ // Currently this is not a problem because /flys/map-print // is whitelisted in GGInAFilter. GetMethod get = new GetMethod(url); + get.addRequestHeader("X_NO_GGINA_AUTH", "TRUE"); int result = client.executeMethod(get); InputStream in = get.getResponseBodyAsStream(); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/RemoteServiceServlet.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/RemoteServiceServlet.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/RemoteServiceServlet.java Fri Sep 27 17:36:50 2013 +0200 @@ -16,7 +16,7 @@ extends com.google.gwt.user.server.rpc.RemoteServiceServlet { /** - * Return the current logged in user from the HTTP Session + * Return the current logged in user from the HTTP Session. */ public User getUser() { HttpSession session = this.getThreadLocalRequest().getSession(); diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/filter/GGInAFilter.java Fri Sep 27 17:36:50 2013 +0200 @@ -100,9 +100,12 @@ // Allow access to localhost if (isLocalAddress(req)) { - logger.debug("Request to localhost"); - chain.doFilter(req, resp); - return; + String noAuth = sreq.getHeader("X_NO_GGINA_AUTH"); + if (noAuth != null && noAuth.equals("TRUE")) { + logger.debug("Request to localhost"); + chain.doFilter(req, resp); + return; + } } // Allow access to login pages diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/shared/model/FixingsOverviewInfo.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/FixingsOverviewInfo.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/FixingsOverviewInfo.java Fri Sep 27 17:36:50 2013 +0200 @@ -61,9 +61,9 @@ } public FixEvent getEventByCId(String cid) { - for (int i = 0; i < events.size(); i++) { - if (events.get(i).getCId().equals(cid)) { - return events.get(i); + for (FixEvent event: events) { + if (event.getCId().equals(cid)) { + return event; } } return null; diff -r 28748bb1b676 -r 7fabae60428b gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java Fri Sep 13 18:29:01 2013 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/ToLoad.java Fri Sep 27 17:36:50 2013 +0200 @@ -21,26 +21,34 @@ { /** Two strings. */ - public class StringPair { + public static class StringTriple { public String first; public String second; - public StringPair(String first, String second) { + public String third; + public StringTriple(String first, String second, String third) { this.first = first; this.second = second; + this.third = third; } + @Override public int hashCode() { - return first.hashCode() + second.hashCode(); + return first.hashCode() + second.hashCode() + third.hashCode(); } - public boolean equals(StringPair other) { - return (this.second.equals(other.second)) && (this.first.equals(other.first)); + @Override + public boolean equals(Object o) { + if (!(o instanceof StringTriple)) { + return false; + } + StringTriple other = (StringTriple) o; + return second.equals(other.second) && first.equals(other.first) && third.equals(other.third); } } public static final String SYNTHETIC_KEY = "key-"; - protected Map<String, Map<StringPair, ArtifactFilter>> artifacts; + protected Map<String, Map<StringTriple, ArtifactFilter>> artifacts; public ToLoad() { - artifacts = new HashMap<String, Map<StringPair, ArtifactFilter>>(); + artifacts = new HashMap<String, Map<StringTriple, ArtifactFilter>>(); } public static final String uniqueKey(Map<?, ?> map) { @@ -81,17 +89,17 @@ artifactName = uniqueKey(artifacts); } - Map<StringPair, ArtifactFilter> artifact = artifacts.get(artifactName); + Map<StringTriple, ArtifactFilter> artifact = artifacts.get(artifactName); if (artifact == null) { - artifact = new HashMap<StringPair, ArtifactFilter>(); + artifact = new HashMap<StringTriple, ArtifactFilter>(); artifacts.put(artifactName, artifact); } ArtifactFilter filter = artifact.get(factory); if (filter == null) { filter = new ArtifactFilter(factory); - artifact.put(new StringPair(factory, displayName), filter); + artifact.put(new StringTriple(factory, displayName, targetOut), filter); } filter.add(out, name, ids); @@ -104,7 +112,7 @@ public List<Recommendation> toRecommendations() { List<Recommendation> recommendations = new ArrayList<Recommendation>(); - for (Map.Entry<String, Map<StringPair, ArtifactFilter>> all: + for (Map.Entry<String, Map<StringTriple, ArtifactFilter>> all: artifacts.entrySet() ) { String masterArtifact = all.getKey(); @@ -113,11 +121,12 @@ masterArtifact = null; } - for (Map.Entry<StringPair, ArtifactFilter> entry: + for (Map.Entry<StringTriple, ArtifactFilter> entry: all.getValue().entrySet() ) { - StringPair pair = entry.getKey(); - String factory = pair.first; + StringTriple triple = entry.getKey(); + String factory = triple.first; + String targetOut = triple.third; ArtifactFilter artifactFilter = entry.getValue(); String ids; @@ -133,8 +142,8 @@ } Recommendation recommendation = new Recommendation( - factory, ids, masterArtifact, filter); - recommendation.setDisplayName(pair.second); + factory, ids, masterArtifact, filter, targetOut); + recommendation.setDisplayName(triple.second); recommendations.add(recommendation); }