comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java @ 3468:f37e7e8907cb

merged flys-artifacts/2.8.1
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:39 +0200
parents b0ba96bbf01d
children afc7bfb4800b
comparison
equal deleted inserted replaced
3387:5ffad8bde8ad 3468:f37e7e8907cb
1 package de.intevation.flys.artifacts;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import org.apache.log4j.Logger;
7
8 import org.w3c.dom.Document;
9
10 import java.awt.geom.Point2D;
11
12 import de.intevation.artifactdatabase.state.Facet;
13 import de.intevation.artifactdatabase.state.DefaultOutput;
14 import de.intevation.artifactdatabase.state.State;
15
16 import de.intevation.artifacts.Artifact;
17 import de.intevation.artifacts.ArtifactFactory;
18 import de.intevation.artifacts.CallMeta;
19 import de.intevation.flys.artifacts.math.Distance;
20 import de.intevation.flys.artifacts.math.Linear;
21
22 import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet;
23 import de.intevation.flys.artifacts.model.FacetTypes;
24 import de.intevation.flys.artifacts.model.RelativePointFacet;
25 import de.intevation.flys.artifacts.model.WKms;
26 import de.intevation.flys.artifacts.model.WKmsFacet;
27 import de.intevation.flys.artifacts.model.WKmsFactory;
28
29 import de.intevation.flys.artifacts.states.StaticState;
30 import de.intevation.flys.artifacts.resources.Resources;
31
32 import de.intevation.artifacts.common.utils.XMLUtils;
33
34 import de.intevation.flys.artifacts.geom.Lines;
35
36 import de.intevation.flys.model.FastCrossSectionLine;
37
38
39 /**
40 * Artifact to access additional "waterlevel"-type of data, like the height
41 * of protective measures (dikes).
42 *
43 * This artifact neglects (Static)FLYSArtifacts capabilities of interaction
44 * with the StateEngine by overriding the getState*-methods.
45 */
46 public class StaticWKmsArtifact
47 extends StaticFLYSArtifact
48 implements FacetTypes, WaterLineArtifact
49 {
50 /** The logger for this class. */
51 private static Logger logger =
52 Logger.getLogger(StaticWKmsArtifact.class);
53
54 public static final String STATIC_STATE_NAME =
55 "state.additional_wkms.static";
56
57 /** Data Item name to know whether we are Heighmarks and reveive
58 * some data slightly different. */
59 public static final String DATA_HEIGHT_TYPE =
60 "height_marks";
61
62 /** One and only state to be in. */
63 protected transient State state = null;
64
65
66 /**
67 * Trivial Constructor.
68 */
69 public StaticWKmsArtifact() {
70 logger.debug("StaticWKmsArtifact.StaticWKmsArtifact");
71 }
72
73
74 /**
75 * Gets called from factory, to set things up.
76 */
77 @Override
78 public void setup(
79 String identifier,
80 ArtifactFactory factory,
81 Object context,
82 CallMeta callMeta,
83 Document data)
84 {
85 logger.debug("StaticWKmsArtifact.setup");
86
87 state = new StaticState(STATIC_STATE_NAME);
88
89 List<Facet> fs = new ArrayList<Facet>();
90 logger.debug(XMLUtils.toString(data));
91 String code = getDatacageIDValue(data);
92
93 // TODO Go for JSON, one day.
94 //ex.: flood_protection-wstv-114-12
95 if (code != null) {
96 String [] parts = code.split("-");
97
98 if (parts.length >= 4) {
99 int col = -1;
100 int wst = Integer.parseInt(parts[3]);
101
102 if (!parts[2].equals("A")) {
103 col = Integer.parseInt(parts[2]);
104 }
105
106 addStringData("col_pos", parts[2]);
107 addStringData("wst_id", parts[3]);
108
109 String wkmsName;
110 if (col >= 0) {
111 wkmsName = WKmsFactory.getWKmsName(col, wst);
112 }
113 else {
114 wkmsName = WKmsFactory.getWKmsName(wst);
115 }
116
117 String name;
118 if (parts[0].equals(HEIGHTMARKS_POINTS)) {
119 name = HEIGHTMARKS_POINTS;
120 addStringData(DATA_HEIGHT_TYPE, "true");
121 }
122 else {
123 name = STATIC_WKMS;
124 }
125
126 String facetDescription = Resources.getMsg(
127 callMeta, wkmsName, wkmsName);
128 Facet wKmsFacet = new WKmsFacet(
129 name,
130 facetDescription);
131 Facet csFacet = new CrossSectionWaterLineFacet(0,
132 facetDescription);
133 Facet rpFacet = new RelativePointFacet(facetDescription);
134
135 fs.add(wKmsFacet);
136 fs.add(csFacet);
137 fs.add(rpFacet);
138 facets.put(state.getID(), fs);
139 }
140 }
141
142 spawnState();
143 super.setup(identifier, factory, context, callMeta, data);
144 }
145
146
147 /**
148 * Initialize the static state with output.
149 * @return static state
150 */
151 protected State spawnState() {
152 state = new StaticState(STATIC_STATE_NAME);
153 List<Facet> fs = facets.get(STATIC_STATE_NAME);
154 DefaultOutput output = new DefaultOutput(
155 "general",
156 "general", "image/png",
157 fs,
158 "chart");
159
160 state.getOutputs().add(output);
161 return state;
162 }
163
164
165 /**
166 * Called via setup.
167 *
168 * @param artifact The master-artifact.
169 */
170 @Override
171 protected void initialize(
172 Artifact artifact,
173 Object context,
174 CallMeta meta)
175 {
176 logger.debug("StaticWKmsArtifact.initialize");
177 FLYSArtifact winfo = (FLYSArtifact) artifact;
178 // TODO: The river is of no interest, so far.
179 addData("river", winfo.getData("river"));
180 }
181
182
183 /**
184 * Get a list containing the one and only State.
185 * @param context ignored.
186 * @return list with one and only state.
187 */
188 @Override
189 protected List<State> getStates(Object context) {
190 ArrayList<State> states = new ArrayList<State>();
191 states.add(getState());
192 return states;
193 }
194
195
196 /**
197 * Get the "current" state (there is but one).
198 * @param cc ignored.
199 * @return the "current" (only possible) state.
200 */
201 @Override
202 public State getCurrentState(Object cc) {
203 return getState();
204 }
205
206
207 /**
208 * Get the only possible state.
209 * @return the state.
210 */
211 protected State getState() {
212 return getState(null, null);
213 }
214
215
216 /**
217 * Get the state.
218 * @param context ignored.
219 * @param stateID ignored.
220 * @return the state.
221 */
222 @Override
223 protected State getState(Object context, String stateID) {
224 return (state != null)
225 ? state
226 : spawnState();
227 }
228
229
230 /**
231 * Get WKms from factory.
232 * @param idx param is not needed (TODO?)
233 * @return WKms according to parameterization (can be null);
234 */
235 public WKms getWKms(int idx) {
236 logger.debug("StaticWKmsArtifact.getWKms");
237
238 return WKmsFactory.getWKms(
239 Integer.parseInt(getDataAsString("col_pos")),
240 Integer.parseInt(getDataAsString("wst_id")));
241 }
242
243
244 /**
245 * Returns W at Km of WKms, linearly interpolated.
246 * Returns -1 if not found.
247 */
248 public static double getWAtKmLin(WKms wkms, double km) {
249 // Uninformed search.
250 int size = wkms.size();
251 int idx = 0;
252 boolean kmIncreasing = (wkms.getKm(0) < wkms.getKm(wkms.size()-1))
253 ? true : false;
254 if (kmIncreasing) {
255 while (idx < size && wkms.getKm(idx) < km) {
256 idx++;
257 }
258 }
259 else {
260 idx = wkms.size() -1;
261 while (idx > 0 && wkms.getKm(idx) > km) {
262 idx--;
263 }
264 }
265
266 if (idx == size -1 || idx == 0) {
267 return -1;
268 }
269
270 // Do linear interpolation
271 int mod = kmIncreasing ? -1 : +1;
272 return Linear.linear(km, wkms.getKm(idx+mod), wkms.getKm(idx), wkms.getW(idx+mod), wkms.getW(idx));
273 }
274
275
276 /**
277 * Get the W at a specific km, only if it is closer to km than to any of
278 * the other given km.
279 * Return Double.NaN otherwise
280 *
281 * @param wkms WKms in which to search for a spatially close W value.
282 * @param km the input km, which is compared to values from wkms.
283 * @param next the next available input km (-1 if unavailable).
284 * @param prev the previous available input km (-1 if unavailable).
285 *
286 * @return W in wkms that is closer to km than to next and prev, or Double.NaN.
287 */
288 public double getWAtCloseKm(WKms wkms, double km, double next, double prev) {
289 int size = wkms.size();
290 for (int i = 0; i < size; i++) {
291 double wkmsKm = wkms.getKm(i);
292 double dist = Distance.distance(wkmsKm, km);
293 if ((prev == -1d || dist <= Distance.distance(wkmsKm, prev))
294 && (next == -1d || dist <= Distance.distance(wkmsKm, next))) {
295 return wkms.getW(i);
296 }
297 }
298
299 return Double.NaN;
300 }
301
302
303 /**
304 * Returns W at Km of WKms, searching linearly.
305 * Returns -1 if not found.
306 * @param wkms the WKms object to search for given km.
307 * @param km The searched km.
308 * @return W at given km if in WKms, -1 if not found.
309 */
310 public static double getWAtKm(WKms wkms, double km) {
311 // Uninformed search, intolerant.
312 double TOLERANCE = 0.0d;
313 int size = wkms.size();
314 for (int i = 0; i < size; i++) {
315 if (Distance.within(wkms.getKm(i), km, TOLERANCE)) {
316 return wkms.getW(i);
317 }
318 }
319
320 return -1;
321 }
322
323
324 /**
325 * Get points of line describing the surface of water at cross section.
326 *
327 * @param idx Index of facet and in wkms array.
328 * @param csl FastCrossSectionLine to compute water surface agains.
329 * @param next The km of the next crosssectionline.
330 * @param prev The km of the previous crosssectionline.
331 *
332 * @return an array holding coordinates of points of surface of water (
333 * in the form {{x1, x2}, {y1, y2}} ).
334 */
335 @Override
336 public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl,
337 double next, double prev
338 ) {
339 logger.debug("getWaterLines(" + idx + ")/" + identifier());
340
341 List<Point2D> points = csl.getPoints();
342
343 WKms wkms = getWKms(0);
344
345 double km = csl.getKm();
346
347 // Find W at km.
348 double wAtKm;
349
350 // If heightmarks, only deliver if data snaps.
351 if (getDataAsString(DATA_HEIGHT_TYPE) != null &&
352 getDataAsString(DATA_HEIGHT_TYPE).equals("true")) {
353 wAtKm = getWAtCloseKm(wkms, km, next, prev);
354 }
355 else {
356 wAtKm = getWAtKm(wkms, km);
357 }
358
359 if (wAtKm == -1 || Double.isNaN(wAtKm)) {
360 logger.warn("Waterlevel at km " + km + " unknown.");
361 return new Lines.LineData(new double[][] {{}}, 0d, 0d);
362 }
363
364 return Lines.createWaterLines(points, wAtKm);
365 }
366
367
368 /**
369 * Determines Facets initial disposition regarding activity (think of
370 * selection in Client ThemeList GUI). This will be checked one time
371 * when the facet enters a collections describe document.
372 *
373 * @param facetName name of the facet.
374 * @param index index of the facet.
375 *
376 * @return Always 0. Static Data will enter plots inactive.
377 */
378 @Override
379 public int getInitialFacetActivity(
380 String outputName,
381 String facetName,
382 int index)
383 {
384 return 0;
385 }
386 }
387 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org