Skip to content

FlyView: display Catmull-Rom curve for spline waypoints#14433

Open
leonfliesthings-dev wants to merge 1 commit into
mavlink:masterfrom
leonfliesthings-dev:feature/spline-curve-display
Open

FlyView: display Catmull-Rom curve for spline waypoints#14433
leonfliesthings-dev wants to merge 1 commit into
mavlink:masterfrom
leonfliesthings-dev:feature/spline-curve-display

Conversation

@leonfliesthings-dev

Copy link
Copy Markdown

Summary

QGC draws straight lines between NAV_SPLINE_WAYPOINT (cmd 82) mission items, even though ArduPilot flies smooth Hermite/Catmull-Rom curves through them. This makes it difficult for operators to visualize the actual flight path when using spline waypoints.

This PR adds a cyan Catmull-Rom interpolation overlay on the fly map that shows the approximate spline curve between consecutive spline waypoints.

How it works

  • A MapPolyline in FlyViewMap.qml polls the mission controller's visualItems every 3 seconds
  • When spline waypoints (cmd 82) are detected, it computes Catmull-Rom interpolation between consecutive waypoints
  • The curve is drawn as a cyan overlay on the map (3px wide, 85% opacity)
  • Only renders when spline waypoints are present — no effect on regular waypoint missions
  • Minimal performance impact: computation only runs when the mission item count changes

Screenshots

The cyan line shows the approximate spline curve ArduPilot will fly, overlaid on the straight-line mission path display.

Testing

  • Loaded mission with NAV_SPLINE_WAYPOINT items in SITL
  • Cyan curve appears on the fly map showing smooth paths between waypoints
  • No curve shown for missions using only NAV_WAYPOINT (cmd 16)
  • No performance impact observed

QGC draws straight lines between NAV_SPLINE_WAYPOINT (cmd 82) items,
even though ArduPilot flies smooth Hermite curves through them. This
adds a Catmull-Rom interpolation overlay on the fly map showing the
approximate spline curve in cyan.

The curve updates automatically when the mission changes and only
renders when spline waypoints (cmd 82) are present.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your first pull request! 🎉

A maintainer will review this soon. Please ensure:

  • CI checks pass
  • Code follows coding standards
  • Changes tested on relevant platforms

We appreciate your contribution to QGroundControl!

@codecov

codecov Bot commented May 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 26.47%. Comparing base (f29efd3) to head (0946f8b).
⚠️ Report is 32 commits behind head on master.

