Mercurial > dive4elements > gnv-client
view gnv-artifacts/src/main/java/de/intevation/gnv/math/LinearToMap.java @ 1129:ccfa07b88476
merged geo-backend
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:01 +0200 |
parents | f953c9a559d8 |
children |
line wrap: on
line source
/* * Copyright (c) 2010 by Intevation GmbH * * This program is free software under the LGPL (>=v2.1) * Read the file LGPL.txt coming with the software for details * or visit http://www.gnu.org/licenses/ if it does not exist. */ package de.intevation.gnv.math; import com.vividsolutions.jts.geom.Coordinate; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Given a list of line segments instances of this class are able * to span a metric system between a start and an end point * represented as scalar values to 2D coordinate on the * course of the segments. * * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> */ public class LinearToMap { /** * Represents a segment of the line string. */ public static final class Range { private Range next; private double from; private double to; private double b; private Coordinate p1; private Coordinate p2; private Interpolator interpolator; /** * Default constructor. */ public Range() { } /** * Constructor to create a segment that maps * a coordinate pair to two scalar values. * Interpolations inside this segment are done with * a given interpolator. * @param from Start point of the segment. * @param to End point of the segment. * @param interpolator The interpolator. * @param p1 The scalar value mapped to the start point. * @param p2 The scalar value mappend to the end point. */ public Range( double from, double to, Interpolator interpolator, Coordinate p1, Coordinate p2 ) { this.from = from; this.to = to; this.interpolator = interpolator; this.p1 = p1; this.p2 = p2; b = from == to ? 0d : 1.0d/(to - from); } /** * Interpolated a coordinate on the segment given a scalar value * between the start and end point of the range. * @param x The scalar value. * @param v The interpolated value is stored here. */ public void eval(double x, Coordinate v) { interpolator.interpolate((x - from)*b, v); } /** * Checks if a given value is inside this segment. * @param x The value to test * @return true if inside, else false. */ public boolean inside(double x) { return x >= from && x <= to; } /** * Returns the start point of this segment. * @return The start point. */ public Coordinate startPoint() { return p1; } /** * Return the end point of this segment. * @return The end point. */ public Coordinate endPoint() { return p2; } } // class Range /** * The head of the internal range list. */ protected Range head; /** * The last accessed segment. Used to accelerate * the access of the right segment. */ protected Range last; /** * Default constructor. */ public LinearToMap() { } /** * Constructor to create a LinearToMap that maps * given scalar values to coordinates of a given * list of line segments. * @param path The list of line segments. * @param from The start value mapped to the start point * of the first line segment. * @param to The end value mapped to the end point of * the last line segment. * @param metrics The metric used to span the 2D space. */ public LinearToMap( List<? extends Coordinate> path, double from, double to, Metrics metrics ) { double diagramLength = Math.abs(to - from); double worldLength = length(path, metrics); double rangeStart = from; Range last = null; for (int i = 1, N = path.size(); i < N; ++i) { Coordinate p1 = path.get(i-1); Coordinate p2 = path.get(i); double segmentLength = metrics.distance(p1, p2); double relativeLength = segmentLength / worldLength; double rangeLength = diagramLength * relativeLength; double rangeEnd = rangeStart + rangeLength; Range range = new Range( rangeStart, rangeEnd, metrics.getInterpolator(p1, p2), p1, p2); if (last == null) { last = head = range; } else { last.next = range; last = range; } rangeStart = rangeEnd; } } /** * Returns a segment on which a given value is found. * @param diagramX The value. * @return The segment or null if no matching segment was found. */ protected Range locateRange(double diagramX) { if (last != null && last.inside(diagramX)) { return last; } Range current = head; while (current != null) { if (current.inside(diagramX)) { return last = current; } current = current.next; } return null; } /** * Interpolates a coordinate at a given scalar position. * @param diagramX The scalar position. * @param v The interpolated coordinate is stored here. * @return true if the scalar position is inside the * spanned range of the line string, else false. */ public boolean locate(double diagramX, Coordinate v) { Range range = locateRange(diagramX); if (range == null) { return false; } range.eval(diagramX, v); return true; } /** * Returns the length of a given line string using * a given metric. * @param path The line string. * @param metrics The used metric. * @return The length of the line string. */ public static double length( List<? extends Coordinate> path, Metrics metrics ) { double sum = 0d; for (int i = path.size()-1; i >= 1; --i) { Coordinate p1 = path.get(i); Coordinate p2 = path.get(i-1); sum += metrics.distance(p1, p2); } return sum; } /** * Return the number of segments in this map. * @return the number of segments. */ public int numRanges() { int count = 0; Range current = head; while (current != null) { ++count; current = current.next; } return count; } /** * Returns an iterator over all segments of this map. * @return The iterator. */ public Iterator ranges() { return new Iterator() { Range current = head; public boolean hasNext() { return current != null; } public Object next() { if (!hasNext()) { throw new NoSuchElementException(); } Range x = current; current = current.next; return x; } public void remove() { throw new UnsupportedOperationException(); } }; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :