sascha@360: package de.intevation.gnv.math; sascha@360: sascha@360: import java.awt.geom.Point2D; sascha@360: sascha@360: import java.util.List; sascha@360: import java.util.Iterator; sascha@360: import java.util.NoSuchElementException; sascha@360: sascha@360: /** sascha@360: * @author Sascha L. Teichmann sascha@360: */ sascha@360: public class LinearToMap sascha@360: { sascha@360: public interface Interpolator { sascha@360: sascha@360: void interpolate(double t, Point2D v); sascha@360: sascha@360: } // interface Interpolator sascha@360: sascha@360: public interface Metrics { sascha@360: sascha@360: double distance(Point2D p1, Point2D p2); sascha@360: sascha@360: Interpolator getInterpolator(Point2D p1, Point2D p2); sascha@360: sascha@360: } // interface Metrics sascha@360: sascha@360: public static final class Range { sascha@360: private Range next; sascha@360: sascha@360: private double from; sascha@360: private double to; sascha@360: private double b; sascha@360: sascha@360: private Point2D p1; sascha@360: private Point2D p2; sascha@360: sascha@360: private Interpolator interpolator; sascha@360: sascha@360: public Range() { sascha@360: } sascha@360: sascha@360: public Range( sascha@360: double from, sascha@360: double to, sascha@360: Interpolator interpolator, sascha@360: Point2D p1, sascha@360: Point2D p2 sascha@360: ) { sascha@360: this.from = from; sascha@360: this.to = to; sascha@360: this.interpolator = interpolator; sascha@360: this.p1 = p1; sascha@360: this.p2 = p2; sascha@360: sascha@360: b = from == to sascha@360: ? 0d sascha@360: : 1.0d/(to - from); sascha@360: } sascha@360: sascha@360: public void eval(double x, Point2D v) { sascha@360: interpolator.interpolate((x - from)*b, v); sascha@360: } sascha@360: sascha@360: public boolean inside(double x) { sascha@360: return x >= from && x <= to; sascha@360: } sascha@360: sascha@360: public Point2D startPoint() { sascha@360: return p1; sascha@360: } sascha@360: sascha@360: public Point2D endPoint() { sascha@360: return p2; sascha@360: } sascha@360: } // class Range sascha@360: sascha@360: protected Range head; sascha@360: protected Range last; sascha@360: sascha@360: public LinearToMap() { sascha@360: } sascha@360: sascha@360: public LinearToMap( sascha@360: List path, sascha@360: double from, sascha@360: double to, sascha@360: Metrics metrics sascha@360: ) { sascha@360: double diagramLength = Math.abs(to - from); sascha@360: sascha@360: double worldLength = length(path, metrics); sascha@360: sascha@360: double rangeStart = from; sascha@360: sascha@360: Range last = null; sascha@360: sascha@360: for (int i = 1, N = path.size(); i < N; ++i) { sascha@360: Point2D p1 = (Point2D)path.get(i-1); sascha@360: Point2D p2 = (Point2D)path.get(i); sascha@360: double segmentLength = metrics.distance(p1, p2); sascha@360: sascha@360: double relativeLength = segmentLength / worldLength; sascha@360: sascha@360: double rangeLength = diagramLength * relativeLength; sascha@360: sascha@360: double rangeEnd = rangeStart + rangeLength; sascha@360: sascha@360: Range range = new Range( sascha@360: rangeStart, rangeEnd, sascha@360: metrics.getInterpolator(p1, p2), sascha@360: p1, p2); sascha@360: sascha@360: if (last == null) { sascha@360: last = head = range; sascha@360: } sascha@360: else { sascha@360: last.next = range; sascha@360: last = range; sascha@360: } sascha@360: rangeStart = rangeEnd; sascha@360: } sascha@360: } sascha@360: sascha@360: protected Range locateRange(double diagramX) { sascha@360: sascha@360: if (last != null && last.inside(diagramX)) { sascha@360: return last; sascha@360: } sascha@360: sascha@360: Range current = head; sascha@360: while (current != null) { sascha@360: if (current.inside(diagramX)) { sascha@360: return last = current; sascha@360: } sascha@360: current = current.next; sascha@360: } sascha@360: sascha@360: return null; sascha@360: } sascha@360: sascha@360: public boolean locate(double diagramX, Point2D v) { sascha@360: Range range = locateRange(diagramX); sascha@360: if (range == null) { sascha@360: return false; sascha@360: } sascha@360: range.eval(diagramX, v); sascha@360: return true; sascha@360: } sascha@360: sascha@360: public static double length(List path, Metrics metrics) { sascha@360: double sum = 0d; sascha@360: for (int i = path.size()-1; i >= 1; --i) { sascha@360: Point2D p1 = (Point2D)path.get(i); sascha@360: Point2D p2 = (Point2D)path.get(i-1); sascha@360: sum += metrics.distance(p1, p2); sascha@360: } sascha@360: return sum; sascha@360: } sascha@360: sascha@360: public int numRanges() { sascha@360: int count = 0; sascha@360: Range current = head; sascha@360: while (current != null) { sascha@360: ++count; sascha@360: current = current.next; sascha@360: } sascha@360: return count; sascha@360: } sascha@360: sascha@360: public Iterator ranges() { sascha@360: return new Iterator() { sascha@360: sascha@360: Range current = head; sascha@360: sascha@360: public boolean hasNext() { sascha@360: return current != null; sascha@360: } sascha@360: sascha@360: public Object next() { sascha@360: if (!hasNext()) { sascha@360: throw new NoSuchElementException(); sascha@360: } sascha@360: Range x = current; sascha@360: current = current.next; sascha@360: return x; sascha@360: } sascha@360: sascha@360: public void remove() { sascha@360: throw new UnsupportedOperationException(); sascha@360: } sascha@360: }; sascha@360: } sascha@360: } sascha@360: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: