36 const double s10_x = p1_x - p0_x;
37 const double s10_y = p1_y - p0_y;
38 const double s32_x = p3_x - p2_x;
39 const double s32_y = p3_y - p2_y;
41 const double denom = s10_x * s32_y - s32_x * s10_y;
44 const bool denomPositive = denom > 0;
46 const double s02_x = p0_x - p2_x;
47 const double s02_y = p0_y - p2_y;
48 const double s_numer = s10_x * s02_y - s10_y * s02_x;
49 if ((s_numer < 0.0) == denomPositive)
52 const double t_numer = s32_x * s02_y - s32_y * s02_x;
53 if ((t_numer < 0.0) == denomPositive)
56 if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
59 *i_t = t_numer / denom;
60 *i_x = p0_x + (*i_t * s10_x);
61 *i_y = p0_y + (*i_t * s10_y);
73 const QList<QDoubleVector2D> &l,
74 const QList<QDoubleVector2D> &poly)
76 QList<QList<QDoubleVector2D> > res;
77 if (poly.size() < 2 || l.size() < 2)
81 std::vector<std::array<
double, 4> > edges;
82 for (qsizetype i = 1; i < poly.size(); i++)
83 edges.push_back({ { poly.at(i-1).x(), poly.at(i-1).y(), poly.at(i).x(), poly.at(i).y() } });
84 edges.push_back({ { poly.at(poly.size()-1).x(), poly.at(poly.size()-1).y(), poly.at(0).x(), poly.at(0).y() } });
87 QList<QDoubleVector2D> subLine;
88 std::array<
double, 4> intersections = { { 0.0, 0.0, 0.0, 0.0 } };
90 for (qsizetype i = 0; i < l.size() - 1; ++i) {
96 const int firstContained = QClipperUtils::pointInPolygon(l.at(i), poly);
97 const int secondContained = QClipperUtils::pointInPolygon(l.at(i+1), poly);
99 if (firstContained && secondContained) {
101 subLine.push_back(l.at(i));
102 subLine.push_back(l.at(i+1));
106 for (
unsigned int j = 0; j < edges.size(); ++j) {
107 const bool intersects = get_line_intersection(l.at(i).x(),
119 if (previousT >= 0.0) {
121 intersections[2] = intersections[0];
122 intersections[3] = intersections[1];
123 intersections[0] = i_x;
124 intersections[1] = i_y;
126 intersections[2] = i_x;
127 intersections[3] = i_y;
133 intersections[0] = i_x;
134 intersections[1] = i_y;
142 if (!firstContained && !secondContained) {
144 }
else if (firstContained && secondContained) {
148 res.push_back(subLine);
152 if (firstContained <= 0 && secondContained > 0) {
154 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
155 subLine.push_back(l.at(i+1));
156 }
else if (firstContained > 0 && secondContained <= 0) {
158 subLine.push_back(l.at(i));
159 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
160 res.push_back(subLine);
164 res.push_back(subLine);
170 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
171 subLine.push_back(QDoubleVector2D(intersections[2], intersections[3]));
172 res.push_back(subLine);
178 res.push_back(subLine);
301 const QList<QDoubleVector2D> &basePath)
307 const QGeoProjectionWebMercator &p =
static_cast<
const QGeoProjectionWebMercator&>(map.geoProjection());
308 srcPath_ = QPainterPath();
309 srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(0, 0));
313 QVarLengthArray<QList<QDoubleVector2D>, 3> wrappedPaths;
314 wrappedPaths << QList<QDoubleVector2D>({basePath[0]});
315 wrappedPaths.last().reserve(basePath.size());
316 for (
int i = 1; i < basePath.size(); i++) {
317 if (basePath[i].x() > wrappedPaths.last().last().x() + 0.5)
318 wrappedPaths.last() << basePath[i] - QDoubleVector2D(1.0, 0.0);
319 else if (basePath[i].x() < wrappedPaths.last().last().x() - 0.5)
320 wrappedPaths.last() << basePath[i] + QDoubleVector2D(1.0, 0.0);
322 wrappedPaths.last() << basePath[i];
328 const QRectF cameraRect = QDeclarativeGeoMapItemUtils::boundingRectangleFromList(p.visibleGeometry());
330 for (
const auto &path : wrappedPaths)
331 itemRect |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path).adjusted(-1e-6, -1e-6, 2e-6, 2e-6);
332 for (
double xoffset : {-1.0, 1.0}) {
333 if (!cameraRect.intersects(itemRect.translated(QPointF(xoffset,0))))
335 wrappedPaths.append(QList<QDoubleVector2D>());
336 QList<QDoubleVector2D> &wP = wrappedPaths.last();
337 wP.reserve(wrappedPaths.first().size());
338 for (
const QDoubleVector2D &coord : wrappedPaths.first())
339 wP.append(coord + QDoubleVector2D(xoffset, 0.0));
341 if (wrappedPaths.isEmpty())
345 QList<QList<QDoubleVector2D>> clippedPaths;
346 const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometryExpanded();
347 for (
const auto &path : wrappedPaths) {
348 if (visibleRegion.size()) {
349 clippedPaths << clipLine(path, visibleRegion);
352 clippedPaths.append(path);
355 if (clippedPaths.isEmpty())
359 for (
const auto &path: clippedPaths)
360 bb |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path);
363 srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(bb.left(), bb.top()));
364 QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(p.geoToWrappedMapProjection(srcOrigin_));
365 for (
const auto &path: clippedPaths) {
366 QDoubleVector2D lastAddedPoint;
367 for (qsizetype i = 0; i < path.size(); ++i) {
368 QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i));
369 point = point - origin;
371 if (qMax(point.x(), point.y()) > maxCoord_)
372 maxCoord_ = qMax(point.x(), point.y());
375 srcPath_.moveTo(point.toPointF());
376 lastAddedPoint = point;
378 if ((point - lastAddedPoint).manhattanLength() > 3 ||
379 i == path.size() - 1) {
380 srcPath_.lineTo(point.toPointF());
381 lastAddedPoint = point;
387 sourceBounds_ = srcPath_.boundingRect();
398QDeclarativePolylineMapItemPrivateCPU::QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly)
399 : QDeclarativePolylineMapItemPrivate(poly)
401 m_shape =
new QQuickShape(&m_poly);
402 m_shape->setObjectName(
"_qt_map_item_shape");
404 m_shape->setContainsMode(QQuickShape::FillContains);
406 m_shapePath =
new QQuickShapePath(m_shape);
407 m_painterPath =
new QDeclarativeGeoMapPainterPath(m_shapePath);
409 auto pathElements = m_shapePath->pathElements();
410 pathElements.append(&pathElements, m_painterPath);
412 auto shapePaths = m_shape->data();
413 shapePaths.append(&shapePaths, m_shapePath);
421void QDeclarativePolylineMapItemPrivateCPU::regenerateCache()
423 if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
425 const QGeoProjectionWebMercator &p =
static_cast<
const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
426 m_geopathProjected.clear();
427 if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe) {
428 const QList<QGeoCoordinate> realPath = QDeclarativeGeoMapItemUtils::greaterCirclePath(m_poly.m_geopath.path());
429 m_geopathProjected.reserve(realPath.size());
430 for (
const QGeoCoordinate &c : realPath)
431 m_geopathProjected << p.geoToMapProjection(c);
433 m_geopathProjected.reserve(m_poly.m_geopath.path().size());
434 const QList<QGeoCoordinate> path = m_poly.m_geopath.path();
435 for (
const QGeoCoordinate &c : path)
436 m_geopathProjected << p.geoToMapProjection(c);
448void QDeclarativePolylineMapItemPrivateCPU::updatePolish()
450 if (m_poly.m_geopath.path().length() < 2) {
454 m_shape->setVisible(
false);
457 QScopedValueRollback<
bool> rollback(m_poly.m_updatingGeometry);
458 m_poly.m_updatingGeometry =
true;
460 const QGeoMap *map = m_poly.map();
461 const qreal borderWidth = m_poly.m_line.width();
463 m_geometry.updateSourcePoints(*map, m_geopathProjected);
465 const QRectF bb = m_geometry.sourceBoundingBox();
466 m_poly.setSize(bb.size() + QSizeF(borderWidth, borderWidth));
468 m_poly.setPositionOnMap(m_geometry.origin(), -1 * bb.topLeft() + QPointF(borderWidth, borderWidth) * 0.5);
471 m_poly.setShapeTriangulationScale(m_shape, m_geometry.maxCoord_);
473 m_shapePath->setStrokeColor(m_poly.m_line.color());
474 m_shapePath->setStrokeWidth(borderWidth);
475 m_shapePath->setFillColor(Qt::transparent);
477 QPainterPath path = m_geometry.srcPath();
478 path.translate(-bb.left() + borderWidth * 0.5, -bb.top() + borderWidth * 0.5);
479 m_painterPath->setPath(path);
481 m_shape->setSize(m_poly.size());
482 m_shape->setOpacity(m_poly.zoomLevelOpacity());
483 m_shape->setVisible(
true);
497bool QDeclarativePolylineMapItemPrivateCPU::contains(
const QPointF &point)
const
503 const QPainterPath &path = m_shapePath->path();
504 const double &lineWidth = m_poly.m_line.width();
505 const QPointF p = m_poly.mapToItem(m_shape, point);
507 for (
int i = 1; i < path.elementCount(); i++) {
508 if (path.elementAt(i).type == QPainterPath::MoveToElement)
510 const double dsqr = QDeclarativeGeoMapItemUtils::distanceSqrPointLine(p.x(), p.y(),
511 path.elementAt(i - 1).x, path.elementAt(i - 1).y,
512 path.elementAt(i).x, path.elementAt(i).y);
513 if (dsqr < 0.25 * lineWidth * lineWidth)
523QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
524 : QDeclarativeGeoMapItemBase(parent), m_line(
this),
525 m_d(
new QDeclarativePolylineMapItemPrivateCPU(*
this))
527 m_itemType = QGeoMap::MapPolyline;
528 m_geopath = QGeoPathEager();
529 setFlag(ItemHasContents,
true);
530 QObject::connect(&m_line, &QDeclarativeMapLineProperties::colorChanged,
531 this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
532 QObject::connect(&m_line, &QDeclarativeMapLineProperties::widthChanged,
533 this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
534 QObject::connect(
this, &QDeclarativePolylineMapItem::referenceSurfaceChanged,
535 this, [
this]() { m_d->onGeoGeometryChanged(); });
722void QDeclarativePolylineMapItem::removeCoordinate(
const QGeoCoordinate &coordinate)
724 int length = m_geopath.path().length();
725 m_geopath.removeCoordinate(coordinate);
726 if (m_geopath.path().length() == length)
729 m_d->onGeoGeometryChanged();
777void QDeclarativePolylineMapItem::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
779 if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopath.isValid() || m_updatingGeometry) {
780 QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry);
784 QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()),
false);
785 QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()),
false);
786 if (!newCenter.isValid() || !oldCenter.isValid())
788 double offsetLongi = newCenter.longitude() - oldCenter.longitude();
789 double offsetLati = newCenter.latitude() - oldCenter.latitude();
790 if (offsetLati == 0.0 && offsetLongi == 0.0)
793 m_geopath.translate(offsetLati, offsetLongi);
794 m_d->onGeoGeometryChanged();
static QT_BEGIN_NAMESPACE bool get_line_intersection(const double p0_x, const double p0_y, const double p1_x, const double p1_y, const double p2_x, const double p2_y, const double p3_x, const double p3_y, double *i_x, double *i_y, double *i_t)