diff options
-rw-r--r-- | src/location/maps/qgeocameratiles.cpp | 178 | ||||
-rw-r--r-- | tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp | 24 |
2 files changed, 54 insertions, 148 deletions
diff --git a/src/location/maps/qgeocameratiles.cpp b/src/location/maps/qgeocameratiles.cpp index 27044ee0..75d4512e 100644 --- a/src/location/maps/qgeocameratiles.cpp +++ b/src/location/maps/qgeocameratiles.cpp @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE struct Frustum { + QDoubleVector3D apex; QDoubleVector3D topLeftNear; QDoubleVector3D topLeftFar; QDoubleVector3D topRightNear; @@ -103,16 +104,6 @@ public: Frustum createFrustum(double viewExpansion) const; - class LengthSorter - { - public: - QDoubleVector3D base; - bool operator()(const QDoubleVector3D &lhs, const QDoubleVector3D &rhs) - { - return (lhs - base).lengthSquared() < (rhs - base).lengthSquared(); - } - }; - struct ClippedFootprint { ClippedFootprint(const PolygonVector &left_, const PolygonVector &mid_, const PolygonVector &right_) @@ -123,7 +114,6 @@ public: PolygonVector right; }; - void appendZIntersects(const QDoubleVector3D &start, const QDoubleVector3D &end, double z, QVector<QDoubleVector3D> &results) const; PolygonVector frustumFootprint(const Frustum &frustum) const; QPair<PolygonVector, PolygonVector> splitPolygonAtAxisValue(const PolygonVector &polygon, int axis, double value) const; @@ -373,168 +363,60 @@ Frustum QGeoCameraTilesPrivate::createFrustum(double viewExpansion) const Frustum frustum; - frustum.topLeftFar = cf + (up * hhf) - (right * hwf); - frustum.topRightFar = cf + (up * hhf) + (right * hwf); - frustum.bottomLeftFar = cf - (up * hhf) - (right * hwf); - frustum.bottomRightFar = cf - (up * hhf) + (right * hwf); + frustum.apex = eye; + + frustum.topLeftFar = cf - (up * hhf) - (right * hwf); + frustum.topRightFar = cf - (up * hhf) + (right * hwf); + frustum.bottomLeftFar = cf + (up * hhf) - (right * hwf); + frustum.bottomRightFar = cf + (up * hhf) + (right * hwf); - frustum.topLeftNear = cn + (up * hhn) - (right * hwn); - frustum.topRightNear = cn + (up * hhn) + (right * hwn); - frustum.bottomLeftNear = cn - (up * hhn) - (right * hwn); - frustum.bottomRightNear = cn - (up * hhn) + (right * hwn); + frustum.topLeftNear = cn - (up * hhn) - (right * hwn); + frustum.topRightNear = cn - (up * hhn) + (right * hwn); + frustum.bottomLeftNear = cn + (up * hhn) - (right * hwn); + frustum.bottomRightNear = cn + (up * hhn) + (right * hwn); return frustum; } -void QGeoCameraTilesPrivate::appendZIntersects(const QDoubleVector3D &start, +static bool appendZIntersects(const QDoubleVector3D &start, const QDoubleVector3D &end, double z, - QVector<QDoubleVector3D> &results) const + QVector<QDoubleVector3D> &results) { if (start.z() == end.z()) { - if (start.z() == z) { - results.append(start); - results.append(end); - } + return false; } else { double f = (start.z() - z) / (start.z() - end.z()); - if ((0 <= f) && (f <= 1.0)) { + if ((f >= 0) && (f <= 1.0)) { results.append((1 - f) * start + f * end); + return true; } } + return false; } -/***************************************************/ -/* Local copy of qSort & qSortHelper to suppress deprecation warnings - * following the deprecation of QtAlgorithms. The comparison has subtle - * differences which eluded detection so far. We just reuse old qSort for now. - **/ - -template <typename RandomAccessIterator, typename LessThan> -inline void localqSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan) -{ - if (start != end) - localqSortHelper(start, end, *start, lessThan); -} - -template <typename RandomAccessIterator, typename T, typename LessThan> -void localqSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan) -{ -top: - int span = int(end - start); - if (span < 2) - return; - - --end; - RandomAccessIterator low = start, high = end - 1; - RandomAccessIterator pivot = start + span / 2; - - if (lessThan(*end, *start)) - qSwap(*end, *start); - if (span == 2) - return; - - if (lessThan(*pivot, *start)) - qSwap(*pivot, *start); - if (lessThan(*end, *pivot)) - qSwap(*end, *pivot); - if (span == 3) - return; - - qSwap(*pivot, *end); - - while (low < high) { - while (low < high && lessThan(*low, *end)) - ++low; - - while (high > low && lessThan(*end, *high)) - --high; - - if (low < high) { - qSwap(*low, *high); - ++low; - --high; - } else { - break; - } - } - - if (lessThan(*low, *end)) - ++low; - - qSwap(*end, *low); - localqSortHelper(start, low, t, lessThan); - - start = low + 1; - ++end; - goto top; -} -/***************************************************/ - - // Returns the intersection of the plane of the map and the camera frustum as a right handed polygon PolygonVector QGeoCameraTilesPrivate::frustumFootprint(const Frustum &frustum) const { PolygonVector points; - points.reserve(24); + points.reserve(4); - appendZIntersects(frustum.topLeftNear, frustum.topLeftFar, 0.0, points); - appendZIntersects(frustum.topRightNear, frustum.topRightFar, 0.0, points); - appendZIntersects(frustum.bottomLeftNear, frustum.bottomLeftFar, 0.0, points); - appendZIntersects(frustum.bottomRightNear, frustum.bottomRightFar, 0.0, points); + // The camera is always upright. Tilting angle never reach 90degrees. + // Meaning: bottom frustum edges always intersect the map plane, top ones may not. - appendZIntersects(frustum.topLeftNear, frustum.bottomLeftNear, 0.0, points); - appendZIntersects(frustum.bottomLeftNear, frustum.bottomRightNear, 0.0, points); - appendZIntersects(frustum.bottomRightNear, frustum.topRightNear, 0.0, points); - appendZIntersects(frustum.topRightNear, frustum.topLeftNear, 0.0, points); + // Top Right + if (!appendZIntersects(frustum.apex, frustum.topRightFar, 0.0, points)) + appendZIntersects(frustum.topRightFar, frustum.bottomRightFar, 0.0, points); - appendZIntersects(frustum.topLeftFar, frustum.bottomLeftFar, 0.0, points); - appendZIntersects(frustum.bottomLeftFar, frustum.bottomRightFar, 0.0, points); - appendZIntersects(frustum.bottomRightFar, frustum.topRightFar, 0.0, points); - appendZIntersects(frustum.topRightFar, frustum.topLeftFar, 0.0, points); + // Bottom Right + appendZIntersects(frustum.apex, frustum.bottomRightFar, 0.0, points); - if (points.isEmpty()) - return points; + // Bottom Left + appendZIntersects(frustum.apex, frustum.bottomLeftFar, 0.0, points); - // sort points into a right handed polygon - - LengthSorter sorter; - - // - initial sort to remove duplicates - sorter.base = points.first(); - localqSort(points.begin(), points.end(), sorter); - //std::sort(points.begin(), points.end(), sorter); - for (int i = points.size() - 1; i > 0; --i) { - if (points.at(i) == points.at(i - 1)) - points.remove(i); - } - - // - proper sort - // - start with the first point, put it in the sorted part of the list - // - add the nearest unsorted point to the last sorted point to the end - // of the sorted points - PolygonVector::iterator i; - for (i = points.begin(); i != points.end(); ++i) { - sorter.base = *i; - if (i + 1 != points.end()) - std::sort(i + 1, points.end(), sorter) ; - } - - // - determine if what we have is right handed - int size = points.size(); - if (size >= 3) { - QDoubleVector3D normal = QDoubleVector3D::normal(points.at(1) - points.at(0), - points.at(2) - points.at(1)); - // - if not, reverse the list - if (normal.z() < 0.0) { - int halfSize = size / 2; - for (int i = 0; i < halfSize; ++i) { - QDoubleVector3D spare = points.at(i); - points[i] = points[size - 1 - i]; - points[size - 1 - i] = spare; - } - } - } + // Top Left + if (!appendZIntersects(frustum.apex, frustum.topLeftFar, 0.0, points)) + appendZIntersects(frustum.topLeftFar, frustum.bottomLeftFar, 0.0, points); return points; } diff --git a/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp b/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp index 33ebda67..1ac0abfa 100644 --- a/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp +++ b/tests/auto/qgeocameratiles/tst_qgeocameratiles.cpp @@ -69,6 +69,7 @@ private slots: void tilesMapType(); void tilesPositions(); void tilesPositions_data(); + void test_tilted_frustum(); }; void tst_QGeoCameraTiles::row(const PositionTestInfo &pti, int xOffset, int yOffset, int tileX, int tileY, int tileW, int tileH) @@ -116,6 +117,29 @@ void tst_QGeoCameraTiles::test_group(const PositionTestInfo &pti, QList<int> &xV } } +void tst_QGeoCameraTiles::test_tilted_frustum() +{ + // ctFull : Full map in the view, all 16 zl2 tiles visible. Using this as control. + QGeoCameraData cameraFull; + cameraFull.setZoomLevel(2); + cameraFull.setCenter(QGeoCoordinate(0,0)); + QGeoCameraTiles ctFull; + ctFull.setTileSize(64); + ctFull.setCameraData(cameraFull); + ctFull.setScreenSize(QSize(256, 256)); + + QGeoCameraData camera; + camera.setZoomLevel(2.322); + camera.setTilt(30); + camera.setCenter(QWebMercator::mercatorToCoord(QDoubleVector2D(0.75, 0.5))); + QGeoCameraTiles ct; + ct.setTileSize(64); + ct.setScreenSize(QSize(320, 180)); + ct.setCameraData(camera); + + QCOMPARE(ct.createTiles(), ctFull.createTiles()); +} + void tst_QGeoCameraTiles::tilesPlugin() { QGeoCameraData camera; |