Find the shortest curvature-constrained path between two oriented points in 3D space. Also known as CLC (Curve-Line-Curve) or CSC (Curve-Straight-Curve) paths. Applications include directional drilling, UAV/drone flight planning, autonomous vehicles, underwater vehicle routing, pipeline routing, and robotics.
A CLC (Curve-Line-Curve) path is the 3D equivalent of a Dubins path (detailed overview) — the shortest route between two oriented points when constrained to a minimum turning radius. In 2D, Dubins (1957) proved that optimal paths consist of circular arcs and straight lines. The CLC type connects two configurations using an arc, a straight tangent line, then a second arc.
Naming conventions: This path type appears under many names in the literature. CLC (Curve-Line-Curve) and CSC (Curve-Straight-Curve) are equivalent. In Dubins path notation, the specific variants are RSR, RSL, LSR, LSL (R = right turn, S = straight, L = left turn). In directional drilling, the same geometry is called a build-hold-drop or turn-hold-turn trajectory. The other Dubins family — CCC (three consecutive arcs with no straight segment) — is not covered by this solver.
Extending this to 3D is significantly harder. In 2D there are only 6 possible path types; in 3D the turning circle at each point becomes a full family of circles — every possible turning direction perpendicular to the heading. Finding which pair of circles (one at the start, one at the target) can be connected by a straight tangent line is a challenging geometric search problem.
Each configuration is a point in space with a direction (position + unit vector). The solver finds all valid CLC paths connecting them, ranked by total arc angle or path length.
The path passes through four points, each with a position and direction:
| Point | Position | Direction | Role |
|---|---|---|---|
| P0 | pos0 | vec0 | Start — given as input |
| P1 | p1 | vec1 | End of first arc, start of straight line |
| P2 | p2 | vec2 | End of straight line, start of second arc |
| P3 | pos3 | vec3 | Target — given as input |
r. The arc departs P0 in direction vec0 and arrives at P1 in direction vec1.r3. The arc departs P2 in direction vec2 and arrives at P3 in direction vec3.The key constraint: vec1 = vec2 — the direction at P1 must equal the direction at P2, since the straight line segment connects them.
Blue: gentle path (133° total arc). Red: wrap-around path (356° total arc). Both are valid CLC solutions connecting the same P0 and P3.
| Field | Description |
|---|---|
pos0 | P0 — start position [x, y, z] |
vec0 | P0 — start direction (unit vector) |
pos3 | P3 — target position [x, y, z] |
vec3 | P3 — target direction (unit vector) — desired arrival heading |
r | Turning radius for C1 (arc at P0) |
r3 | Turning radius for C2 (arc at P3) — defaults to r if omitted |
| Field | Description |
|---|---|
p1, vec1 | P1 — junction between C1 and L |
p2, vec2 | P2 — junction between L and C2 |
arc1_deg | Arc angle of C1 (P0 → P1) in degrees |
arc2_deg | Arc angle of C2 (P2 → P3) in degrees |
total_arc_deg | arc1 + arc2 in degrees |
L_length | Length of straight segment (P1 → P2) |
md | Total path length: L1 + L2 + L3 where L1 = arc1 length, L2 = line length, L3 = arc2 length. (In drilling: measured depth.) |
error_deg | Angular matching error — lower is more accurate |
r_used, r3_used | Actual turning radii used (may differ from input if radius sweep is active) |
Many geometries have more than one valid CLC path. For example, a path can wrap the "short way" or the "long way" around a turning circle. The solver finds multiple solutions where they exist, ranked by your chosen criterion (minimize: "arc" for gentlest path, or "md" for shortest total path length).
| Tier | Error | Speed (GPU)* | Use case |
|---|---|---|---|
fast | ~5-20° | ~0.2ms/pair | Screening, existence check |
medium | ~0.5° | ~0.5ms/pair | Default, most applications |
high | ~0.05° | ~0.8ms/pair | Precision planning |
ultra | ~0.01° | ~2ms/pair | Maximum accuracy |
* GPU timings on NVIDIA RTX 3080 Ti at batch sizes of 1,000+ pairs. Small batches (< 10 pairs) run on CPU where GPU launch overhead exceeds compute time — expect ~20-40ms/pair. The compute field in the response indicates which was used.
r_scale_min and r_scale_max are ratio multipliers applied to the turning radius r. For example, with DLS = 3°/30m the design radius is r ≈ 573m:
| r_scale | Effective radius | Meaning |
|---|---|---|
| 0.9 | 573 × 0.9 = 516m | 10% tighter turns (DLS ≈ 3.33°/30m) |
| 1.0 | 573 × 1.0 = 573m | Design radius (DLS = 3.00°/30m) |
| 1.1 | 573 × 1.1 = 630m | 10% gentler turns (DLS ≈ 2.73°/30m) |
Set r_scale_min=0.9 and r_scale_max=1.1 with n_r_steps=5 to solve at exactly 5 radii across that range (0.9, 0.95, 1.0, 1.05, 1.1). If the design radius (1.0) falls within the range, the nearest grid point is snapped to it — so you always get the design radius without using an extra solve. All radii are batched in a single GPU call, so the incremental cost of additional radii is low.
Useful for finding the optimal turning radius or checking feasibility at different curvatures. A minor increase in DLS (smaller radius) can result in a significantly shorter total path length. In drilling: optimising dogleg severity.
Coordinate system: The solver uses x = East, y = North, z = Down (TVD). Survey data in (North, East, TVD) must be transformed to (x, y, z) = (East, North, TVD) before submitting to the API.
DLS to radius: The turning radius r is derived from dogleg severity (DLS) and course length:
r = (180 / π) × (course_length / DLS)
where DLS is in degrees per course_length (e.g. °/30m or °/100ft). For example, DLS = 3°/30m gives r ≈ 573m.
Terminology mapping:
| Solver term | Drilling term |
|---|---|
| r, r3 | Turning radius (from DLS) |
| arc1, arc2 | Dogleg angles |
| md (total path length) | Measured depth |
| rotation1, rotation2 | Toolface angles (referenced to high side, or north when inclination is near zero) |
The WellEng CLC Solver is available as a REST API — send a JSON request with your start and target configurations, get ranked CLC solutions back in milliseconds. No installation required.
The solver runs on GPU (NVIDIA RTX 3080 Ti) and handles batch workloads of up to 100,000 pairs per request at ~0.1ms/pair. Small batches run on CPU. The compute field in the response tells you which was used.
curl -s --compressed -X POST https://api.welleng.org/api/v1/solve \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_KEY" \
-d '{
"pairs": [{
"pos0": [0, 0, 0], "vec0": [0, 0, 1],
"pos3": [100, 50, 600], "vec3": [0.2, 0.1, 0.97],
"r": 573
}],
"solver": "analytical",
"shortest_only": true
}'
Important: Always use https://api.welleng.org (no port number). Use --compressed to enable gzip — large batch responses compress ~5-10x, significantly reducing transfer time. Responses are gzip-encoded automatically when the client supports it.
To test multiple turning radii, add r_scale_min, r_scale_max, and optionally n_r_steps:
{
"pairs": [{"pos0": ..., "vec0": ..., "pos3": ..., "vec3": ..., "r": 573}],
"solver": "analytical",
"shortest_only": true,
"r_scale_min": 0.8,
"r_scale_max": 1.2,
"n_r_steps": 5
}
This tests 5 r1-scales × 5 r2-scales = 25 permutations per pair, returning the shortest solution from each. If n_r_steps is omitted, it defaults to 3 when a sweep is requested.
In 1957, Lester Dubins proved that the shortest path between two oriented points in a plane, subject to a minimum turning radius, is composed of at most three segments — each either a circular arc (C) at the minimum radius or a straight line (S). This gives six possible Dubins path types: CSC (three variants) and CCC (three variants). The problem has elegant closed-form solutions in 2D and is widely used in robot motion planning, UAV path planning, and vehicle routing.
Extending Dubins paths to 3D is an open problem in computational geometry. The key difficulty: in 2D, each point has exactly two turning circles (left and right). In 3D, the set of all possible turning circles from a point forms a continuous family — every direction perpendicular to the heading defines a valid turning circle. Finding a valid CLC path requires identifying one circle at the start and one at the target that can be connected by a mutual tangent line — a search over a much larger space than the 2D case.
Several approaches have been proposed for 3D Dubins-like path planning:
Analytical extensions of 2D Dubins. Some work extends Dubins' 2D results to restricted 3D cases — for example, Chitsaz and LaValle (2007) characterised time-optimal paths for a Dubins airplane, and Owen, Beard and McLain (2014) provided implementations for fixed-wing UAVs. These are effective for their specific domains but don't generalise to arbitrary 3D orientations.
Iterative numerical methods. In directional drilling, the standard approach is a fixed-point iteration that adjusts toolface and dogleg angles until the endpoint converges. The welleng library's Connector class uses this approach and is reliable for realistic well geometries. However, iterative methods can converge to local minima — particularly at extreme curvatures — and are inherently sequential (one pair at a time), limiting throughput.
The scaling problem. All of these approaches process one pair at a time. In applications like multi-target well planning, anti-collision checking, or real-time UAV re-routing, you may need to solve thousands to hundreds of thousands of pairs simultaneously. Sequential methods that take 5-15ms per pair become impractical at this scale. This solver was designed specifically for batch throughput — solving 100,000 pairs in ~12 seconds on a single GPU.
This solver uses a novel geometric formulation that is natively GPU-parallel, enabling batch throughput orders of magnitude faster than sequential methods. Key properties:
3D CLC paths appear in any domain where a vehicle or tool must travel between two oriented points with constrained curvature:
Interactive API docs · [email protected] · Author · Guide v3.5