bool CustomPoiMatch::_isExactMatch(const ConstNodePtr& n1, const ConstNodePtr& n2) const { // distance that is considered an exact match. Defaults to 1mm. Meters epsilon = conf().getDouble(epsilonDistanceKey(), 1e-3); bool result = true; if (n1->getElementId() == n2->getElementId()) { // pass, return = true } else if (n1->toCoordinate().distance(n2->toCoordinate()) > epsilon) { result = false; } else { // if at least one name pair is an exact match then it is an exact string match. double stringDistance = NameExtractor(new ExactStringDistance()).extract(n1, n2); if (stringDistance != 1.0) { result = false; } } return result; }
WayLocation::WayLocation(ConstOsmMapPtr map, ConstWayPtr way, double distance) : _map(map) { double d = 0.0; _segmentIndex = -1; _segmentFraction = -1; _way = way; double length = ElementConverter(map).convertToLineString(way)->getLength(); if (distance <= 0) { _segmentIndex = 0.0; _segmentFraction = 0; } else if (distance >= length) { _segmentIndex = _way->getNodeCount() - 1; _segmentFraction = 0.0; } else { Coordinate last = _map->getNode(way->getNodeId(0))->toCoordinate(); _segmentIndex = way->getNodeCount() - 1; _segmentFraction = 0; for (size_t i = 1; i < way->getNodeCount(); i++) { ConstNodePtr n = _map->getNode(_way->getNodeId(i)); Coordinate next = n->toCoordinate(); double delta = next.distance(last); last = next; if (d <= distance && d + delta > distance) { _segmentIndex = i - 1; _segmentFraction = (distance - d) / delta; // this can sometimes happen due to rounding errors. if (_segmentFraction >= 1.0) { _segmentFraction = 0.0; _segmentIndex++; } _way = way; break; } d += delta; } } assert(_segmentFraction < 1.0); assert((size_t)_segmentIndex <= _way->getNodeCount() - 1); }
bool CustomPoiMatch::_isDistanceMatch(const ConstNodePtr &n1, const ConstNodePtr &n2) const { double d = n1->toCoordinate().distance(n2->toCoordinate()); double s1 = n1->getCircularError() / 2.0; double s2 = n2->getCircularError() / 2.0; // calculated the expected sigma for the distance value. double sigma = sqrt(s1 * s1 + s2 * s2); // if the distance is within 2 sigma of the expected distance, then call it a match. return d < sigma * 2.0; }
void PertyWaySplitVisitor::_updateNewNodeProperties(NodePtr newNode, ConstNodePtr firstSplitBetweenNode, ConstNodePtr lastSplitBetweenNode) { //arbitrarily copy the status from one split between node to the new node newNode->setStatus(firstSplitBetweenNode->getStatus()); //add a circular error to the new node that's a weighted average of the circular error on the //two split between nodes newNode->setCircularError( (firstSplitBetweenNode->getCircularError() + lastSplitBetweenNode->getCircularError()) / 2); LOG_TRACE( "Updated the properties of a node created as a result of a way split: " << newNode->toString()); }
void GeometryPainter::drawWay(QPainter& pt, const OsmMap* map, const Way* way, const QMatrix& m) { int size = way->getNodeCount(); QPolygonF a(size); for (int j = 0; j < size; j++) { ConstNodePtr n = map->getNode(way->getNodeId(j)); a[j] = QPointF(m.map(QPointF(n->getX(), n->getY())) - QPointF(0.5, 0.5)); } pt.drawPolyline(a); }
void DualWaySplitter::_reconnectEnd(long centerNodeId, shared_ptr<Way> edge) { Coordinate centerNodeC = _result->getNode(centerNodeId)->toCoordinate(); // determine which end of edge we're operating on Coordinate edgeEnd; long edgeEndId; ConstNodePtr first = _result->getNode(edge->getNodeId(0)); ConstNodePtr last = _result->getNode(edge->getLastNodeId()); if (first->toCoordinate().distance(centerNodeC) < last->toCoordinate().distance(centerNodeC)) { edgeEnd = first->toCoordinate(); edgeEndId = first->getId(); } else { edgeEnd = last->toCoordinate(); edgeEndId = last->getId(); } // find all the nodes that are about the right distance from centerNodeId shared_ptr<DistanceNodeFilter> filterOuter(new DistanceNodeFilter(Filter::KeepMatches, centerNodeC, _splitSize * 1.01)); shared_ptr<DistanceNodeFilter> filterInner(new DistanceNodeFilter(Filter::FilterMatches, centerNodeC, _splitSize * .99)); ChainNodeFilter chain(filterOuter, filterInner); vector<long> nids = _result->filterNodes(chain, centerNodeC, _splitSize * 1.02); Radians bestAngle = std::numeric_limits<Radians>::max(); long bestNid = numeric_limits<long>::max(); Radians edgeAngle = WayHeading::calculateHeading(centerNodeC, edgeEnd); // find the smallest angle from edgeEnd to any of the candidate nodes for (size_t i = 0; i < nids.size(); i++) { if (edgeEndId != nids[i]) { Coordinate c = _result->getNode(nids[i])->toCoordinate(); Radians thisAngle = WayHeading::calculateHeading(centerNodeC, c); Radians deltaMagnitude = WayHeading::deltaMagnitude(edgeAngle, thisAngle); if (deltaMagnitude < bestAngle) { bestAngle = deltaMagnitude; bestNid = nids[i]; } } } // if the smallest angle is less than 45 deg, then connect them. if (toDegrees(bestAngle) < 45) { edge->replaceNode(edgeEndId, bestNid); } }
bool ContainsNodeCriterion::isSatisfied(const ConstElementPtr& e) const { if (e->getElementType() == ElementType::Way) { ConstWayPtr w = boost::dynamic_pointer_cast<const Way>(e); return w->hasNode(_nodeId); } else if (e->getElementType() == ElementType::Relation) { ConstRelationPtr r = boost::dynamic_pointer_cast<const Relation>(e); return r->contains(ElementId(ElementType::Node, _nodeId)); } else if (e->getElementType() == ElementType::Node) { ConstNodePtr n = boost::dynamic_pointer_cast<const Node>(e); return (n->getId() == _nodeId); } return false; }
QString OsmApiDbSqlChangesetFileWriter::_getUpdateValuesNodeStr(ConstNodePtr node) const { return QString("latitude=%2, longitude=%3, changeset_id=%4, visible=%5, \"timestamp\"=%8, tile=%6, version=%7 WHERE id=%1;\n") .arg(node->getId()) .arg((qlonglong)OsmApiDb::toOsmApiDbCoord(node->getY())) .arg((qlonglong)OsmApiDb::toOsmApiDbCoord(node->getX())) .arg(node->getChangeset()) .arg(_getVisibleStr(node->getVisible())) .arg(ApiDb::tileForPoint(node->getY(), node->getX())) .arg(node->getVersion()) .arg(OsmApiDb::TIMESTAMP_FUNCTION); }
set<long> _findNeighbors(const ConstNodePtr& n) { set<long> result; set<QString> allNames = _getNamePermutations(n->getTags().getNames()); double minSimilarity = conf().getDouble(PlacesPoiMatch::minimumEditSimilarityKey(), PlacesPoiMatch::minimumEditSimilarityDefault()); for (set<QString>::const_iterator it = allNames.begin(); it != allNames.end(); ++it) { const QString& s = *it; // if the string we're comparing against is longer then D may be bigger than // (1 - minSimilarity) * string length. Account for that below. int D = (int)round((double)s.size() / minSimilarity) - s.size(); set<long> r = _index->find(n->toCoordinate(), n->getCircularError(), s, D); result.insert(r.begin(), r.end()); } return result; }
QString OsmApiDbSqlChangesetFileWriter::_getInsertValuesNodeStr(ConstNodePtr node) const { return QString("latitude, longitude, changeset_id, visible, \"timestamp\", " "tile, version) VALUES (%1, %2, %3, %4, %5, %8, %6, %7);\n") .arg(node->getId()) .arg((qlonglong)OsmApiDb::toOsmApiDbCoord(node->getY())) .arg((qlonglong)OsmApiDb::toOsmApiDbCoord(node->getX())) .arg(node->getChangeset()) .arg(_getVisibleStr(node->getVisible())) .arg(ApiDb::tileForPoint(node->getY(), node->getX())) .arg(node->getVersion()) .arg(OsmApiDb::TIMESTAMP_FUNCTION); }
Meters WayLocation::calculateDistanceOnWay() const { //LOG_TRACE("Calculating distance on way..."); Meters result = 0.0; Coordinate last = _map->getNode(_way->getNodeId(0))->toCoordinate(); for (int i = 1; i < (int)_way->getNodeCount() && i <= _segmentIndex; i++) { ConstNodePtr n = _map->getNode(_way->getNodeId(i)); Coordinate next = n->toCoordinate(); result += next.distance(last); last = next; } if (_segmentIndex < (int)_way->getNodeCount() - 1) { ConstNodePtr n = _map->getNode(_way->getNodeId(_segmentIndex + 1)); Coordinate next = n->toCoordinate(); Meters d = next.distance(last); result += d * _segmentFraction; } return result; }
WayLocation WayLocation::move(Meters distance) const { WayLocation result(*this); Coordinate last = result.getCoordinate(); // This odd statement avoid us adding irrelevantly small distances. while (1 + distance > 1) { // if we're at the end of the way if (result.isLast()) { return result; } ConstNodePtr n = _map->getNode(_way->getNodeId(result.getSegmentIndex() + 1)); Coordinate next = n->toCoordinate(); double delta = last.distance(next); // if the next node is too far if (distance - delta < 0) { // figure out what distance we need to move along the segment. Coordinate lastSegment = _map->getNode(_way->getNodeId(result.getSegmentIndex()))-> toCoordinate(); double segmentLength = lastSegment.distance(next); result._segmentFraction += (distance / segmentLength); // this can happen due to floating point errors when the new location is very close to a // node. if (result._segmentFraction >= 1.0) { result._segmentFraction = 0.0; result._segmentIndex = result._segmentIndex + 1; } distance = 0; } // if we need to go past the next node else { distance -= delta; last = next; result._segmentIndex = result.getSegmentIndex() + 1; result._segmentFraction = 0.0; } } // This odd statement avoid us subtracting irrelevantly small distances. while (1 + distance < 1) { // if we're at the end of the way if (result.isFirst()) { return result; } if (result._segmentFraction > 0) { Coordinate next = _map->getNode(_way->getNodeId(result.getSegmentIndex()))->toCoordinate(); Meters delta = last.distance(next); if (distance + delta > 0) { // figure out what distance we need to move along the segment. Coordinate last = _map->getNode(_way->getNodeId(result._segmentIndex + 1))->toCoordinate(); double segmentLength = last.distance(next); result._segmentFraction += (distance / segmentLength); // this can happen due to floating point errors when the new location is very close to a // node. if (result._segmentFraction >= 1.0) { result._segmentFraction = 0.0; result._segmentIndex = result._segmentIndex + 1; } distance = 0; } else { result._segmentFraction = 0; distance += delta; last = next; } } else { Coordinate next = _map->getNode(_way->getNodeId(result.getSegmentIndex() - 1))-> toCoordinate(); Meters delta = last.distance(next); if (distance + delta > 0) { // figure out what distance we need to move along the segment. Coordinate last = _map->getNode(_way->getNodeId(result.getSegmentIndex()))->toCoordinate(); double segmentLength = last.distance(next); result._segmentFraction = 1.0 + (distance / segmentLength); // if we're suffering from a floating point issue. if (result._segmentFraction >= 1.0) { // make sure the floating point issue is within the expected bounds. assert(result._segmentFraction < 1.0 + 1e-14); result._segmentFraction = 0; } else { result._segmentIndex = result.getSegmentIndex() - 1; } distance = 0; } else { result._segmentIndex--; distance += delta; last = next; } } } assert(result._segmentFraction < 1.0 && result._segmentFraction >= 0); assert(result._segmentIndex >= 0 && result._segmentIndex < (int)result.getWay()->getNodeCount()); return result; }
void ElementCacheLRU::addElement(ConstElementPtr &newElement) { ConstNodePtr newNode; ConstWayPtr newWay; ConstRelationPtr newRelation; switch ( newElement->getElementType().getEnum() ) { case ElementType::Node: newNode = dynamic_pointer_cast<const Node>(newElement); if ( newNode != ConstNodePtr() ) { // Do we have to replace an entry? if ( _nodes.size() == _maxCountPerType ) { _removeOldest(ElementType::Node); } _nodes.insert(std::make_pair(newNode->getId(), std::make_pair(newNode, boost::posix_time::microsec_clock::universal_time()))); //LOG_DEBUG("Added new node with ID " << newNode->getId() ); } break; case ElementType::Way: newWay = dynamic_pointer_cast<const Way>(newElement); if ( newWay != ConstWayPtr() ) { // Do we have to replace an entry? if ( _ways.size() == _maxCountPerType ) { _removeOldest(ElementType::Way); } _ways.insert(std::make_pair(newWay->getId(), std::make_pair(newWay, boost::posix_time::microsec_clock::universal_time()))); } break; case ElementType::Relation: newRelation = dynamic_pointer_cast<const Relation>(newElement); if ( newRelation != ConstRelationPtr() ) { // Do we have to replace an entry? if ( _relations.size() == _maxCountPerType ) { _removeOldest(ElementType::Relation); } _relations.insert(std::make_pair(newRelation->getId(), std::make_pair(newRelation, boost::posix_time::microsec_clock::universal_time()))); } break; default: throw HootException(QString("Unexpected element type: %1").arg( newElement->getElementType().toString())); break; } // Reset all iterators to maintain interface contract resetElementIterators(); }
void OsmApiDbSqlChangesetFileWriter::write(const QString path, ChangesetProviderPtr changesetProvider) { LOG_DEBUG("Writing changeset to " << path); LOG_VARD(path); LOG_VARD(changesetProvider->hasMoreChanges()); _changesetBounds.init(); _outputSql.setFileName(path); if (_outputSql.open(QIODevice::WriteOnly | QIODevice::Text) == false) { throw HootException(QObject::tr("Error opening %1 for writing").arg(path)); } int changes = 0; _createChangeSet(); while (changesetProvider->hasMoreChanges()) { LOG_TRACE("Reading next SQL change..."); Change change = changesetProvider->readNextChange(); switch (change.getType()) { case Change::Create: _createNewElement(change.getElement()); break; case Change::Modify: _updateExistingElement(change.getElement()); break; case Change::Delete: _deleteExistingElement(change.getElement()); break; case Change::Unknown: //see comment in ChangesetDeriver::_nextChange() when //_fromE->getElementId() < _toE->getElementId() as to why we do a no-op here. break; default: throw IllegalArgumentException("Unexpected change type."); } if (change.getType() != Change::Unknown) { if (change.getElement()->getElementType().getEnum() == ElementType::Node) { ConstNodePtr node = boost::dynamic_pointer_cast<const Node>(change.getElement()); _changesetBounds.expandToInclude(node->getX(), node->getY()); } changes++; } if (changes > _changesetMaxSize) { _updateChangeset(changes); _createChangeSet(); changes = 0; } } _updateChangeset(changes); _outputSql.close(); }
bool has(ConstNodePtr node) const {return has(node.lock()->id());}