8884
|
1 /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde |
|
2 * Software engineering by |
|
3 * Björnsen Beratende Ingenieure GmbH |
|
4 * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt |
|
5 * |
|
6 * This file is Free Software under the GNU AGPL (>=v3) |
|
7 * and comes with ABSOLUTELY NO WARRANTY! Check out the |
|
8 * documentation coming with Dive4Elements River for details. |
|
9 */ |
|
10 |
8916
|
11 package org.dive4elements.river.artifacts.sinfo.common; |
8884
|
12 |
9200
|
13 import java.util.Map; |
8884
|
14 import java.util.Set; |
|
15 |
|
16 import org.apache.log4j.Logger; |
|
17 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; |
9203
|
18 import org.dive4elements.artifactdatabase.state.Facet; |
9200
|
19 import org.dive4elements.artifacts.Artifact; |
|
20 import org.dive4elements.artifacts.CallContext; |
|
21 import org.dive4elements.river.artifacts.D4EArtifact; |
|
22 import org.dive4elements.river.artifacts.access.RiverAccess; |
|
23 import org.dive4elements.river.artifacts.common.AbstractCalculationResult; |
|
24 import org.dive4elements.river.artifacts.common.IResultType; |
|
25 import org.dive4elements.river.artifacts.context.RiverContext; |
|
26 import org.dive4elements.river.artifacts.math.MovingAverage; |
|
27 import org.dive4elements.river.artifacts.model.ZoomScale; |
9203
|
28 import org.dive4elements.river.artifacts.resources.Resources; |
|
29 import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; |
8884
|
30 import org.dive4elements.river.exports.DiagramGenerator; |
9200
|
31 import org.dive4elements.river.exports.StyledSeriesBuilder; |
8884
|
32 import org.dive4elements.river.exports.process.DefaultProcessor; |
9200
|
33 import org.dive4elements.river.jfree.StyledAreaSeriesCollection; |
|
34 import org.dive4elements.river.jfree.StyledXYSeries; |
8884
|
35 import org.dive4elements.river.themes.ThemeDocument; |
|
36 |
|
37 /** |
|
38 * Abstraction for some processor implementation within S-INFO. Probably this abstraction could also be used for other |
|
39 * cases as well. |
|
40 * |
|
41 * @author Gernot Belger |
|
42 * |
|
43 */ |
8916
|
44 public abstract class AbstractSInfoProcessor extends DefaultProcessor { |
8884
|
45 |
9200
|
46 protected static final double GAP_DISTANCE = 0.101; |
|
47 |
8884
|
48 private final static Logger log = Logger.getLogger(AbstractSInfoProcessor.class); |
|
49 |
|
50 private String yAxisLabel; |
|
51 |
|
52 private final Set<String> handled_facet_types; |
|
53 |
|
54 private final String i18n_axis_label; |
|
55 |
|
56 public AbstractSInfoProcessor(final String i18n_axis_label, final Set<String> handled_facet_types) { |
|
57 this.i18n_axis_label = i18n_axis_label; |
|
58 this.handled_facet_types = handled_facet_types; |
|
59 } |
|
60 |
|
61 @Override |
|
62 public final void doOut(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { |
8886
|
63 try { |
|
64 this.yAxisLabel = generateSeries(generator, bundle, theme, visible); |
8884
|
65 } |
8886
|
66 catch (final Exception e) { |
|
67 log.error(e.getMessage(), e); |
|
68 } |
8884
|
69 } |
|
70 |
|
71 /** |
8886
|
72 * @return The axis label |
8884
|
73 */ |
8886
|
74 protected abstract String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible); |
8884
|
75 |
9200
|
76 protected final String buildSeriesForType(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible, |
|
77 final IResultType resultType, final Double gapDistance) { |
|
78 final CallContext context = generator.getContext(); |
|
79 final Map<String, String> metaData = bundle.getFacet().getMetaData(); |
|
80 |
|
81 final Artifact artifact = bundle.getArtifact(); |
|
82 |
|
83 final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); |
|
84 series.putMetaData(metaData, artifact, context); |
|
85 |
|
86 final String facetName = bundle.getFacetName(); |
|
87 |
|
88 final AbstractCalculationResult data = (AbstractCalculationResult) bundle.getData(context); |
|
89 if (data == null) { |
|
90 // Check has been here before so we keep it for security reasons |
|
91 // this should never happen though. |
|
92 throw new IllegalStateException("Data is null for facet: " + facetName); |
|
93 } |
|
94 |
|
95 final double[][] points = generatePoints(context, artifact, data, facetName, resultType); |
|
96 |
|
97 if (gapDistance == null) |
|
98 StyledSeriesBuilder.addPoints(series, points, true); |
|
99 else |
|
100 StyledSeriesBuilder.addPoints(series, points, true, gapDistance); |
|
101 |
|
102 generator.addAxisSeries(series, getAxisName(), visible); |
|
103 |
|
104 return metaData.get("Y"); |
|
105 } |
|
106 |
|
107 protected final String buildSeriesForTkh(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, |
|
108 final boolean visible) { |
|
109 final CallContext context = generator.getContext(); |
|
110 |
|
111 final String facetName = bundle.getFacetName(); |
|
112 final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context); |
|
113 if (data == null) { |
|
114 // Check has been here before so we keep it for security reasons |
|
115 // this should never happen though. |
|
116 throw new IllegalStateException("Data is null for facet: " + facetName); |
|
117 } |
|
118 |
|
119 final StyledXYSeries seriesUp = new StyledXYSeries(bundle.getFacetDescription(), theme); |
|
120 final double[][] pointsUp = data.getTkhUpPoints(); |
|
121 StyledSeriesBuilder.addPoints(seriesUp, pointsUp, true); |
|
122 |
|
123 // REMARK: we add " " because the description is misused as id, which must be unique. |
|
124 final StyledXYSeries seriesDown = new StyledXYSeries(bundle.getFacetDescription() + " ", theme); |
|
125 final double[][] pointsDown = data.getTkhDownPoints(); |
|
126 StyledSeriesBuilder.addPoints(seriesDown, pointsDown, true); |
|
127 |
|
128 final StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme); |
|
129 area.setMode(StyledAreaSeriesCollection.FILL_MODE.BETWEEN); |
|
130 area.addSeries(seriesUp); |
|
131 area.addSeries(seriesDown); |
|
132 |
|
133 generator.addAreaSeries(area, getAxisName(), visible); |
|
134 |
|
135 return null; |
|
136 } |
|
137 |
|
138 private Double findRadius(final CallContext context, final Artifact artifact) { |
|
139 final Double start = (Double) context.getContextValue("startkm"); |
|
140 final Double end = (Double) context.getContextValue("endkm"); |
|
141 |
|
142 if (start == null || end == null) |
|
143 return null; |
|
144 |
|
145 final RiverContext fc = (RiverContext) context.globalContext(); |
|
146 final ZoomScale scales = (ZoomScale) fc.get("zoomscale"); |
|
147 final RiverAccess access = new RiverAccess((D4EArtifact) artifact); |
|
148 final String river = access.getRiverName(); |
|
149 |
|
150 return scales.getRadius(river, start, end); |
|
151 } |
|
152 |
|
153 private double[][] generatePoints(final CallContext context, final Artifact artifact, final AbstractCalculationResult data, final String facetName, |
|
154 final IResultType resultType) { |
|
155 |
|
156 final double[][] points = data.getStationPoints(resultType); |
|
157 if (facetName.endsWith(".filtered")) { |
|
158 final Double radius = findRadius(context, artifact); |
|
159 return movingAverage(radius, points); |
|
160 } |
|
161 |
|
162 return points; |
|
163 } |
|
164 |
|
165 private double[][] movingAverage(final Double radius, final double[][] points) { |
|
166 |
|
167 if (radius == null) |
|
168 return points; |
|
169 |
|
170 return MovingAverage.weighted(points, radius); |
|
171 } |
|
172 |
8884
|
173 @Override |
|
174 public final boolean canHandle(final String facettype) { |
|
175 return this.handled_facet_types.contains(facettype); |
|
176 } |
|
177 |
|
178 @Override |
|
179 public final String getAxisLabel(final DiagramGenerator generator) { |
|
180 if (this.yAxisLabel != null && !this.yAxisLabel.isEmpty()) { |
|
181 // REMARK/UNINTENDED: yAxisLabel may also be a resolved message (side-effect of StyledXYSeries#putMetadata), |
|
182 // and cannot be resolved, so we need to give the resolved value as default |
9040
|
183 // TODO: In other implementations (i.e. FlowVelocityProcessor), an explicit (German) default label is given here, |
8884
|
184 // probably the English version will also show German (CHECK) |
|
185 return generator.msg(this.yAxisLabel, this.yAxisLabel); |
|
186 } |
|
187 return generator.msg(this.i18n_axis_label, "MISSING"); |
|
188 } |
9203
|
189 |
|
190 // Moved from SInfoLineProcessor: |
|
191 protected static final Facet createFacet(final CallContext context, final String hash, final String id, final AbstractCalculationResult result, |
|
192 final int index, final String axisLabel, final String facetId, final String description) { |
|
193 final String facetFlowDepthFilteredDescription = Resources.getMsg(context.getMeta(), description, description, result.getLabel()); |
|
194 return new SInfoResultFacet(index, facetId, facetFlowDepthFilteredDescription, axisLabel, ComputeType.ADVANCE, id, hash); |
|
195 } |
|
196 |
8884
|
197 } |