地圖匹配算法-離散Fréchet距離(弗雷歇算法)Java實現

詳細實現思路可以看論文:
弗雷歇算法文獻

下面是java版本的實現

package momenta.hdmap.diffosm.Frechet;

import org.locationtech.jts.geom.Coordinate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class DiscreteFrechetDistance {

   /**
     * Dynamic programming memory array
     */
    private static double[][] mem;

    private static List<Coordinate> timeSeriesP;
    private static List<Coordinate> timeSeriesQ;

    /**-
     * 計算Frechet距離
     * @param cp
     * @param cq
     * @return
     */
    public static double getDiscreteFrechet(Coordinate[] cp, Coordinate[] cq) {

        timeSeriesP = Arrays.asList(cp);
        timeSeriesQ = Arrays.asList(cq);
        double distance = computeDiscreteFrechet(timeSeriesP, timeSeriesQ);
        // 四捨五入保留兩位小數輸出結果 (單位米)
        BigDecimal b = new BigDecimal(distance);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * Wrapper that makes a call to computeDFD. Initializes mem array with all
     * -1 values.
     *
     * @param P - the first time series
     * @param Q - the second time series
     * @return The length of the shortest distance that can traverse both time
     * series.
     */
    private static double computeDiscreteFrechet(List<Coordinate> P, List<Coordinate> Q) {

        mem = new double[P.size()][Q.size()];

        // initialize all values to -1
        for (int i = 0; i < mem.length; i++) {
            for (int j = 0; j < mem[i].length; j++) {
                mem[i][j] = -1.0;
            }
        }

        return computeDFD(P.size() - 1, Q.size() - 1);
    }

    /**
     * @param i - the row
     * @param j - the column
     * @return The length of the shortest distance that can traverse both time
     * series.
     */
    private static double computeDFD(int i, int j) {
        // if the value has already been solved
        if (mem[i][j] > -1)
            return mem[i][j];
            // if top left column, just compute the distance
        else if (i == 0 && j == 0)
            mem[i][j] = euclideanDistance(timeSeriesP.get(i), timeSeriesQ.get(j));
            // can either be the actual distance or distance pulled from above
        else if (i > 0 && j == 0)
            mem[i][j] = max(computeDFD(i - 1, 0), euclideanDistance(timeSeriesP.get(i), timeSeriesQ.get(j)));
            // can either be the distance pulled from the left or the actual
            // distance
        else if (i == 0 && j > 0)
            mem[i][j] = max(computeDFD(0, j - 1), euclideanDistance(timeSeriesP.get(i), timeSeriesQ.get(j)));
            // can be the actual distance, or distance from above or from the left
        else if (i > 0 && j > 0) {
            mem[i][j] = max(min(computeDFD(i - 1, j), computeDFD(i - 1, j - 1), computeDFD(i, j - 1)), euclideanDistance(timeSeriesP.get(i), timeSeriesQ.get(j)));
        }
        // infinite
        else
            mem[i][j] = Integer.MAX_VALUE;


        // printMemory();
        // return the DFD
        return mem[i][j];
    }

    /**
     * Get the max value of all the values.
     *
     * @param values - the values being compared
     * @return The max value of all the values.
     */
    private static double max(double... values) {
        double max = Integer.MIN_VALUE;
        for (double i : values) {
            if (i >= max)
                max = i;
        }
        return max;
    }

    /**
     * Get the minimum value of all the values.
     *
     * @param values - the values being compared
     * @return The minimum value of all the values.
     */
    private static double min(double... values) {
        double min = Integer.MAX_VALUE;
        for (double i : values) {
            if (i <= min)
                min = i;
        }
        return min;
    }

    /**
     * Given two points, calculate the Euclidean distance between them, where
     * the Euclidean distance: sum from 1 to n dimensions of ((x - y)^2)^1/2
     *
     * @param i - the first point
     * @param j - the second point
     * @return The total Euclidean distance between two points.
     */
    private static double euclideanDistance(Coordinate i, Coordinate j) {

        double distance = 0;
        distance = i.distance(j) * 100000;
        // System.out.println(i.toString() + "_" + j.toString() + "_dis:" + distance);
        return distance;
    }

    /**
     * Test method that prints the 2D dynamic programming array.
     */
    private static void printMemory() {
        System.out.println("\n\n memory");
        for (int row = 0; row < mem.length; row++) {
            for (int col = 0; col < mem[row].length; col++) {
                System.out.print(mem[row][col] + "\t");
            }
            System.out.println();
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章