Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java @ 3318:dbe2f85bf160
merged flys-artifacts/2.8
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:35 +0200 |
parents | d9af29a4bb85 |
children | b0ba96bbf01d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java Fri Sep 28 12:14:35 2012 +0200 @@ -0,0 +1,387 @@ +package de.intevation.flys.artifacts; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +import java.awt.geom.Point2D; + +import de.intevation.artifactdatabase.state.Facet; +import de.intevation.artifactdatabase.state.DefaultOutput; +import de.intevation.artifactdatabase.state.State; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.CallMeta; +import de.intevation.flys.artifacts.math.Distance; +import de.intevation.flys.artifacts.math.Linear; + +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.RelativePointFacet; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WKmsFacet; +import de.intevation.flys.artifacts.model.WKmsFactory; + +import de.intevation.flys.artifacts.states.StaticState; +import de.intevation.flys.artifacts.resources.Resources; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.artifacts.geom.Lines; + +import de.intevation.flys.model.FastCrossSectionLine; + + +/** + * Artifact to access additional "waterlevel"-type of data, like the height + * of protective measures (dikes). + * + * This artifact neglects (Static)FLYSArtifacts capabilities of interaction + * with the StateEngine by overriding the getState*-methods. + */ +public class StaticWKmsArtifact +extends StaticFLYSArtifact +implements FacetTypes, WaterLineArtifact +{ + /** The logger for this class. */ + private static Logger logger = + Logger.getLogger(StaticWKmsArtifact.class); + + public static final String STATIC_STATE_NAME = + "state.additional_wkms.static"; + + /** Data Item name to know whether we are Heighmarks and reveive + * some data slightly different. */ + public static final String DATA_HEIGHT_TYPE = + "height_marks"; + + /** One and only state to be in. */ + protected transient State state = null; + + + /** + * Trivial Constructor. + */ + public StaticWKmsArtifact() { + logger.debug("StaticWKmsArtifact.StaticWKmsArtifact"); + } + + + /** + * Gets called from factory, to set things up. + */ + @Override + public void setup( + String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { + logger.debug("StaticWKmsArtifact.setup"); + + state = new StaticState(STATIC_STATE_NAME); + + List<Facet> fs = new ArrayList<Facet>(); + logger.debug(XMLUtils.toString(data)); + String code = getDatacageIDValue(data); + + // TODO Go for JSON, one day. + //ex.: flood_protection-wstv-114-12 + if (code != null) { + String [] parts = code.split("-"); + + if (parts.length >= 4) { + int col = -1; + int wst = Integer.valueOf(parts[3]); + + if (!parts[2].equals("A")) { + col = Integer.valueOf(parts[2]); + } + + addStringData("col_pos", parts[2]); + addStringData("wst_id", parts[3]); + + String wkmsName; + if (col >= 0) { + wkmsName = WKmsFactory.getWKmsName(col, wst); + } + else { + wkmsName = WKmsFactory.getWKmsName(wst); + } + + String name; + if (parts[0].equals(HEIGHTMARKS_POINTS)) { + name = HEIGHTMARKS_POINTS; + addStringData(DATA_HEIGHT_TYPE, "true"); + } + else { + name = STATIC_WKMS; + } + + String facetDescription = Resources.getMsg( + callMeta, wkmsName, wkmsName); + Facet wKmsFacet = new WKmsFacet( + name, + facetDescription); + Facet csFacet = new CrossSectionWaterLineFacet(0, + facetDescription); + Facet rpFacet = new RelativePointFacet(facetDescription); + + fs.add(wKmsFacet); + fs.add(csFacet); + fs.add(rpFacet); + facets.put(state.getID(), fs); + } + } + + spawnState(); + super.setup(identifier, factory, context, callMeta, data); + } + + + /** + * Initialize the static state with output. + * @return static state + */ + protected State spawnState() { + state = new StaticState(STATIC_STATE_NAME); + List<Facet> fs = facets.get(STATIC_STATE_NAME); + DefaultOutput output = new DefaultOutput( + "general", + "general", "image/png", + fs, + "chart"); + + state.getOutputs().add(output); + return state; + } + + + /** + * Called via setup. + * + * @param artifact The master-artifact. + */ + @Override + protected void initialize( + Artifact artifact, + Object context, + CallMeta meta) + { + logger.debug("StaticWKmsArtifact.initialize"); + FLYSArtifact winfo = (FLYSArtifact) artifact; + // TODO: The river is of no interest, so far. + addData("river", winfo.getData("river")); + } + + + /** + * 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(); + } + + + /** + * Get WKms from factory. + * @param idx param is not needed (TODO?) + * @return WKms according to parameterization (can be null); + */ + public WKms getWKms(int idx) { + logger.debug("StaticWKmsArtifact.getWKms"); + + return WKmsFactory.getWKms( + Integer.valueOf(getDataAsString("col_pos")), + Integer.valueOf(getDataAsString("wst_id"))); + } + + + /** + * Returns W at Km of WKms, linearly interpolated. + * Returns -1 if not found. + */ + public static double getWAtKmLin(WKms wkms, double km) { + // Uninformed search. + int size = wkms.size(); + int idx = 0; + boolean kmIncreasing = (wkms.getKm(0) < wkms.getKm(wkms.size()-1)) + ? true : false; + if (kmIncreasing) { + while (idx < size && wkms.getKm(idx) < km) { + idx++; + } + } + else { + idx = wkms.size() -1; + while (idx > 0 && wkms.getKm(idx) > km) { + idx--; + } + } + + if (idx == size -1 || idx == 0) { + return -1; + } + + // Do linear interpolation + int mod = kmIncreasing ? -1 : +1; + return Linear.linear(km, wkms.getKm(idx+mod), wkms.getKm(idx), wkms.getW(idx+mod), wkms.getW(idx)); + } + + + /** + * Get the W at a specific km, only if it is closer to km than to any of + * the other given km. + * Return Double.NaN otherwise + * + * @param wkms WKms in which to search for a spatially close W value. + * @param km the input km, which is compared to values from wkms. + * @param next the next available input km (-1 if unavailable). + * @param prev the previous available input km (-1 if unavailable). + * + * @return W in wkms that is closer to km than to next and prev, or Double.NaN. + */ + public double getWAtCloseKm(WKms wkms, double km, double next, double prev) { + int size = wkms.size(); + for (int i = 0; i < size; i++) { + double wkmsKm = wkms.getKm(i); + double dist = Distance.distance(wkmsKm, km); + if ((prev == -1d || dist <= Distance.distance(wkmsKm, prev)) + && (next == -1d || dist <= Distance.distance(wkmsKm, next))) { + return wkms.getW(i); + } + } + + return Double.NaN; + } + + + /** + * Returns W at Km of WKms, searching linearly. + * Returns -1 if not found. + * @param wkms the WKms object to search for given km. + * @param km The searched km. + * @return W at given km if in WKms, -1 if not found. + */ + public static double getWAtKm(WKms wkms, double km) { + // Uninformed search, intolerant. + double TOLERANCE = 0.0d; + int size = wkms.size(); + for (int i = 0; i < size; i++) { + if (Distance.within(wkms.getKm(i), km, TOLERANCE)) { + return wkms.getW(i); + } + } + + return -1; + } + + + /** + * Get points of line describing the surface of water at cross section. + * + * @param idx Index of facet and in wkms array. + * @param csl FastCrossSectionLine to compute water surface agains. + * @param next The km of the next crosssectionline. + * @param prev The km of the previous crosssectionline. + * + * @return an array holding coordinates of points of surface of water ( + * in the form {{x1, x2}, {y1, y2}} ). + */ + @Override + public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, + double next, double prev + ) { + logger.debug("getWaterLines(" + idx + ")/" + identifier()); + + List<Point2D> points = csl.getPoints(); + + WKms wkms = getWKms(0); + + double km = csl.getKm(); + + // Find W at km. + double wAtKm; + + // If heightmarks, only deliver if data snaps. + if (getDataAsString(DATA_HEIGHT_TYPE) != null && + getDataAsString(DATA_HEIGHT_TYPE).equals("true")) { + wAtKm = getWAtCloseKm(wkms, km, next, prev); + } + else { + wAtKm = getWAtKm(wkms, km); + } + + if (wAtKm == -1 || Double.isNaN(wAtKm)) { + logger.warn("Waterlevel at km " + km + " unknown."); + return new Lines.LineData(new double[][] {{}}, 0d, 0d); + } + + return Lines.createWaterLines(points, wAtKm); + } + + + /** + * Determines Facets initial disposition regarding activity (think of + * selection in Client ThemeList GUI). This will be checked one time + * when the facet enters a collections describe document. + * + * @param facetName name of the facet. + * @param index index of the facet. + * + * @return Always 0. Static Data will enter plots inactive. + */ + @Override + public int getInitialFacetActivity( + String outputName, + String facetName, + int index) + { + return 0; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :