All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.common.geometry.AccumulativeGridSampler Maven / Gradle / Ivy

package org.opentripplanner.common.geometry;

import java.util.ArrayList;
import java.util.List;

import org.opentripplanner.common.geometry.ZSampleGrid.ZSamplePoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.locationtech.jts.geom.Coordinate;

/**
 * Helper class to fill-in a ZSampleGrid from a given loosely-defined set of sampling points.
 * 
 * The process is customized by an "accumulative" metric which gives the behavior of cumulating
 * several values onto one sampling point.
 * 
 * To use this class, create an instance giving an AccumulativeMetric implementation as parameter.
 * Then for each source sample, call "addSample" with the its TZ value. At the end, call close() to
 * close the sample grid (ie add grid node at the edge to make sure borders are correctly defined,
 * the definition of correct is left to the client).
 * 
 * @author laurent
 */
public class AccumulativeGridSampler {

    /**
     * An accumulative metric give the behavior of combining several samples to a regular sample
     * grid, ie how we should weight and add several TZ values from inside a cell to compute the
     * cell corner TZ values.
     * 
     * @author laurent
     * @param 
     */
    public interface AccumulativeMetric {
        /**
         * Callback function to handle a new added sample.
         * 
         * @param C0 The initial position of the sample, as given in the addSample() call.
         * @param Cs The position of the sample on the grid, never farther away than (dX,dY)
         * @param z The z value of the initial sample, as given in the addSample() call.
         * @param zS The previous z value of the sample. Can be null if this is the first time, it's
         *        up to the caller to initialize the z value.
         * @param offRoadSpeed The offroad speed to assume.
         * @return The modified z value for the sample.
         */
        public TZ cumulateSample(Coordinate C0, Coordinate Cs, TZ z, TZ zS, double offRoadSpeed);

        /**
         * Callback function to handle a "closing" sample (that is a sample post-created to surround
         * existing samples and provide nice and smooth edges for the algorithm).
         * 
         * @param point The point to set Z.
         * @return True if the point "close" the set.
         */
        public boolean closeSample(ZSamplePoint point);
    }

    private static final Logger LOG = LoggerFactory.getLogger(AccumulativeGridSampler.class);

    private AccumulativeMetric metric;

    private ZSampleGrid sampleGrid;

    private boolean closed = false;

    /**
     * @param metric TZ data "behavior" and "metric".
     */
    public AccumulativeGridSampler(ZSampleGrid sampleGrid, AccumulativeMetric metric) {
        this.metric = metric;
        this.sampleGrid = sampleGrid;
    }

    public final void addSamplingPoint(Coordinate C0, TZ z, double offRoadSpeed) {
        if (closed)
            throw new IllegalStateException("Can't add a sample after closing.");
        int[] xy = sampleGrid.getLowerLeftIndex(C0);
        int x = xy[0];
        int y = xy[1];
        @SuppressWarnings("unchecked")
        ZSamplePoint[] ABCD = new ZSamplePoint[4];
        ABCD[0] = sampleGrid.getOrCreate(x, y);
        ABCD[1] = sampleGrid.getOrCreate(x + 1, y);
        ABCD[2] = sampleGrid.getOrCreate(x, y + 1);
        ABCD[3] = sampleGrid.getOrCreate(x + 1, y + 1);
        for (ZSamplePoint P : ABCD) {
            Coordinate C = sampleGrid.getCoordinates(P);
            P.setZ(metric.cumulateSample(C0, C, z, P.getZ(), offRoadSpeed));
        }
    }

    /**
     * Surround all existing samples on the edge by a layer of closing samples.
     */
    public final void close() {
        if (closed)
            return;
        closed = true;
        List> processList = new ArrayList>(sampleGrid.size());
        for (ZSamplePoint A : sampleGrid) {
            processList.add(A);
        }
        int round = 0;
        int n = 0;
        while (!processList.isEmpty()) {
            List> newProcessList = new ArrayList>(
                    processList.size());
            for (ZSamplePoint A : processList) {
                if (A.right() == null) {
                    ZSamplePoint B = closeSample(A.getX() + 1, A.getY());
                    if (B != null)
                        newProcessList.add(B);
                    n++;
                }
                if (A.left() == null) {
                    ZSamplePoint B = closeSample(A.getX() - 1, A.getY());
                    if (B != null)
                        newProcessList.add(B);
                    n++;
                }
                if (A.up() == null) {
                    ZSamplePoint B = closeSample(A.getX(), A.getY() + 1);
                    if (B != null)
                        newProcessList.add(B);
                    n++;
                }
                if (A.down() == null) {
                    ZSamplePoint B = closeSample(A.getX(), A.getY() - 1);
                    if (B != null)
                        newProcessList.add(B);
                    n++;
                }
            }
            processList = newProcessList;
            LOG.debug("Round {} : next process list {}", round, processList.size());
            round++;
        }
        LOG.info("Added {} closing samples to get a total of {}.", n, sampleGrid.size());
    }

    private final ZSamplePoint closeSample(int x, int y) {
        ZSamplePoint A = sampleGrid.getOrCreate(x, y);
        boolean ok = metric.closeSample(A);
        if (ok) {
            return null;
        } else {
            return A;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy