11#include <QtCore/QLineF>
19 , _interactive (false)
27 , _interactive (false)
43 QVariantList vertices = other.
path();
44 for (
int i=0; i<vertices.count(); i++) {
53void QGCMapPolyline::_init(
void)
67 _polylinePath.clear();
79 _polylinePath[vertexIndex] = QVariant::fromValue(coordinate);
81 if (!_deferredPathChanged) {
82 _deferredPathChanged =
true;
85 QTimer::singleShot(0,
this, [
this]() {
87 _deferredPathChanged =
false;
90 QTimer::singleShot(0,
this, [
this]() {
92 _deferredPathChanged =
false;
101 if (_dirty !=
dirty) {
109QGeoCoordinate QGCMapPolyline::_coordFromPointF(
const QPointF& point)
const
111 QGeoCoordinate coord;
113 if (_polylinePath.count() > 0) {
114 QGeoCoordinate tangentOrigin = _polylinePath[0].value<QGeoCoordinate>();
121QPointF QGCMapPolyline::_pointFFromCoord(
const QGeoCoordinate& coordinate)
const
123 if (_polylinePath.count() > 0) {
125 QGeoCoordinate tangentOrigin = _polylinePath[0].value<QGeoCoordinate>();
128 return QPointF(x, -y);
138 _polylinePath.clear();
140 for (
const QGeoCoordinate& coord:
path) {
141 _polylinePath.append(QVariant::fromValue(coord));
154 _polylinePath =
path;
156 for (
int i=0; i<_polylinePath.count(); i++) {
167 QJsonValue jsonValue;
191 for (
int i=0; i<_polylinePath.count(); i++) {
203 QList<QGeoCoordinate> coords;
205 for (
int i=0; i<_polylinePath.count(); i++) {
206 coords.append(_polylinePath[i].value<QGeoCoordinate>());
214 int nextIndex = vertexIndex + 1;
215 if (nextIndex > _polylinePath.length() - 1) {
219 QGeoCoordinate firstVertex = _polylinePath[vertexIndex].value<QGeoCoordinate>();
220 QGeoCoordinate nextVertex = _polylinePath[nextIndex].value<QGeoCoordinate>();
222 double distance = firstVertex.distanceTo(nextVertex);
223 double azimuth = firstVertex.azimuthTo(nextVertex);
224 QGeoCoordinate newVertex = firstVertex.atDistanceAndAzimuth(distance / 2, azimuth);
226 if (nextIndex == 0) {
230 _polylinePath.insert(nextIndex, QVariant::fromValue(newVertex));
237 _polylinePath.append(QVariant::fromValue(coordinate));
244 if (vertexIndex < 0 || vertexIndex > _polylinePath.length() - 1) {
245 qCWarning(QGCMapPolylineLog) <<
"Call to removeVertex with bad vertexIndex:count" << vertexIndex << _polylinePath.length();
249 if (_polylinePath.length() <= 2) {
254 QObject* coordObj = _polylineModel.
removeAt(vertexIndex);
255 coordObj->deleteLater();
256 if(vertexIndex == _selectedVertexIndex) {
258 }
else if (vertexIndex < _selectedVertexIndex) {
262 _polylinePath.removeAt(vertexIndex);
288 if (vertex >= 0 && vertex < _polylinePath.count()) {
289 return _polylinePath[vertex].value<QGeoCoordinate>();
291 qCWarning(QGCMapPolylineLog) <<
"QGCMapPolyline::vertexCoordinate bad vertex requested";
292 return QGeoCoordinate();
303 for (
int i=0; i<_polylinePath.count(); i++) {
321 QList<QGeoCoordinate> rgNewPolyline;
330 QList<QLineF> rgOffsetEdges;
331 for (
int i=0; i<rgNedVertices.count() - 1; i++) {
333 QLineF originalEdge(rgNedVertices[i], rgNedVertices[i + 1]);
335 QLineF workerLine = originalEdge;
336 workerLine.setLength(distance);
337 workerLine.setAngle(workerLine.angle() - 90.0);
338 offsetEdge.setP1(workerLine.p2());
340 workerLine.setPoints(originalEdge.p2(), originalEdge.p1());
341 workerLine.setLength(distance);
342 workerLine.setAngle(workerLine.angle() + 90.0);
343 offsetEdge.setP2(workerLine.p2());
345 rgOffsetEdges.append(offsetEdge);
351 QGeoCoordinate coord;
353 rgNewPolyline.append(coord);
357 for (
int i=1; i<rgOffsetEdges.count(); i++) {
358 auto intersect = rgOffsetEdges[i - 1].intersects(rgOffsetEdges[i], &newVertex);
359 if (intersect == QLineF::NoIntersection) {
361 newVertex = rgOffsetEdges[i].p2();
364 rgNewPolyline.append(coord);
368 int lastIndex = rgOffsetEdges.count() - 1;
369 QGCGeo::convertNedToGeo(rgOffsetEdges[lastIndex].p2().y(), rgOffsetEdges[lastIndex].p2().x(), 0, tangentOrigin, coord);
370 rgNewPolyline.append(coord);
373 return rgNewPolyline;
379 QList<QList<QGeoCoordinate>> polylines;
384 if (polylines.isEmpty()) {
388 const QList<QGeoCoordinate>& rgCoords = polylines.first();
398void QGCMapPolyline::_polylineModelDirtyChanged(
bool dirty)
405void QGCMapPolyline::_polylineModelCountChanged(
int count)
415 for (
int i=0; i<_polylinePath.count() - 1; i++) {
416 QGeoCoordinate from = _polylinePath[i].value<QGeoCoordinate>();
417 QGeoCoordinate to = _polylinePath[i+1].value<QGeoCoordinate>();
418 length += from.distanceTo(to);
428 QList<QObject*> objects;
429 for (
const QGeoCoordinate& coordinate: coordinates) {
431 _polylinePath.append(QVariant::fromValue(coordinate));
433 _polylineModel.
append(objects);
460 if(index == _selectedVertexIndex)
return;
462 if(-1 <= index && index <
count()) {
463 _selectedVertexIndex = index;
465 qCWarning(QGCMapPolylineLog) << QStringLiteral(
"QGCMapPolyline: Selected vertex index (%1) is out of bounds! "
466 "Polyline vertices indexes range is [%2..%3].").arg(index).arg(0).arg(
count()-1);
467 _selectedVertexIndex = -1;
Geographic coordinate conversion utilities using GeographicLib.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
void endResetModel()
Depth-counted endResetModel — only the outermost call has effect.
void beginResetModel()
Depth-counted beginResetModel — only the outermost call has effect.
void dirtyChanged(bool dirty)
void countChanged(int count)
QModelIndex index(int row, int column=0, const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE void beginReset(void)
QList< QGeoCoordinate > offsetPolyline(double distance)
void dirtyChanged(bool dirty)
static constexpr const char * jsonPolylineKey
QList< QPointF > nedPolyline(void)
Convert polyline to NED and return (D is ignored)
Q_INVOKABLE void clear(void)
Q_INVOKABLE bool loadKMLOrSHPFile(const QString &file)
Q_INVOKABLE void splitSegment(int vertexIndex)
Splits the line segment comprised of vertexIndex -> vertexIndex + 1.
Q_INVOKABLE void removeVertex(int vertexIndex)
void interactiveChanged(bool interactive)
void traceModeChanged(bool traceMode)
Q_INVOKABLE void adjustVertex(int vertexIndex, const QGeoCoordinate coordinate)
void dragPathChanged(void)
void setTraceMode(bool traceMode)
void isEmptyChanged(void)
Q_INVOKABLE QGeoCoordinate vertexCoordinate(int vertex) const
Returns the QGeoCoordinate for the vertex specified.
void selectVertex(int index)
void setPath(const QList< QGeoCoordinate > &path)
void setDirty(bool dirty)
bool interactive(void) const
Q_INVOKABLE void appendVertex(const QGeoCoordinate &coordinate)
~QGCMapPolyline() override
void vertexDragChanged(bool vertexDrag)
bool vertexDrag(void) const
void saveToJson(QJsonObject &json)
QList< QGeoCoordinate > coordinateList(void) const
Returns the path in a list of QGeoCoordinate's format.
const QGCMapPolyline & operator=(const QGCMapPolyline &other)
Q_INVOKABLE void endReset(void)
Q_INVOKABLE void appendVertices(const QList< QGeoCoordinate > &coordinates)
QVariantList path(void) const
void isValidChanged(void)
bool loadFromJson(const QJsonObject &json, bool required, QString &errorString)
QGCMapPolyline(QObject *parent=nullptr)
double length(void) const
Returns the length of the polyline in meters.
void countChanged(int count)
void setVertexDrag(bool vertexDrag)
bool traceMode(void) const
void selectedVertexChanged(int index)
void setInteractive(bool interactive)
This is a QGeoCoordinate within a QObject such that it can be used on a QmlObjectListModel.
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
void setDirty(bool dirty) override final
QObject * removeAt(int index)
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
void insert(int index, QObject *object)
static bool loadPolylinesFromFile(const QString &file, QList< QList< QGeoCoordinate > > &polylines, QString &errorString, double filterMeters=kDefaultVertexFilterMeters)
bool loadGeoCoordinateArray(const QJsonValue &jsonValue, bool altitudeRequired, QVariantList &rgVarPoints, QString &errorString)
Loads a list of QGeoCoordinates (QGC plan format) from a json array.
void saveGeoCoordinateArray(const QVariantList &rgVarPoints, bool writeAltitude, QJsonValue &jsonValue)
Saves a list of QGeoCoordinates (QGC plan format) to a json array.
bool validateRequiredKeys(const QJsonObject &jsonObject, const QStringList &keys, QString &errorString)
Validates that all listed keys are present in the object.
void convertGeoToNed(const QGeoCoordinate &coord, const QGeoCoordinate &origin, double &x, double &y, double &z)
void convertNedToGeo(double x, double y, double z, const QGeoCoordinate &origin, QGeoCoordinate &coord)
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.