Seit einiger Zeit verwende ich QML, um grafische Oberflächen zu erstellen, aber bisher gab es keine Möglichkeit, mit der
Qt Location API und der QML Map in einem realen Projekt zu arbeiten.
Daher wurde es interessant, diese Komponente für den Bau von Atemwegen auszuprobieren.
Unter dem Cutter befindet sich die Beschreibung der Implementierung des Editors, um ähnliche Pfade auf der Karte zu erstellen:

Um die Implementierung zu vereinfachen, fliegen unsere Flugzeuge in der 2D-Ebene auf derselben Höhe. Die Geschwindigkeit und die zulässige Überlast sind fest - 920 km / h und 3 g, was einen Wenderadius ergibt
Die Flugbahn besteht aus folgenden Segmenten:

Dabei ist S der Beginn des Manövers (es ist der Ausgangspunkt des vorherigen Manövers), M der Beginn der Kurve, E der Ausgang des Manövers und F der Endpunkt (M für den nächsten).
Um den Eintritts- und Austrittspunkt aus der Flugbahn zu berechnen, habe ich die
Gleichung einer Tangente an einen Kreis verwendet. Die Berechnungen erwiesen sich als ziemlich umständlich. Ich bin sicher, dass dies einfacher gemacht werden kann.
void Manoeuvre::calculate() {
Nachdem wir die Fehlberechnung des mathematischen Modells unserer Flugbahn abgeschlossen haben, arbeiten wir direkt mit der Karte. Eine natürliche Wahl zum
Erstellen von Polylinien auf einer QML-Karte besteht darin,
MapPolyline direkt zur Karte hinzuzufügen.
Map { id: map plugin: Plugin { name: "osm" } MapPolyline { path: [ { latitude: -27, longitude: 153.0 }, ... ] } }
Zunächst wollte ich dem Benutzer die Möglichkeit geben, jeden nachfolgenden Abschnitt der Route „on the fly“ zu simulieren - um den Effekt der Bewegung der Flugbahn hinter dem Cursor zu erzeugen.

Das Ändern des
Pfads beim Bewegen des Cursors ist eine ziemlich teure Operation. Daher habe ich versucht, vorläufige „Pixel“ -Pfade zu verwenden, die angezeigt werden, bis der Benutzer die Route endgültig speichert.
Repeater { id: trajectoryView model: flightRegistry.hasActiveFlight ? flightRegistry.flightModel : [] FlightItem { anchors.fill: parent startPoint: start endPoint: end manoeuvreRect: rect manoeuvreStartAngle: startAngle manoeuvreSpanAngle: spanAngle isVirtualLink: isVirtual } }
FlightItem ist ein
QQuickItem , und mit
QAbstractListModel FlightModel können Sie die erforderlichen Abschnitte der Flugbahn aktualisieren, wenn Sie Daten für das Manöver ändern.
QVariant FlightModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } switch (role) { case FlightRoles::StartPoint: return mFlight->flightSegment(index.row()).line().p1(); case FlightRoles::EndPoint: return mFlight->flightSegment(index.row()).line().p2(); ... }
Mit einem solchen Live-Update können Sie den Benutzer vor nicht realisierbaren Manövern warnen.

Erst nach Abschluss der Erstellung des Atemwegs (z. B. mit der rechten Maustaste) wird die Route endgültig als GeoPath mit der Möglichkeit der Georeferenzierung zur QML-Karte hinzugefügt (bis zu diesem Moment kann die Karte nicht verschoben und gezoomt werden, die Pixel wissen nichts über Längen- und Breitengrad).
Um ein Pixelsegment in eine Geokoordinate neu zu berechnen, müssen wir für jedes Manöver zunächst ein Koordinatensystem verwenden, das lokal zum Manövereintrittspunkt (unserem Punkt S) liegt.
QPointF FlightGeoRoute::toPlaneCoordinate(const QGeoCoordinate &origin, const QGeoCoordinate &point) { auto distance = origin.distanceTo(point); auto azimuth = origin.azimuthTo(point); auto x = qSin(qDegreesToRadians(azimuth)) * distance; auto y = qCos(qDegreesToRadians(azimuth)) * distance; return QPointF(x, y); }
Nachdem wir das Manöver bereits Meter neu berechnet haben, müssen Sie den umgekehrten Vorgang ausführen und die Geolokalisierung von Punkt S kennen, um die Meter in Längen- und Breitengrad zu übersetzen.
QGeoCoordinate FlightGeoRoute::toGeoCoordinate(const QGeoCoordinate &origin, const QPointF &point) { auto distance = qSqrt(point.x()*point.x() + point.y()*point.y()); auto radianAngle = qAtan2(point.x(), point.y()); auto azimuth = qRadiansToDegrees(radianAngle < 0 ? radianAngle + 2*M_PI : radianAngle); return origin.atDistanceAndAzimuth(distance, azimuth); }
Aus formaler Sicht ist es natürlich unmöglich, unsere Flugbahn „Pixel“ und „in Metern“ als identisch zu betrachten, aber es schien mir sehr lecker, in die Zukunft zu schauen und dem Benutzer zu zeigen, was wann passieren wird (oder nicht passieren wird, wenn das Flugzeug nicht so fliegt) Er wird das nächste Mal klicken. Nach Abschluss der Flugbahn (sie unterscheidet sich geringfügig von der Pixelbahn in Farbe und Transparenz, da selbst statische gestrichelte Linien auf der Karte nicht sehr glatt aussehen).

Quellen sind
hier verfügbar, für die Kompilierung habe ich Qt 5.11.2 verwendet.
Im nächsten Teil werden wir unserem Editor beibringen, die Referenzpunkte der Flugbahn zu verschieben sowie vorhandene Spuren für die anschließende Simulation der Bewegung von Flugzeugen zu speichern / öffnen.