Exemplo n.º 1
0
void OsmApiDbSqlChangesetFileWriter::_createNewElement(ConstElementPtr element)
{
  const QString elementTypeStr = element->getElementType().toString().toLower();
  ElementPtr changeElement = _getChangeElement(element);

  //we only grab and assign a new id if we have a new element with a negative id, since we'll be
  //writing this directly to the database and negative ids aren't allowed
  LOG_TRACE("ID before: " << changeElement->getElementId());
  long id;
  if (changeElement->getId() < 0)
  {
    id = _db.getNextId(element->getElementType().getEnum());
  }
  else
  {
    id = changeElement->getId();
  }
  LOG_TRACE("ID after: " << ElementId(changeElement->getElementType(), id));

  changeElement->setId(id);
  changeElement->setVersion(1);
  changeElement->setVisible(true);
  changeElement->setChangeset(_changesetId);
  LOG_TRACE("Creating: " << changeElement->getElementId());

  QString note = "";
  LOG_VART(changeElement->getId());
  LOG_VART(note);
  LOG_VART(changeElement->getVersion());
  QString commentStr = "/* create " + elementTypeStr + " " + QString::number(changeElement->getId());
  commentStr += "*/\n";
  _outputSql.write((commentStr).toUtf8());

  const QString values = _getInsertValuesStr(changeElement);
  _outputSql.write(
    ("INSERT INTO " + elementTypeStr + "s (" + elementTypeStr + "_id, " + values).toUtf8());
  _outputSql.write(("INSERT INTO current_" + elementTypeStr + "s (id, " + values).toUtf8());

  _createTags(changeElement);

  switch (changeElement->getElementType().getEnum())
  {
    case ElementType::Way:
      _createWayNodes(boost::dynamic_pointer_cast<const Way>(changeElement));
      break;
    case ElementType::Relation:
      _createRelationMembers(boost::dynamic_pointer_cast<const Relation>(changeElement));
      break;
    default:
      //node
      break;
  }
}
Exemplo n.º 2
0
void OsmApiDbSqlChangesetFileWriter::_updateExistingElement(ConstElementPtr element)
{
  const QString elementTypeStr = element->getElementType().toString().toLower();
  ElementPtr changeElement = _getChangeElement(element);

  //if another parsed change previously modified the element with this id, we want to get the
  //modified version
  const long currentVersion = changeElement->getVersion();
  const long newVersion = currentVersion + 1;

  changeElement->setVersion(newVersion);
  changeElement->setChangeset(_changesetId);
  changeElement->setVisible(true);
  LOG_TRACE("Updating: " << changeElement->getElementId());

  QString note = "";
  LOG_VART(changeElement->getId());
  LOG_VART(note);
  LOG_VART(changeElement->getVersion());
  QString commentStr = "/* modify " + elementTypeStr + " " + QString::number(changeElement->getId());
  commentStr += "*/\n";
  _outputSql.write((commentStr).toUtf8());

  //<element-name> table contains all version of all elements of that type in a history, so insert
  //into that table.
  _outputSql.write(
    ("INSERT INTO " + elementTypeStr + "s (" + elementTypeStr + "_id, " +
     _getInsertValuesStr(changeElement)).toUtf8());
  //current_<element-name> contains the single latest version of the element, so update that record
  _outputSql.write(
    ("UPDATE current_" + elementTypeStr + "s SET " + _getUpdateValuesStr(changeElement)).toUtf8());

  _deleteCurrentTags(changeElement->getElementId());
  _createTags(changeElement);

  switch (changeElement->getElementType().getEnum())
  {
    case ElementType::Way:
      _deleteAll(ApiDb::getCurrentWayNodesTableName(), "way_id", changeElement->getId());
      _deleteAll(ApiDb::getWayNodesTableName(), "way_id", changeElement->getId());
      _createWayNodes(boost::dynamic_pointer_cast<const Way>(changeElement));
      break;
    case ElementType::Relation:
      _deleteAll(ApiDb::getCurrentRelationMembersTableName(), "relation_id", changeElement->getId());
      _deleteAll(ApiDb::getRelationMembersTableName(), "relation_id", changeElement->getId());
      _createRelationMembers(boost::dynamic_pointer_cast<const Relation>(changeElement));
      break;
    default:
      //node
      break;
  }
}
Exemplo n.º 3
0
vector<ElementPtr> PertyWaySplitVisitor::_split(ElementPtr element)
{
  //randomly select elements and split them into two parts
  boost::uniform_real<> randomSplitDistribution(0.0, 1.0);
  const double randomSplitNum = randomSplitDistribution(*_rng);
  if (randomSplitNum <= _waySplitProbability)
  {
    LOG_TRACE("element " << element->getElementId() << " *will* be split based on a split " <<
      "probability of: " <<  _waySplitProbability << " and a randomly generated number: " <<
      randomSplitNum << "\n");

    _splitRecursionLevel++;
    LOG_VART(_splitRecursionLevel);

    const int numNodesBeforeSplit = _map->getNodes().size();
    LOG_VART(numNodesBeforeSplit);
    const int numWaysBeforeSplit = _map->getWays().size();
    LOG_VART(numWaysBeforeSplit);

    WayLocation waySplitPoint;
    MultiLineStringLocation multiLineSplitPoint;
    QList<long> nodeIdsBeforeSplit;
    int segmentIndex = -1;
    ElementId wayId;
    //determine where to split the element
    if (element->getElementType() == ElementType::Way)
    {
      WayPtr way = boost::dynamic_pointer_cast<Way>(element);
      LOG_VART(way->getNodeCount());
      nodeIdsBeforeSplit = QVector<long>::fromStdVector(way->getNodeIds()).toList();
      LOG_VART(nodeIdsBeforeSplit);
      waySplitPoint = _calcSplitPoint(way);
    }
    else
    {
      multiLineSplitPoint = _calcSplitPoint(boost::dynamic_pointer_cast<Relation>(element), wayId);
      waySplitPoint = multiLineSplitPoint.getWayLocation();
    }

    const QString distanceMsgStrEnd =
      QString("a minimum node spacing of ")
        .append(QString::number(_minNodeSpacing))
        .append(" meters");
    if (!waySplitPoint.isValid())
    {
      _splitRecursionLevel--;
      LOG_VART(_splitRecursionLevel);

      LOG_TRACE("split point *will not* be used because *it violates* " << distanceMsgStrEnd);
      //if it violates the min node spacing, return an empty element collection, which will end the
      //recursive splitting on the current way
      return vector<ElementPtr>();
    }
    else
    {
      LOG_TRACE("split point *will* be used because it *does not* violate " << distanceMsgStrEnd);
      segmentIndex = waySplitPoint.getSegmentIndex();
      LOG_VART(segmentIndex);
    }

    //split the element
    vector<ElementPtr> newElementsAfterSplit;
    if (element->getElementType() == ElementType::Way)
    {
      vector<WayPtr> newWaysAfterSplit =
        WaySplitter::split(_map->shared_from_this(),
        boost::dynamic_pointer_cast<Way>(element), waySplitPoint);
      for (size_t i = 0; i < newWaysAfterSplit.size(); i++)
      {
        newElementsAfterSplit.push_back(newWaysAfterSplit.at(i));
      }
    }
    else
    {
      ElementPtr match;
      MultiLineStringSplitter().split(_map->shared_from_this(), multiLineSplitPoint, match);
      newElementsAfterSplit.push_back(match);
    }

    const int numNodesAfterSplit = _map->getNodes().size();
    LOG_VART(numNodesAfterSplit);
    const int numNewNodesCreatedBySplit = numNodesAfterSplit - numNodesBeforeSplit;
    LOG_VART(numNewNodesCreatedBySplit);
    LOG_VART(_map->getWays().size());

    if (numNewNodesCreatedBySplit > 0)
    {
      WayPtr way = boost::dynamic_pointer_cast<Way>(element);
      //Its possible that the splitting of a relation could generate a new node.  In that case,
      //_updateNewNodeProperties does not need to be called b/c the MultiLineStringSplitter has
      //already properly updated the new node's properties.  when a way is split, however, the
      //new node's properties must be updated by the call to _updateNewNodeProperties.
      if (way != 0)
      {
        assert(nodeIdsBeforeSplit.size() > 0);
        //update properties on any nodes added as a result of the way splitting (new ways created as a
        //result of the splitting will already have had their parent's tags added by WaySplitter)
        _updateNewNodeProperties(
          _getNodeAddedBySplit(nodeIdsBeforeSplit, newElementsAfterSplit),
          _map->getNode(way->getNodeId(segmentIndex)),
          _map->getNode(way->getNodeId(segmentIndex + 1)));
      }
    }

    //recursive call
    for (vector<ElementPtr>::const_iterator it = newElementsAfterSplit.begin();
         it != newElementsAfterSplit.end(); ++it)
    {
      _split(*it);
    }

    return newElementsAfterSplit;
  }
  else
  {
    LOG_TRACE("element " << element->getElementId() << " *will not* be split based on a split " <<
      "probability of: " << _waySplitProbability << " and a randomly generated number: " <<
      randomSplitNum << "\n");
  }

  //end the recursive splitting on the current way
  return vector<ElementPtr>();
}
Exemplo n.º 4
0
void OsmApiDbSqlChangesetFileWriter::_deleteExistingElement(ConstElementPtr element)
{
  const QString elementIdStr = QString::number(element->getId());
  const QString elementTypeStr = element->getElementType().toString().toLower();
  ElementPtr changeElement = _getChangeElement(element);

  const long currentVersion = changeElement->getVersion();
  const long newVersion = currentVersion + 1;

  changeElement->setVersion(newVersion);
  changeElement->setVisible(false);
  changeElement->setChangeset(_changesetId);
  LOG_TRACE("Deleting: " << changeElement->getElementId());

  QString note = "";
  LOG_VART(changeElement->getId());
  LOG_VART(note);
  LOG_VART(changeElement->getVersion());
  QString commentStr = "/* delete " + elementTypeStr + " " + QString::number(changeElement->getId());
  commentStr += "*/\n";
  _outputSql.write((commentStr).toUtf8());

  //OSM API DB keeps history for all elements, so the existing element in the master table is not
  //modified and a new record is added with the updated version and visible set to false
  _outputSql.write(("INSERT INTO " + elementTypeStr + "s (" + elementTypeStr + "_id, " +
                    _getInsertValuesStr(changeElement)).toUtf8());

  _deleteCurrentTags(changeElement->getElementId());

  switch (changeElement->getElementType().getEnum())
  {
    case ElementType::Node:

      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentWayNodesTableName() +
         " WHERE node_id=" + elementIdStr + ";\n").toUtf8());
      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentRelationMembersTableName() +
         " WHERE member_type = 'Node' AND member_id = " +
         elementIdStr + ";\n").toUtf8());

      break;

    case ElementType::Way:

      //all of its entries in current way nodes are removed
      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentWayNodesTableName() +
         " WHERE way_id=" + elementIdStr + ";\n").toUtf8());
      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentRelationMembersTableName() +
         " WHERE member_type = 'Way' AND member_id = " +
         elementIdStr + ";\n").toUtf8());

      break;

    case ElementType::Relation:

      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentRelationMembersTableName() +
         " WHERE relation_id=" + elementIdStr + ";\n").toUtf8());
      _outputSql.write(
        ("DELETE FROM " + ApiDb::getCurrentRelationMembersTableName() +
         " WHERE member_type = 'Relation' AND member_id = " +
         elementIdStr + ";\n").toUtf8());

      break;

    default:
      throw HootException("Unknown element type");
  }

  //in the current table, the element isn't deleted but set to be invisible
  const QString values =
    QString("changeset_id=%1, visible=%2, version=%3 WHERE id=%4;\n")
      .arg(changeElement->getChangeset())
      .arg(_getVisibleStr(changeElement->getVisible()))
      .arg(changeElement->getVersion())
      .arg(changeElement->getId());
  _outputSql.write(("UPDATE current_" + elementTypeStr + "s SET " + values).toUtf8());
}