1/****************************************************************************
2**
3** Copyright (C) 2020 Paolo Angelelli <paolo.angelelli@gmail.com>
4** Copyright (C) 2020 The Qt Company Ltd.
5** Contact: http://www.qt.io/licensing/
6**
7** This file is part of the QtLocation module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL3$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see http://www.qt.io/terms-conditions. For further
16** information use the contact form at http://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPLv3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or later as published by the Free
29** Software Foundation and appearing in the file LICENSE.GPL included in
30** the packaging of this file. Please review the following information to
31** ensure the GNU General Public License version 2.0 requirements will be
32** met: http://www.gnu.org/licenses/gpl-2.0.html.
33**
34** $QT_END_LICENSE$
35**
36****************************************************************************/
37
38#include "qdeclarativegeomapitemutils_p.h"
39#include <QtPositioning/private/qdoublevector3d_p.h>
40#include <QtPositioning/private/qdoublematrix4x4_p.h>
41#include <QtPositioning/QGeoCoordinate>
42#include <QPointF>
43#include <QMatrix4x4>
44#include <QPainterPath>
45#include <QPainterPathStroker>
46#include <QtGui/private/qvectorpath_p.h>
47#include <QtGui/private/qtriangulatingstroker_p.h>
48#include <QtGui/private/qtriangulator_p.h>
49#include <QtPositioning/private/qclipperutils_p.h>
50
51QT_BEGIN_NAMESPACE
52
53void QDeclarativeGeoMapItemUtils::wrapPath(const QList<QGeoCoordinate> &perimeter,
54 const QGeoCoordinate &geoLeftBound,
55 const QGeoProjectionWebMercator &p,
56 QList<QDoubleVector2D> &wrappedPath,
57 QList<QDoubleVector2D> &wrappedPathMinus1,
58 QList<QDoubleVector2D> &wrappedPathPlus1,
59 QDoubleVector2D *leftBoundWrapped)
60{
61 QList<QDoubleVector2D> path;
62 for (const QGeoCoordinate &c : perimeter)
63 path << p.geoToMapProjection(coordinate: c);
64 const QDoubleVector2D leftBound = p.geoToMapProjection(coordinate: geoLeftBound);
65 wrappedPath.clear();
66 wrappedPathPlus1.clear();
67 wrappedPathMinus1.clear();
68 // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0
69 for (int i = 0; i < path.size(); ++i) {
70 QDoubleVector2D coord = path.at(i);
71
72 // We can get NaN if the map isn't set up correctly, or the projection
73 // is faulty -- probably best thing to do is abort
74 if (!qIsFinite(d: coord.x()) || !qIsFinite(d: coord.y()))
75 return;
76
77 const bool isPointLessThanUnwrapBelowX = (coord.x() < leftBound.x());
78 // unwrap x to preserve geometry if moved to border of map
79 if (isPointLessThanUnwrapBelowX)
80 coord.setX(coord.x() + 1.0);
81
82 QDoubleVector2D coordP1(coord.x() + 1.0, coord.y());
83 QDoubleVector2D coordM1(coord.x() - 1.0, coord.y());
84
85 wrappedPath.append(t: coord);
86 wrappedPathPlus1.append(t: coordP1);
87 wrappedPathMinus1.append(t: coordM1);
88 }
89 if (leftBoundWrapped)
90 *leftBoundWrapped = leftBound;
91}
92
93void QDeclarativeGeoMapItemUtils::wrapPath(const QList<QGeoCoordinate> &perimeter,
94 const QGeoCoordinate &geoLeftBound,
95 const QGeoProjectionWebMercator &p,
96 QList<QDoubleVector2D> &wrappedPath,
97 QDoubleVector2D *leftBoundWrapped)
98{
99 QList<QDoubleVector2D> path;
100 for (const QGeoCoordinate &c : perimeter)
101 path << p.geoToMapProjection(coordinate: c);
102 const QDoubleVector2D leftBound = p.geoToMapProjection(coordinate: geoLeftBound);
103 wrapPath(path, geoLeftBound: leftBound,wrappedPath);
104 if (leftBoundWrapped)
105 *leftBoundWrapped = leftBound;
106}
107
108void QDeclarativeGeoMapItemUtils::wrapPath(const QList<QDoubleVector2D> &path,
109 const QDoubleVector2D &geoLeftBound,
110 QList<QDoubleVector2D> &wrappedPath)
111{
112 wrappedPath.clear();
113 // compute 3 sets of "wrapped" coordinates: one w regular mercator, one w regular mercator +- 1.0
114 for (int i = 0; i < path.size(); ++i) {
115 QDoubleVector2D coord = path.at(i);
116
117 // We can get NaN if the map isn't set up correctly, or the projection
118 // is faulty -- probably best thing to do is abort
119 if (!qIsFinite(d: coord.x()) || !qIsFinite(d: coord.y()))
120 return;
121
122 const bool isPointLessThanUnwrapBelowX = (coord.x() < geoLeftBound.x());
123 // unwrap x to preserve geometry if moved to border of map
124 if (isPointLessThanUnwrapBelowX)
125 coord.setX(coord.x() + 1.0);
126
127 wrappedPath.append(t: coord);
128 }
129}
130
131void QDeclarativeGeoMapItemUtils::clipPolygon(const QList<QDoubleVector2D> &wrappedPath, const QGeoProjectionWebMercator &p, QList<QList<QDoubleVector2D> > &clippedPaths, QDoubleVector2D *leftBoundWrapped, const bool closed)
132{
133 // 2) Clip bounding box
134 clippedPaths.clear();
135 const QList<QDoubleVector2D> &visibleRegion = p.projectableGeometry();
136 if (visibleRegion.size()) {
137 c2t::clip2tri clipper;
138 clipper.addSubjectPath(path: QClipperUtils::qListToPath(list: wrappedPath), closed);
139 clipper.addClipPolygon(path: QClipperUtils::qListToPath(list: visibleRegion));
140 Paths res = clipper.execute(op: c2t::clip2tri::Intersection, subjFillType: QtClipperLib::pftEvenOdd, clipFillType: QtClipperLib::pftEvenOdd);
141 clippedPaths = QClipperUtils::pathsToQList(paths: res);
142
143 if (leftBoundWrapped) {
144 // 2.1) update srcOrigin_ and leftBoundWrapped with the point with minimum X
145 QDoubleVector2D lb(qInf(), qInf());
146 for (const QList<QDoubleVector2D> &path: clippedPaths)
147 for (const QDoubleVector2D &p: path)
148 if (p.x() < lb.x() || (p.x() == lb.x() && p.y() < lb.y()))
149 // y-minimization needed to find the same point on polygon and border
150 lb = p;
151
152 if (qIsInf(d: lb.x())) // e.g., when the polygon is clipped entirely
153 return;
154
155 // 2.2) Prevent the conversion to and from clipper from introducing tiny negative offsets which,
156 // in turn will make the geometry wrap around.
157 lb.setX(qMax(a: leftBoundWrapped->x(), b: lb.x()));
158
159 *leftBoundWrapped = lb;
160 // srcOrigin_ = p.mapProjectionToGeo(p.unwrapMapProjection(lb));
161 }
162 } else {
163 clippedPaths.append(t: wrappedPath);
164 }
165}
166
167void QDeclarativeGeoMapItemUtils::projectBbox(const QList<QDoubleVector2D> &clippedBbox, const QGeoProjectionWebMercator &p, QPainterPath &projectedBbox)
168{
169 projectedBbox = QPainterPath(); // clear() is added in 5.13..
170 for (int i = 0; i < clippedBbox.size(); ++i) {
171 QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(wrappedProjection: clippedBbox.at(i));
172 if (i == 0)
173 projectedBbox.moveTo(p: point.toPointF());
174 else
175 projectedBbox.lineTo(p: point.toPointF());
176 }
177 projectedBbox.closeSubpath();
178}
179
180QT_END_NAMESPACE
181

source code of qtlocation/src/location/declarativemaps/qdeclarativegeomapitemutils.cpp