/*! * \brief GetPointForTurn returns ingoingPoint or outgoingPoint for turns. * These points belongs to the route but they often are not neighbor of junctionPoint. * To calculate the resulting point the function implements the following steps: * - going from junctionPoint along feature ft according to the direction which is set in GetPointIndex(). * - until one of following conditions is fulfilled: * - the end of ft is reached; (returns the last feature point) * - more than kMaxPointsCount points are passed; (returns the kMaxPointsCount-th point) * - the length of passed parts of segment exceeds kMinDistMeters; (returns the next point after the event) * \param segment is a ingoing or outgoing feature segment. * \param ft is a ingoing or outgoing feature. * \param junctionPoint is a junction point. * \param maxPointsCount returned poit could't be more than maxPointsCount poins away from junctionPoint * \param minDistMeters returned point should be minDistMeters away from junctionPoint if ft is long and consists of short segments * \param GetPointIndex is a function for getting points by index. * It defines a direction of following along a feature. So it differs for ingoing and outgoing cases. * It has following parameters: * - start is an index of the start point of a feature segment. For example, FtSeg::m_pointStart. * - end is an index of the end point of a feature segment. For example, FtSeg::m_pointEnd. * - shift is a number of points which shall be added to end or start index. After that * the sum reflects an index of a feature segment point which will be used for a turn calculation. * The sum shall belongs to a range [min(start, end), max(start, end)]. * shift belongs to a range [0, abs(end - start)]. * \return an ingoing or outgoing point for a turn calculation. */ m2::PointD GetPointForTurn(OsrmMappingTypes::FtSeg const & segment, FeatureType const & ft, m2::PointD const & junctionPoint, size_t const maxPointsCount, double const minDistMeters, size_t (*GetPointIndex)(const size_t start, const size_t end, const size_t shift)) { double curDistanceMeters = 0.; m2::PointD point = junctionPoint; m2::PointD nextPoint; size_t const numSegPoints = abs(segment.m_pointEnd - segment.m_pointStart); ASSERT_GREATER(numSegPoints, 0, ()); ASSERT_LESS(numSegPoints, ft.GetPointsCount(), ()); size_t const usedFtPntNum = min(maxPointsCount, numSegPoints); for (size_t i = 1; i <= usedFtPntNum; ++i) { nextPoint = ft.GetPoint(GetPointIndex(segment.m_pointStart, segment.m_pointEnd, i)); curDistanceMeters += MercatorBounds::DistanceOnEarth(point, nextPoint); if (curDistanceMeters > minDistMeters) return nextPoint; point = nextPoint; } return nextPoint; }
/*! * \brief GetPointForTurn returns ingoingPoint or outgoingPoint for turns. * These points belongs to the route but they often are not neighbor of junctionPoint. * To calculate the resulting point the function implements the following steps: * - going from junctionPoint along feature ft according to the direction which is set in GetPointIndex(). * - until one of following conditions is fulfilled: * - the end of ft is reached; (returns the last feature point) * - more than kMaxPointsCount points are passed; (returns the kMaxPointsCount-th point) * - the length of passed parts of segment exceeds kMinDistMeters; (returns the next point after the event) * \param segment is a ingoing or outgoing feature segment. * \param ft is a ingoing or outgoing feature. * \param junctionPoint is a junction point. * \param GetPointIndex is a function for getting points by index. * It defines a direction of following along a feature. So it differs for ingoing and outgoing cases. * It has following parameters: * - start is an index of the start point of a feature segment. For example, FtSeg::m_pointStart. * - end is an index of the end point of a feature segment. For example, FtSeg::m_pointEnd. * - shift is a number of points which shall be added to end or start index. After that * the sum reflects an index of a point of a feature segment which will be used for turn calculation. * The sum shall belongs to a range [min(start, end), max(start, end)]. * shift belongs to a range [0, abs(end - start)]. * \return an ingoing or outgoing point for turn calculation. */ m2::PointD GetPointForTurn(OsrmMappingTypes::FtSeg const & segment, FeatureType const & ft, m2::PointD const & junctionPoint, size_t (*GetPointIndex)(const size_t start, const size_t end, const size_t shift)) { // An ingoing and outgoing point could be farther then kMaxPointsCount points from the junctionPoint size_t const kMaxPointsCount = 7; // If ft feature is long enough and consist of short segments // the point for turn generation is taken as the next point the route after kMinDistMeters. double const kMinDistMeters = 300.; double curDistanceMeters = 0.; m2::PointD point = junctionPoint; m2::PointD nextPoint; size_t const numSegPoints = abs(segment.m_pointEnd - segment.m_pointStart); ASSERT_GREATER(numSegPoints, 0, ()); ASSERT_LESS(numSegPoints, ft.GetPointsCount(), ()); size_t const usedFtPntNum = min(kMaxPointsCount, numSegPoints); for (size_t i = 1; i <= usedFtPntNum; ++i) { nextPoint = ft.GetPoint(GetPointIndex(segment.m_pointStart, segment.m_pointEnd, i)); curDistanceMeters += MercatorBounds::DistanceOnEarth(point, nextPoint); if (curDistanceMeters > kMinDistMeters) return nextPoint; point = nextPoint; } return nextPoint; }
void Point2PhantomNode::CalculateWeight(OsrmMappingTypes::FtSeg const & seg, m2::PointD const & segPt, NodeID const & nodeId, bool calcFromRight, int & weight, int & offset) const { // nodeId can be INVALID_NODE_ID when reverse node is absent. This node has no weight. if (nodeId == INVALID_NODE_ID) { offset = 0; weight = 0; return; } Index::FeaturesLoaderGuard loader(m_index, m_routingMapping.GetMwmId()); // Offset is measured in milliseconds. We don't know about speed restrictions on the road. // So we find it by a whole edge weight. // Distance from the node border to the projection point is in meters. double distanceM = 0.; // Whole node distance in meters. double fullDistanceM = 0.; // Minimal OSRM edge weight in milliseconds. EdgeWeight minWeight = 0; auto const range = m_routingMapping.m_segMapping.GetSegmentsRange(nodeId); OsrmMappingTypes::FtSeg segment; size_t const startIndex = calcFromRight ? range.second - 1 : range.first; size_t const endIndex = calcFromRight ? range.first - 1 : range.second; int const indexIncrement = calcFromRight ? -1 : 1; bool foundSeg = false; m2::PointD lastPoint; for (size_t segmentIndex = startIndex; segmentIndex != endIndex; segmentIndex += indexIncrement) { m_routingMapping.m_segMapping.GetSegmentByIndex(segmentIndex, segment); if (!segment.IsValid()) continue; FeatureType ft; loader.GetFeatureByIndex(segment.m_fid, ft); ft.ParseGeometry(FeatureType::BEST_GEOMETRY); // Find whole edge weight by node outgoing point. if (segmentIndex == range.second - 1) minWeight = GetMinNodeWeight(nodeId, ft.GetPoint(segment.m_pointEnd)); // Calculate distances. double distance = CalculateDistance(ft, segment.m_pointStart, segment.m_pointEnd); fullDistanceM += distance; if (foundSeg) continue; if (segment.m_fid == seg.m_fid && OsrmMappingTypes::IsInside(segment, seg)) { auto const splittedSegment = OsrmMappingTypes::SplitSegment(segment, seg, !calcFromRight); distanceM += CalculateDistance(ft, splittedSegment.m_pointStart, splittedSegment.m_pointEnd); // node.m_seg always forward ordered (m_pointStart < m_pointEnd) distanceM -= MercatorBounds::DistanceOnEarth( ft.GetPoint(calcFromRight ? seg.m_pointStart : seg.m_pointEnd), segPt); foundSeg = true; } else { distanceM += distance; } } ASSERT_GREATER(fullDistanceM, 0, ("No valid segments on the edge.")); double const ratio = (fullDistanceM == 0) ? 0 : distanceM / fullDistanceM; ASSERT_LESS_OR_EQUAL(ratio, 1., ()); // OSRM calculates edge weight form start to user point how offset + weight. // But it doesn't place info about start and end edge result weight into result structure. // So we store whole edge weight into offset and calculates this weights at a postprocessing step. offset = minWeight; weight = max(static_cast<int>(minWeight * ratio), 0) - minWeight; }
void Point2PhantomNode::MakeResult(vector<FeatureGraphNode> & res, size_t maxCount) { vector<OsrmMappingTypes::FtSeg> segments; sort(m_candidates.begin(), m_candidates.end(), [](Candidate const & r1, Candidate const & r2) { return (r1.m_dist < r2.m_dist); }); size_t const n = min(m_candidates.size(), maxCount); segments.resize(n); for (size_t j = 0; j < n; ++j) { OsrmMappingTypes::FtSeg & seg = segments[j]; Candidate const & c = m_candidates[j]; seg.m_fid = c.m_fid; seg.m_pointStart = c.m_segIdx; seg.m_pointEnd = c.m_segIdx + 1; } OsrmFtSegMapping::OsrmNodesT nodes; m_routingMapping.m_segMapping.GetOsrmNodes(segments, nodes); res.clear(); res.resize(maxCount); for (size_t j = 0; j < maxCount; ++j) { if (!segments[j].IsValid()) continue; auto it = nodes.find(segments[j].Store()); if (it == nodes.cend()) continue; FeatureGraphNode & node = res[j]; if (!m_direction.IsAlmostZero()) { // Filter income nodes by direction mode OsrmMappingTypes::FtSeg const & node_seg = segments[j]; FeatureType feature; Index::FeaturesLoaderGuard loader(m_index, m_routingMapping.GetMwmId()); loader.GetFeatureByIndex(node_seg.m_fid, feature); feature.ParseGeometry(FeatureType::BEST_GEOMETRY); m2::PointD const featureDirection = feature.GetPoint(node_seg.m_pointEnd) - feature.GetPoint(node_seg.m_pointStart); bool const sameDirection = (m2::DotProduct(featureDirection, m_direction) > 0); if (sameDirection) { node.node.forward_node_id = it->second.first; node.node.reverse_node_id = INVALID_NODE_ID; } else { node.node.forward_node_id = INVALID_NODE_ID; node.node.reverse_node_id = it->second.second; } } else { node.node.forward_node_id = it->second.first; node.node.reverse_node_id = it->second.second; } node.segment = segments[j]; node.segmentPoint = m_candidates[j].m_point; node.mwmId = m_routingMapping.GetMwmId(); CalculateWeights(node); } res.erase(remove_if(res.begin(), res.end(), [](FeatureGraphNode const & f) { return !f.mwmId.IsAlive(); }), res.end()); }
int main(int argc, char * argv[]) { google::SetUsageMessage("SRTM coverage checker."); google::ParseCommandLineFlags(&argc, &argv, true); Platform & platform = GetPlatform(); if (!FLAGS_mwm_path.empty()) platform.SetWritableDirForTests(FLAGS_mwm_path); if (FLAGS_srtm_path.empty()) { LOG(LERROR, ("SRTM files directory is not specified.")); return -1; } LOG(LINFO, ("writable dir =", platform.WritableDir())); LOG(LINFO, ("srtm dir =", FLAGS_srtm_path)); vector<platform::LocalCountryFile> localFiles; platform::FindAllLocalMapsAndCleanup(numeric_limits<int64_t>::max() /* latestVersion */, localFiles); auto fetcher = integration::CreateFeaturesFetcher(localFiles); generator::SrtmTileManager manager(FLAGS_srtm_path); for (auto & file : localFiles) { file.SyncWithDisk(); if (file.GetFiles() != MapOptions::MapWithCarRouting) { LOG(LINFO, ("Warning! Routing file not found for:", file.GetCountryName())); continue; } FilesMappingContainer container(file.GetPath(MapOptions::CarRouting)); if (!container.IsExist(ROUTING_FTSEG_FILE_TAG)) { LOG(LINFO, ("Warning! Mwm file has not routing ftseg section:", file.GetCountryName())); continue; } routing::TDataFacade dataFacade; dataFacade.Load(container); OsrmFtSegMapping segMapping; segMapping.Load(container, file); segMapping.Map(container); size_t all = 0; size_t good = 0; for (size_t i = 0; i < dataFacade.GetNumberOfNodes(); ++i) { buffer_vector<OsrmMappingTypes::FtSeg, 8> buffer; segMapping.ForEachFtSeg(i, MakeBackInsertFunctor(buffer)); vector<m2::PointD> path; for (size_t k = 0; k < buffer.size(); ++k) { auto const & segment = buffer[k]; if (!segment.IsValid()) continue; // Load data from drive. FeatureType ft; Index::FeaturesLoaderGuard loader( fetcher->GetIndex(), fetcher->GetIndex().GetMwmIdByCountryFile(file.GetCountryFile())); loader.GetFeatureByIndex(segment.m_fid, ft); ft.ParseGeometry(FeatureType::BEST_GEOMETRY); // Get points in proper direction. auto const startIdx = segment.m_pointStart; auto const endIdx = segment.m_pointEnd; for (auto idx = min(startIdx, endIdx); idx <= max(startIdx, endIdx); ++idx) path.push_back(ft.GetPoint(idx)); all += path.size(); for (auto const & point : path) { auto const height = manager.GetHeight(MercatorBounds::ToLatLon(point)); if (height != generator::SrtmTile::kInvalidHeight) good++; } } } auto const bad = all - good; auto const percent = all == 0 ? 0.0 : bad * 100.0 / all; if (percent > 10.0) { LOG(LINFO, ("Huge error rate in:", file.GetCountryName(), "good:", good, "bad:", bad, "all:", all, "%:", percent)); } } return 0; }