A C++20 / Qt6 application that analytically solves the classic constant-velocity interception problem: given a target moving in a straight line at constant speed, compute the heading a hunter must take (also at constant speed) to intercept it in minimum time.
No iterative methods, no numerical integration — just a clean quadratic equation derived from first principles.
Two entities move on a 2D plane:
| Entity | Known | Unknown |
|---|---|---|
| Target | Position |
— |
| Hunter | Position |
Heading |
Both travel in straight lines at constant speed. The question is: what heading should the hunter choose so that both arrive at the same point at the same time?
This is not a pursuit curve (where the hunter continuously turns toward the target). The hunter picks a single heading at
Using navigation convention (0° = North, clockwise), the target's velocity decomposes as:
where
The hunter must reach
Expanding with
Rearranging into standard quadratic form
where
Note that
$a$ simplifies to$V_T^2 - V_H^2$ because$v_{Tx}^2 + v_{Ty}^2 = V_T^2 \sin^2\theta + V_T^2 \cos^2\theta = V_T^2$ .
This yields zero, one, or two real roots. The physical constraints are:
-
$t > 0$ (interception must be in the future) - If two positive roots exist, the smallest is the optimal (earliest) interception
Once
The hunter's required heading (in navigation convention) is:
Note the argument order: atan2(east, north) directly produces a navigation angle (0° = North, CW positive).
| Condition | Interpretation | Result |
|---|---|---|
| Already co-located |
|
|
|
|
Degenerates to linear: |
|
| No real roots | Interception impossible | |
| Both |
Solutions in the past | Interception impossible |
| Hunter cannot move | Impossible (unless co-located) | |
|
|
Discriminant goes negative | Correctly returns no solution |
Setup:
- Hunter at
$(0, 0)$ , speed$V_H = 15$ - Target at
$(100, 100)$ , speed$V_T = 8$ , heading$180°$ (due South)
Computation:
Only
Intercept point:
Hunter heading:
Verification: Hunter distance
LeadPursuit/
├── CMakeLists.txt
├── README.md
└── src/
├── main.cpp
├── math/
│ ├── Types.h # Point2D, InterceptionParams, InterceptionResult
│ ├── AngleUtils.h # Degree/radian and navigation/math conversions
│ └── InterceptionSolver.h/cpp # Pure analytical solver (no Qt dependency)
└── gui/
├── MainWindow.h/cpp # Input panel, results display, layout
└── InterceptCanvas.h/cpp # Custom QWidget: grid, paths, markers
The math engine has zero dependency on Qt and can be used standalone.
Requires C++20 and Qt6.
cmake -B build
cmake --build build
./build/LeadPursuit