10#include <QtCore/QLineF>
18 , _interactive (false)
26 , _interactive (false)
42 QVariantList vertices = other.
path();
43 for (
int i=0; i<vertices.count(); i++) {
52void QGCMapPolyline::_init(
void)
64void QGCMapPolyline::clear(
void)
66 _polylinePath.clear();
78 _polylinePath[vertexIndex] = QVariant::fromValue(coordinate);
80 if (!_deferredPathChanged) {
81 _deferredPathChanged =
true;
82 QTimer::singleShot(0,
this, [
this]() {
84 _deferredPathChanged =
false;
92 if (_dirty !=
dirty) {
100QGeoCoordinate QGCMapPolyline::_coordFromPointF(
const QPointF& point)
const
102 QGeoCoordinate coord;
104 if (_polylinePath.count() > 0) {
105 QGeoCoordinate tangentOrigin = _polylinePath[0].value<QGeoCoordinate>();
112QPointF QGCMapPolyline::_pointFFromCoord(
const QGeoCoordinate& coordinate)
const
114 if (_polylinePath.count() > 0) {
116 QGeoCoordinate tangentOrigin = _polylinePath[0].value<QGeoCoordinate>();
119 return QPointF(x, -y);
129 _polylinePath.clear();
131 for (
const QGeoCoordinate& coord:
path) {
132 _polylinePath.append(QVariant::fromValue(coord));
145 _polylinePath =
path;
147 for (
int i=0; i<_polylinePath.count(); i++) {
158 QJsonValue jsonValue;
182 for (
int i=0; i<_polylinePath.count(); i++) {
194 QList<QGeoCoordinate> coords;
196 for (
int i=0; i<_polylinePath.count(); i++) {
197 coords.append(_polylinePath[i].value<QGeoCoordinate>());
205 int nextIndex = vertexIndex + 1;
206 if (nextIndex > _polylinePath.length() - 1) {
210 QGeoCoordinate firstVertex = _polylinePath[vertexIndex].value<QGeoCoordinate>();
211 QGeoCoordinate nextVertex = _polylinePath[nextIndex].value<QGeoCoordinate>();
213 double distance = firstVertex.distanceTo(nextVertex);
214 double azimuth = firstVertex.azimuthTo(nextVertex);
215 QGeoCoordinate newVertex = firstVertex.atDistanceAndAzimuth(distance / 2, azimuth);
217 if (nextIndex == 0) {
221 _polylinePath.insert(nextIndex, QVariant::fromValue(newVertex));
228 _polylinePath.append(QVariant::fromValue(coordinate));
235 if (vertexIndex < 0 || vertexIndex > _polylinePath.length() - 1) {
236 qCWarning(QGCMapPolylineLog) <<
"Call to removeVertex with bad vertexIndex:count" << vertexIndex << _polylinePath.length();
240 if (_polylinePath.length() <= 2) {
245 QObject* coordObj = _polylineModel.
removeAt(vertexIndex);
246 coordObj->deleteLater();
247 if(vertexIndex == _selectedVertexIndex) {
249 }
else if (vertexIndex < _selectedVertexIndex) {
253 _polylinePath.removeAt(vertexIndex);
267 if (vertex >= 0 && vertex < _polylinePath.count()) {
268 return _polylinePath[vertex].value<QGeoCoordinate>();
270 qCWarning(QGCMapPolylineLog) <<
"QGCMapPolyline::vertexCoordinate bad vertex requested";
271 return QGeoCoordinate();
282 for (
int i=0; i<_polylinePath.count(); i++) {
300 QList<QGeoCoordinate> rgNewPolyline;
309 QList<QLineF> rgOffsetEdges;
310 for (
int i=0; i<rgNedVertices.count() - 1; i++) {
312 QLineF originalEdge(rgNedVertices[i], rgNedVertices[i + 1]);
314 QLineF workerLine = originalEdge;
315 workerLine.setLength(distance);
316 workerLine.setAngle(workerLine.angle() - 90.0);
317 offsetEdge.setP1(workerLine.p2());
319 workerLine.setPoints(originalEdge.p2(), originalEdge.p1());
320 workerLine.setLength(distance);
321 workerLine.setAngle(workerLine.angle() + 90.0);
322 offsetEdge.setP2(workerLine.p2());
324 rgOffsetEdges.append(offsetEdge);
330 QGeoCoordinate coord;
332 rgNewPolyline.append(coord);
336 for (
int i=1; i<rgOffsetEdges.count(); i++) {
337 auto intersect = rgOffsetEdges[i - 1].intersects(rgOffsetEdges[i], &newVertex);
338 if (intersect == QLineF::NoIntersection) {
340 newVertex = rgOffsetEdges[i].p2();
343 rgNewPolyline.append(coord);
347 int lastIndex = rgOffsetEdges.count() - 1;
348 QGCGeo::convertNedToGeo(rgOffsetEdges[lastIndex].p2().y(), rgOffsetEdges[lastIndex].p2().x(), 0, tangentOrigin, coord);
349 rgNewPolyline.append(coord);
352 return rgNewPolyline;
358 QList<QList<QGeoCoordinate>> polylines;
359 if (!ShapeFileHelper::loadPolylinesFromFile(file, polylines,
errorString)) {
363 if (polylines.isEmpty()) {
364 qgcApp()->showAppMessage(tr(
"No polylines found in file"));
367 const QList<QGeoCoordinate>& rgCoords = polylines.first();
377void QGCMapPolyline::_polylineModelDirtyChanged(
bool dirty)
384void QGCMapPolyline::_polylineModelCountChanged(
int count)
394 for (
int i=0; i<_polylinePath.count() - 1; i++) {
395 QGeoCoordinate from = _polylinePath[i].value<QGeoCoordinate>();
396 QGeoCoordinate to = _polylinePath[i+1].value<QGeoCoordinate>();
397 length += from.distanceTo(to);
407 QList<QObject*> objects;
408 for (
const QGeoCoordinate& coordinate: coordinates) {
410 _polylinePath.append(QVariant::fromValue(coordinate));
412 _polylineModel.
append(objects);
439 if(index == _selectedVertexIndex)
return;
441 if(-1 <= index && index <
count()) {
442 _selectedVertexIndex = index;
444 qCWarning(QGCMapPolylineLog) << QStringLiteral(
"QGCMapPolyline: Selected vertex index (%1) is out of bounds! "
445 "Polyline vertices indexes range is [%2..%3].").arg(index).arg(0).arg(
count()-1);
446 _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)
int count READ count NOTIFY countChanged(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) bool dirty() const
QModelIndex index(int row, int column=0, const QModelIndex &parent=QModelIndex()) const override
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)
bool loadKMLOrSHPFile(const QString &file)
void splitSegment(int vertexIndex)
Splits the line segment comprised of vertexIndex -> vertexIndex + 1.
void removeVertex(int vertexIndex)
void interactiveChanged(bool interactive)
void traceModeChanged(bool traceMode)
void adjustVertex(int vertexIndex, const QGeoCoordinate coordinate)
void setTraceMode(bool traceMode)
void isEmptyChanged(void)
int count READ count NOTIFY countChanged(QVariantList path READ path NOTIFY pathChanged) 1(QmlObjectListModel *pathModel READ qmlPathModel CONSTANT) 1(bool dirty READ dirty WRITE setDirty NOTIFY dirtyChanged) 1(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged) 1(bool isValid READ isValid NOTIFY isValidChanged) 1(bool empty READ empty NOTIFY isEmptyChanged) 1(bool traceMode READ traceMode WRITE setTraceMode NOTIFY traceModeChanged) 1(int selectedVertex READ selectedVertex WRITE selectVertex NOTIFY selectedVertexChanged) 1 void clear(void)
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
void appendVertex(const QGeoCoordinate &coordinate)
~QGCMapPolyline() override
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)
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.
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)
void saveGeoCoordinateArray(const QVariantList &rgVarPoints, bool writeAltitude, QJsonValue &jsonValue)
Saves a list of QGeoCoordinates to a json array.
bool loadGeoCoordinateArray(const QJsonValue &jsonValue, bool altitudeRequired, QVariantList &rgVarPoints, QString &errorString)
returned error string if load failure
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)