37 const double s10_x = p1_x - p0_x;
38 const double s10_y = p1_y - p0_y;
39 const double s32_x = p3_x - p2_x;
40 const double s32_y = p3_y - p2_y;
42 const double denom = s10_x * s32_y - s32_x * s10_y;
45 const bool denomPositive = denom > 0;
47 const double s02_x = p0_x - p2_x;
48 const double s02_y = p0_y - p2_y;
49 const double s_numer = s10_x * s02_y - s10_y * s02_x;
50 if ((s_numer < 0.0) == denomPositive)
53 const double t_numer = s32_x * s02_y - s32_y * s02_x;
54 if ((t_numer < 0.0) == denomPositive)
57 if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
60 *i_t = t_numer / denom;
61 *i_x = p0_x + (*i_t * s10_x);
62 *i_y = p0_y + (*i_t * s10_y);
74 const QList<QDoubleVector2D> &l,
75 const QList<QDoubleVector2D> &poly)
77 QList<QList<QDoubleVector2D> > res;
78 if (poly.size() < 2 || l.size() < 2)
82 std::vector<std::array<
double, 4> > edges;
83 for (qsizetype i = 1; i < poly.size(); i++)
84 edges.push_back({ { poly.at(i-1).x(), poly.at(i-1).y(), poly.at(i).x(), poly.at(i).y() } });
85 edges.push_back({ { poly.at(poly.size()-1).x(), poly.at(poly.size()-1).y(), poly.at(0).x(), poly.at(0).y() } });
88 QList<QDoubleVector2D> subLine;
89 std::array<
double, 4> intersections = { { 0.0, 0.0, 0.0, 0.0 } };
91 for (qsizetype i = 0; i < l.size() - 1; ++i) {
97 const int firstContained = QClipperUtils::pointInPolygon(l.at(i), poly);
98 const int secondContained = QClipperUtils::pointInPolygon(l.at(i+1), poly);
100 if (firstContained && secondContained) {
102 subLine.push_back(l.at(i));
103 subLine.push_back(l.at(i+1));
107 for (
unsigned int j = 0; j < edges.size(); ++j) {
108 const bool intersects = get_line_intersection(l.at(i).x(),
120 if (previousT >= 0.0) {
122 intersections[2] = intersections[0];
123 intersections[3] = intersections[1];
124 intersections[0] = i_x;
125 intersections[1] = i_y;
127 intersections[2] = i_x;
128 intersections[3] = i_y;
134 intersections[0] = i_x;
135 intersections[1] = i_y;
143 if (!firstContained && !secondContained) {
145 }
else if (firstContained && secondContained) {
149 res.push_back(subLine);
153 if (firstContained <= 0 && secondContained > 0) {
155 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
156 subLine.push_back(l.at(i+1));
157 }
else if (firstContained > 0 && secondContained <= 0) {
159 subLine.push_back(l.at(i));
160 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
161 res.push_back(subLine);
165 res.push_back(subLine);
171 subLine.push_back(QDoubleVector2D(intersections[0], intersections[1]));
172 subLine.push_back(QDoubleVector2D(intersections[2], intersections[3]));
173 res.push_back(subLine);
179 res.push_back(subLine);
302 const QList<QDoubleVector2D> &basePath)
308 const QGeoProjectionWebMercator &p =
static_cast<
const QGeoProjectionWebMercator&>(map.geoProjection());
309 srcPath_ = QPainterPath();
310 srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(0, 0));
314 QVarLengthArray<QList<QDoubleVector2D>, 3> wrappedPaths;
315 wrappedPaths << QList<QDoubleVector2D>({basePath[0]});
316 wrappedPaths.last().reserve(basePath.size());
317 for (
int i = 1; i < basePath.size(); i++) {
318 if (basePath[i].x() > wrappedPaths.last().last().x() + 0.5)
319 wrappedPaths.last() << basePath[i] - QDoubleVector2D(1.0, 0.0);
320 else if (basePath[i].x() < wrappedPaths.last().last().x() - 0.5)
321 wrappedPaths.last() << basePath[i] + QDoubleVector2D(1.0, 0.0);
323 wrappedPaths.last() << basePath[i];
329 const QRectF cameraRect = QDeclarativeGeoMapItemUtils::boundingRectangleFromList(p.visibleGeometry());
331 for (
const auto &path : wrappedPaths)
332 itemRect |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path).adjusted(-1e-6, -1e-6, 2e-6, 2e-6);
333 for (
double xoffset : {-1.0, 1.0}) {
334 if (!cameraRect.intersects(itemRect.translated(QPointF(xoffset,0))))
336 wrappedPaths.append(QList<QDoubleVector2D>());
337 QList<QDoubleVector2D> &wP = wrappedPaths.last();
338 wP.reserve(wrappedPaths.first().size());
339 for (
const QDoubleVector2D &coord : wrappedPaths.first())
340 wP.append(coord + QDoubleVector2D(xoffset, 0.0));
342 if (wrappedPaths.isEmpty())
346 QList<QList<QDoubleVector2D>> clippedPaths;
347 const QList<QDoubleVector2D> &visibleRegion = p.visibleGeometryExpanded();
348 for (
const auto &path : wrappedPaths) {
349 if (visibleRegion.size()) {
350 clippedPaths << clipLine(path, visibleRegion);
353 clippedPaths.append(path);
356 if (clippedPaths.isEmpty())
360 for (
const auto &path: clippedPaths)
361 bb |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path);
364 srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(bb.left(), bb.top()));
365 QDoubleVector2D origin = p.wrappedMapProjectionToItemPosition(p.geoToWrappedMapProjection(srcOrigin_));
366 for (
const auto &path: clippedPaths) {
367 QDoubleVector2D lastAddedPoint;
368 for (qsizetype i = 0; i < path.size(); ++i) {
369 QDoubleVector2D point = p.wrappedMapProjectionToItemPosition(path.at(i));
370 point = point - origin;
372 if (qMax(point.x(), point.y()) > maxCoord_)
373 maxCoord_ = qMax(point.x(), point.y());
376 srcPath_.moveTo(point.toPointF());
377 lastAddedPoint = point;
379 if ((point - lastAddedPoint).manhattanLength() > 3 ||
380 i == path.size() - 1) {
381 srcPath_.lineTo(point.toPointF());
382 lastAddedPoint = point;
388 sourceBounds_ = srcPath_.boundingRect();
399QDeclarativePolylineMapItemPrivateCPU::QDeclarativePolylineMapItemPrivateCPU(QDeclarativePolylineMapItem &poly)
400 : QDeclarativePolylineMapItemPrivate(poly)
402 m_shape =
new QQuickShape(&m_poly);
403 m_shape->setObjectName(
"_qt_map_item_shape");
405 m_shape->setContainsMode(QQuickShape::FillContains);
407 m_shapePath =
new QQuickShapePath(m_shape);
408 m_painterPath =
new QDeclarativeGeoMapPainterPath(m_shapePath);
410 auto pathElements = m_shapePath->pathElements();
411 pathElements.append(&pathElements, m_painterPath);
413 auto shapePaths = m_shape->data();
414 shapePaths.append(&shapePaths, m_shapePath);
422void QDeclarativePolylineMapItemPrivateCPU::regenerateCache()
424 if (!m_poly.map() || m_poly.map()->geoProjection().projectionType() != QGeoProjection::ProjectionWebMercator)
426 const QGeoProjectionWebMercator &p =
static_cast<
const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
427 m_geopathProjected.clear();
428 if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe) {
429 const QList<QGeoCoordinate> realPath = QDeclarativeGeoMapItemUtils::greaterCirclePath(m_poly.m_geopath.path());
430 m_geopathProjected.reserve(realPath.size());
431 for (
const QGeoCoordinate &c : realPath)
432 m_geopathProjected << p.geoToMapProjection(c);
434 m_geopathProjected.reserve(m_poly.m_geopath.path().size());
435 const QList<QGeoCoordinate> path = m_poly.m_geopath.path();
436 for (
const QGeoCoordinate &c : path)
437 m_geopathProjected << p.geoToMapProjection(c);
449void QDeclarativePolylineMapItemPrivateCPU::updatePolish()
451 if (m_poly.m_geopath.path().length() < 2) {
455 m_shape->setVisible(
false);
458 QScopedValueRollback<
bool> rollback(m_poly.m_updatingGeometry);
459 m_poly.m_updatingGeometry =
true;
461 const QGeoMap *map = m_poly.map();
462 const qreal borderWidth = m_poly.m_line.width();
464 m_geometry.updateSourcePoints(*map, m_geopathProjected);
466 const QRectF bb = m_geometry.sourceBoundingBox();
467 m_poly.setSize(bb.size() + QSizeF(borderWidth, borderWidth));
469 m_poly.setPositionOnMap(m_geometry.origin(), -1 * bb.topLeft() + QPointF(borderWidth, borderWidth) * 0.5);
472 m_poly.setShapeTriangulationScale(m_shape, m_geometry.maxCoord_);
474 m_shapePath->setStrokeColor(m_poly.m_line.color());
475 m_shapePath->setStrokeWidth(borderWidth);
476 m_shapePath->setFillColor(Qt::transparent);
478 QPainterPath path = m_geometry.srcPath();
479 path.translate(-bb.left() + borderWidth * 0.5, -bb.top() + borderWidth * 0.5);
480 m_painterPath->setPath(path);
482 m_shape->setSize(m_poly.size());
483 m_shape->setOpacity(m_poly.zoomLevelOpacity());
484 m_shape->setVisible(
true);
498bool QDeclarativePolylineMapItemPrivateCPU::contains(
const QPointF &point)
const
504 const QPainterPath &path = m_shapePath->path();
505 const double &lineWidth = m_poly.m_line.width();
506 const QPointF p = m_poly.mapToItem(m_shape, point);
508 for (
int i = 1; i < path.elementCount(); i++) {
509 if (path.elementAt(i).type == QPainterPath::MoveToElement)
511 const double dsqr = QDeclarativeGeoMapItemUtils::distanceSqrPointLine(p.x(), p.y(),
512 path.elementAt(i - 1).x, path.elementAt(i - 1).y,
513 path.elementAt(i).x, path.elementAt(i).y);
514 if (dsqr < 0.25 * lineWidth * lineWidth)
524QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
525 : QDeclarativeGeoMapItemBase(parent), m_line(
this),
526 m_d(
new QDeclarativePolylineMapItemPrivateCPU(*
this))
528 m_itemType = QGeoMap::MapPolyline;
529 m_geopath = QGeoPathEager();
530 setFlag(ItemHasContents,
true);
531 QObject::connect(&m_line, &QDeclarativeMapLineProperties::colorChanged,
532 this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
533 QObject::connect(&m_line, &QDeclarativeMapLineProperties::widthChanged,
534 this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
535 QObject::connect(
this, &QDeclarativePolylineMapItem::referenceSurfaceChanged,
536 this, [
this]() { m_d->onGeoGeometryChanged(); });
723void QDeclarativePolylineMapItem::removeCoordinate(
const QGeoCoordinate &coordinate)
725 int length = m_geopath.path().length();
726 m_geopath.removeCoordinate(coordinate);
727 if (m_geopath.path().length() == length)
730 m_d->onGeoGeometryChanged();
778void QDeclarativePolylineMapItem::geometryChange(
const QRectF &newGeometry,
const QRectF &oldGeometry)
780 if (newGeometry.topLeft() == oldGeometry.topLeft() || !map() || !m_geopath.isValid() || m_updatingGeometry) {
781 QDeclarativeGeoMapItemBase::geometryChange(newGeometry, oldGeometry);
785 QGeoCoordinate newCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(newGeometry.center()),
false);
786 QGeoCoordinate oldCenter = map()->geoProjection().itemPositionToCoordinate(QDoubleVector2D(oldGeometry.center()),
false);
787 if (!newCenter.isValid() || !oldCenter.isValid())
789 double offsetLongi = newCenter.longitude() - oldCenter.longitude();
790 double offsetLati = newCenter.latitude() - oldCenter.latitude();
791 if (offsetLati == 0.0 && offsetLongi == 0.0)
794 m_geopath.translate(offsetLati, offsetLongi);
795 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)