[PATCH] FastAnnotations (Locations, POIs, Streckenfavoriten) deterministisch
Wald Commits
scm-commit at wald.intevation.org
Mon Nov 5 10:18:41 CET 2018
# HG changeset patch
# User gernotbelger
# Date 1541409487 -3600
# Node ID 4809e23ffd27c4208854de3590704f0fc4f831fb
# Parent 1f6fbbe88af8267b08e651c0c42b6e5f072e90a3
FastAnnotations (Locations, POIs, Streckenfavoriten) deterministisch
diff -r 1f6fbbe88af8 -r 4809e23ffd27 backend/src/main/java/org/dive4elements/river/model/FastAnnotations.java
--- a/backend/src/main/java/org/dive4elements/river/model/FastAnnotations.java Tue Oct 30 17:46:52 2018 +0100
+++ b/backend/src/main/java/org/dive4elements/river/model/FastAnnotations.java Mon Nov 05 10:18:07 2018 +0100
@@ -8,81 +8,65 @@
package org.dive4elements.river.model;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
-import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
-import java.io.Serializable;
-
+import org.dive4elements.river.backend.SessionHolder;
+import org.dive4elements.river.backend.utils.StringUtil;
+import org.hibernate.SQLQuery;
import org.hibernate.Session;
-import org.hibernate.SQLQuery;
-
import org.hibernate.type.StandardBasicTypes;
-import org.dive4elements.river.backend.SessionHolder;
+public class FastAnnotations implements Serializable {
+ private static final long serialVersionUID = 1L;
-public class FastAnnotations
-implements Serializable
-{
- public static final String SQL_BY_RIVER_NAME =
- "SELECT r.a AS a, r.b AS b, p.value AS position, " +
- "at.value AS attribute, ant.name AS name, " +
- "e.top AS top, e.bottom AS bottom " +
- "FROM annotations an " +
- "JOIN ranges r " +
- "ON an.range_id = r.id " +
- "JOIN attributes at " +
- "ON an.attribute_id = at.id " +
- "JOIN positions p " +
- "ON an.position_id = p.id " +
- "JOIN rivers riv " +
- "ON r.river_id = riv.id " +
- "LEFT JOIN annotation_types ant " +
- "ON an.type_id = ant.id " +
- "LEFT JOIN edges e " +
- "ON an.edge_id = e.id " +
- "WHERE riv.name = :river_name " +
- "ORDER BY r.a";
+ public static final String SQL_BY_RIVER_NAME = //
+ "SELECT r.a AS a, r.b AS b, p.value AS position, " + //
+ "at.value AS attribute, ant.name AS name, " + //
+ "e.top AS top, e.bottom AS bottom " + //
+ "FROM annotations an " + //
+ "JOIN ranges r " + "ON an.range_id = r.id " + //
+ "JOIN attributes at " + "ON an.attribute_id = at.id "//
+ + "JOIN positions p " + "ON an.position_id = p.id " + //
+ "JOIN rivers riv " + "ON r.river_id = riv.id " + //
+ "LEFT JOIN annotation_types ant " + "ON an.type_id = ant.id " + //
+ "LEFT JOIN edges e " + "ON an.edge_id = e.id " + //
+ "WHERE riv.name = :river_name " + "ORDER BY r.a, position";
- public static final String SQL_BY_RIVER_ID =
- "SELECT r.a AS a, r.b AS b, p.value AS position, " +
- "at.value AS attribute, ant.name AS name, " +
- "e.top AS top, e.bottom AS bottom " +
- "FROM annotations an " +
- "JOIN ranges r " +
- "ON an.range_id = r.id " +
- "JOIN attributes at " +
- "ON an.attribute_id = at.id " +
- "JOIN positions p " +
- "ON an.position_id = p.id " +
- "LEFT JOIN annotation_types ant " +
- "ON an.type_id = ant.id " +
- "LEFT JOIN edges e " +
- "ON an.edge_id = e.id " +
- "WHERE r.id = :river_id " +
- "ORDER BY r.a";
+ public static final String SQL_BY_RIVER_ID = "SELECT r.a AS a, r.b AS b, p.value AS position, "//
+ + "at.value AS attribute, ant.name AS name, "//
+ + "e.top AS top, e.bottom AS bottom " + "FROM annotations an " + //
+ "JOIN ranges r " + "ON an.range_id = r.id " + //
+ "JOIN attributes at " + "ON an.attribute_id = at.id "//
+ + "JOIN positions p " + "ON an.position_id = p.id " + //
+ "LEFT JOIN annotation_types ant " + "ON an.type_id = ant.id "//
+ + "LEFT JOIN edges e " + "ON an.edge_id = e.id " + //
+ "WHERE r.id = :river_id " + "ORDER BY r.a, position";
public static final double EPSILON = 1e-5;
- public static final Comparator<Annotation> KM_CMP =
- new Comparator<Annotation>() {
- @Override
- public int compare(Annotation a, Annotation b) {
- double diff = a.a - b.a;
- if (diff < -EPSILON) return -1;
- if (diff > +EPSILON) return +1;
- return 0;
- }
- };
+ public static final Comparator<Annotation> KM_CMP = new Comparator<Annotation>() {
+ @Override
+ public int compare(final Annotation a, final Annotation b) {
+ final double diff = a.a - b.a;
- public static final class Annotation
- implements Serializable
- {
+ if (diff < -EPSILON)
+ return -1;
+ if (diff > +EPSILON)
+ return +1;
+
+ return 0;
+ }
+ };
+
+ public static final class Annotation implements Serializable, Comparable<Annotation> {
+ private static final long serialVersionUID = 1L;
private double a;
private double b;
private String position;
@@ -94,62 +78,68 @@
public Annotation() {
}
- public Annotation(double a) {
+ public Annotation(final double a) {
this.a = a;
}
- public Annotation(
- double a,
- double b,
- String position,
- String attribute,
- String name,
- double top,
- double bottom
- ) {
- this.a = a;
- this.b = b;
- this.position = position;
+ public Annotation(final double a, final double b, final String position, final String attribute, final String name, final double top,
+ final double bottom) {
+ this.a = a;
+ this.b = b;
+ this.position = position;
this.attribute = attribute;
- this.name = name;
- this.top = top;
- this.bottom = bottom;
+ this.name = name;
+ this.top = top;
+ this.bottom = bottom;
}
public double getA() {
- return a;
+ return this.a;
}
public double getB() {
- return b;
+ return this.b;
}
public String getPosition() {
- return position;
+ return this.position;
}
public String getAttribute() {
- return attribute;
+ return this.attribute;
}
public String getName() {
- return name;
+ return this.name;
}
public double getTop() {
- return top;
+ return this.top;
}
public double getBottom() {
- return bottom;
+ return this.bottom;
}
@Override
public String toString() {
- return "[a=" + a + ";b=" + b +
- ";pos=" + position + ";attr=" + attribute +
- ";name=" + name + ";top=" + top +
- ";bot=" + bottom + "]";
+ return "[a=" + this.a + ";b=" + this.b + ";pos=" + this.position + ";attr=" + this.attribute + ";name=" + this.name + ";top=" + this.top + ";bot="
+ + this.bottom + "]";
+ }
+
+ @Override
+ public int compareTo(final Annotation o) {
+
+ // Comparable interface introduced to make annotations deterministic (for testing etc)
+ final int compareKmStart = Double.valueOf(this.a).compareTo(Double.valueOf(o.a));
+ if (compareKmStart != 0)
+ return compareKmStart;
+
+ // Although position must not be null by database definition, Null-Checks are provided for safety reasons
+ if (StringUtil.isEmpty(this.position))
+ return +1; // leere Strings ans Ende
+
+ return String.valueOf(this.position).compareTo(String.valueOf(o.position));
}
} // class Annotation
@@ -161,62 +151,62 @@
public static class NameFilter implements Filter {
- private Pattern namePattern;
+ private final Pattern namePattern;
- public NameFilter(String name) {
+ public NameFilter(final String name) {
this.namePattern = Pattern.compile(name);
}
@Override
- public boolean accept(Annotation annotation) {
- return namePattern.matcher(annotation.getName()).matches();
+ public boolean accept(final Annotation annotation) {
+ return this.namePattern.matcher(annotation.getName()).matches();
}
} // class NameFilter
public static final Filter ALL = new Filter() {
@Override
- public boolean accept(Annotation annotation) {
+ public boolean accept(final Annotation annotation) {
return true;
}
};
public static final Filter IS_POINT = new Filter() {
@Override
- public boolean accept(Annotation annotation) {
+ public boolean accept(final Annotation annotation) {
return Double.isNaN(annotation.getB());
}
};
public static final Filter IS_RANGE = new Filter() {
@Override
- public boolean accept(Annotation annotation) {
+ public boolean accept(final Annotation annotation) {
return !Double.isNaN(annotation.getB());
}
};
- private Annotation [] annotations;
+ private Annotation[] annotations;
public FastAnnotations() {
}
- public FastAnnotations(Annotation [] annotations) {
+ public FastAnnotations(final Annotation[] annotations) {
this.annotations = annotations;
}
- public FastAnnotations(String riverName) {
+ public FastAnnotations(final String riverName) {
this(loadByRiverName(riverName));
}
- public FastAnnotations(int riverId) {
+ public FastAnnotations(final int riverId) {
this(loadByRiverId(riverId));
}
- public FastAnnotations(Iterator<Annotation> iter) {
+ public FastAnnotations(final Iterator<Annotation> iter) {
this(toArray(iter));
}
public int size() {
- return annotations.length;
+ return this.annotations.length;
}
public Iterator<Annotation> filter(final Filter filter) {
@@ -227,23 +217,23 @@
@Override
public boolean hasNext() {
- return current != null;
+ return this.current != null;
}
@Override
public Annotation next() {
- if (current == null) {
+ if (this.current == null) {
throw new NoSuchElementException();
}
- Annotation result = current;
- current = findNext();
+ final Annotation result = this.current;
+ this.current = findNext();
return result;
}
private Annotation findNext() {
- while (idx < annotations.length) {
- Annotation annotation = annotations[idx++];
+ while (this.idx < FastAnnotations.this.annotations.length) {
+ final Annotation annotation = FastAnnotations.this.annotations[this.idx++];
if (filter.accept(annotation)) {
return annotation;
}
@@ -259,9 +249,9 @@
};
}
- public static Annotation [] toArray(Iterator<Annotation> iter) {
+ public static Annotation[] toArray(final Iterator<Annotation> iter) {
- ArrayList<Annotation> list = new ArrayList<Annotation>();
+ final ArrayList<Annotation> list = new ArrayList<>();
while (iter.hasNext()) {
list.add(iter.next());
@@ -270,75 +260,84 @@
return list.toArray(new Annotation[list.size()]);
}
- public Annotation findByKm(double km) {
- Annotation key = new Annotation(km);
- int idx = Arrays.binarySearch(annotations, key, KM_CMP);
- return idx < 0 ? null : annotations[idx];
+ public Annotation findByKm(final double km) {
+ final Annotation key = new Annotation(km);
+ final int idx = Arrays.binarySearch(this.annotations, key, KM_CMP);
+
+ if ((idx < 0))
+ return null;
+
+ if (idx == 0)
+ return this.annotations[idx]; // lowest possible index
+
+ // REMARK: binary search my find any annotation at kmTest, but we want the first entry (because the list of annotations
+ // is ordered by name)
+ for (int lowestIndex = idx; lowestIndex > 0; lowestIndex--) {
+ final double kmTest = this.annotations[lowestIndex].a;
+ if (Math.abs(kmTest - this.annotations[idx].a) > EPSILON)
+ return this.annotations[lowestIndex + 1];
+ }
+
+ return this.annotations[0];
}
- private static SQLQuery createQuery(String query) {
- Session session = SessionHolder.HOLDER.get();
+ private static SQLQuery createQuery(final String query) {
+ final Session session = SessionHolder.HOLDER.get();
- return session.createSQLQuery(query)
- .addScalar("a", StandardBasicTypes.DOUBLE)
- .addScalar("b", StandardBasicTypes.DOUBLE)
- .addScalar("position", StandardBasicTypes.STRING)
- .addScalar("attribute", StandardBasicTypes.STRING)
- .addScalar("name", StandardBasicTypes.STRING)
- .addScalar("top", StandardBasicTypes.DOUBLE)
- .addScalar("bottom", StandardBasicTypes.DOUBLE);
+ return session.createSQLQuery(query).addScalar("a", StandardBasicTypes.DOUBLE).addScalar("b", StandardBasicTypes.DOUBLE)
+ .addScalar("position", StandardBasicTypes.STRING).addScalar("attribute", StandardBasicTypes.STRING).addScalar("name", StandardBasicTypes.STRING)
+ .addScalar("top", StandardBasicTypes.DOUBLE).addScalar("bottom", StandardBasicTypes.DOUBLE);
}
- private static Annotation [] buildAnnotations(List<Object []> list) {
- Annotation [] anns = new Annotation[list.size()];
+ private static Annotation[] buildAnnotations(final List<Object[]> list) {
+ final Annotation[] anns = new Annotation[list.size()];
// Names are likely the same because they are a type
// like 'Pegel' or 'Hafen'.
- HashMap<String, String> names = new HashMap<String, String>();
+ // final HashMap<String, String> names = new HashMap<>();
for (int i = 0; i < anns.length; ++i) {
- Object [] data = list.get(i);
- double a = ((Double)data[0]);
- double b = data[1] != null ? (Double)data[1] : Double.NaN;
- String position = (String)data[2];
- String attribute = (String)data[3];
- String name = (String)data[4];
- double top = data[5] != null ? (Double)data[5] : Double.NaN;
- double bottom = data[6] != null ? (Double)data[6] : Double.NaN;
+ final Object[] data = list.get(i);
+ final double a = ((Double) data[0]);
+ final double b = data[1] != null ? (Double) data[1] : Double.NaN;
+ final String position = (String) data[2];
+ final String attribute = (String) data[3];
+ final String name = (String) data[4];
+ final double top = data[5] != null ? (Double) data[5] : Double.NaN;
+ final double bottom = data[6] != null ? (Double) data[6] : Double.NaN;
- if (name != null) {
- String old = names.get(name);
- if (old != null) {
- name = old;
- }
- else {
- names.put(name, name);
- }
- }
+ // if (name != null) {
+ // final String old = names.get(name);
+ // if (old != null) {
+ // name = old;
+ // } else {
+ // names.put(name, name);
+ // }
+ // }
- anns[i] = new Annotation(
- a, b, position, attribute, name, top, bottom);
+ anns[i] = new Annotation(a, b, position, attribute, name, top, bottom);
+
}
+ Arrays.sort(anns); // Comparable interface introduced to make annotations deterministic (for testing etc)
return anns;
}
- public static Annotation [] loadByRiverName(String riverName) {
+ public static Annotation[] loadByRiverName(final String riverName) {
- SQLQuery query = createQuery(SQL_BY_RIVER_NAME);
+ final SQLQuery query = createQuery(SQL_BY_RIVER_NAME);
query.setString("river_name", riverName);
return buildAnnotations(query.list());
}
- public static Annotation [] loadByRiverId(int riverId) {
+ public static Annotation[] loadByRiverId(final int riverId) {
- SQLQuery query = createQuery(SQL_BY_RIVER_ID);
+ final SQLQuery query = createQuery(SQL_BY_RIVER_ID);
query.setInteger("river_id", riverId);
return buildAnnotations(query.list());
}
}
-// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
diff -r 1f6fbbe88af8 -r 4809e23ffd27 gwt-client/src/main/java/org/dive4elements/river/client/server/ChartServiceHelper.java
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/ChartServiceHelper.java Tue Oct 30 17:46:52 2018 +0100
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/ChartServiceHelper.java Mon Nov 05 10:18:07 2018 +0100
@@ -230,7 +230,7 @@
ElementCreator ec)
{
log.debug("ChartServiceHelper.appendCurrentKm");
-
+
Element currentKm = ec.create("currentKm");
String km = req.get("km");
More information about the Dive4Elements-commits
mailing list