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
61 QT_BEGIN_NAMESPACE
62
computeBBox(const QList<QGeoCoordinate> & m_path,QVector<double> & m_deltaXs,double & m_minX,double & m_maxX,double & m_minLati,double & m_maxLati,QGeoRectangle & m_bbox)63 inline 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(0).latitude();
82 int minId = 0;
83 int maxId = 0;
84 m_deltaXs.resize(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-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(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(minId).longitude()),
116 QGeoCoordinate(m_minLati, m_path.at(maxId).longitude()));
117 }
118
updateBBox(const QList<QGeoCoordinate> & m_path,QVector<double> & m_deltaXs,double & m_minX,double & m_maxX,double & m_minLati,double & m_maxLati,QGeoRectangle & m_bbox)119 inline 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(1);
137 m_deltaXs[0] = m_minX = m_maxX = 0.0;
138 m_minLati = m_maxLati = m_path.at(0).latitude();
139 m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()),
140 QGeoCoordinate(m_minLati, m_path.at(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(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(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(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
180 class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivate : public QGeoShapePrivate
181 {
182 public:
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
227 class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivateEager : public QGeoPathPrivate
228 {
229 public:
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=
255 class Q_POSITIONING_PRIVATE_EXPORT QGeoPathEager : public QGeoPath
256 {
257 Q_GADGET
258 public:
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
267 QT_END_NAMESPACE
268
269 #endif // QGEOPATH_P_H
270