# HG changeset patch # User Raimund Renkert # Date 1358690672 -3600 # Node ID 47c529e2be268551bb9da579c6437ff4f74999e6 # Parent bf2fd9c58ac4f775eac30baefb1d9c737911f3d7# Parent 65bfb6faa538c06c41dec3e15e2820a452afada5 merged. diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/doc/conf/mapserver/river-mapfile.vm --- a/flys-artifacts/doc/conf/mapserver/river-mapfile.vm Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/doc/conf/mapserver/river-mapfile.vm Sun Jan 20 15:04:32 2013 +0100 @@ -3,7 +3,7 @@ STATUS ON SIZE 600 400 MAXSIZE 4000 - EXTENT 3233232.55407617 5303455.37850183 3421524.44644752 5585825.50888523 + #EXTENT 3233232.55407617 5303455.37850183 3421524.44644752 5585825.50888523 UNITS DD SHAPEPATH "$SHAPEFILEPATH" FONTSET "$CONFIGDIR/mapserver/fontset.txt" @@ -13,13 +13,13 @@ "init=epsg:31467" END - DEBUG 5 + DEBUG 3 CONFIG "MS_ERRORFILE" "log/rivers.log" WEB METADATA "wms_title" "FLYS Rivers Web Map Service" - "wms_onlineresource" "$MAPSERVERURL" + #"wms_onlineresource" "http://localhost:7777/river-wms" # "$MAPSERVERURL" "wms_accessconstraints" "none" "wms_fees" "none" "wms_addresstype" "postal" diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/doc/conf/mapserver/riveraxis-layer.vm --- a/flys-artifacts/doc/conf/mapserver/riveraxis-layer.vm Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/doc/conf/mapserver/riveraxis-layer.vm Sun Jan 20 15:04:32 2013 +0100 @@ -20,10 +20,6 @@ LABELITEM $LAYER.getLabelItem() #end - PROJECTION - "init=epsg:31467" - END - METADATA "wms_title" "$LAYER.getTitle()" "gml_include_items" "all" @@ -36,7 +32,7 @@ $LAYER.getStyle() #else CLASS - NAME "" + NAME "unnamedclass" STYLE SIZE 5 OUTLINECOLOR "#000000" @@ -52,6 +48,7 @@ OFFSET 2 2 END #end + END - #end + #end END \ No newline at end of file diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/doc/conf/rivermap.xml --- a/flys-artifacts/doc/conf/rivermap.xml Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/doc/conf/rivermap.xml Sun Jan 20 15:04:32 2013 +0100 @@ -11,4 +11,20 @@ + + + + + + + + + + + + + + + + diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java Sun Jan 20 15:04:32 2013 +0100 @@ -10,6 +10,8 @@ import de.intevation.artifacts.common.utils.StringUtils; +import de.intevation.flys.artifacts.access.Calculation4Access; + import de.intevation.flys.artifacts.geom.Lines; import de.intevation.flys.artifacts.model.Calculation1; @@ -22,15 +24,16 @@ import de.intevation.flys.artifacts.model.CalculationResult; import de.intevation.flys.artifacts.model.DischargeTables; import de.intevation.flys.artifacts.model.FacetTypes; -import de.intevation.flys.artifacts.model.Segment; import de.intevation.flys.artifacts.model.WQCKms; import de.intevation.flys.artifacts.model.WQKms; import de.intevation.flys.artifacts.model.WW; import de.intevation.flys.artifacts.model.WstValueTable; import de.intevation.flys.artifacts.model.WstValueTableFactory; + import de.intevation.flys.artifacts.model.extreme.ExtremeResult; import de.intevation.flys.artifacts.states.DefaultState.ComputeType; + import de.intevation.flys.artifacts.states.LocationDistanceSelect; import de.intevation.flys.model.DischargeTable; @@ -47,7 +50,6 @@ import java.util.Arrays; import java.util.Calendar; -import java.util.Collections; import java.util.GregorianCalendar; import java.util.List; import java.util.Map; @@ -169,6 +171,12 @@ return this.getWaterlevelData(null); } + // THIS IS FREAKY BULLSHIT! Felix, why do you call the calculation directly???? + protected CalculationResult getDischargeLongitudinalSectionData() { + // XXX: THIS AN _EXPENSIVE_ CALCULATION! CACHE IT! + return new Calculation4(new Calculation4Access(this)).calculate(); + } + /** * Returns the data that is computed by a waterlevel computation. * @@ -405,48 +413,6 @@ /** - * Returns the data computed by the discharge longitudinal section - * computation. - * - * @return an array of WQKms object - one object for each given Q value. - */ - public CalculationResult getDischargeLongitudinalSectionData() { - - logger.debug("WINFOArtifact.getDischargeLongitudinalSectionData"); - - River river = FLYSUtils.getRiver(this); - if (river == null) { - logger.debug("No river selected."); - return error(new WQKms[0], "no.river.selected"); - } - - WstValueTable table = WstValueTableFactory.getTable(river); - if (table == null) { - logger.debug("No wst found for selected river."); - return error(new WQKms[0], "no.wst.for.river"); - } - - List segments = getSegments(); - - if (segments == null) { - logger.debug("Cannot create segments."); - return error(new WQKms[0], "cannot.create.segments"); - } - - double [] range = getFromToStep(); - - if (range == null) { - logger.debug("Cannot figure out range."); - return error(new WQKms[0], "no.range.found"); - } - - Calculation4 calc4 = new Calculation4(segments, river, isQ()); - - return calc4.calculate(table, range[0], range[1], range[2]); - } - - - /** * Returns the data that is computed by a reference curve computation. * * @return the data computed by a reference curve computation. @@ -574,21 +540,6 @@ } - public List getSegments() { - StateData wqValues = getData("wq_values"); - if (wqValues == null) { - logger.warn("no wq_values given"); - return Collections.emptyList(); - } - String input = (String) wqValues.getValue(); - if (input == null || (input = input.trim()).length() == 0) { - logger.warn("wq_values are empty"); - return Collections.emptyList(); - } - return Segment.parseSegments(input); - } - - /** * Get corrected waterline against surface/profile. */ diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/Calculation4Access.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/access/Calculation4Access.java Sun Jan 20 15:04:32 2013 +0100 @@ -0,0 +1,90 @@ +package de.intevation.flys.artifacts.access; + +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.model.Segment; + +import java.util.Collections; +import java.util.List; + +import org.apache.log4j.Logger; + +import de.intevation.flys.utils.DoubleUtil; +import de.intevation.flys.utils.FLYSUtils; + +public class Calculation4Access +extends RiverAccess +{ + private static Logger log = Logger.getLogger(Calculation4Access.class); + + protected List segments; + + protected double [] fromToStep; + + protected Boolean isQ; + + protected Boolean isRange; + + public Calculation4Access() { + } + + public Calculation4Access(FLYSArtifact artifact) { + super(artifact); + } + + public List getSegments() { + if (segments == null) { + String input = getString("wq_values"); + if (input == null || (input = input.trim()).length() == 0) { + log.warn("no wq_values given"); + segments = Collections.emptyList(); + } + } + return segments; + } + + public boolean isQ() { + if (isQ == null) { + Boolean value = getBoolean("wq_isq"); + isQ = value != null && value; + } + return isQ; + } + + public boolean isRange() { + if (isRange == null) { + String mode = getString("ld_mode"); + isRange = mode == null || mode.equals("distance"); + } + return isRange; + } + + public double [] getFromToStep() { + if (fromToStep == null) { + // XXX: Is this really needed in this calculation? + if (!isRange()) { + return null; + } + + // XXX: FLYSArtifact sucks! + double [] fromTo = FLYSUtils.getKmRange(artifact); + + if (fromTo == null) { + return null; + } + + Double dStep = getDouble("ld_step"); + if (dStep == null) { + return null; + } + + fromToStep = new double [] { + fromTo[0], + fromTo[1], + DoubleUtil.round(dStep / 1000d) + }; + } + return fromToStep; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/datacage/templating/CompiledStatement.java Sun Jan 20 15:04:32 2013 +0100 @@ -188,6 +188,7 @@ int index = 0; + // Find variables like ${varname}. while (m.find()) { String key = m.group(1).toUpperCase(); List indices = positions.get(key); diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/StdDevOutlier.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/StdDevOutlier.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/math/StdDevOutlier.java Sun Jan 20 15:04:32 2013 +0100 @@ -2,21 +2,12 @@ import java.util.List; -import org.apache.commons.math.MathException; - -import org.apache.commons.math.distribution.TDistributionImpl; - -import org.apache.commons.math.stat.descriptive.moment.Mean; import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; import org.apache.log4j.Logger; -import de.intevation.flys.artifacts.model.sq.SQ; - public class StdDevOutlier { - public static final double EPSILON = 1e-5; - public static final double DEFAULT_FACTOR = 3; private static Logger log = Logger.getLogger(StdDevOutlier.class); @@ -28,7 +19,11 @@ return findOutlier(values, DEFAULT_FACTOR, null); } - public static Integer findOutlier(List values, double factor, double[] stdDevResult) { + public static Integer findOutlier( + List values, + double factor, + double [] stdDevResult + ) { boolean debug = log.isDebugEnabled(); if (debug) { @@ -41,7 +36,7 @@ log.debug("Values to check: " + N); } - if (values.size() < 3) { + if (N < 3) { return null; } @@ -49,15 +44,13 @@ double maxValue = -Double.MAX_VALUE; int maxIndex = -1; - int ndx = 0; - for (int i = values.size()-1; i >= 0; --i) { + for (int i = N-1; i >= 0; --i) { double value = Math.abs(values.get(i)); stdDev.increment(value); if (value > maxValue) { maxValue = value; - maxIndex = ndx; + maxIndex = i; } - ++ndx; } double sd = stdDev.getResult(); @@ -69,9 +62,11 @@ log.debug("accepted: " + accepted); log.debug("max value: " + maxValue); } + if (stdDevResult != null) { stdDevResult[0] = sd; } + return maxValue > accepted ? maxIndex : null; } } diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/Calculation4.java Sun Jan 20 15:04:32 2013 +0100 @@ -5,12 +5,16 @@ import de.intevation.flys.artifacts.math.Identity; import de.intevation.flys.artifacts.math.Linear; +import de.intevation.flys.artifacts.model.RiverFactory; import de.intevation.flys.artifacts.model.WstValueTable.QPosition; import de.intevation.flys.model.River; import de.intevation.flys.utils.DoubleUtil; +import de.intevation.flys.artifacts.access.Calculation4Access; + +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -25,23 +29,69 @@ protected List segments; - protected boolean isQ; + protected boolean isQ; + protected double from; + protected double to; + protected double step; + protected String river; public Calculation4() { } - public Calculation4(List segments, River river, boolean isQ) { + public Calculation4(Calculation4Access access) { + String river = access.getRiver(); + List segments = access.getSegments(); + double [] range = access.getFromToStep(); + boolean isQ = access.isQ(); - this.segments = segments; - this.isQ = isQ; + if (river == null) { + addProblem("no.river.selected"); + } - Segment.setReferencePointConvertQ(segments, river, isQ, this); + if (range == null) { + addProblem("no.range.found"); + } + + if (segments == null || segments.isEmpty()) { + addProblem("cannot.create.segments"); + } + + if (!hasProblems()) { + this.river = river; + this.segments = segments; + this.from = range[0]; + this.to = range[1]; + this.step = range[2]; + this.isQ = isQ; + } } - public CalculationResult calculate( - WstValueTable table, - double from, double to, double step - ) { + public CalculationResult calculate() { + if (hasProblems()) { + return new CalculationResult(new WQKms[0], this); + } + + WstValueTable table = null; + River r = RiverFactory.getRiver(river); + if (r == null) { + addProblem("no.river.found"); + } + else { + table = WstValueTableFactory.getTable(r); + if (table == null) { + addProblem("no.wst.for.river"); + } + else { + Segment.setReferencePointConvertQ(segments, r, isQ, this); + } + } + + return hasProblems() + ? new CalculationResult(new WQKms[0], this) + : innerCalculate(table); + } + + protected CalculationResult innerCalculate(WstValueTable table) { boolean debug = logger.isDebugEnabled(); if (debug) { @@ -53,12 +103,6 @@ } } - if (segments.isEmpty()) { - logger.debug("no segments found"); - addProblem("no.segments.found"); - return new CalculationResult(new WQKms[0], this); - } - int numResults = segments.get(0).values.length; if (numResults < 1) { @@ -228,9 +272,63 @@ results[i].setName(createName(i)); } + // Generate the "Umhuellende". + results = generateInfolding(table, results, from, to, step); + return new CalculationResult(results, this); } + protected WQKms [] generateInfolding( + WstValueTable wst, + WQKms [] results, + double from, + double to, + double step + ) { + WstValueTable.Column [] columns = wst.getColumns(); + + InfoldingColumns ic = new InfoldingColumns(columns); + ic.markInfoldingColumns(results); + + List infoldings = new ArrayList(); + + boolean [] infoldingColumns = ic.getInfoldingColumns(); + for (int i = 0; i < infoldingColumns.length; ++i) { + if (!infoldingColumns[i]) { + continue; + } + double q = columns[i].getQRangeTree().findQ(from); + if (Double.isNaN(q)) { + addProblem(from, "cannot.find.q"); + continue; + } + double [] kms = DoubleUtil.explode(from, to, step); + double [] oqs = new double[kms.length]; + double [] ows = new double[kms.length]; + boolean success = + wst.interpolate(q, from, kms, ows, oqs, this) != null; + + if (success) { + // TODO: generate a better name. I18N. + String name = "Umh\u00fcllende " + columns[i].getName(); + WQKms wqkms = new WQKms(kms, oqs, ows, name); + infoldings.add(wqkms); + } + } + + int N = infoldings.size(); + if (N > 0) { + WQKms [] newResults = new WQKms[results.length + N]; + System.arraycopy(results, 0, newResults, 0, results.length); + for (int i = 0; i < N; ++i) { + newResults[i+results.length] = infoldings.get(i); + } + results = newResults; + } + + return results; + } + protected String createName(int index) { // TODO: i18n StringBuilder sb = new StringBuilder(isQ ? "Q" : "W"); diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/InfoldingColumns.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/InfoldingColumns.java Sun Jan 20 15:04:32 2013 +0100 @@ -0,0 +1,78 @@ +package de.intevation.flys.artifacts.model; + +/** A pretty naive pointwise algorithm to find out the columns + * of a WSTValueTable which imfold ("umhuellen") a set of WQKMs + * in terms of Q. + * A better implemention would exploit the fact that the + * Qs normally are constant for a while along km. This would + * reduce the runtime complexity to only a few Q spans instead + * of the pointwise evaluation. + */ +public class InfoldingColumns +{ + private QRangeTree.QuickQFinder [] qFinders; + + private boolean [] infoldingColumns; + + public InfoldingColumns() { + } + + public InfoldingColumns(WstValueTable.Column [] columns) { + + qFinders = new QRangeTree.QuickQFinder[columns.length]; + for (int i = 0; i < qFinders.length; ++i) { + qFinders[i] = columns[i].getQRangeTree().new QuickQFinder(); + } + + infoldingColumns = new boolean[columns.length]; + } + + public boolean [] getInfoldingColumns() { + return infoldingColumns; + } + + public void markInfoldingColumns(WQKms [] wqkms) { + for (WQKms wqk: wqkms) { + markInfoldingColumns(wqk); + } + } + + public void markInfoldingColumns(WQKms wqkms) { + int N = wqkms.size(); + int C = qFinders.length-1; + for (int i = 0; i < N; ++i) { + double km = wqkms.getKm(i); + double q = wqkms.getQ(i); + double above = Double.MAX_VALUE; + double below = -Double.MAX_VALUE; + int aboveIdx = -1; + int belowIdx = -1; + + for (int j = C; j >= 0; --j) { + double qc = qFinders[j].findQ(km); + if (Double.isNaN(qc)) { + continue; + } + if (qc <= q) { + if (qc > below) { + below = qc; + belowIdx = j; + } + } + else if (qc < above) { // qc > q + above = qc; + aboveIdx = j; + } + } + + if (aboveIdx != -1) { + infoldingColumns[aboveIdx] = true; + } + + if (belowIdx != -1) { + infoldingColumns[belowIdx] = true; + } + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Sun Jan 20 15:04:32 2013 +0100 @@ -101,8 +101,52 @@ return current.q; } } + + public Node findNode(double pos) { + Node current = this; + while (current != null) { + if (pos < current.a) { + current = current.left; + } + else if (pos > current.b) { + current = current.right; + } + return current; + } + return null; + } + + public boolean contains(double c) { + return c >= a && c <= b; + } } // class Node + /** Class to cache the last found tree leaf in a search for Q. + * Its likely that a neighbored pos search + * results in using the same leaf node. So + * caching this leaf will minimize expensive + * tree traversals. + * Modeled as inner class because the QRangeTree + * itself is a shared data structure. + * Using this class omits interpolation between + * leaves. + */ + public final class QuickQFinder { + + private Node last; + + public QuickQFinder() { + } + + public double findQ(double pos) { + if (last != null && last.contains(pos)) { + return last.q; + } + last = QRangeTree.this.findNode(pos); + return last != null ? last.q : Double.NaN; + } + } // class QuickQFinder + protected Node root; public QRangeTree() { @@ -212,6 +256,10 @@ return root != null ? root.findQ(pos) : Double.NaN; } + public Node findNode(double pos) { + return root != null ? root.findNode(pos) : null; + } + protected Node head() { Node head = root; while (head.left != null) { @@ -220,6 +268,20 @@ return head; } + public boolean intersectsQRange(double qMin, double qMax) { + if (qMin > qMax) { + double t = qMin; + qMin = qMax; + qMax = t; + } + for (Node curr = head(); curr != null; curr = curr.next) { + if (curr.q >= qMin || curr.q <= qMax) { + return true; + } + } + return false; + } + public List findSegments(double a, double b) { if (a > b) { double t = a; a = b; b = t; } return findSegments(new Range(a, b)); diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/WstValueTable.java Sun Jan 20 15:04:32 2013 +0100 @@ -59,7 +59,7 @@ this.name = name; } - public QRangeTree getQRangeTree() { + public QRangeTree getQRangeTree() { return qRangeTree; } @@ -540,6 +540,10 @@ this.rows = rows; } + public Column [] getColumns() { + return columns; + } + /** Sort rows (by km). */ public void sortRows() { Collections.sort(rows); diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/BedQualityCalculation.java Sun Jan 20 15:04:32 2013 +0100 @@ -329,3 +329,4 @@ return weight; } } +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/minfo/QualityMeasurementFactory.java Sun Jan 20 15:04:32 2013 +0100 @@ -200,4 +200,5 @@ //session.close(); } } -} \ No newline at end of file +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/sq/Outlier.java Sun Jan 20 15:04:32 2013 +0100 @@ -1,20 +1,17 @@ package de.intevation.flys.artifacts.model.sq; +import de.intevation.artifacts.common.utils.Config; + +import de.intevation.flys.artifacts.math.GrubbsOutlier; +import de.intevation.flys.artifacts.math.StdDevOutlier; + import java.util.ArrayList; import java.util.List; import org.apache.commons.math.MathException; -import org.apache.commons.math.stat.descriptive.moment.StandardDeviation; - import org.apache.log4j.Logger; -import de.intevation.artifacts.GlobalContext; -import de.intevation.artifacts.common.utils.Config; -import de.intevation.flys.artifacts.context.FLYSContext; -import de.intevation.flys.artifacts.math.GrubbsOutlier; -import de.intevation.flys.artifacts.math.StdDevOutlier; - public class Outlier { private static Logger log = Logger.getLogger(Outlier.class); @@ -24,7 +21,7 @@ private static final String GRUBBS = "grubbs"; - private static final String STD_DEV = "std-dev"; + //private static final String STD_DEV = "std-dev"; public interface Callback { @@ -48,42 +45,54 @@ { boolean debug = log.isDebugEnabled(); - if (debug) { - log.debug("stdDevFactor: " + stdDevFactor); - } String method = Config.getStringXPath(OUTLIER_METHOD); - log.debug("method: " + method); + if (method == null) { method = "std-dev"; } + + if (debug) { + log.debug("stdDevFactor: " + stdDevFactor); + log.debug("method: " + method); + } + List data = new ArrayList(sqs); + double [] stdDev = new double[1]; + + boolean useGrubbs = method.equals(GRUBBS); + + if (useGrubbs) { + stdDevFactor = Math.max(0d, Math.min(stdDevFactor/100d, 1d)); + } + + List values = new ArrayList(data.size()); + while (data.size() > 2) { callback.initialize(data); - List values = new ArrayList(); for (SQ sq: data) { values.add(callback.eval(sq)); } - Integer ndx = null; - double[] stdDev = new double[1]; - if (method.equals(GRUBBS)) { - ndx = GrubbsOutlier.findOutlier(values, stdDevFactor/100, stdDev); - } - else { - ndx = StdDevOutlier.findOutlier(values, stdDevFactor, stdDev); - } + Integer ndx = useGrubbs + ? GrubbsOutlier.findOutlier(values, stdDevFactor, stdDev) + : StdDevOutlier.findOutlier(values, stdDevFactor, stdDev); + if (ndx == null) { callback.iterationFinished(stdDev[0], null, data); break; } - SQ outlier = data.remove((int)ndx); - log.debug("stdDev: " + stdDev[0]); - log.debug("removed " + ndx + "; S: " + outlier.getS() + " Q: " + outlier.getQ()); + SQ outlier = data.remove(ndx.intValue()); + if (debug) { + log.debug("stdDev: " + stdDev[0]); + log.debug("removed " + ndx + + "; S: " + outlier.getS() + " Q: " + outlier.getQ()); + } callback.iterationFinished(stdDev[0], outlier, data); + values.clear(); } } } diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MapInfoService.java Sun Jan 20 15:04:32 2013 +0100 @@ -1,29 +1,25 @@ package de.intevation.flys.artifacts.services; -import org.apache.log4j.Logger; - -import java.util.Map; -import java.util.HashMap; - -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.Element; - -import javax.xml.xpath.XPathConstants; - import com.vividsolutions.jts.geom.Envelope; +import de.intevation.artifactdatabase.XMLService; import de.intevation.artifacts.CallMeta; import de.intevation.artifacts.GlobalContext; - import de.intevation.artifacts.common.ArtifactNamespaceContext; import de.intevation.artifacts.common.utils.Config; import de.intevation.artifacts.common.utils.XMLUtils; import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator; +import de.intevation.flys.utils.GeometryUtils; -import de.intevation.artifactdatabase.XMLService; +import java.util.HashMap; +import java.util.Map; -import de.intevation.flys.utils.GeometryUtils; +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; /** * This service provides information about the supported rivers by this @@ -36,14 +32,16 @@ /** XPath that points to the river.*/ public static final String XPATH_RIVER = "/mapinfo/river/text()"; - public static final String XPATH_RIVER_PROJECTION = - "/artifact-database/floodmap/river[@name=$river]/srid/@value"; + public static final String XPATH_MAPTYPE = "/mapinfo/maptype/text()"; - public static final String XPATH_RIVER_BACKGROUND = - "/artifact-database/floodmap/river[@name=$river]/background-wms"; + private static final String XPATH_RIVER_PROJECTION = + "/artifact-database/*[local-name()=$maptype]/river[@name=$river]/srid/@value"; - public static final String XPATH_RIVER_WMS = - "/artifact-database/floodmap/river[@name=$river]/river-wms/@url"; + private static final String XPATH_RIVER_BACKGROUND = + "/artifact-database/*[local-name()=$maptype]/river[@name=$river]/background-wms"; + + private static final String XPATH_RIVER_WMS = + "/artifact-database/*[local-name()=$maptype]/river[@name=$river]/river-wms"; /** The logger used in this service.*/ @@ -94,6 +92,12 @@ return result; } + String mapType = extractMaptype(data); + if (mapType == null + || !(mapType.equals("floodmap") || mapType.equals("rivermap"))) { + mapType = "floodmap"; + } + Element root = cr.create("river"); cr.addAttr(root, "name", river); mapinfo.appendChild(root); @@ -101,7 +105,9 @@ Envelope env = GeometryUtils.getRiverBoundary(river); if (env != null) { String bounds = GeometryUtils.jtsBoundsToOLBounds(env); - logger.debug("River '" + river + "' bounds: " + bounds); + if (logger.isDebugEnabled()) { + logger.debug("River '" + river + "' bounds: " + bounds); + } Element bbox = cr.create("bbox"); cr.addAttr(bbox, "value", bounds); @@ -109,6 +115,7 @@ } Map vars = new HashMap(); + vars.put("maptype", mapType); vars.put("river", river); String sridStr = getStringXPath(XPATH_RIVER_PROJECTION, vars); @@ -119,28 +126,55 @@ root.appendChild(srid); } - Element back = (Element)getNodeXPath(XPATH_RIVER_BACKGROUND, vars); - if (back != null) { - Element background = cr.create("background-wms"); - cr.addAttr(background, "url", back.getAttribute("url")); - cr.addAttr(background, "layers", back.getAttribute("layers")); - root.appendChild(background); + if (logger.isDebugEnabled()) { + logger.debug("processXML: " + XMLUtils.toString(root)); } - String wmsStr = getStringXPath(XPATH_RIVER_WMS, vars); - if (wmsStr != null && wmsStr.length() > 0) { - Element wms = cr.create("river-wms"); - cr.addAttr(wms, "url", wmsStr); - root.appendChild(wms); - } + root.appendChild( + createWMSElement("background-wms", + XPATH_RIVER_BACKGROUND, vars, cr)); + + root.appendChild( + createWMSElement("river-wms", + XPATH_RIVER_WMS, vars, cr)); return result; } - protected String extractRiver(Document data) { + protected Element createWMSElement( + String elementName, + String xpath, + Map vars, + ElementCreator cr) + { + logger.debug("createWMSElement()"); + + Element el = cr.create(elementName); + Element wms = (Element)getNodeXPath(xpath, vars); + + if (wms != null) { + cr.addAttr(el, "url", wms.getAttribute("url")); + cr.addAttr(el, "layers", wms.getAttribute("layers")); + + logger.debug("createWMSElement: " + XMLUtils.toString(el)); + } + else { + logger.debug("createWMSElement: wms == null"); + } + + return el; + } + + + private static String extractRiver(Document data) { return XMLUtils.xpathString( data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); } + + private static String extractMaptype(Document data) { + return XMLUtils.xpathString( + data, XPATH_MAPTYPE, ArtifactNamespaceContext.INSTANCE); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/states/DischargeLongitudinalSection.java Sun Jan 20 15:04:32 2013 +0100 @@ -1,37 +1,36 @@ package de.intevation.flys.artifacts.states; +import de.intevation.artifactdatabase.state.Facet; + +import de.intevation.artifacts.CallContext; + +import de.intevation.flys.artifacts.ChartArtifact; +import de.intevation.flys.artifacts.FLYSArtifact; + +import de.intevation.flys.artifacts.access.Calculation4Access; + +import de.intevation.flys.artifacts.model.Calculation4; +import de.intevation.flys.artifacts.model.CalculationResult; +import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; +import de.intevation.flys.artifacts.model.DataFacet; +import de.intevation.flys.artifacts.model.EmptyFacet; +import de.intevation.flys.artifacts.model.FacetTypes; +import de.intevation.flys.artifacts.model.ReportFacet; +import de.intevation.flys.artifacts.model.WQCKms; +import de.intevation.flys.artifacts.model.WQKms; +import de.intevation.flys.artifacts.model.WaterlevelFacet; + import java.util.List; import org.apache.log4j.Logger; -import de.intevation.artifacts.CallContext; - -import de.intevation.artifactdatabase.state.Facet; - -import de.intevation.flys.artifacts.FLYSArtifact; -import de.intevation.flys.artifacts.WINFOArtifact; -import de.intevation.flys.artifacts.ChartArtifact; - -import de.intevation.flys.artifacts.model.CrossSectionWaterLineFacet; -import de.intevation.flys.artifacts.model.FacetTypes; -import de.intevation.flys.artifacts.model.ReportFacet; -import de.intevation.flys.artifacts.model.WaterlevelFacet; -import de.intevation.flys.artifacts.model.EmptyFacet; - -import de.intevation.flys.artifacts.model.WQKms; -import de.intevation.flys.artifacts.model.WQCKms; -import de.intevation.flys.artifacts.model.CalculationResult; - -import de.intevation.flys.artifacts.model.DataFacet; - public class DischargeLongitudinalSection extends DefaultState implements FacetTypes { - private static Logger logger = + private static Logger log = Logger.getLogger(DischargeLongitudinalSection.class); - @Override public Object computeAdvance( FLYSArtifact artifact, @@ -46,11 +45,11 @@ return null; } - WINFOArtifact winfo = (WINFOArtifact)artifact; + Calculation4Access access = new Calculation4Access(artifact); CalculationResult res = old instanceof CalculationResult ? (CalculationResult)old - : winfo.getDischargeLongitudinalSectionData(); + : new Calculation4(access).calculate(); if (facets == null) { return res; @@ -62,7 +61,7 @@ String nameW = null; String nameQ = null; - if (winfo.isQ()) { + if (access.isQ()) { nameQ = wqkms[i].getName(); nameW = "W(" + nameQ + ")"; } diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java --- a/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java Sun Jan 20 15:04:32 2013 +0100 @@ -225,15 +225,13 @@ if (mode == null || mode.length() == 0) { return KM_MODE.NONE; } - else if (mode.equals("distance")) { + if (mode.equals("distance")) { return KM_MODE.RANGE; } - else if (mode.equals("locations")) { + if (mode.equals("locations")) { return KM_MODE.LOCATIONS; } - else { - return KM_MODE.NONE; - } + return KM_MODE.NONE; } /** diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-artifacts/src/main/java/de/intevation/flys/utils/RiverMapfileGenerator.java --- a/flys-artifacts/src/main/java/de/intevation/flys/utils/RiverMapfileGenerator.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/RiverMapfileGenerator.java Sun Jan 20 15:04:32 2013 +0100 @@ -1,8 +1,12 @@ package de.intevation.flys.utils; +import com.vividsolutions.jts.geom.Envelope; +import com.vividsolutions.jts.geom.LineString; + import de.intevation.flys.artifacts.model.LayerInfo; import de.intevation.flys.artifacts.model.RiverFactory; import de.intevation.flys.model.River; +import de.intevation.flys.model.RiverAxis; import java.io.File; import java.io.FileNotFoundException; @@ -48,11 +52,26 @@ List riverFiles = new ArrayList(); for (River river : rivers) { + // We expect that every river has only one RiverAxis. + // This is not correct but currently the case here, see + // RiverAxis.java. + List riverAxis = RiverAxis.getRiverAxis(river.getName()); + if (riverAxis == null) { + logger.warn("River " + river.getName() + " has no river axis!"); + continue; + } + LineString geom = riverAxis.get(0).getGeom(); + Envelope extent = geom.getEnvelopeInternal(); + createRiverAxisLayer( river.getName(), river.getId(), - "41677", - "-10000 -10000 10000 10000"); + Integer.toString(geom.getSRID()), + extent.getMinX() + " " + + extent.getMinY() + " " + + extent.getMaxX() + " " + + extent.getMaxY()); + riverFiles.add("river-" + river.getName() + ".map"); } writeMapfile(riverFiles); @@ -64,7 +83,7 @@ layerInfo.setSrid(srid); layerInfo.setExtent(extend); layerInfo.setType("line"); - layerInfo.setData("geom FROM river_axis"); // FIXME: Use templates for that + layerInfo.setData("geom FROM river_axes"); // FIXME: Use templates for that layerInfo.setFilter("river_id = " + riverID); layerInfo.setTitle(riverName + " RiverAxis"); diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java --- a/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java Sun Jan 20 15:04:32 2013 +0100 @@ -190,7 +190,7 @@ addCrossSections(parser); } - } + } // ImportRiverCrossSectionParserCallback public ImportRiver() { diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-backend/src/main/java/de/intevation/flys/importer/parsers/W80Parser.java --- a/flys-backend/src/main/java/de/intevation/flys/importer/parsers/W80Parser.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/importer/parsers/W80Parser.java Sun Jan 20 15:04:32 2013 +0100 @@ -62,10 +62,27 @@ private Anchor anchor; + /** + * Reference point for distance calculations, introduced to + * deal with bends in the lines. + * Array has two entrys: first is GK-Right, second GK-High. + */ + private double[] lastPointGK; + + /** Measurement date of anchor as listed in w80 file. */ private Date anchorDate; + private double distanceToLastPoint(double gkr, double gkh) { + double dx = gkr - lastPointGK[0]; + double dy = gkh - lastPointGK[1]; + double d = dx*dx + dy*dy; + + return Math.sqrt(d); + } + + /** Trivial constructor. */ public W80Parser() { data = new TreeMap>(EpsilonComparator.CMP); @@ -103,7 +120,6 @@ public void parseW80s(File root, final Callback callback) { - // TODO use the removeExtension/guess description and date. FileTools.walkTree(root, new FileTools.FileVisitor() { @Override public boolean visit(File file) { @@ -135,6 +151,7 @@ currentLine = new ArrayList(); anchor = null; anchorDate = null; + lastPointGK = new double[] {0d,0d}; } @@ -142,7 +159,7 @@ * Get the Index of the last cross-section lines point. * @return last points index, -1 if not available. */ - private int lastPointIdx() { + private int getLastPointIdx() { if (currentLine == null || currentLine.isEmpty()) { return -1; } @@ -151,6 +168,15 @@ } + private double getLastPointX() { + if (currentLine == null || currentLine.isEmpty()) { + return 0d; + } + XY lastPoint = this.currentLine.get(currentLine.size()-1); + return lastPoint.getX(); + } + + /** * Add a Point (YZ,Index) to the current cross section line. * @param y The y coordinate of new point. @@ -160,22 +186,22 @@ * parsable y or z values. */ private boolean addPoint(double gkr, double gkh, double height, String idx) { - // Calculate distance between this and anchor-point. - double d = anchor.distance(gkr, gkh); - - // TODO: Scale to have "x==0" e.g. at axis of river. - // TODO: Handle "not straight lines." + // Calculate distance between this and lst point (add distances). + double d = distanceToLastPoint(gkr, gkh); + double totalX = getLastPointX() + d; // We ignore idx, and increment instead. int index; - int lastPointIdx = lastPointIdx(); + int lastPointIdx = getLastPointIdx(); if (lastPointIdx <= 0) { index = 1; } else { index = lastPointIdx + 1; } - currentLine.add(new XY(d, height/1000d, index)); + this.lastPointGK[0] = gkr; + this.lastPointGK[1] = gkh; + currentLine.add(new XY(totalX, height/1000d, index)); return true; } @@ -191,10 +217,10 @@ // negative. String pointId = line.substring(0,20); String station = line.substring(9,15); - String shore = line.substring(15,17); + String shore = line.substring(15,16); // TODO: There is 'station' and a 'shore'-code behind. // 1 = left, 2 = right. none = middle - String pointIndex = line.substring(17,21); + String pointIndex = line.substring(16,21); // For GK, first seven digits are of interest. String gkRight = line.substring(20,30); String gkHigh = line.substring(30,40); @@ -222,9 +248,11 @@ // New (or first) line. if (anchor == null || !anchor.sameStation(stationKm)) { anchor = new Anchor(gkRightKm, gkHighKm, heightM, stationKm); + lastPointGK[0] = gkRightKm; + lastPointGK[1] = gkHighKm; currentLine = new ArrayList(); data.put(stationKm, currentLine); - currentLine.add(new XY(0d, heightM,0)); + currentLine.add(new XY(0d, heightM, 0)); try { anchorDate = DateGuesser.guessDate(date); } @@ -252,8 +280,8 @@ logger.warn("Start parsing files."); for (String arg: args) { + logger.warn("Parsing a file."); parser.parseW80s(new File(arg), null); - logger.warn("Parsing a file."); } logger.error("Finished parsing files."); } diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-backend/src/main/java/de/intevation/flys/model/River.java --- a/flys-backend/src/main/java/de/intevation/flys/model/River.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/model/River.java Sun Jan 20 15:04:32 2013 +0100 @@ -1,31 +1,29 @@ package de.intevation.flys.model; +import de.intevation.flys.backend.SessionHolder; + import java.io.Serializable; - import java.math.BigDecimal; import java.math.MathContext; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.GeneratedValue; -import javax.persistence.Column; -import javax.persistence.SequenceGenerator; +import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.OrderBy; -import javax.persistence.JoinColumn; -import javax.persistence.GenerationType; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; -import java.util.List; -import java.util.Comparator; -import java.util.Map; -import java.util.TreeMap; - +import org.hibernate.Query; import org.hibernate.Session; -import org.hibernate.Query; - -import de.intevation.flys.backend.SessionHolder; @Entity @@ -37,7 +35,7 @@ public static final double EPSILON = 1e-5; - public static final Comparator KM_CMP = new Comparator() { + public static final Comparator KM_CMP = new Comparator() { @Override public int compare(Double a, Double b) { double diff = a - b; @@ -147,6 +145,7 @@ + @Override public String toString() { return name != null ? name : ""; } diff -r bf2fd9c58ac4 -r 47c529e2be26 flys-client/src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java --- a/flys-client/src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java Sun Jan 20 15:02:19 2013 +0100 +++ b/flys-client/src/main/java/de/intevation/flys/client/client/ui/DigitizePanel.java Sun Jan 20 15:04:32 2013 +0100 @@ -2,7 +2,6 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; - import com.smartgwt.client.types.Encoding; import com.smartgwt.client.types.VerticalAlignment; import com.smartgwt.client.util.SC; @@ -22,6 +21,8 @@ import com.smartgwt.client.widgets.tab.events.TabSelectedHandler; import de.intevation.flys.client.client.Config; +import de.intevation.flys.client.client.FLYS; +import de.intevation.flys.client.client.FLYSConstants; import de.intevation.flys.client.client.services.MapInfoService; import de.intevation.flys.client.client.services.MapInfoServiceAsync; import de.intevation.flys.client.client.ui.map.FloodMap; @@ -58,6 +59,8 @@ public static final String UESK_BARRIERS = "uesk.barriers"; + /** The message class that provides i18n strings. */ + protected FLYSConstants MSG = GWT.create(FLYSConstants.class); public DigitizePanel() { } @@ -104,7 +107,7 @@ String msg = caught.getMessage(); GWT.log("Error while fetching MapInfo: " + msg); - SC.warn(MSG.getString(msg)); + SC.warn(FLYS.getExceptionString(MSG, caught)); } @Override