HHBinaryFileWriter.java :  » Tools » mapsforge » org » mapsforge » preprocessing » highwayHierarchies » mobile » Android Open Source

Android Open Source » Tools » mapsforge 
mapsforge » org » mapsforge » preprocessing » highwayHierarchies » mobile » HHBinaryFileWriter.java
/*
 * Copyright 2010, 2011 mapsforge.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.mapsforge.preprocessing.highwayHierarchies.mobile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;

import org.mapsforge.core.GeoCoordinate;
import org.mapsforge.core.Rect;
import org.mapsforge.preprocessing.highwayHierarchies.mobile.LevelGraph.Level;
import org.mapsforge.preprocessing.highwayHierarchies.mobile.LevelGraph.Level.LevelEdge;
import org.mapsforge.preprocessing.highwayHierarchies.mobile.LevelGraph.Level.LevelVertex;

/**
 * This class is responsible for writing a binary file for the mobile highway hierarchies
 * algorithm.
 */
public class HHBinaryFileWriter {
  /** parameter for specifying the clustering algorithm */
  public static final String CLUSTERING_ALGORTHM_K_CENTER = "k_center";
  /** parameter for specifying the clustering algorithm */
  public static final String CLUSTERING_ALGORITHM_QUAD_TREE = "quad_tree";

  private final static byte[] HEADER_MAGIC = HHGlobals.BINARY_FILE_HEADER_MAGIC;
  private final static int HEADER_LENGTH = HHGlobals.BINARY_FILE_HEADER_LENGTH;

  private final static int BUFFER_SIZE = 16384 * 1000;

