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;
}
Exemple #2
0
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;
}
Exemple #4
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());
}
Exemple #5
0
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;
}
Exemple #8
0
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;
  }
Exemple #10
0
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);
}
Exemple #11
0
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;
}
Exemple #12
0
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();
}
Exemple #14
0
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());}