| 226 | {} |
| 227 | |
| 228 | bool DecodeSegment(LinearSegment const & segment, DecodedPath & path, v2::Stats & stat) |
| 229 | { |
| 230 | double constexpr kPathLengthTolerance = 0.30; |
| 231 | uint32_t constexpr kMaxJunctionCandidates = 10; |
| 232 | uint32_t constexpr kMaxProjectionCandidates = 5; |
| 233 | |
| 234 | m_graph.ResetFakes(); |
| 235 | |
| 236 | path.m_segmentId.Set(segment.m_segmentId); |
| 237 | |
| 238 | auto const & points = segment.GetLRPs(); |
| 239 | CHECK_GREATER(points.size(), 1, ("A segment cannot consist of less than two points")); |
| 240 | vector<vector<Graph::EdgeVector>> lineCandidates; |
| 241 | lineCandidates.reserve(points.size()); |
| 242 | LOG(LDEBUG, ("Decoding segment:", segment.m_segmentId, "with", points.size(), "points")); |
| 243 | |
| 244 | CandidatePointsGetter pointsGetter(kMaxJunctionCandidates, kMaxProjectionCandidates, m_dataSource, m_graph); |
| 245 | CandidatePathsGetter pathsGetter(pointsGetter, m_graph, m_infoGetter, stat); |
| 246 | |
| 247 | if (!pathsGetter.GetLineCandidatesForPoints(points, lineCandidates)) |
| 248 | return false; |
| 249 | |
| 250 | vector<Graph::EdgeVector> resultPath; |
| 251 | PathsConnector connector(kPathLengthTolerance, m_graph, m_infoGetter, stat); |
| 252 | if (!connector.ConnectCandidates(points, lineCandidates, resultPath)) |
| 253 | return false; |
| 254 | |
| 255 | Graph::EdgeVector route; |
| 256 | for (auto const & part : resultPath) |
| 257 | route.insert(end(route), begin(part), end(part)); |
| 258 | |
| 259 | double requiredRouteDistanceM = 0.0; |
| 260 | // Sum app all distances between points. Last point's m_distanceToNextPoint |
| 261 | // should be equal to zero, but let's skip it just in case. |
| 262 | CHECK(!points.empty(), ()); |
| 263 | for (auto it = begin(points); it != prev(end(points)); ++it) |
| 264 | requiredRouteDistanceM += it->m_distanceToNextPoint; |
| 265 | |
| 266 | double actualRouteDistanceM = 0.0; |
| 267 | for (auto const & e : route) |
| 268 | actualRouteDistanceM += EdgeLength(e); |
| 269 | |
| 270 | auto const scale = actualRouteDistanceM / requiredRouteDistanceM; |
| 271 | LOG(LDEBUG, ("actualRouteDistance:", actualRouteDistanceM, "requiredRouteDistance:", requiredRouteDistanceM, |
| 272 | "scale:", scale)); |
| 273 | |
| 274 | auto const positiveOffsetM = segment.m_locationReference.m_positiveOffsetMeters * scale; |
| 275 | auto const negativeOffsetM = segment.m_locationReference.m_negativeOffsetMeters * scale; |
| 276 | |
| 277 | if (positiveOffsetM + negativeOffsetM >= requiredRouteDistanceM) |
| 278 | { |
| 279 | ++stat.m_wrongOffsets; |
| 280 | LOG(LINFO, ("Wrong offsets for segment:", segment.m_segmentId)); |
| 281 | return false; |
| 282 | } |
| 283 | |
| 284 | ExpandFakes(m_dataSource, m_graph, route); |
| 285 | ASSERT(none_of(begin(route), end(route), mem_fn(&Graph::Edge::IsFake)), (segment.m_segmentId)); |
no test coverage detected