# HG changeset patch # User Felix Wolfsteller # Date 1341934316 0 # Node ID 31168ac9c7e762bb08920c24c984c437f4b9fe38 # Parent 4c4ec9e9650af5d2641405c40b69309779f7b19b Partial fix for issue694 (heightmarks snap to nearest cross section). flys-artifacts/trunk@4916 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/ChangeLog Tue Jul 10 15:31:56 2012 +0000 @@ -1,3 +1,28 @@ +2012-07-10 Felix Wolfsteller + + Partial fix for issue694 (Heightmarks snap to nearest cross section + line). + + * src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java: + Extended signature of getWaterLines to allow behaviour of only + delivering data if it snaps to the km (is closest). + + * src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java, + src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: + Documentation, updated signature of getWaterLines(). + + * src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java: + Remember if Heightmarks are displayed, if so deliver data + only if cross-section is closest (snap). + + * src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java: + Make next and previous km of cross-sections available as data. + + * src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java, + src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java: + Provide next and previous cross-section km via blackboard, adjusted + call to getWaterLines. + 2012-07-10 Sascha L. Teichmann * src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java: diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/CrossSectionArtifact.java Tue Jul 10 15:31:56 2012 +0000 @@ -54,6 +54,12 @@ /** Name of data item flagging whether we are the newest. */ public static final String DATA_IS_NEWEST = "cross_section.newest?"; + /** Name of data item storing the previous possible km. */ + public static final String DATA_PREV_KM = "cross_section.km.previous"; + + /** Name of data item storing the next possible km. */ + public static final String DATA_NEXT_KM = "cross_section.km.next"; + /** Own logger. */ private static final Logger logger = Logger.getLogger(CrossSectionArtifact.class); @@ -98,14 +104,14 @@ CrossSectionLine csl = csls.get(0); // Find min-km of cross sections, // then set DATA_KM to min(DATA_KM, minCross). - double masterKm = Double.valueOf(getDataAsString(DATA_KM)); - if (masterKm < csl.getKm().doubleValue()) { + double dataKm = Double.valueOf(getDataAsString(DATA_KM)); + if (dataKm < csl.getKm().doubleValue()) { addStringData(DATA_KM, csl.getKm().toString()); } } fs.add(new CrossSectionFacet(0, cs.getDescription())); - // Find out if we are newest. + // Find out if we are newest and become master if so. boolean isNewest = CrossSectionFactory.isNewest(cs); String newString = (isNewest) ? "1" : "0"; addStringData(DATA_IS_NEWEST, newString); @@ -136,6 +142,15 @@ } + public Double getNextKm() { + return getDataAsDouble(DATA_NEXT_KM); + } + + public Double getPrevKm() { + return getDataAsDouble(DATA_PREV_KM); + } + + /** * Create and return a new StaticState with charting output. */ @@ -238,6 +253,9 @@ * Get CrossSectionLine spatially closest to what is specified in the data * "cross_section.km", null if considered too far. * + * It also adds DataItems to store the next and previous (numerically) + * values at which cross-section data was recorded. + * * @return CrossSectionLine closest to "cross_section.km", might be null * if considered too far. */ @@ -258,6 +276,9 @@ Double floor = kms.floorKey(wishKM); Double ceil = kms.ceilingKey(wishKM); + Double nextKm; + Double prevKm; + double floorD = floor != null ? Math.abs(floor - wishKM) : Double.MAX_VALUE; @@ -266,13 +287,33 @@ ? Math.abs(ceil - wishKM) : Double.MAX_VALUE; - double km = floorD < ceilD ? floor : ceil; + double km; + if (floorD < ceilD) { + km = floor; + } + else { + km = ceil; + } // If we are too far from the wished km, return null. if (Math.abs(km - wishKM) > TOO_FAR) { return null; } + // Store next and previous km. + nextKm = kms.higherKey(km); + prevKm = kms.lowerKey(km); + + if (prevKm == null) { + prevKm = -1d; + } + if (nextKm == null) { + nextKm = -1d; + } + + addStringData(DATA_PREV_KM, prevKm.toString()); + addStringData(DATA_NEXT_KM, nextKm.toString()); + return FastCrossSectionLineFactory .getCrossSectionLine(crossSection, km); } diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/ManualPointsArtifact.java Tue Jul 10 15:31:56 2012 +0000 @@ -132,9 +132,12 @@ /** * Get the water line "surface". + * @param index index of facets data. + * @param points 'ground' against which to determine water surface. + * @param data describing water surface. */ @Override - public Lines.LineData getWaterLines(int index, FastCrossSectionLine csl) { + public Lines.LineData getWaterLines(int index, FastCrossSectionLine csl, double a, double b) { List points = csl.getPoints(); return Lines.createWaterLines(points, getLine(index)); } diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/StaticWKmsArtifact.java Tue Jul 10 15:31:56 2012 +0000 @@ -16,6 +16,7 @@ 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; @@ -34,6 +35,7 @@ import de.intevation.flys.model.FastCrossSectionLine; + /** * Artifact to access additional "waterlevel"-type of data, like the height * of protective measures (dikes). @@ -52,6 +54,11 @@ 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; @@ -110,6 +117,7 @@ String name; if (parts[0].equals(HEIGHTMARKS_POINTS)) { name = HEIGHTMARKS_POINTS; + addStringData(DATA_HEIGHT_TYPE, "true"); } else { name = STATIC_WKMS; @@ -266,6 +274,34 @@ /** + * 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. + * @param prev the previous available input km. + * + * @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(); + // TODO handle edge cases (with no next or prev). + for (int i = 0; i < size; i++) { + double wkmsKm = wkms.getKm(i); + double dist = Distance.distance(wkmsKm, km); + if ((prev != km && dist <= Distance.distance(wkmsKm, prev)) + && 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. @@ -273,10 +309,11 @@ * @return W at given km if in WKms, -1 if not found. */ public static double getWAtKm(WKms wkms, double km) { - // Uninformed search. + // Uninformed search, intolerant. + double TOLERANCE = 0.0d; int size = wkms.size(); for (int i = 0; i < size; i++) { - if (wkms.getKm(i) == km) { + if (Distance.within(wkms.getKm(i), km, TOLERANCE)) { return wkms.getW(i); } } @@ -288,12 +325,19 @@ /** * 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) { - logger.debug("getWaterLines(" + idx + ")"); + public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, + double next, double prev + ) { + logger.debug("getWaterLines(" + idx + ")/" + identifier()); List points = csl.getPoints(); @@ -302,8 +346,18 @@ double km = csl.getKm(); // Find W at km. - double wAtKm = getWAtKm(wkms, km); - if (wAtKm == -1) { + 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); } diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Tue Jul 10 15:31:56 2012 +0000 @@ -209,7 +209,7 @@ * in WstValueTable. * * @param kms The kilometer values. - * @param qa The discharge values. + * @param qs The discharge values. * @param wst The WstValueTable used for the interpolation. * * @return an array of data triples that consist of W, Q and Kms. @@ -329,7 +329,8 @@ /** * Computes the data used to create computed discharge curves. * - * @param wst The WstValueTable that is used for the interpolation. + * @param wst The WstValueTable that is used for the interpolation (river- + * bound). * @param location The location where the computation should be based on. * * @return an object that contains tuples of W/Q values at the specified @@ -346,6 +347,8 @@ return calculation.calculate(wst); } + + /** Create CalculationResult with data and message. */ protected static final CalculationResult error(Object data, String msg) { return new CalculationResult(data, new Calculation(msg)); } @@ -580,12 +583,15 @@ * * @param idx Index for getWaterlevelData. * @param csl The profile/surface to fill with water. + * @param nextIgnored Ignored in this implementation of WaterLineArtifact. + * @param prevIgnored Ignored in this implementation of WaterLineArtifact. * * @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) { + public Lines.LineData getWaterLines(int idx, FastCrossSectionLine csl, + double nextIgnored, double prevIgnored) { logger.debug("getWaterLines(" + idx + ")"); List points = csl.getPoints(); @@ -1188,8 +1194,9 @@ DURATION_Q }; + /** - * Returns the WstValueTable. + * Returns the WstValueTable of current river. */ public WstValueTable getWstValueTable() { River r = FLYSUtils.getRiver(this); diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WaterLineArtifact.java Tue Jul 10 15:31:56 2012 +0000 @@ -9,6 +9,6 @@ /** Get points that define a line of a (water)facet against a cross- * section. */ - public Lines.LineData getWaterLines(int facetIdx, FastCrossSectionLine csl); + public Lines.LineData getWaterLines(int facetIdx, FastCrossSectionLine csl, double d, double w); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionFacet.java Tue Jul 10 15:31:56 2012 +0000 @@ -25,6 +25,13 @@ public static String BLACKBOARD_CS_MASTER_DATA = "crosssection.masterprofile.data"; + public static String BLACKBOARD_CS_PREV_KM + = "crosssection.masterprofile.km.prev"; + + public static String BLACKBOARD_CS_NEXT_KM + = "crosssection.masterprofile.km.next"; + + private static Logger logger = Logger.getLogger(CrossSectionFacet.class); protected ComputeType type; @@ -43,6 +50,8 @@ List keys = new ArrayList(); if (artifact.isMaster()) { keys.add(BLACKBOARD_CS_MASTER_DATA); + keys.add(BLACKBOARD_CS_PREV_KM); + keys.add(BLACKBOARD_CS_NEXT_KM); } keys.add(artifact.identifier() + getIndex()); keys.addAll(super.getStaticDataProviderKeys(art)); @@ -71,6 +80,12 @@ else if (key.equals(artifact.identifier() + getIndex())) { return getData(artifact, context); } + else if (key.equals(BLACKBOARD_CS_NEXT_KM)) { + return crossSection.getNextKm(); + } + else if (key.equals(BLACKBOARD_CS_PREV_KM)) { + return crossSection.getPrevKm(); + } else { Object obj = super.provideBlackboardData(artifact, key, param, context); diff -r 4c4ec9e9650a -r 31168ac9c7e7 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java Tue Jul 10 13:26:13 2012 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/CrossSectionWaterLineFacet.java Tue Jul 10 15:31:56 2012 +0000 @@ -24,7 +24,9 @@ extends BlackboardDataFacet implements FacetTypes { - private static Logger logger = Logger.getLogger(CrossSectionWaterLineFacet.class); + /** Private logger to use. */ + private static Logger logger = + Logger.getLogger(CrossSectionWaterLineFacet.class); /** Trivial constructor, set (maybe localized) description. */ @@ -33,13 +35,17 @@ } - /** Trivial constructor, set (maybe localized) description. */ + /** + * Trivial constructor, set (maybe localized) description. + * @param idx Index of this facet. + * @param name 'type' of this facet. + * @param description (maybe) localized user-visible description. + */ public CrossSectionWaterLineFacet(int idx, String name, String description) { super(idx, name, description); } - /** * Gets waterline (crossed with cross section) of waterlevel. */ @@ -54,13 +60,22 @@ } Object crossSection = providers.get(0) - .provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, null, context); + .provideData(CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA, + null, context); + Object nextKm = providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_NEXT_KM, null, context); + Object prevKm = providers.get(0). + provideData(CrossSectionFacet.BLACKBOARD_CS_PREV_KM, null, context); + if (prevKm == null) + prevKm = new Double(-1d); + if (nextKm == null) + nextKm = new Double(-1d); - WaterLineArtifact winfo = (WaterLineArtifact)artifact; + WaterLineArtifact lineArtifact = (WaterLineArtifact) artifact; if (crossSection != null) { - return winfo.getWaterLines(this.getIndex(), - (FastCrossSectionLine) crossSection); + return lineArtifact.getWaterLines(this.getIndex(), + (FastCrossSectionLine) crossSection, (Double) nextKm, (Double) prevKm); } else { return new Lines.LineData(new double[][] {}, 0d,0d);