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