view gnv-artifacts/src/main/java/de/intevation/gnv/math/LinearToMap.java @ 448:3cb2bea50456

Generate iso line classes according gnv-issues/issue108 gnv-artifacts/trunk@496 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 03 Jan 2010 12:16:55 +0000
parents aec85d00d82c
children 9a828e5a2390
line wrap: on
line source
package de.intevation.gnv.math;

import com.vividsolutions.jts.geom.Coordinate;

import java.util.List;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 *  @author Sascha L. Teichmann
 */
public class LinearToMap
{
    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;

        public Range() {
        }

        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);
        }

        public void eval(double x, Coordinate v) {
            interpolator.interpolate((x - from)*b, v);
        }

        public boolean inside(double x) {
            return x >= from && x <= to;
        }

        public Coordinate startPoint() {
            return p1;
        }

        public Coordinate endPoint() {
            return p2;
        }
    } // class Range

    protected Range head;
    protected Range last;

    public LinearToMap() {
    }

    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;
        }
    }

    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;
    }

    public boolean locate(double diagramX, Coordinate v) {
        Range range = locateRange(diagramX);
        if (range == null) {
            return false;
        }
        range.eval(diagramX, v);
        return true;
    }

    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;
    }

    public int numRanges() {
        int count = 0;
        Range current = head;
        while (current != null) {
            ++count;
            current = current.next;
        }
        return count;
    }

    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:

http://dive4elements.wald.intevation.org