1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Cross-track distance calculation implementations.
//!
//! This module provides different methods for calculating the perpendicular
//! distance from a point to a line segment, which is the core operation
//! in the Douglas-Peucker algorithm.
//!
//! The choice of distance calculation method affects both accuracy and performance:
//!
//! - [`XtGreatCircle`]: Most accurate for geographic data, works globally
//! - [`XtEnu`]: Good balance of accuracy and performance for regional data
//! - [`XtEuclid`]: Fastest, suitable for projected or non-geographic data
use ;
/// Trait for calculating perpendicular distance from a point to a line segment.
///
/// This abstraction allows the Douglas-Peucker algorithm to work with different
/// distance calculation methods without changing the core algorithm.
/// Great circle distance calculation using spherical geometry.
///
/// Uses the [great circle method](https://en.wikipedia.org/wiki/Great_circle)
/// to calculate the shortest distance between a point and a line segment on
/// the Earth's surface. This is the most accurate method for geographic data
/// but requires more computation.
///
/// # Examples
///
/// ```rust
/// use rapidgeo_distance::LngLat;
/// use rapidgeo_simplify::xt::{PerpDistance, XtGreatCircle};
///
/// let backend = XtGreatCircle;
/// let distance = backend.d_perp_m(
/// LngLat::new_deg(-122.0, 37.0), // San Francisco area
/// LngLat::new_deg(-121.0, 37.0), // Point east
/// LngLat::new_deg(-121.5, 37.1), // Point slightly north of line
/// );
///
/// // Distance should be roughly 11km (0.1 degree latitude difference)
/// assert!((distance - 11100.0).abs() < 1000.0);
/// ```
;
/// East-North-Up (ENU) planar projection distance calculation.
///
/// Projects coordinates to a local [East-North-Up coordinate system](https://en.wikipedia.org/wiki/Local_tangent_plane_coordinates)
/// around the specified origin point, then calculates Euclidean distance.
/// This provides better performance than great circle calculations while
/// maintaining reasonable accuracy for regional datasets.
///
/// # Examples
///
/// ```rust
/// use rapidgeo_distance::LngLat;
/// use rapidgeo_simplify::xt::{PerpDistance, XtEnu};
///
/// let origin = LngLat::new_deg(-121.5, 37.0); // Midpoint
/// let backend = XtEnu { origin };
///
/// let distance = backend.d_perp_m(
/// LngLat::new_deg(-122.0, 37.0),
/// LngLat::new_deg(-121.0, 37.0),
/// LngLat::new_deg(-121.5, 37.1), // 0.1 degree north
/// );
///
/// // Should be close to great circle result for this regional example
/// assert!(distance > 10000.0 && distance < 12000.0);
/// ```
/// Raw Euclidean distance calculation between coordinates.
///
/// Treats longitude and latitude values as Cartesian coordinates and
/// calculates standard Euclidean distance. This is the fastest method
/// but should only be used for:
///
/// - Non-geographic coordinate systems (screen coordinates, etc.)
/// - Already-projected data where coordinates represent planar distances
/// - Data where geographic accuracy is not important
///
/// # Examples
///
/// ```rust
/// use rapidgeo_distance::LngLat;
/// use rapidgeo_simplify::xt::{PerpDistance, XtEuclid};
///
/// let backend = XtEuclid;
///
/// // Using as screen coordinates (not geographic)
/// let distance = backend.d_perp_m(
/// LngLat::new_deg(0.0, 0.0), // Point A
/// LngLat::new_deg(10.0, 0.0), // Point B
/// LngLat::new_deg(5.0, 3.0), // Point P (3 units above midpoint)
/// );
///
/// assert!((distance - 3.0).abs() < 0.001); // Should be exactly 3.0
/// ```
;