Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java @ 3818:dc18457b1cef
merged flys-artifacts/pre2.7-2012-03-16
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:59 +0200 |
parents | 9144e5a5027b |
children | ed550e325248 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/QRangeTree.java Fri Sep 28 12:14:59 2012 +0200 @@ -0,0 +1,195 @@ +package de.intevation.flys.artifacts.model; + +import java.io.Serializable; + +import java.util.List; + +import org.apache.log4j.Logger; + +public class QRangeTree +implements Serializable +{ + private static Logger log = Logger.getLogger(QRangeTree.class); + + public static class Node + implements Serializable + { + Node left; + Node right; + Node prev; + Node next; + + double a; + double b; + double q; + + public Node() { + } + + public Node(double a, double b, double q) { + this.a = a; + this.b = b; + this.q = q; + } + + protected final double interpolatePrev(double pos) { + /* + f(prev.b) = prev.q + f(a) = q + + prev.q = m*prev.b + n + q = m*a + n <=> n = q - m*a + + q - prev.q = m*(a - prev.b) + + m = (q - prev.q)/(a - prev.b) # a != prev.b + */ + + if (a == prev.b) { + return 0.5*(q + prev.q); + } + double m = (q - prev.q)/(a - prev.b); + double n = q - m*a; + return m*pos + n; + } + + protected final double interpolateNext(double pos) { + /* + f(next.a) = next.q + f(b) = q + + next.q = m*next.a + n + q = m*b + n <=> n = q - m*b + + q - next.q = m*(b - next.a) + m = (q - next.q)/(b - next.a) # b != next.a + */ + + if (b == next.a) { + return 0.5*(q + next.q); + } + double m = (q - next.q)/(b - next.a); + double n = q - m*b; + return m*pos + n; + } + + public double findQ(double pos) { + + Node current = this; + for (;;) { + if (pos < current.a) { + if (current.left != null) { + current = current.left; + continue; + } + return current.prev != null + ? current.interpolatePrev(pos) + : Double.NaN; + } + if (pos > current.b) { + if (current.right != null) { + current = current.right; + continue; + } + return current.next != null + ? current.interpolateNext(pos) + : Double.NaN; + } + return current.q; + } + } + } // class Node + + protected Node root; + + public QRangeTree() { + } + + /** wstQRanges need to be sorted by range.a */ + public QRangeTree(List<Object []> qRanges, int start, int stop) { + + if (stop <= start) { + return; + } + + Node [] nodes = new Node[stop-start]; + for (int i = 0; i < nodes.length; ++i) { + Object [] qRange = qRanges.get(start + i); + Double q = (Double)qRange[1]; + Double a = (Double)qRange[2]; + Double b = (Double)qRange[3]; + + nodes[i] = new Node( + a != null ? a.doubleValue() : -Double.MAX_VALUE, + b != null ? b.doubleValue() : Double.MAX_VALUE, + q.doubleValue()); + } + + root = wireTree(nodes); + } + + protected static Node wireTree(Node [] nodes) { + for (int i = 0; i < nodes.length; ++i) { + Node node = nodes[i]; + if (i > 0 ) node.prev = nodes[i-1]; + if (i < nodes.length-1) node.next = nodes[i+1]; + } + + return buildTree(nodes, 0, nodes.length-1); + } + + protected static Node buildTree(Node [] nodes, int lo, int hi) { + + if (lo > hi) { + return null; + } + + int mid = (lo + hi) >> 1; + Node parent = nodes[mid]; + + parent.left = buildTree(nodes, lo, mid-1); + parent.right = buildTree(nodes, mid+1, hi); + + return parent; + } + + public double findQ(double pos) { + return root != null ? root.findQ(pos) : Double.NaN; + } + + private static final String name(Object o) { + return String.valueOf(System.identityHashCode(o) & 0xffffffffL); + } + + public String toGraph() { + StringBuilder sb = new StringBuilder(); + sb.append("subgraph c"); + sb.append(name(this)); + sb.append(" {\n"); + if (root != null) { + java.util.Deque<Node> stack = new java.util.ArrayDeque<Node>(); + stack.push(root); + while (!stack.isEmpty()) { + Node current = stack.pop(); + String name = "n" + name(current); + sb.append(name); + sb.append(" [label=\""); + sb.append(current.a).append(", ").append(current.b); + sb.append(": ").append(current.q).append("\"]\n"); + if (current.left != null) { + String leftName = name(current.left); + sb.append(name).append(" -- n").append(leftName).append("\n"); + stack.push(current.left); + } + if (current.right != null) { + String rightName = name(current.right); + sb.append(name).append(" -- n").append(rightName).append("\n"); + stack.push(current.right); + } + } + } + sb.append("}\n"); + return sb.toString(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :