1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtPositioning module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QGEOPATH_P_H
41#define QGEOPATH_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtPositioning/private/qpositioningglobal_p.h>
55#include "qgeoshape_p.h"
56#include "qgeocoordinate.h"
57#include "qlocationutils_p.h"
58#include <QtPositioning/qgeopath.h>
59#include <QtCore/QVector>
60
61QT_BEGIN_NAMESPACE
62
63inline static void computeBBox( const QList<QGeoCoordinate> &m_path,
64 QVector<double> &m_deltaXs,
65 double &m_minX,
66 double &m_maxX,
67 double &m_minLati,
68 double &m_maxLati,
69 QGeoRectangle &m_bbox)
70{
71 if (m_path.isEmpty()) {
72 m_deltaXs.clear();
73 m_minX = qInf();
74 m_maxX = -qInf();
75 m_minLati = qInf();
76 m_maxLati = -qInf();
77 m_bbox = QGeoRectangle();
78 return;
79 }
80
81 m_minLati = m_maxLati = m_path.at(i: 0).latitude();
82 int minId = 0;
83 int maxId = 0;
84 m_deltaXs.resize(asize: m_path.size());
85 m_deltaXs[0] = m_minX = m_maxX = 0.0;
86
87 for (int i = 1; i < m_path.size(); i++) {
88 const QGeoCoordinate &geoFrom = m_path.at(i: i-1);
89 const QGeoCoordinate &geoTo = m_path.at(i);
90 double longiFrom = geoFrom.longitude();
91 double longiTo = geoTo.longitude();
92 double deltaLongi = longiTo - longiFrom;
93 if (qAbs(t: deltaLongi) > 180.0) {
94 if (longiTo > 0.0)
95 longiTo -= 360.0;
96 else
97 longiTo += 360.0;
98 deltaLongi = longiTo - longiFrom;
99 }
100 m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi;
101 if (m_deltaXs[i] < m_minX) {
102 m_minX = m_deltaXs[i];
103 minId = i;
104 }
105 if (m_deltaXs[i] > m_maxX) {
106 m_maxX = m_deltaXs[i];
107 maxId = i;
108 }
109 if (geoTo.latitude() > m_maxLati)
110 m_maxLati = geoTo.latitude();
111 if (geoTo.latitude() < m_minLati)
112 m_minLati = geoTo.latitude();
113 }
114
115 m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(i: minId).longitude()),
116 QGeoCoordinate(m_minLati, m_path.at(i: maxId).longitude()));
117}
118
119inline static void updateBBox( const QList<QGeoCoordinate> &m_path,
120 QVector<double> &m_deltaXs,
121 double &m_minX,
122 double &m_maxX,
123 double &m_minLati,
124 double &m_maxLati,
125 QGeoRectangle &m_bbox)
126{
127 if (m_path.isEmpty()) {
128 m_deltaXs.clear();
129 m_minX = qInf();
130 m_maxX = -qInf();
131 m_minLati = qInf();
132 m_maxLati = -qInf();
133 m_bbox = QGeoRectangle();
134 return;
135 } else if (m_path.size() == 1) { // was 0 now is 1
136 m_deltaXs.resize(asize: 1);
137 m_deltaXs[0] = m_minX = m_maxX = 0.0;
138 m_minLati = m_maxLati = m_path.at(i: 0).latitude();
139 m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(i: 0).longitude()),
140 QGeoCoordinate(m_minLati, m_path.at(i: 0).longitude()));
141 return;
142 } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen
143 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); // something went wrong
144 return;
145 }
146
147 const QGeoCoordinate &geoFrom = m_path.at(i: m_path.size()-2);
148 const QGeoCoordinate &geoTo = m_path.last();
149 double longiFrom = geoFrom.longitude();
150 double longiTo = geoTo.longitude();
151 double deltaLongi = longiTo - longiFrom;
152 if (qAbs(t: deltaLongi) > 180.0) {
153 if (longiTo > 0.0)
154 longiTo -= 360.0;
155 else
156 longiTo += 360.0;
157 deltaLongi = longiTo - longiFrom;
158 }
159
160 m_deltaXs.push_back(t: m_deltaXs.last() + deltaLongi);
161 double currentMinLongi = m_bbox.topLeft().longitude();
162 double currentMaxLongi = m_bbox.bottomRight().longitude();
163 if (m_deltaXs.last() < m_minX) {
164 m_minX = m_deltaXs.last();
165 currentMinLongi = geoTo.longitude();
166 }
167 if (m_deltaXs.last() > m_maxX) {
168 m_maxX = m_deltaXs.last();
169 currentMaxLongi = geoTo.longitude();
170 }
171 if (geoTo.latitude() > m_maxLati)
172 m_maxLati = geoTo.latitude();
173 if (geoTo.latitude() < m_minLati)
174 m_minLati = geoTo.latitude();
175 m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi),
176 QGeoCoordinate(m_minLati, currentMaxLongi));
177}
178
179// Lazy by default. Eager, within the module, used only in MapItems/MapObjectsQSG
180class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivate : public QGeoShapePrivate
181{
182public:
183 QGeoPathPrivate();
184 QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width = 0.0);
185 ~QGeoPathPrivate();
186
187// QGeoShape API
188 virtual QGeoShapePrivate *clone() const override;
189 virtual bool isValid() const override;
190 virtual bool isEmpty() const override;
191 virtual QGeoCoordinate center() const override;
192 virtual bool operator==(const QGeoShapePrivate &other) const override;
193 virtual bool contains(const QGeoCoordinate &coordinate) const override;
194 virtual QGeoRectangle boundingGeoRectangle() const override;
195
196 virtual void extendShape(const QGeoCoordinate &coordinate) override;
197
198// QGeoPathPrivate API
199 virtual const QList<QGeoCoordinate> &path() const;
200 virtual bool lineContains(const QGeoCoordinate &coordinate) const;
201 virtual qreal width() const;
202 virtual double length(int indexFrom, int indexTo) const;
203 virtual int size() const;
204 virtual QGeoCoordinate coordinateAt(int index) const;
205 virtual bool containsCoordinate(const QGeoCoordinate &coordinate) const;
206
207 virtual void setWidth(const qreal &width);
208 virtual void translate(double degreesLatitude, double degreesLongitude);
209 virtual void setPath(const QList<QGeoCoordinate> &path);
210 virtual void clearPath();
211 virtual void addCoordinate(const QGeoCoordinate &coordinate);
212 virtual void insertCoordinate(int index, const QGeoCoordinate &coordinate);
213 virtual void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
214 virtual void removeCoordinate(const QGeoCoordinate &coordinate);
215 virtual void removeCoordinate(int index);
216 virtual void computeBoundingBox();
217 virtual void markDirty();
218
219// data members
220 QList<QGeoCoordinate> m_path;
221 qreal m_width = 0;
222 QGeoRectangle m_bbox; // cached
223 double m_leftBoundWrapped; // cached
224 bool m_bboxDirty = false;
225};
226
227class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivateEager : public QGeoPathPrivate
228{
229public:
230 QGeoPathPrivateEager();
231 QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width = 0.0);
232 ~QGeoPathPrivateEager();
233
234// QGeoShapePrivate API
235 virtual QGeoShapePrivate *clone() const override;
236 virtual void translate(double degreesLatitude, double degreesLongitude) override;
237
238// QGeoShapePrivate API
239 virtual void markDirty() override;
240 virtual void addCoordinate(const QGeoCoordinate &coordinate) override;
241 virtual void computeBoundingBox() override;
242
243// *Eager API
244 void updateBoundingBox();
245
246// data members
247 QVector<double> m_deltaXs; // longitude deltas from m_path[0]
248 double m_minX = 0; // minimum value inside deltaXs
249 double m_maxX = 0; // maximum value inside deltaXs
250 double m_minLati = 0; // minimum latitude. paths do not wrap around through the poles
251 double m_maxLati = 0; // minimum latitude. paths do not wrap around through the poles
252};
253
254// This is a mean of creating a QGeoPathPrivateEager and injecting it into QGeoPaths via operator=
255class Q_POSITIONING_PRIVATE_EXPORT QGeoPathEager : public QGeoPath
256{
257 Q_GADGET
258public:
259
260 QGeoPathEager();
261 QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width = 0.0);
262 QGeoPathEager(const QGeoPath &other);
263 QGeoPathEager(const QGeoShape &other);
264 ~QGeoPathEager();
265};
266
267QT_END_NAMESPACE
268
269#endif // QGEOPATH_P_H
270

source code of qtlocation/src/positioning/qgeopath_p.h