package vroom.common.utilities.gis; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import vroom.common.utilities.logging.Logging; /** * <code>MapPoint</code> is a utility class that uses the MapPointDist library to evaluate a time and distance matrix * using MapPoint. * <p> * Creation date: Jun 12, 2012 - 4:02:13 PM * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 1.0 */ public class MapPointDist { /** The separator for CSV files */ public static String sSeparator = ";"; /** Path to the MapPointDist executable */ public static String sMapPointPath = "../Libraries/mappointdist/MapPointDist.exe"; /** * Generate a file containing all the coordinates, and two files containing the corresponding distance and time * matrices * * @param coordinates * an array containing the coordinates of all points * @param coordFile * the file in which the coordinates will be written * @param destFile * the file in which the matrices will be written * @param symmetric * {@code true} if the instance is symmetric, {@code false} otherwise * @param numThreads * the number of threads for the evaluation of the matrices * @throws IOException */ public static void generateDistanceTimeMatrixFiles(double[][] coordinates, String coordFile, String destFile, boolean symmetric, int numThreads) throws IOException { // Write the coordinates file String formatString = "%s" + sSeparator + "%s" + sSeparator + "%s\n"; BufferedWriter out = new BufferedWriter(new FileWriter(coordFile)); out.write(String.format(formatString, "id", "x", "y")); for (int i = 0; i < coordinates.length; i++) { out.write(String.format(formatString, i, coordinates[i][0], coordinates[i][1])); } out.flush(); out.close(); Process calc = Runtime.getRuntime() .exec(new String[] { sMapPointPath, coordFile, destFile, "" + symmetric, "" + numThreads }); try { Logging.getBaseLogger().info( "MapPointDist: Calculating distance and time matrix for file %s (size:%s-%s)", coordFile, coordinates.length, symmetric ? "symmetric" : "asymmetric"); calc.waitFor(); } catch (InterruptedException e) { e.printStackTrace(); } if (calc.exitValue() != 0) { throw new IllegalStateException("The MapPoint subprocess exited with value " + calc.exitValue()); } } /** * Evaluate the distance and time matrices * * @param coordinates * an array containing the coordinates of all points * @param coordFile * the file in which the coordinates will be written * @param destFile * the file in which the matrices will be written * @param symmetric * {@code true} if the instance is symmetric, {@code false} otherwise * @return an array of dimension [2][size][size] containing the distances matrix in the first index and the times in * the second * @param numThreads * the number of threads for the evaluation of the matrices * @throws IOException * @see {@link #generateDistanceTimeMatrixFiles(String, String, String)} */ public static double[][][] evaluateDistanceTimeMatrix(double[][] coordinates, String coordFile, String destFile, boolean symmetric, int numThreads) throws IOException { generateDistanceTimeMatrixFiles(coordinates, coordFile, destFile, symmetric, numThreads); return loadDistanceTimeMatrix(destFile); } /** * Load a distance and travel time matrix from a file generated by {@code MapPointDist}. * <p> * Note that even if the matrices are symmetric, the full matrices will be returned * </p> * * @param dataFile * the file containing the matrices * @return an array of dimension [2][size][size] containing the distances matrix in the first index and the times in * the second * @throws IOException */ public static double[][][] loadDistanceTimeMatrix(String dataFile) throws IOException { BufferedReader in = new BufferedReader(new FileReader(dataFile)); int type = 0; String row = in.readLine(); String[] cols = row.split(sSeparator); int size = Integer.valueOf(cols[0]); boolean symmetric = Boolean.valueOf(cols[1]); in.close(); return loadDistanceTimeMatrix(dataFile, size, symmetric); } /** * Load a distance and travel time matrix from a file generated by {@code MapPointDist}. * <p> * Note that even if the matrices are symmetric, the full matrices will be returned * </p> * * @param dataFile * the file containing the matrices * @param size * the number of nodes in the instance * @param symmetric * {@code true} if the distance matrix is symmetric, {@code false} otherwise * @return an array of dimension [2][size][size] containing the distances matrix in the first index and the times in * the second * @throws IOException */ public static double[][][] loadDistanceTimeMatrix(String dataFile, int size, boolean symmetric) throws IOException { BufferedReader in = new BufferedReader(new FileReader(dataFile)); int type = 0; String row = in.readLine(); String[] cols; row = in.readLine(); double[][][] matrix = new double[2][size][size]; while (row != null && !(row.startsWith("DISTANCES") || row.startsWith("TIMES"))) row = in.readLine(); int i = 0; while (row != null) { if (row.contains("TIMES")) type = 1; else if (row.contains("DISTANCES")) type = 0; cols = row.split(sSeparator); if (cols.length > 1) { i = Integer.valueOf(cols[0]); for (int j = 1; j < cols.length; j++) { if (symmetric) { matrix[type][i][i + j] = Double.valueOf(cols[j]); matrix[type][i + j][i] = matrix[type][i][i + j]; } else { matrix[type][i][j - 1] = Double.valueOf(cols[j]); } } } row = in.readLine(); } in.close(); return matrix; } }