202Frustum QGeoCameraTilesPrivate::createFrustum(
double viewExpansion)
const
204 double apertureSize = 1.0;
205 if (m_camera.fieldOfView() != 90.0)
206 apertureSize = tan(QLocationUtils::radians(m_camera.fieldOfView()) * 0.5);
207 QDoubleVector3D center = m_sideLength * QWebMercator::coordToMercator(m_camera.center());
208#ifdef QT_LOCATION_DEBUG
209 m_createFrustum_center = center;
213 double f = m_screenSize.height();
215 double z = std::pow(2.0, m_camera.zoomLevel() - m_intZoomLevel) * m_tileSize;
217 double altitude = (f / (2.0 * z)) / apertureSize;
218 QDoubleVector3D eye = center;
221 QDoubleVector3D view = eye - center;
222 QDoubleVector3D side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
223 QDoubleVector3D up = QDoubleVector3D::normal(side, view);
228 mBearing.rotate(1.0 * m_camera.bearing(), toVector3D(view));
229 up = toDoubleVector3D(mBearing.map(toVector3D(up)));
232 QDoubleVector3D side2 = QDoubleVector3D::normal(up, view);
234 mTilt.rotate(-1.0 * m_camera.tilt(), toVector3D(side2));
235 eye = toDoubleVector3D((mTilt.map(toVector3D(view))) + toVector3D(center));
238 side = QDoubleVector3D::normal(view, QDoubleVector3D(0.0, 1.0, 0.0));
239 up = QDoubleVector3D::normal(view, side2);
241 double nearPlane = 1.0 / 32.0;
245 double farPlane = altitude + 8.0;
247 double aspectRatio = 1.0 * m_screenSize.width() / m_screenSize.height();
250 double hhn,hwn,hhf,hwf = 0.0;
254 viewExpansion *= apertureSize;
256 hhn = viewExpansion * nearPlane;
257 hwn = hhn * aspectRatio;
259 hhf = viewExpansion * farPlane;
260 hwf = hhf * aspectRatio;
262 QDoubleVector3D d = center - eye;
265 QDoubleVector3D right = QDoubleVector3D::normal(d, up);
267 QDoubleVector3D cf = eye + d * farPlane;
268 QDoubleVector3D cn = eye + d * nearPlane;
273#ifdef QT_LOCATION_DEBUG
274 m_createFrustum_eye = eye;
277 QRectF va = m_visibleArea;
279 va = QRectF(0, 0, m_screenSize.width(), m_screenSize.height());
280 QRectF screen = QRectF(QPointF(0,0),m_screenSize);
281 QPointF vaCenter = va.center();
282 QPointF screenCenter = screen.center();
283 QPointF diff = screenCenter - vaCenter;
284 double xdiffpct = diff.x() / m_screenSize.width();
285 double ydiffpct = -(diff.y() / m_screenSize.height());
287 double wn = (2 * hwn) * xdiffpct;
288 double hn = (2 * hhn) * ydiffpct;
289 double wf = (2 * hwf) * xdiffpct;
290 double hf = (2 * hhf) * ydiffpct;
294 frustum.topLeftFar = cf - (up * (hhf + hf)) - (right * (hwf + wf));
295 frustum.topRightFar = cf - (up * (hhf + hf)) + (right * (hwf + wf));
296 frustum.bottomLeftFar = cf + (up * (hhf + hf)) - (right * (hwf + wf));
297 frustum.bottomRightFar = cf + (up * (hhf + hf)) + (right * (hwf + wf));
299 frustum.topLeftNear = cn - (up * (hhn + hn)) - (right * (hwn + wn));
300 frustum.topRightNear = cn - (up * (hhn + hn)) + (right * (hwn + wn));
301 frustum.bottomLeftNear = cn + (up * (hhn + hn)) - (right * (hwn + wn));
302 frustum.bottomRightNear = cn + (up * (hhn + hn)) + (right * (hwn + wn));
348QPair<PolygonVector, PolygonVector> QGeoCameraTilesPrivate::splitPolygonAtAxisValue(
const PolygonVector &polygon,
int axis,
double value)
const
350 PolygonVector polygonBelow;
351 PolygonVector polygonAbove;
353 const qsizetype size = polygon.size();
356 return QPair<PolygonVector, PolygonVector>(polygonBelow, polygonAbove);
358 QList<
int> comparisons(polygon.size());
360 for (qsizetype i = 0; i < size; ++i) {
361 const double v = polygon.at(i).get(axis);
362 if (qFuzzyCompare(v - value + 1.0, 1.0)) {
367 }
else if (value < v) {
373 for (qsizetype index = 0; index < size; ++index) {
374 qsizetype prevIndex = index - 1;
377 const qsizetype nextIndex = (index + 1) % size;
379 int prevComp = comparisons[prevIndex];
380 int comp = comparisons[index];
381 int nextComp = comparisons[nextIndex];
384 if (prevComp == -1) {
385 polygonBelow.append(polygon.at(index));
387 polygonAbove.append(polygon.at(index));
389 }
else if (prevComp == 1) {
390 polygonAbove.append(polygon.at(index));
391 if (nextComp == -1) {
392 polygonBelow.append(polygon.at(index));
394 }
else if (prevComp == 0) {
395 if (nextComp == -1) {
396 polygonBelow.append(polygon.at(index));
397 }
else if (nextComp == 1) {
398 polygonAbove.append(polygon.at(index));
399 }
else if (nextComp == 0) {
405 polygonBelow.append(polygon.at(index));
406 }
else if (comp == 1) {
407 polygonAbove.append(polygon.at(index));
414 if ((nextComp != 0) && (nextComp != comp)) {
415 QDoubleVector3D p1 = polygon.at(index);
416 QDoubleVector3D p2 = polygon.at(nextIndex);
418 double p1v = p1.get(axis);
419 double p2v = p2.get(axis);
421 double f = (p1v - value) / (p1v - p2v);
423 if (((0 <= f) && (f <= 1.0))
424 || qFuzzyCompare(f + 1.0, 1.0)
425 || qFuzzyCompare(f + 1.0, 2.0) ) {
426 QDoubleVector3D midPoint = (1.0 - f) * p1 + f * p2;
427 polygonBelow.append(midPoint);
428 polygonAbove.append(midPoint);
434 return QPair<PolygonVector, PolygonVector>(polygonBelow, polygonAbove);
443QGeoCameraTilesPrivate::ClippedFootprint QGeoCameraTilesPrivate::clipFootprintToMap(
const PolygonVector &footprint)
const
450 double side = 1.0 * m_sideLength;
451 double minX = std::numeric_limits<
double>::max();
452 double maxX = std::numeric_limits<
double>::lowest();
454 for (
const QDoubleVector3D &p: footprint) {
461 PolygonVector results = footprint;
464 results = splitPolygonAtAxisValue(results, 1, 0.0).second;
467 results = splitPolygonAtAxisValue(results, 1, side).first;
469 for (
const QDoubleVector3D &p : std::as_const(results)) {
470 if ((p.x() < 0.0) || (qFuzzyIsNull(p.x())))
472 if ((p.x() > side) || (qFuzzyCompare(side, p.x())))
476 for (
const QDoubleVector3D &v : std::as_const(results)) {
477 minX = qMin(v.x(), minX);
478 maxX = qMax(v.x(), maxX);
481 double footprintWidth = maxX - minX;
485 if (footprintWidth > side) {
486 PolygonVector rightPart = splitPolygonAtAxisValue(results, 0, side).second;
487 addXOffset(rightPart, -side);
488 rightPart = splitPolygonAtAxisValue(rightPart, 0, side).first;
490 PolygonVector leftPart = splitPolygonAtAxisValue(results, 0, 0).first;
491 addXOffset(leftPart, side);
492 leftPart = splitPolygonAtAxisValue(leftPart, 0, 0).second;
494 results = splitPolygonAtAxisValue(results, 0, 0.0).second;
495 results = splitPolygonAtAxisValue(results, 0, side).first;
496 return ClippedFootprint(leftPart, results, rightPart);
498 results = splitPolygonAtAxisValue(results, 0, 0.0).second;
499 results = splitPolygonAtAxisValue(results, 0, side).first;
500 return ClippedFootprint(PolygonVector(), results, PolygonVector());
503 QPair<PolygonVector, PolygonVector> pair = splitPolygonAtAxisValue(results, 0, 0.0);
504 if (pair.first.isEmpty()) {
506 for (
const auto &v : std::as_const(pair.second)) {
507 if (qFuzzyIsNull(v.x()))
508 pair.first.append(v);
510 if (pair.first.size() == 2) {
511 double y0 = pair.first[0].y();
512 double y1 = pair.first[1].y();
514 pair.first.append(QDoubleVector3D(side, y0, 0.0));
515 pair.first.append(QDoubleVector3D(side - 0.001, y0, 0.0));
516 pair.first.append(QDoubleVector3D(side - 0.001, y1, 0.0));
517 pair.first.append(QDoubleVector3D(side, y1, 0.0));
518 }
else if (pair.first.size() == 1) {
524 double y = pair.first.at(0).y();
526 pair.first.append(QDoubleVector3D(side - 0.001, y, 0.0));
527 pair.first.append(QDoubleVector3D(side, y + 0.001, 0.0));
528 pair.first.append(QDoubleVector3D(side, y - 0.001, 0.0));
531 addXOffset(pair.first, side);
532 if (footprintWidth > side)
533 pair.first = splitPolygonAtAxisValue(pair.first, 0, 0).second;
535 return ClippedFootprint(pair.first, pair.second, PolygonVector());
539 QPair<PolygonVector, PolygonVector> pair = splitPolygonAtAxisValue(results, 0, side);
540 if (pair.second.isEmpty()) {
542 for (
const auto &v : std::as_const(pair.first)) {
543 if (qFuzzyCompare(side, v.x()))
544 pair.second.append(v);
546 if (pair.second.size() == 2) {
547 double y0 = pair.second[0].y();
548 double y1 = pair.second[1].y();
550 pair.second.append(QDoubleVector3D(0, y0, 0.0));
551 pair.second.append(QDoubleVector3D(0.001, y0, 0.0));
552 pair.second.append(QDoubleVector3D(0.001, y1, 0.0));
553 pair.second.append(QDoubleVector3D(0, y1, 0.0));
554 }
else if (pair.second.size() == 1) {
560 double y = pair.second.at(0).y();
562 pair.second.append(QDoubleVector3D(0.001, y, 0.0));
563 pair.second.append(QDoubleVector3D(0.0, y - 0.001, 0.0));
564 pair.second.append(QDoubleVector3D(0.0, y + 0.001, 0.0));
567 addXOffset(pair.second, -side);
568 if (footprintWidth > side)
569 pair.second = splitPolygonAtAxisValue(pair.second, 0, side).first;
571 return ClippedFootprint(PolygonVector(), pair.first, pair.second);
573 return ClippedFootprint(PolygonVector(), results, PolygonVector());
610QSet<QGeoTileSpec> QGeoCameraTilesPrivate::tilesFromPolygon(
const PolygonVector &polygon)
const
612 const qsizetype numPoints = polygon.size();
615 return QSet<QGeoTileSpec>();
617 QList<
int> tilesX(polygon.size());
618 QList<
int> tilesY(polygon.size());
621 for (qsizetype i = 0; i < numPoints; ++i) {
623 const QDoubleVector2D p = polygon.at(i).toVector2D();
628 if (qFuzzyCompare(p.x(), m_sideLength * 1.0))
629 x = m_sideLength - 1;
631 x =
static_cast<
int>(p.x()) % m_sideLength;
632 if (!QtPrivate::fuzzyCompare(p.x(), 1.0 * x) && qFuzzyCompare(p.x(), 1.0 * (x + 1)))
636 if (qFuzzyCompare(p.y(), m_sideLength * 1.0))
637 y = m_sideLength - 1;
639 y =
static_cast<
int>(p.y()) % m_sideLength;
640 if (!QtPrivate::fuzzyCompare(p.y(), 1.0 * y) && qFuzzyCompare(p.y(), 1.0 * (y + 1)))
648 QGeoCameraTilesPrivate::TileMap map;
651 for (qsizetype i1 = 0; i1 < numPoints; ++i1) {
652 const qsizetype i2 = (i1 + 1) % numPoints;
654 const double x1 = polygon.at(i1).get(0);
655 const double x2 = polygon.at(i2).get(0);
657 const bool xFixed = QtPrivate::fuzzyCompare(x1, x2);
658 const bool xIntegral = qFuzzyIsNull(x1) || qFuzzyCompare(x1, std::round(x1));
660 QList<QPair<
double,
int> > xIntersects
661 = tileIntersections(x1,
666 const double y1 = polygon.at(i1).get(1);
667 const double y2 = polygon.at(i2).get(1);
669 const bool yFixed = QtPrivate::fuzzyCompare(y1, y2);
670 const bool yIntegral = qFuzzyIsNull(y1) || qFuzzyCompare(y1, std::round(y1));
672 QList<QPair<
double,
int> > yIntersects
673 = tileIntersections(y1,
678 int x = xIntersects.takeFirst().second;
679 int y = yIntersects.takeFirst().second;
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
711 if (xFixed && xIntegral) {
713 xOther = qMax(0, x - 1);
717 if (yFixed && yIntegral) {
719 yOther = qMax(0, y - 1);
727 map.add(xOther, yOther);
737 const qsizetype iPrev = (i1 + numPoints - 1) % numPoints;
738 const double xPrevious = polygon.at(iPrev).get(0);
739 const double yPrevious = polygon.at(iPrev).get(1);
740 const bool xPreviousFixed = QtPrivate::fuzzyCompare(xPrevious, x1);
741 if (xIntegral && xPreviousFixed && yIntegral && yFixed) {
742 if ((x2 > x1) && (yPrevious > y1)) {
743 if ((x - 1) > 0 && (y - 1) > 0)
744 map.add(x - 1, y - 1);
745 }
else if ((x2 < x1) && (yPrevious < y1)) {
754 while (!xIntersects.isEmpty() && !yIntersects.isEmpty()) {
755 const QPair<
double,
int> nextX = xIntersects.first();
756 const QPair<
double,
int> nextY = yIntersects.first();
757 if (nextX.first < nextY.first) {
760 xIntersects.removeFirst();
762 }
else if (nextX.first > nextY.first) {
765 yIntersects.removeFirst();
768 map.add(x, nextY.second);
769 map.add(nextX.second, y);
773 xIntersects.removeFirst();
774 yIntersects.removeFirst();
778 while (!xIntersects.isEmpty()) {
779 x = xIntersects.takeFirst().second;
781 if (yIntegral && yFixed)
786 while (!yIntersects.isEmpty()) {
787 y = yIntersects.takeFirst().second;
789 if (xIntegral && xFixed)
794 QSet<QGeoTileSpec> results;
796 const int z = m_intZoomLevel;
797 for (
auto i = map.data.constBegin(); i != map.data.constEnd(); ++i) {
800 int maxX = i->second;
801 for (
int x = minX; x <= maxX; ++x)
802 results.insert(QGeoTileSpec(m_pluginString, m_mapType.mapId(), z, x, y, m_mapVersion));