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