/** @return converted tower node */
  private int handlePillarNode(
      int tmpNode, long osmId, PointList pointList, boolean convertToTowerNode) {
    tmpNode = tmpNode - 3;
    int intlat = pillarLats.getInt(tmpNode);
    int intlon = pillarLons.getInt(tmpNode);
    if (intlat == Integer.MAX_VALUE || intlon == Integer.MAX_VALUE)
      throw new AssertionError(
          "Conversation pillarNode to towerNode already happended!? "
              + "osmId:"
              + osmId
              + " pillarIndex:"
              + tmpNode);

    double tmpLat = Helper.intToDegree(intlat);
    double tmpLon = Helper.intToDegree(intlon);

    if (convertToTowerNode) {
      // convert pillarNode type to towerNode, make pillar values invalid
      pillarLons.setInt(tmpNode, Integer.MAX_VALUE);
      pillarLats.setInt(tmpNode, Integer.MAX_VALUE);
      tmpNode = addTowerNode(osmId, tmpLat, tmpLon);
    } else pointList.add(tmpLat, tmpLon);

    return tmpNode;
  }
 private int getOrigEdgeCount(int index) {
   // TODO possible memory usage improvement: avoid storing the value 1 for normal edges (does not
   // change)!
   long tmp = (long) index * 4;
   originalEdges.incCapacity(tmp + 4);
   return originalEdges.getInt(tmp);
 }
  private void _setNode(int id, double lat, double lon, double ele) {
    long tmp = (long) id * rowSizeInBytes;
    da.incCapacity(tmp + rowSizeInBytes);
    da.setInt(tmp + LAT, Helper.degreeToInt(lat));
    da.setInt(tmp + LON, Helper.degreeToInt(lon));

    if (is3D()) da.setInt(tmp + ELE, Helper.eleToInt(ele));
  }
  @Override
  public double getElevation(int id) {
    if (!is3D()) return Double.NaN;

    int intVal = da.getInt((long) id * rowSizeInBytes + ELE);
    return Helper.intToEle(intVal);
  }
 public PrepareContractionHierarchies(FlagEncoder encoder, Weighting weighting) {
   prepareEncoder = encoder;
   scOneDir = encoder.setAccess(0, true, false);
   scBothDir = encoder.setAccess(0, true, true);
   prepareWeighting = weighting;
   originalEdges = new GHDirectory("", DAType.RAM_INT).find("originalEdges");
   originalEdges.create(1000);
 }
  @Override
  public boolean addNode(long osmId, double lat, double lon) {
    int nodeType = osmIdToIndexMap.get(osmId);
    if (nodeType == EMPTY) return false;

    if (nodeType == TOWER_NODE) {
      addTowerNode(osmId, lat, lon);
    } else if (nodeType == PILLAR_NODE) {
      int tmp = (pillarId + 1) * 4;
      pillarLats.ensureCapacity(tmp);
      pillarLats.setInt(pillarId, Helper.degreeToInt(lat));
      pillarLons.ensureCapacity(tmp);
      pillarLons.setInt(pillarId, Helper.degreeToInt(lon));
      osmIdToIndexMap.put(osmId, pillarId + 3);
      pillarId++;
    }
    return true;
  }
  /**
   * Preprocessing of OSM file to select nodes which are used for highways. This allows a more
   * compact graph data structure.
   */
  @Override
  public void preProcess(InputStream osmXml) {
    pillarLats.create(Math.max(expectedNodes / 50, 100));
    pillarLons.create(Math.max(expectedNodes / 50, 100));
    if (osmXml == null) throw new AssertionError("Stream cannot be empty");

    XMLInputFactory factory = XMLInputFactory.newInstance();
    XMLStreamReader sReader = null;
    try {
      sReader = factory.createXMLStreamReader(osmXml, "UTF-8");
      long tmpCounter = 1;
      for (int event = sReader.next();
          event != XMLStreamConstants.END_DOCUMENT;
          event = sReader.next(), tmpCounter++) {
        if (tmpCounter % 50000000 == 0)
          logger.info(
              nf(tmpCounter)
                  + " (preprocess), osmIdMap:"
                  + nf(osmIdToIndexMap.size())
                  + " ("
                  + nf(osmIdToIndexMap.capacity())
                  + ") "
                  + Helper.getMemInfo());

        switch (event) {
          case XMLStreamConstants.START_ELEMENT:
            if ("way".equals(sReader.getLocalName())) {
              boolean valid = parseWay(sReader);
              if (valid) {
                int s = wayNodes.size();
                for (int index = 0; index < s; index++) {
                  setHasHighways(wayNodes.get(index));
                }
              }
            }
            break;
        }
      }
    } catch (XMLStreamException ex) {
      throw new RuntimeException("Problem while parsing file", ex);
    } finally {
      Helper7.close(sReader);
    }
  }
  @Override
  public double getEle(double lat, double lon) {
    lat = (int) (lat * precision) / precision;
    lon = (int) (lon * precision) / precision;
    int intKey = calcIntKey(lat, lon);
    HeightTile demProvider = cacheData.get(intKey);
    if (demProvider == null) {
      if (!cacheDir.exists()) cacheDir.mkdirs();

      String fileDetails = getFileString(lat, lon);
      if (fileDetails == null) return 0;

      int minLat = down(lat);
      int minLon = down(lon);
      demProvider = new HeightTile(minLat, minLon, WIDTH, precision);
      cacheData.put(intKey, demProvider);
      try {
        String zippedURL = baseUrl + "/" + fileDetails + "hgt.zip";
        File file = new File(cacheDir, new File(zippedURL).getName());
        InputStream is;
        // get zip file if not already in cacheDir - unzip later and in-memory only!
        if (!file.exists()) {
          for (int i = 0; i < 2; i++) {
            try {
              downloader.downloadFile(zippedURL, file.getAbsolutePath());
              break;
            } catch (FileNotFoundException ex) {
              // now try with point if mirror is used
              zippedURL = baseUrl + "/" + fileDetails + ".hgt.zip";
              continue;
            }
          }
        }

        is = new FileInputStream(file);
        ZipInputStream zis = new ZipInputStream(is);
        zis.getNextEntry();
        BufferedInputStream buff = new BufferedInputStream(zis);
        byte[] bytes = new byte[2 * WIDTH * WIDTH];
        DataAccess heights = getDirectory().find("dem" + intKey);
        heights.create(bytes.length);

        demProvider.setHeights(heights);
        int len;
        while ((len = buff.read(bytes)) > 0) {
          for (int bytePos = 0; bytePos < len; bytePos += 2) {
            short val = BIT_UTIL.toShort(bytes, bytePos);
            if (val < -1000 || val > 10000) {
              // TODO fill unassigned gaps with neighbor values -> flood fill algorithm !
              // -> calculate mean with an associated weight of how long the distance to the
              // neighbor is
              //                            throw new IllegalStateException("Invalid height value "
              // + val
              //                                    + ", y:" + bytePos / WIDTH + ", x:" + (WIDTH -
              // bytePos % WIDTH));
              val = Short.MIN_VALUE;
            }

            heights.setShort(bytePos, val);
          }
        }
        // demProvider.toImage(file.getName() + ".png");
      } catch (Exception ex) {
        throw new RuntimeException(ex);
      }
    }

    short val = demProvider.getHeight(lat, lon);
    if (val == Short.MIN_VALUE) return Double.NaN;
    return val;
  }
 private void setOrigEdgeCount(int index, int value) {
   long tmp = (long) index * 4;
   originalEdges.incCapacity(tmp + 4);
   originalEdges.setInt(tmp, value);
 }
 public void close() {
   algo.close();
   originalEdges.close();
   sortedNodes = null;
   oldPriorities = null;
 }
 @Override
 public double getLongitude(int id) {
   int intVal = da.getInt((long) id * rowSizeInBytes + LON);
   return Helper.intToDegree(intVal);
 }