[PATCH 1 of 3] Merge slt-simplify-cross-sections branch into default
Wald Commits
scm-commit at wald.intevation.org
Wed Jan 22 13:27:53 CET 2014
# HG changeset patch
# User Tom Gottfried <tom at intevation.de>
# Date 1390391658 -3600
# Node ID 228be10e6165cb507bd20e3bd71671dad61c8967
# Parent 772c22b0ea12188a28cfbf807b3ad4070f6ff564
# Parent e1b831fe435a7b2730bfb02f8c63e1b56568acdc
Merge slt-simplify-cross-sections branch into default.
diff -r 772c22b0ea12 -r 228be10e6165 backend/src/main/java/org/dive4elements/river/importer/Config.java
--- a/backend/src/main/java/org/dive4elements/river/importer/Config.java Mon Jan 20 14:54:35 2014 +0100
+++ b/backend/src/main/java/org/dive4elements/river/importer/Config.java Wed Jan 22 12:54:18 2014 +0100
@@ -100,6 +100,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();
@@ -113,6 +116,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);
}
diff -r 772c22b0ea12 -r 228be10e6165 backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java Mon Jan 20 14:54:35 2014 +0100
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java Wed Jan 22 12:54:18 2014 +0100
@@ -39,23 +39,29 @@
import org.dive4elements.river.model.River;
import org.dive4elements.river.model.Unit;
+import org.dive4elements.river.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.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Iterator;
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
@@ -183,24 +189,24 @@
protected River peer;
- /** Callback-implementation for CrossSectionParsers:
- * Accept files with different md5(?)sums than what has already been parsed,
- * on successfull parse, add data. */
- class ImportRiverCrossSectionParserCallback implements CrossSectionParser.Callback {
- Set<HashedFile> files = new HashSet<HashedFile>();
- String type;
+ /** Callback-implementation for CrossSectionParsers. */
+ private class ImportRiverCrossSectionParserCallback
+ implements CrossSectionParser.Callback {
+ private Set<HashedFile> files = new HashSet<HashedFile>();
+ private String type;
/**
* Create new Callback, given type which is used for logging
* purposes only.
*/
- public ImportRiverCrossSectionParserCallback (String type) {
+ public ImportRiverCrossSectionParserCallback(String type) {
this.type = type;
}
/** Accept file if not duplicate. */
+ @Override
public boolean accept(File file) {
HashedFile hf = new HashedFile(file);
boolean success = files.add(hf);
@@ -212,14 +218,60 @@
/** Add crosssection. */
+ @Override
public void parsed(CrossSectionParser parser) {
log.debug("callback from " + type + " parser");
- addCrossSections(parser);
+ String description = parser.getDescription();
+ Integer year = parser.getYear();
+ ImportTimeInterval ti = year != null
+ ? new ImportTimeInterval(yearToDate(year))
+ : null;
+
+ Map<Double, List<XY>> data = parser.getData();
+
+ List<ImportCrossSectionLine> lines =
+ new ArrayList<ImportCrossSectionLine>(data.size());
+
+ Double simplificationEpsilon =
+ Config.INSTANCE.getCrossSectionSimplificationEpsilon();
+
+ long numReadPoints = 0L;
+ long numRemainingPoints = 0L;
+
+ for (Map.Entry<Double, List<XY>> entry: data.entrySet()) {
+ Double km = entry.getKey();
+ List<XY> points = entry.getValue();
+ numReadPoints += points.size();
+ if (simplificationEpsilon != null) {
+ points = DouglasPeuker.simplify(points, simplificationEpsilon);
+ }
+ numRemainingPoints += points.size();
+ lines.add(new ImportCrossSectionLine(km, points));
+ }
+
+ ImportRiver.this.addCrossSections(description, ti, lines);
+
+ double percent = numReadPoints > 0L
+ ? ((double)numRemainingPoints/numReadPoints)*100d
+ : 0d;
+
+ log.info(String.format(
+ "Number of points in cross section: %d / %d (%.2f%%)",
+ numReadPoints, numRemainingPoints, percent));
}
} // ImportRiverCrossSectionParserCallback
+ private void addCrossSections(
+ String description,
+ ImportTimeInterval ti,
+ List<ImportCrossSectionLine> lines
+ ) {
+ crossSections.add(new ImportCrossSection(this, description, ti, lines));
+ }
+
+
public ImportRiver() {
hyks = new ArrayList<ImportHYK>();
crossSections = new ArrayList<ImportCrossSection>();
@@ -1052,30 +1104,6 @@
}
- /** Add cross sections with description, years and lines to
- * store. */
- private void addCrossSections(CrossSectionParser parser) {
- String description = parser.getDescription();
- Integer year = parser.getYear();
- ImportTimeInterval ti = year != null
- ? new ImportTimeInterval(yearToDate(year))
- : null;
-
- Map<Double, List<XY>> data = parser.getData();
-
- List<ImportCrossSectionLine> lines =
- new ArrayList<ImportCrossSectionLine>(data.size());
-
- for (Map.Entry<Double, List<XY>> entry: data.entrySet()) {
- Double km = entry.getKey();
- List<XY> points = entry.getValue();
- lines.add(new ImportCrossSectionLine(km, points));
- }
-
- crossSections.add(new ImportCrossSection(
- ImportRiver.this, description, ti, lines));
- }
-
/** Create a W80 Parser and parse w80 files found. */
public void parseW80s() {
if (Config.INSTANCE.skipW80s()) {
@@ -1134,6 +1162,7 @@
ImportRiverCrossSectionParserCallback da50Callback =
new ImportRiverCrossSectionParserCallback("da50");
+
parser.parseDA50s(riverDir, da50Callback);
}
@@ -1155,6 +1184,7 @@
ImportRiverCrossSectionParserCallback da66Callback =
new ImportRiverCrossSectionParserCallback("da66");
+
parser.parseDA66s(riverDir, da66Callback);
}
diff -r 772c22b0ea12 -r 228be10e6165 backend/src/main/java/org/dive4elements/river/importer/XY.java
--- a/backend/src/main/java/org/dive4elements/river/importer/XY.java Mon Jan 20 14:54:35 2014 +0100
+++ b/backend/src/main/java/org/dive4elements/river/importer/XY.java Wed Jan 22 12:54:18 2014 +0100
@@ -22,6 +22,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;
@@ -60,5 +64,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 :
diff -r 772c22b0ea12 -r 228be10e6165 backend/src/main/java/org/dive4elements/river/utils/DouglasPeuker.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/backend/src/main/java/org/dive4elements/river/utils/DouglasPeuker.java Wed Jan 22 12:54:18 2014 +0100
@@ -0,0 +1,81 @@
+package org.dive4elements.river.utils;
+
+import org.dive4elements.river.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 :
More information about the Dive4elements-commits
mailing list