❌ Your project check has failed because the head coverage (26.47%) is below the target coverage (30.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #14433      +/-   ##
==========================================
+ Coverage   25.47%   26.47%   +1.00%     
==========================================
  Files         769      767       -2     
  Lines       65912    66285     +373     
  Branches    30495    30667     +172     
==========================================
+ Hits        16788    17546     +758     
+ Misses      37285    36280    -1005     
- Partials    11839    12459     +620     
Flag Coverage Δ
unittests 26.47% <ø> (+1.00%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 133 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0425145...0946f8b. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

Copy link
Copy Markdown
Contributor

Build Results

Platform Status

Platform Status Details
Linux Passed View
Windows Passed View
MacOS Passed View
Android Passed View

All builds passed.

Pre-commit

Check Status Details
pre-commit Failed (non-blocking) View

Pre-commit hooks: 2 passed, 42 failed, 7 skipped.

Test Results

linux-coverage: 88 passed, 0 skipped
Total: 88 passed, 0 skipped

Code Coverage

Coverage Baseline Change
60.4% 60.4% +0.0%

Artifact Sizes

Artifact Size Δ from master
QGroundControl 216.77 MB -4.61 MB (decrease)
QGroundControl-aarch64 176.66 MB -0.01 MB (decrease)
QGroundControl-installer-AMD64 134.68 MB -0.00 MB (decrease)
QGroundControl-installer-AMD64-ARM64 77.48 MB -0.01 MB (decrease)
QGroundControl-installer-ARM64 106.03 MB +0.00 MB (increase)
QGroundControl-linux 186.86 MB -147.82 MB (decrease)
QGroundControl-mac 186.86 MB No change
QGroundControl-windows 186.87 MB No change
QGroundControl-x86_64 172.32 MB +0.01 MB (increase)
Total size decreased by 152.44 MB

Updated: 2026-05-24 08:59:15 UTC • Triggered by: Linux

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

I'll try to get this into 5.1 but if it is too invasive it will need to wait till 5.2 so it has some bake time

@DonLakeFlyer DonLakeFlyer added this to the Release V5.1 milestone Jul 6, 2026
@leonfliesthings-dev

Copy link
Copy Markdown
Author

I'll try to get this into 5.1 but if it is too invasive it will need to wait till 5.2 so it has some bake time

Thanks, DonLakeFlyer. If it's too much, let me know; I can make some adjustments. I have a new version that colour-ramps altitude on the splines, which gives good alt context to the flight paths.

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

Here is what Claude-Fable has to say about this change. For now I'm moving this to 5.2 since it requires some significant cleanup I think:

Code Review: leonfliesthings-dev-feature/spline-curve-display

Branch: leonfliesthings-dev-feature/spline-curve-display
Changes: One feature commit (0946f8b37) plus a merge commit (df900d155) — 67 lines added to src/FlyView/FlyViewMap.qml
Feature: Catmull-Rom curve overlay in Fly view approximating ArduPilot NAV_SPLINE_WAYPOINT (MAV_CMD 82) flight paths.

Correctness

  1. Curve is drawn through every waypoint if any item is a spline waypointFlyViewMap.qml#L299 sets hasSpline globally, then the loop at FlyViewMap.qml#L307-L320 splines through all coordinate items. ArduPilot only flies a spline between NAV_SPLINE_WAYPOINT items; regular waypoints in the same mission are flown as straight legs. In a mixed mission the overlay draws a curved path over segments the vehicle will fly straight — actively misleading. The interpolation must be gated per-segment (segment p1→p2 is curved only when the relevant items are cmd 82).

  2. Stale curve never cleared when the mission shrinks or is removed — the early return at FlyViewMap.qml#L284 (items.count < 2) exits without clearing splineCurve.path. Remove the mission (or switch vehicles) and the old cyan curve stays on the map indefinitely.

  3. Change detection by item count onlyFlyViewMap.qml#L285-L286. Dragging a waypoint, editing its coordinate, or loading a different plan with the same number of items leaves the curve stale/wrong. Count is not a valid proxy for "mission changed".

  4. Planned-home is included in the curvevisualItems item 0 (MissionSettingsItem/home) reports specifiesCoordinate == true once home is set, so home becomes a Catmull-Rom control point and distorts the first segment's tangent. The vehicle never splines through home.

  5. Longitude interpolated as a raw scalarFlyViewMap.qml#L317. No antimeridian handling: waypoints straddling ±180° produce a curve wrapping across the entire globe. (High-latitude lat/lon-space interpolation inaccuracy is probably acceptable for a visual aid, but the wrap is a real bug.)

  6. Silent try/catch swallowing everythingFlyViewMap.qml#L324-L326. Any logic error in this block is invisible forever. QGC code doesn't use blanket catch; remove it and let qmllint/console surface problems.

Performance (map display)

  1. Polling timer instead of signalsFlyViewMap.qml#L277-L278. A 3-second repeating timer wakes the UI event loop for the life of the Fly view even when nothing changes, and adds up to 3s of latency after a mission load. MissionController already emits visualItemsReset (see src/MissionManager/MissionController.h#L52) — use a Connections on the controller instead. This would also fix issues 2 and 3.

  2. The PIP map instance runs the timer toorunning: _root.visible is true for the pip-mode map instance, so a second copy of this computation runs every 3s and builds a path that visible: !pipMode then hides. Gate with running: _root.visible && !pipMode.

  3. Full path reassignment with dense sampling — 10 samples/segment for all segments means a large mission (hundreds of items) produces thousands of QGeoCoordinate JS objects plus a full MapPolyline geometry re-tessellation on every update, and every subsequent pan/zoom pays per-point re-projection cost for the polyline. Fixing issue 1 (spline segments only) shrinks this dramatically; also consider building the points as a plain array once and skipping regeneration when the plan is unchanged (signal-driven, per Detached widgets can be impossible to redock #7).

  4. This belongs in C++, not a QML overlay — the mission line geometry is already computed centrally (simpleFlightPathSegments / FlightPathSegment, src/MissionManager/MissionController.h#L60). Doing spline rendering there would: apply to Plan view too (currently the Plan view still shows straight lines for the same mission — inconsistent UX), reuse existing change notification, and keep the interpolation out of the JS engine. If a QML-side prototype is intended as a first step, that tradeoff should at least be stated in the PR.

Style / conventions

  1. Multiple statements per line with semicolons (interval: 3000; running: ...; repeat: true, and { splineCurve.path = []; return }) — FlyViewMap.qml#L278 and FlyViewMap.qml#L302. One property/statement per line, and no brace-less/single-line ifs (FlyViewMap.qml#L282-L285).

  2. property var _splineMissionController declared mid-file between child items — FlyViewMap.qml#L275. Private properties belong at the top of the root item with the other _-prefixed properties.

  3. Magic number 82FlyViewMap.qml#L297-L299. Should reference the MAV_CMD enum value symbolically (or at minimum a named readonly property int _mavCmdNavSplineWaypoint).

  4. Hardcoded "cyan"FlyViewMap.qml#L269. There's precedent for hardcoded map-line colors (trajectory red), but cyan on satellite imagery vs. the existing mission-line color scheme deserves a deliberate choice; consider matching the mission line palette with a dashed/derived style instead.

  5. Branch history contains a merge commit (df900d155) on top of the single feature commit — should be rebased flat before PR.

Summary

The idea is genuinely useful (QGC has never visualized NAV_SPLINE_WAYPOINT paths), but as written the overlay draws incorrect curves for mixed missions (#1), leaves stale geometry on screen (#2, #3), and uses a polling architecture that costs CPU and adds latency when signal-driven updates are readily available (#7). Items #1, #2, and #7 are the minimum fixes; the C++ FlightPathSegment approach (#10) is the proper home for this so Plan view benefits too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants