Mercurial > dive4elements > river
changeset 5083:7bbee0cfc171 slt-simplify-cross-sections
Added experimental Douglas Peuker simplification of cross sections.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 24 Feb 2013 17:29:52 +0100 |
parents | fb4d87274f28 |
children | ca45dd039b54 |
files | flys-backend/src/main/java/de/intevation/flys/importer/Config.java flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java flys-backend/src/main/java/de/intevation/flys/importer/XY.java flys-backend/src/main/java/de/intevation/flys/utils/DouglasPeuker.java |
diffstat | 4 files changed, 183 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/flys-backend/src/main/java/de/intevation/flys/importer/Config.java Sun Feb 24 13:03:44 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/importer/Config.java Sun Feb 24 17:29:52 2013 +0100 @@ -86,6 +86,9 @@ public static final String SKIP_SQ_RELATION = "flys.backend.importer.skip.sq.relation"; + public static final Double CROSS_SECTION_SIMPLIFICATION_EPSILON = + getDouble("flys.backend.importer.cross.section.simplification.epsilon"); + public static final Config INSTANCE = new Config(); @@ -99,6 +102,21 @@ : Boolean.getBoolean(SKIP_DEFAULT); } + public static final Double getDouble(String key) { + try { + String value = System.getProperty(key); + return value != null + ? Double.valueOf(value) + : null; + } catch (NumberFormatException nfe) { + return null; + } + } + + public Double getCrossSectionSimplificationEpsilon() { + return CROSS_SECTION_SIMPLIFICATION_EPSILON; + } + public boolean dryRun() { return getFlag(DRY_RUN); }
--- a/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java Sun Feb 24 13:03:44 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/importer/ImportRiver.java Sun Feb 24 17:29:52 2013 +0100 @@ -1,23 +1,9 @@ package de.intevation.flys.importer; -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.log4j.Logger; -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.exception.ConstraintViolationException; +import de.intevation.artifacts.common.utils.FileTools.HashedFile; import de.intevation.artifacts.common.utils.FileTools; -import de.intevation.artifacts.common.utils.FileTools.HashedFile; + import de.intevation.flys.importer.parsers.AnnotationClassifier; import de.intevation.flys.importer.parsers.AnnotationsParser; import de.intevation.flys.importer.parsers.BedHeightEpochParser; @@ -39,9 +25,32 @@ import de.intevation.flys.importer.parsers.WaterlevelDifferencesParser; import de.intevation.flys.importer.parsers.WaterlevelParser; import de.intevation.flys.importer.parsers.WstParser; + import de.intevation.flys.model.River; import de.intevation.flys.model.Unit; +import de.intevation.flys.utils.DouglasPeuker; + +import java.io.File; +import java.io.IOException; + +import java.sql.SQLException; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; + +import org.hibernate.Query; +import org.hibernate.Session; + +import org.hibernate.exception.ConstraintViolationException; + /** Import all river-related data (files) that can be found. */ public class ImportRiver @@ -159,9 +168,11 @@ /** Callback-implementation for CrossSectionParsers. */ - class ImportRiverCrossSectionParserCallback implements CrossSectionParser.Callback { - Set<HashedFile> files = new HashSet<HashedFile>(); - String type; + private class ImportRiverCrossSectionParserCallback + implements CrossSectionParser.Callback { + + private Set<HashedFile> files = new HashSet<HashedFile>(); + private String type; /** @@ -185,7 +196,7 @@ /** Add crosssection. */ - public void parsed(CrossSectionParser parser) { + public void parsed(CrossSectionParser parser) { log.debug("callback from " + type + " parser"); addCrossSections(parser); @@ -941,14 +952,20 @@ List<ImportCrossSectionLine> lines = new ArrayList<ImportCrossSectionLine>(data.size()); + Double simplificationEpsilon = + Config.INSTANCE.getCrossSectionSimplificationEpsilon(); + for (Map.Entry<Double, List<XY>> entry: data.entrySet()) { Double km = entry.getKey(); List<XY> points = entry.getValue(); + if (simplificationEpsilon != null) { + points = DouglasPeuker.simplify(points, simplificationEpsilon); + } lines.add(new ImportCrossSectionLine(km, points)); } crossSections.add(new ImportCrossSection( - ImportRiver.this, description, ti, lines)); + this, description, ti, lines)); } /** Create a W80 Parser and parse w80 files found. */ @@ -1080,7 +1097,10 @@ } public void storeCrossSections() { - if (!Config.INSTANCE.skipPRFs() || !Config.INSTANCE.skipDA66s() || !Config.INSTANCE.skipDA50s() || !Config.INSTANCE.skipW80s()) { + if (!Config.INSTANCE.skipPRFs() + || !Config.INSTANCE.skipDA66s() + || !Config.INSTANCE.skipDA50s() + || !Config.INSTANCE.skipW80s()) { log.info("store cross sections"); getPeer(); for (ImportCrossSection crossSection: crossSections) {
--- a/flys-backend/src/main/java/de/intevation/flys/importer/XY.java Sun Feb 24 13:03:44 2013 +0100 +++ b/flys-backend/src/main/java/de/intevation/flys/importer/XY.java Sun Feb 24 17:29:52 2013 +0100 @@ -14,6 +14,10 @@ public XY() { } + public XY(XY other) { + this(other.x, other.y, other.index); + } + public XY(double x, double y, int index) { this.x = x; this.y = y; @@ -52,5 +56,43 @@ public void setIndex(int index) { this.index = index; } + + public double dot(double ox, double oy) { + return x*ox + y*oy; + } + + public double dot(XY other) { + return dot(other.x, other.y); + } + + public XY sub(XY other) { + x -= other.x; + y -= other.y; + return this; + } + + public XY ortho() { + double z = x; + x = y; + y = -z; + return this; + } + + public XY normalize() { + double len = dot(this); + + if (len > 1e-6) { + len = 1d/Math.sqrt(len); + x *= len; + y *= len; + } + + return this; + } + + // x*nx + y*ny + d = 0 <=> d = -x*nx -y*ny + public double lineOffset(XY p) { + return -x*p.x -y*p.y; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-backend/src/main/java/de/intevation/flys/utils/DouglasPeuker.java Sun Feb 24 17:29:52 2013 +0100 @@ -0,0 +1,81 @@ +package de.intevation.flys.utils; + +import de.intevation.flys.importer.XY; // TODO: Move to a more common package. + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public final class DouglasPeuker +{ + public static final double EPSILON = 1e-4; + + private DouglasPeuker() { + } + + public static List<XY> simplify(List<XY> input) { + return simplify(input, EPSILON); + } + + public static List<XY> simplify(List<XY> input, double epsilon) { + + int N = input.size(); + + if (N < 3) { + return new ArrayList<XY>(input); + } + + List<XY> simplified = recursiveSimplify(input, 0, N-1, epsilon); + + List<XY> output = new ArrayList<XY>(simplified.size()+2); + output.add(input.get(0)); + output.addAll(simplified); + output.add(input.get(N-1)); + + return output; + } + + private static List recursiveSimplify( + List<XY> input, + int start, + int end, + double epsilon + ) { + XY a = input.get(start); + XY b = input.get(end); + + // Normal of hesse normal form. + XY n = new XY(b).sub(a).ortho().normalize(); + + // distance offset of the hesse normal form. + double d = n.lineOffset(a); + + double maxDist = -Double.MAX_VALUE; + int maxIdx = -1; + + for (int i = start+1; i < end; ++i) { + double dist = Math.abs(n.dot(input.get(i)) + d); + if (dist > maxDist) { + maxDist = dist; + maxIdx = i; + } + } + + if (maxDist < epsilon) { + // All points between a and b can be ignored. + return Collections.<XY>emptyList(); + } + + // Split by input[maxIdx]. + List<XY> before = recursiveSimplify(input, start, maxIdx, epsilon); + List<XY> after = recursiveSimplify(input, maxIdx, end, epsilon); + + List<XY> output = new ArrayList<XY>(before.size()+1+after.size()); + output.addAll(before); + output.add(input.get(maxIdx)); + output.addAll(after); + + return output; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :