Good changes
This commit is contained in:
parent
80a5a2a774
commit
791bc6976b
24 changed files with 890 additions and 312 deletions
|
|
@ -71,6 +71,10 @@ pub struct HexagonStatsParams {
|
|||
/// Comma-separated feature names to include in stats response.
|
||||
/// Only listed features are computed; if absent or empty, no features are returned.
|
||||
pub fields: Option<String>,
|
||||
/// When set (with journey_slug), pick central_postcode as the postcode with the
|
||||
/// shortest travel time for this mode+slug (so it has journey data).
|
||||
pub journey_mode: Option<String>,
|
||||
pub journey_slug: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn get_hexagon_stats(
|
||||
|
|
@ -107,6 +111,17 @@ pub async fn get_hexagon_stats(
|
|||
|
||||
let (fields_specified, field_set) = parse_field_set(params.fields.as_deref());
|
||||
|
||||
// Load travel time data for central_postcode selection (if requested)
|
||||
let journey_travel_data = match (¶ms.journey_mode, ¶ms.journey_slug) {
|
||||
(Some(mode), Some(slug)) if state.travel_time_store.has_destination(mode, slug) => {
|
||||
state
|
||||
.travel_time_store
|
||||
.get(mode, slug)
|
||||
.ok()
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let response = tokio::task::spawn_blocking(move || {
|
||||
let start_time = std::time::Instant::now();
|
||||
let precomputed = &state.h3_cells;
|
||||
|
|
@ -138,27 +153,58 @@ pub async fn get_hexagon_stats(
|
|||
|
||||
let total_count = matching_rows.len();
|
||||
|
||||
// Find the postcode of the property closest to the hexagon center
|
||||
// Pick central_postcode: prefer the postcode with the shortest travel time
|
||||
// for the requested journey destination (so it has journey data). Fall back
|
||||
// to geographic proximity to the hexagon center.
|
||||
let central_postcode = if !matching_rows.is_empty() {
|
||||
let center: h3o::LatLng = cell.into();
|
||||
let center_lat = center.lat() as f32;
|
||||
let center_lon = center.lng() as f32;
|
||||
let closest_row = matching_rows
|
||||
.iter()
|
||||
.copied()
|
||||
.min_by(|&a, &b| {
|
||||
let da_lat = state.data.lat[a] - center_lat;
|
||||
let da_lon = state.data.lon[a] - center_lon;
|
||||
let db_lat = state.data.lat[b] - center_lat;
|
||||
let db_lon = state.data.lon[b] - center_lon;
|
||||
let dist_a = da_lat * da_lat + da_lon * da_lon;
|
||||
let dist_b = db_lat * db_lat + db_lon * db_lon;
|
||||
dist_a
|
||||
.partial_cmp(&dist_b)
|
||||
.unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.expect("matching_rows is non-empty");
|
||||
Some(state.data.postcode(closest_row).to_string())
|
||||
if let Some(ref travel_data) = journey_travel_data {
|
||||
// Find the row with the shortest travel time in the travel data
|
||||
let best_row = matching_rows
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(|row| {
|
||||
let pc = state.data.postcode(row);
|
||||
travel_data.get(pc).map(|td| (row, td.minutes))
|
||||
})
|
||||
.min_by_key(|&(_, mins)| mins)
|
||||
.map(|(row, _)| row);
|
||||
|
||||
// Fall back to geographic center if no row has travel data
|
||||
let row = best_row.unwrap_or_else(|| {
|
||||
let center: h3o::LatLng = cell.into();
|
||||
let center_lat = center.lat() as f32;
|
||||
let center_lon = center.lng() as f32;
|
||||
matching_rows
|
||||
.iter()
|
||||
.copied()
|
||||
.min_by(|&a, &b| {
|
||||
let da = (state.data.lat[a] - center_lat).powi(2)
|
||||
+ (state.data.lon[a] - center_lon).powi(2);
|
||||
let db = (state.data.lat[b] - center_lat).powi(2)
|
||||
+ (state.data.lon[b] - center_lon).powi(2);
|
||||
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.expect("matching_rows is non-empty")
|
||||
});
|
||||
Some(state.data.postcode(row).to_string())
|
||||
} else {
|
||||
// No journey destination requested — use geographic center
|
||||
let center: h3o::LatLng = cell.into();
|
||||
let center_lat = center.lat() as f32;
|
||||
let center_lon = center.lng() as f32;
|
||||
let closest_row = matching_rows
|
||||
.iter()
|
||||
.copied()
|
||||
.min_by(|&a, &b| {
|
||||
let da = (state.data.lat[a] - center_lat).powi(2)
|
||||
+ (state.data.lon[a] - center_lon).powi(2);
|
||||
let db = (state.data.lat[b] - center_lat).powi(2)
|
||||
+ (state.data.lon[b] - center_lon).powi(2);
|
||||
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
|
||||
})
|
||||
.expect("matching_rows is non-empty");
|
||||
Some(state.data.postcode(closest_row).to_string())
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue