Marble

RouteSegment.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2011 Dennis Nienhüser <nienhueser@kde.org>
4//
5
6#include "RouteSegment.h"
7
8#include "GeoDataLatLonAltBox.h"
9
10namespace Marble
11{
12
13RouteSegment::RouteSegment()
14 : m_valid(false)
15 , m_distance(0.0)
16 , m_travelTime(0)
17 , m_nextRouteSegment(nullptr)
18{
19 // nothing to do
20}
21
22qreal RouteSegment::distance() const
23{
24 return m_distance;
25}
26
27const Maneuver &RouteSegment::maneuver() const
28{
29 return m_maneuver;
30}
31
32void RouteSegment::setManeuver(const Maneuver &maneuver)
33{
34 m_maneuver = maneuver;
35 m_valid = true;
36}
37
38const GeoDataLineString &RouteSegment::path() const
39{
40 return m_path;
41}
42
43void RouteSegment::setPath(const GeoDataLineString &path)
44{
45 m_path = path;
46 m_distance = m_path.length(EARTH_RADIUS);
47 m_bounds = m_path.latLonAltBox();
48 m_valid = true;
49}
50
51int RouteSegment::travelTime() const
52{
53 return m_travelTime;
54}
55
56void RouteSegment::setTravelTime(int seconds)
57{
58 m_travelTime = seconds;
59 m_valid = true;
60}
61
62GeoDataLatLonBox RouteSegment::bounds() const
63{
64 return m_bounds;
65}
66
67const RouteSegment &RouteSegment::nextRouteSegment() const
68{
69 if (m_nextRouteSegment) {
70 return *m_nextRouteSegment;
71 }
72
73 static RouteSegment invalid;
74 return invalid;
75}
76
77void RouteSegment::setNextRouteSegment(const RouteSegment *segment)
78{
79 m_nextRouteSegment = segment;
80 if (segment) {
81 m_valid = true;
82 }
83}
84
85bool RouteSegment::isValid() const
86{
87 return m_valid;
88}
89
90qreal RouteSegment::distancePointToLine(const GeoDataCoordinates &p, const GeoDataCoordinates &a, const GeoDataCoordinates &b)
91{
92 return EARTH_RADIUS * p.sphericalDistanceTo(projected(p, a, b));
93}
94
95GeoDataCoordinates RouteSegment::projected(const GeoDataCoordinates &p, const GeoDataCoordinates &a, const GeoDataCoordinates &b)
96{
97 qreal const y0 = p.latitude();
98 qreal const x0 = p.longitude();
99 qreal const y1 = a.latitude();
100 qreal const x1 = a.longitude();
101 qreal const y2 = b.latitude();
102 qreal const x2 = b.longitude();
103 qreal const y01 = x0 - x1;
104 qreal const x01 = y0 - y1;
105 qreal const y21 = x2 - x1;
106 qreal const x21 = y2 - y1;
107 qreal const len = x21 * x21 + y21 * y21;
108 qreal const t = (x01 * x21 + y01 * y21) / len;
109 if (t < 0.0) {
110 return a;
111 } else if (t > 1.0) {
112 return b;
113 } else {
114 // a + t (b - a);
115 qreal const lon = x1 + t * (x2 - x1);
116 qreal const lat = y1 + t * (y2 - y1);
117 return {lon, lat};
118 }
119}
120
121qreal RouteSegment::distanceTo(const GeoDataCoordinates &point, GeoDataCoordinates &closest, GeoDataCoordinates &interpolated) const
122{
123 Q_ASSERT(!m_path.isEmpty());
124
125 if (m_path.size() == 1) {
126 closest = m_path.first();
127 return EARTH_RADIUS * m_path.first().sphericalDistanceTo(point);
128 }
129
130 qreal minDistance = -1.0;
131 int minIndex = 0;
132 for (int i = 1; i < m_path.size(); ++i) {
133 qreal const distance = distancePointToLine(point, m_path[i - 1], m_path[i]);
134 if (minDistance < 0.0 || distance < minDistance) {
135 minDistance = distance;
136 minIndex = i;
137 }
138 }
139
140 closest = m_path[minIndex];
141 if (minIndex == 0) {
142 interpolated = closest;
143 } else {
144 interpolated = projected(point, m_path[minIndex - 1], m_path[minIndex]);
145 }
146
147 return minDistance;
148}
149
150qreal RouteSegment::minimalDistanceTo(const GeoDataCoordinates &point) const
151{
152 if (bounds().contains(point)) {
153 return 0.0;
154 }
155
156 qreal north(0.0), east(0.0), south(0.0), west(0.0);
157 bounds().boundaries(north, south, east, west);
158 GeoDataCoordinates const northWest(west, north);
159 GeoDataCoordinates const northEast(east, north);
160 GeoDataCoordinates const southhWest(west, south);
161 GeoDataCoordinates const southEast(east, south);
162
163 qreal distNorth = distancePointToLine(point, northWest, northEast);
164 qreal distEast = distancePointToLine(point, northEast, southEast);
165 qreal distSouth = distancePointToLine(point, southhWest, southEast);
166 qreal distWest = distancePointToLine(point, northWest, southhWest);
167 return qMin(qMin(distNorth, distEast), qMin(distWest, distSouth));
168}
169
170qreal RouteSegment::projectedDirection(const GeoDataCoordinates &point) const
171{
172 if (m_path.size() < 2) {
173 return 0;
174 }
175
176 qreal minDistance = -1.0;
177 int minIndex = 0;
178 for (int i = 1; i < m_path.size(); ++i) {
179 qreal const distance = distancePointToLine(point, m_path[i - 1], m_path[i]);
180 if (minDistance < 0.0 || distance < minDistance) {
181 minDistance = distance;
182 minIndex = i;
183 }
184 }
185
186 if (minIndex == 0) {
187 return m_path[0].bearing(m_path[1], GeoDataCoordinates::Degree, GeoDataCoordinates::FinalBearing);
188 } else {
189 return m_path[minIndex - 1].bearing(m_path[minIndex], GeoDataCoordinates::Degree, GeoDataCoordinates::FinalBearing);
190 }
191}
192
193bool RouteSegment::operator==(const RouteSegment &other) const
194{
195 return m_valid == other.m_valid && m_distance == other.m_distance && m_maneuver == other.m_maneuver && m_travelTime == other.m_travelTime
196 && m_bounds == other.m_bounds && m_nextRouteSegment == other.m_nextRouteSegment;
197}
198
199bool RouteSegment::operator!=(const RouteSegment &other) const
200{
201 return !(other == *this);
202}
203
204}
QString path(const QString &relativePath)
Binds a QML item to a specific geodetic location in screen coordinates.
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
qsizetype length() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:37:03 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.