  /**
   * Writes the binary file for the mobile highway hierarchies algorithm. input is take from a
   * database.
   * 
   * @param conn
   *            input database.
   * @param clusteringAlgorithmName
   *            name of the clustering algorithm, see static class variables.
   * @param clusterSizeThreshold
   *            limit on the number of nodes per logical block of the graph.
   * @param kcenterOversamplingFactor
   *            controls the quality of the k-center clusters.
   * @param targetFile
   *            file to write output to.
   * @param indexGroupSizeThreshold
   *            controls compression and runtime overhead of the address lookup table.
   * @param rtreeBlockSize
   *            sets size and alignment of r tree nodes.
   * @param includeHopIndices
   *            set to true for storing pre-computed information for shortcut expansion.
   * @throws IOException
   *             on error reading or writing file.
   * @throws SQLException
   *             on error with database.
   */
  public static void writeBinaryFile(Connection conn, String clusteringAlgorithmName,
      int clusterSizeThreshold, int kcenterOversamplingFactor,
      File targetFile, int indexGroupSizeThreshold, int rtreeBlockSize,
      boolean includeHopIndices) throws IOException, SQLException {

    // load the graph into ram
    LevelGraph levelGraph = new LevelGraph(conn);
    conn.close();

    // compute the clustering
    // compute clustering
    System.out.println("compute clustering: ");
    System.out.println("algorithm = " + clusteringAlgorithmName);
    System.out.println("clusterSizeThreshold = " + clusterSizeThreshold);
    Clustering[] clustering;
    if (clusteringAlgorithmName.equals(CLUSTERING_ALGORITHM_QUAD_TREE)) {
      clustering = QuadTreeClusteringAlgorithm.computeClustering(levelGraph
          .getLevels(),
          levelGraph.getVertexLongitudesE6(), levelGraph.getVertexLatitudesE6(),
          QuadTreeClusteringAlgorithm.HEURISTIC_MEDIAN,
          clusterSizeThreshold);

    } else if (clusteringAlgorithmName.equals(CLUSTERING_ALGORTHM_K_CENTER)) {
      clustering = KCenterClusteringAlgorithm.computeClustering(levelGraph
          .getLevels(), clusterSizeThreshold, kcenterOversamplingFactor,
          KCenterClusteringAlgorithm.HEURISTIC_MIN_SIZE);
    } else {
      System.out.println("invalid clustering algorithm specified in properties.");
      return;
    }

    // ---------------- WRITE TEMPORARY FILES --------------------------
    System.out.println("targetFile = '" + targetFile.getAbsolutePath() + "'");

    File fBlocks = new File(targetFile.getAbsolutePath() + ".blocks");
    File fileAddressLookupTable = new File(targetFile.getAbsolutePath()
        + ".addressLookupTable");
    File fRTree = new File(targetFile.getAbsolutePath() + ".rtree");

    // write the graphs cluster blocks
    ClusterBlockMapping mapping = new ClusterBlockMapping(clustering);
    int[] blockSize = BlockWriter.writeClusterBlocks(fBlocks, levelGraph, clustering,
        mapping, includeHopIndices);

    // write block index
    AddressLookupTableWriter.writeTable(blockSize, indexGroupSizeThreshold,
        fileAddressLookupTable);

    // construct and write r-tree (insert only level 0 clusters)
    int[] minLat = new int[clustering[0].size()];
    int[] maxLat = new int[clustering[0].size()];
    int[] minLon = new int[clustering[0].size()];
    int[] maxLon = new int[clustering[0].size()];
    int[] blockId = new int[clustering[0].size()];
    {
      int i = 0;
      for (Cluster c : clustering[0].getClusters()) {
        Rect r = getBoundingBox(c, levelGraph.getLevel(0));
        minLat[i] = r.minLatitudeE6;
        maxLat[i] = r.maxLatitudeE6;
        minLon[i] = r.minLongitudeE6;
        maxLon[i] = r.maxLongitudeE6;
        blockId[i] = mapping.getBlockId(c);
        i++;
      }
    }
    StaticRTreeWriter.packSortTileRecursive(minLon, maxLon, minLat, maxLat, blockId,
        rtreeBlockSize, fRTree);

    // ---------------- WRITE THE BINARY FILE --------------------------

    DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
        new FileOutputStream(targetFile)));

    // write header of the binary
    long startAddrGraph = HEADER_LENGTH;
    long endAddrGraph = startAddrGraph + fBlocks.length();

    long startAddrBlockIdx = endAddrGraph;
    long endAddrBlockIdx = startAddrBlockIdx + fileAddressLookupTable.length();

    long startAddrRTree = endAddrBlockIdx;
    long endAddrRTree = startAddrRTree + fRTree.length();

    out.write(HEADER_MAGIC);
    out.writeLong(startAddrGraph);
    out.writeLong(endAddrGraph);
    out.writeLong(startAddrBlockIdx);
    out.writeLong(endAddrBlockIdx);
    out.writeLong(startAddrRTree);
    out.writeLong(endAddrRTree);
    if (out.size() <= HEADER_LENGTH) {
      out.write(new byte[HEADER_LENGTH - out.size()]);
    } else {
      throw new RuntimeException("need to increase header length.");
    }

    // write components
    writeFile(fBlocks, out);
    writeFile(fileAddressLookupTable, out);
    writeFile(fRTree, out);

    System.out.println(out.size() + " bytes written to '" + targetFile + "'");

    out.flush();
    out.close();

    // ---------------- CLEAN UP TEMPORARY FILES --------------------------
    fBlocks.delete();
    fileAddressLookupTable.delete();
    fRTree.delete();
  }

  private static Rect getBoundingBox(Cluster c, Level graph) {
    int minLat = Integer.MAX_VALUE;
    int maxLat = Integer.MIN_VALUE;
    int minLon = Integer.MAX_VALUE;
    int maxLon = Integer.MIN_VALUE;

    int[] vertexIds = c.getVertices();
    for (int vId : vertexIds) {
      LevelVertex v = graph.getVertex(vId);
      GeoCoordinate coord = v.getCoordinate();
      minLat = Math.min(coord.getLatitudeE6(), minLat);
      maxLat = Math.max(coord.getLatitudeE6(), maxLat);
      minLon = Math.min(coord.getLongitudeE6(), minLon);
      maxLon = Math.max(coord.getLongitudeE6(), maxLon);
      for (LevelEdge e : v.getOutboundEdges()) {
        GeoCoordinate[] waypoints = e.getWaypoints();
        if (waypoints != null) {
          for (GeoCoordinate wp : waypoints) {
            minLat = Math.min(wp.getLatitudeE6(), minLat);
            maxLat = Math.max(wp.getLatitudeE6(), maxLat);
            minLon = Math.min(wp.getLongitudeE6(), minLon);
            maxLon = Math.max(wp.getLongitudeE6(), maxLon);
          }
        }
      }
    }
    return new Rect(minLon, maxLon, minLat, maxLat);
  }

  /**
   * Writes the content of the given file to the output stream.
   * 
   * @param f
   *            the file to be written.
   * @param oStream
   *            the stream to write to.
   * @return number of bytes written.
   * @throws IOException
   *             on write errors.
   */
  private static long writeFile(File f, OutputStream oStream) throws IOException {
    byte[] buff = new byte[BUFFER_SIZE];
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));

    int len;
    long offset = 0;
    while ((len = in.read(buff)) > 0) {
      oStream.write(buff, 0, len);
      offset += len;
    }
    in.close();
    return offset;
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.