comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java @ 3818:dc18457b1cef

merged flys-artifacts/pre2.7-2012-03-16
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:59 +0200
parents 734d5f5e55c0
children d35e37b6a211
comparison
equal deleted inserted replaced
2456:60ab1054069d 3818:dc18457b1cef
1 package de.intevation.flys.artifacts;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.NavigableMap;
6
7 import org.apache.log4j.Logger;
8
9 import org.w3c.dom.Document;
10
11 import de.intevation.artifacts.Artifact;
12 import de.intevation.artifacts.ArtifactFactory;
13 import de.intevation.artifacts.CallMeta;
14
15 import de.intevation.flys.artifacts.model.CrossSectionFacet;
16 import de.intevation.flys.artifacts.model.FastCrossSectionLineFactory;
17
18 import de.intevation.flys.model.FastCrossSectionLine;
19
20 import de.intevation.flys.model.CrossSection;
21 import de.intevation.flys.model.CrossSectionLine;
22 import de.intevation.flys.artifacts.model.CrossSectionFactory;
23 import de.intevation.artifacts.common.ArtifactNamespaceContext;
24 import de.intevation.artifacts.common.utils.XMLUtils;
25
26 import de.intevation.flys.artifacts.states.StaticState;
27
28 import de.intevation.artifactdatabase.state.Facet;
29 import de.intevation.artifactdatabase.state.State;
30
31 import de.intevation.flys.utils.FLYSUtils;
32
33 import de.intevation.flys.artifacts.services.CrossSectionKMService;
34
35
36 /**
37 * Artifact describing a cross-section.
38 */
39 public class CrossSectionArtifact extends StaticFLYSArtifact {
40
41 /** Access ids of doc. */
42 public static final String XPATH_IDS = "/art:action/art:ids/@value";
43
44 /** Name of Artifact. */
45 public static final String CS_ARTIFACT_NAME = "cross_section";
46
47 /** Name of state. */
48 public static final String STATIC_STATE_NAME = "state.cross_section";
49
50 /** Name of data item keeping the position. */
51 public static final String DATA_KM = "cross_section.km";
52
53 /** Name of data item keeping the database id of this c.s.. */
54 public static final String DATA_DBID = "cross_section.dbid";
55
56 /** Name of data item flagging whether we think that we are master. */
57 public static final String DATA_IS_MASTER = "cross_section.master?";
58
59 /** Name of data item flagging whether we are the newest. */
60 public static final String DATA_IS_NEWEST = "cross_section.newest?";
61
62 /** Own logger. */
63 private static final Logger logger =
64 Logger.getLogger(CrossSectionArtifact.class);
65
66
67 /** Return given name. */
68 @Override
69 public String getName() {
70 return CS_ARTIFACT_NAME;
71 }
72
73
74 /** Store ids, create a CrossSectionFacet. */
75 @Override
76 public void setup(
77 String identifier,
78 ArtifactFactory factory,
79 Object context,
80 CallMeta callMeta,
81 Document data)
82 {
83 logger.info("CrossSectionArtifact.setup");
84
85 super.setup(identifier, factory, context, callMeta, data);
86
87 String ids = XMLUtils.xpathString(
88 data, XPATH_IDS, ArtifactNamespaceContext.INSTANCE);
89
90 if (ids != null && ids.length() > 0) {
91 addStringData(DATA_DBID, ids);
92 logger.debug("CrossSectionArtifacts db-id: " + ids);
93 }
94 else {
95 throw new IllegalArgumentException("No attribute 'ids' found!");
96 }
97
98 List<Facet> fs = new ArrayList<Facet>();
99 CrossSection cs = CrossSectionFactory.getCrossSection(
100 Integer.valueOf(ids));
101
102 List<CrossSectionLine> csls = cs.getLines();
103 if (!csls.isEmpty()) {
104 CrossSectionLine csl = csls.get(0);
105 // Find min-km of cross sections,
106 // then set DATA_KM to min(DATA_KM, minCross).
107 double masterKm = Double.valueOf(getDataAsString(DATA_KM));
108 if (masterKm < csl.getKm().doubleValue()) {
109 addStringData(DATA_KM, csl.getKm().toString());
110 }
111 }
112 fs.add(new CrossSectionFacet(0, cs.getDescription()));
113
114 // Find out if we are newest.
115 boolean isNewest = CrossSectionFactory.isNewest(cs);
116 String newString = (isNewest) ? "1" : "0";
117 addStringData(DATA_IS_NEWEST, newString);
118 addStringData(DATA_IS_MASTER, newString);
119
120 StaticState state = (StaticState) getCurrentState(context);
121
122 if (!fs.isEmpty()) {
123 facets.put(getCurrentStateId(), fs);
124 }
125 }
126
127
128 /** Copy km where master-artifact "starts". */
129 @Override
130 protected void initialize(
131 Artifact artifact,
132 Object context,
133 CallMeta callMeta)
134 {
135 FLYSArtifact winfo = (FLYSArtifact) artifact;
136 double[] range = FLYSUtils.getKmRange(winfo);
137 double min = 0.0f;
138 if (range != null && range.length > 0) {
139 min = range[0];
140 }
141 this.addStringData(DATA_KM, Double.toString(min));
142 }
143
144
145 /**
146 * Create and return a new StaticState with charting output.
147 */
148 @Override
149 public State getCurrentState(Object cc) {
150 final List<Facet> fs = facets.get(getCurrentStateId());
151
152 StaticState state = new StaticState(STATIC_STATE_NAME) {
153 @Override
154 public Object staticCompute(List<Facet> facets) {
155 if (facets != null) {
156 facets.addAll(fs);
157 }
158 return null;
159 }
160 };
161
162 state.addDefaultChartOutput("cross_section", fs);
163
164 return state;
165 }
166
167
168 /**
169 * Get a list containing the one and only State.
170 * @param context ignored.
171 * @return list with one and only state.
172 */
173 @Override
174 protected List<State> getStates(Object context) {
175 ArrayList<State> states = new ArrayList<State>();
176 states.add(getCurrentState(context));
177
178 return states;
179 }
180
181 // TODO all data access needs proper caching.
182
183 /**
184 * Get a DataItem casted to int (0 if fails).
185 */
186 public int getDataAsIntNull(String dataName) {
187 String val = getDataAsString(dataName);
188 try {
189 return Integer.valueOf(val);
190 }
191 catch (NumberFormatException e) {
192 logger.warn("Could not get data " + dataName + " as int", e);
193 return 0;
194 }
195 }
196
197
198 /** Returns database-id of cross-section (from data). */
199 protected int getDBID() {
200 return getDataAsIntNull(DATA_DBID);
201 }
202
203
204 /**
205 * Return position (km) from data, 0 if not found.
206 */
207 protected double getKm() {
208 String val = getDataAsString(DATA_KM);
209 try {
210 return Double.valueOf(val);
211 }
212 catch (NumberFormatException e) {
213 logger.warn("Could not get data " + DATA_KM + " as double", e);
214 return 0;
215 }
216 }
217
218
219 /** Returns true if artifact is set to be a "master" (other facets will
220 * refer to this). */
221 public boolean isMaster() {
222 return !getDataAsString(DATA_IS_MASTER).equals("0");
223 }
224
225
226 /**
227 * Get points of Profile of cross section at given kilometer.
228 *
229 * @return an array holding coordinates of points of profile (
230 * in the form {{x1, x2} {y1, y2}} ).
231 */
232 public double [][] getCrossSectionData() {
233 logger.info("getCrossSectionData() for cross_section.km "
234 + getDataAsString(DATA_KM));
235 FastCrossSectionLine line = searchCrossSectionLine();
236
237 return line != null
238 ? line.fetchCrossSectionProfile()
239 : null;
240 }
241
242
243 /**
244 * Get CrossSectionLine spatially closest to what is specified in the data
245 * "cross_section.km".
246 *
247 * @return CrossSectionLine closest to "cross_section.km".
248 */
249 public FastCrossSectionLine searchCrossSectionLine() {
250
251 CrossSection crossSection = CrossSectionFactory
252 .getCrossSection(getDBID());
253
254 if (logger.isDebugEnabled()) {
255 logger.debug("dbid " + getDBID() + " : " + crossSection);
256 }
257
258 NavigableMap<Double, Integer> kms = CrossSectionKMService
259 .getKms(crossSection.getId());
260
261 Double wishKM = getKm();
262
263 Double floor = kms.floorKey(wishKM);
264 Double ceil = kms.ceilingKey(wishKM);
265
266 double floorD = floor != null
267 ? Math.abs(floor - wishKM)
268 : Double.MAX_VALUE;
269
270 double ceilD = ceil != null
271 ? Math.abs(ceil - wishKM)
272 : Double.MAX_VALUE;
273
274 double km = floorD < ceilD ? floor : ceil;
275
276 return FastCrossSectionLineFactory
277 .getCrossSectionLine(crossSection, km);
278 }
279
280
281 /**
282 * Determines Facets initial disposition regarding activity (think of
283 * selection in Client ThemeList GUI). This will be checked one time
284 * when the facet enters a collections describe document.
285 *
286 * @param outputName Ignored.
287 * @param facetName Ignored.
288 * @param index Ignored.
289 * @return 0 if not active
290 */
291 @Override
292 public int getInitialFacetActivity(String outputName, String facetName, int index) {
293 return (getDataAsString(DATA_IS_NEWEST) != null
294 && getDataAsString(DATA_IS_NEWEST).equals("1")) ? 1 : 0;
295 }
296 }
297 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org