@Override
  protected void parseDense(DenseNodes nodes) {
    // parse nodes only if we're not on a single pass mode, or if the nodes
    // collection of single pass mode is done
    if (this.nodesRefCollectionDone) {
      long lastId = 0, lastLat = 0, lastLon = 0;
      int j = 0;
      DenseInfo di = null;
      if (nodes.hasDenseinfo()) {
        di = nodes.getDenseinfo();
      }
      for (int i = 0; i < nodes.getIdCount(); i++) {
        List<Tag> tags = new ArrayList<Tag>();
        long lat = nodes.getLat(i) + lastLat;
        lastLat = lat;
        long lon = nodes.getLon(i) + lastLon;
        lastLon = lon;
        long id = nodes.getId(i) + lastId;
        lastId = id;
        double latf = parseLat(lat), lonf = parseLon(lon);
        if (nodes.getKeysValsCount() > 0) {
          while (nodes.getKeysVals(j) != 0) {
            int keyid = nodes.getKeysVals(j++);
            int valid = nodes.getKeysVals(j++);
            Tag tag = new Tag();
            tag.setKey(getStringById(keyid));
            tag.setValue(getStringById(valid));
            tags.add(tag);
          }
          j++;
        }
        if (di != null) {
          com.osm2xp.model.osm.Node node = new com.osm2xp.model.osm.Node();
          node.setId(id);
          node.setLat(latf);
          node.setLon(lonf);
          node.getTag().addAll(tags);
          try {
            // give the node to the translator for processing
            translator.processNode(node);
            // ask translator if we have to store this node if we
            // aren't on a single pass mode

            if (!GuiOptionsHelper.getOptions().isSinglePass()) {
              if (translator.mustStoreNode(node)) {
                processor.storeNode(node);
              }
            }
            // if we're on a single pass mode, and if
            // nodesRefCollectionDone is true it means we already
            // have the reference of usefull nodes, so we check if
            // this node is one of them, if yes, store it
            else {
              if (processor.getNode(node.getId()) != null) {
                processor.storeNode(node);
              }
            }
          } catch (Osm2xpBusinessException e) {
            Osm2xpLogger.error("Error processing node.", e);
          } catch (DataSinkException e) {
            Osm2xpLogger.error("Error processing node.", e);
          }
        }
      }
    }
  }
 @Override
 protected void parseDense(DenseNodes nodes) {
   if (!nodes.hasDenseinfo()) discourageUpload = true;
   if (exception == null) {
     try {
       int keyIndex = 0;
       // Almost all data is DELTA coded
       long nodeId = 0;
       long nodeLat = 0;
       long nodeLon = 0;
       long changesetId = 0;
       int uid = 0;
       int suid = 0;
       long timestamp = 0;
       for (int i = 0; i < nodes.getIdCount(); i++) {
         // Id (delta) and version (normal)
         Node node =
             new Node(
                 nodeId += nodes.getId(i),
                 nodes.hasDenseinfo() ? nodes.getDenseinfo().getVersion(i) : 1);
         // Lat/Lon (delta)
         node.setCoor(
             new LatLon(
                     parseLat(nodeLat += nodes.getLat(i)), parseLon(nodeLon += nodes.getLon(i)))
                 .getRoundedToOsmPrecision());
         checkCoordinates(node.getCoor());
         if (nodes.hasDenseinfo()) {
           DenseInfo info = nodes.getDenseinfo();
           // Changeset (delta)
           if (info.getChangesetCount() > i) {
             checkChangesetId(changesetId += info.getChangeset(i));
             node.setChangesetId((int) changesetId);
           }
           // User (delta)
           if (info.getUidCount() > i && info.getUserSidCount() > i) {
             node.setUser(
                 User.createOsmUser(
                     uid += info.getUid(i), getStringById(suid += info.getUserSid(i))));
           }
           // Timestamp (delta)
           if (info.getTimestampCount() > i) {
             checkTimestamp(timestamp += info.getTimestamp(i));
             node.setTimestamp(new Date(date_granularity * timestamp));
           }
         }
         // A single table contains all keys/values of all nodes.
         // Each node's tags are encoded in alternating <key_id> <value_id>.
         // A single stringid of 0 delimit when the tags of a node ends and the tags of the next
         // node begin.
         Map<String, String> keys = new HashMap<>();
         while (keyIndex < nodes.getKeysValsCount()) {
           int keyId = nodes.getKeysVals(keyIndex++);
           if (keyId == 0) {
             break; // End of current node's tags
           } else if (keyIndex < nodes.getKeysValsCount()) {
             keys.put(getStringById(keyId), getStringById(nodes.getKeysVals(keyIndex++)));
           } else {
             throw new IllegalDataException(tr("Invalid DenseNodes key/values table"));
           }
         }
         node.setKeys(keys);
         externalIdMap.put(node.getPrimitiveId(), node);
       }
     } catch (IllegalDataException e) {
       exception = e;
     }
   }
 }