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 GeoDataCoordinates( lon, lat );
118 }
119
120}
121
122qreal RouteSegment::distanceTo( const GeoDataCoordinates &point, GeoDataCoordinates &closest, GeoDataCoordinates &interpolated ) const
123{
124 Q_ASSERT( !m_path.isEmpty() );
125
126 if ( m_path.size() == 1 ) {
127 closest = m_path.first();
128 return EARTH_RADIUS * m_path.first().sphericalDistanceTo(point);
129 }
130
131 qreal minDistance = -1.0;
132 int minIndex = 0;
133 for ( int i=1; i<m_path.size(); ++i ) {
134 qreal const distance = distancePointToLine( point, m_path[i-1], m_path[i] );
135 if ( minDistance < 0.0 || distance < minDistance ) {
136 minDistance = distance;
137 minIndex = i;
138 }
139 }
140
141 closest = m_path[minIndex];
142 if ( minIndex == 0 ) {
143 interpolated = closest;
144 } else {
145 interpolated = projected( point, m_path[minIndex-1], m_path[minIndex] );
146 }
147
148 return minDistance;
149}
150
151qreal RouteSegment::minimalDistanceTo( const GeoDataCoordinates &point ) const
152{
153 if ( bounds().contains( point) ) {
154 return 0.0;
155 }
156
157 qreal north(0.0), east(0.0), south(0.0), west(0.0);
158 bounds().boundaries( north, south, east, west );
159 GeoDataCoordinates const northWest( west, north );
160 GeoDataCoordinates const northEast( east, north );
161 GeoDataCoordinates const southhWest( west, south );
162 GeoDataCoordinates const southEast( east, south );
163
164 qreal distNorth = distancePointToLine( point, northWest, northEast );
165 qreal distEast = distancePointToLine( point, northEast, southEast );
166 qreal distSouth = distancePointToLine( point, southhWest, southEast );
167 qreal distWest = distancePointToLine( point, northWest, southhWest );
168 return qMin( qMin( distNorth, distEast ), qMin( distWest, distSouth ) );
169}
170
171qreal RouteSegment::projectedDirection(const GeoDataCoordinates &point) const
172{
173 if (m_path.size() < 2){
174 return 0;
175 }
176
177 qreal minDistance = -1.0;
178 int minIndex = 0;
179 for ( int i=1; i<m_path.size(); ++i ) {
180 qreal const distance = distancePointToLine( point, m_path[i-1], m_path[i] );
181 if ( minDistance < 0.0 || distance < minDistance ) {
182 minDistance = distance;
183 minIndex = i;
184 }
185 }
186
187 if ( minIndex == 0 ) {
188 return m_path[0].bearing( m_path[1], GeoDataCoordinates::Degree, GeoDataCoordinates::FinalBearing );
189 } else {
190 return m_path[minIndex-1].bearing( m_path[minIndex], GeoDataCoordinates::Degree, GeoDataCoordinates::FinalBearing );
191 }
192}
193
194bool RouteSegment::operator ==(const RouteSegment &other) const
195{
196 return m_valid == other.m_valid &&
197 m_distance == other.m_distance &&
198 m_maneuver == other.m_maneuver &&
199 m_travelTime == other.m_travelTime &&
200 m_bounds == other.m_bounds &&
201 m_nextRouteSegment == other.m_nextRouteSegment;
202}
203
204bool RouteSegment::operator !=(const RouteSegment &other) const
205{
206 return !(other == *this);
207}
208
209}
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 Fri Jun 21 2024 12:00:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.