pelorus 0.1.0

A high-performance GPS map-matching library for geospatial road network processing
Documentation
use super::types::{RoadNetwork, SpatialSegment};
use crate::types::{CandidatePoint, RoadSegment, SegmentId};
use geo::{algorithm::euclidean_distance::EuclideanDistance, Point};
use rstar::PointDistance;

pub struct ProjectionResult {
    pub projected_point: Point<f64>,
    pub distance: f64,
}

impl RoadNetwork {
    pub fn query_segments_near(
        &self,
        point: Point<f64>,
        radius: f64,
    ) -> Vec<&RoadSegment> {
        let query_point = [point.x(), point.y()];

        let nearby_spatial_segments: Vec<&SpatialSegment> = self
            .spatial_index
            .locate_within_distance(query_point, radius * radius) // rstar uses squared distance
            .collect();

        nearby_spatial_segments
            .into_iter()
            .filter_map(|spatial_segment| {
                self.segments.get(&spatial_segment.segment_id)
            })
            .collect()
    }

    pub fn project_point_to_segment(
        &self,
        segment_id: SegmentId,
        point: Point<f64>,
    ) -> Option<ProjectionResult> {
        let segment = self.segments.get(&segment_id)?;

        // Create a temporary CandidatePoint to use existing projection logic
        let candidate = CandidatePoint {
            segment_id,
            segment,
            gps_point: point,
        };

        match candidate.projected_point() {
            Ok(projected) => {
                let distance = candidate.distance_to_gps();
                Some(ProjectionResult {
                    projected_point: projected,
                    distance,
                })
            }
            Err(_) => None,
        }
    }
}

impl PointDistance for SpatialSegment {
    fn distance_2(&self, point: &[f64; 2]) -> f64 {
        let query_point = Point::new(point[0], point[1]);
        let center_coord = self.bounding_box.center();
        let center_point = Point::from(center_coord);
        center_point.euclidean_distance(&query_point).powi(2)
    }
}