diff options
Diffstat (limited to 'src/geometry.rs')
| -rw-r--r-- | src/geometry.rs | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/src/geometry.rs b/src/geometry.rs index 0841183..358620f 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -103,8 +103,12 @@ pub struct SpatialGrid { impl SpatialGrid { /// Creates a new spatial grid for the given dimensions pub fn new(width: f64, height: f64, cell_size: f64) -> Self { - let columns = ((width / cell_size).ceil() as usize).max(1); - let rows = ((height / cell_size).ceil() as usize).max(1); + // Safe cast: width and height are positive map dimensions, divided by cell_size and clamped to at least 1.0 + // The resulting grid size will be reasonable (< millions of cells) for typical map sizes + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let columns = (width / cell_size).ceil().max(1.0) as usize; + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let rows = (height / cell_size).ceil().max(1.0) as usize; let cells = vec![Vec::new(); columns * rows]; Self { @@ -122,10 +126,17 @@ impl SpatialGrid { let min_y = line.start.1.min(line.end.1); let max_y = line.start.1.max(line.end.1); - let start_column = ((min_x / self.cell_size).floor() as usize).min(self.columns - 1); - let end_column = ((max_x / self.cell_size).floor() as usize).min(self.columns - 1); - let start_row = ((min_y / self.cell_size).floor() as usize).min(self.rows - 1); - let end_row = ((max_y / self.cell_size).floor() as usize).min(self.rows - 1); + // Safe cast: coordinates are clamped to [0.0, max] before casting, ensuring valid grid indices + // The .max(0.0) ensures non-negative, and .min(columns/rows - 1) ensures within bounds + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let start_column = + ((min_x / self.cell_size).floor().max(0.0) as usize).min(self.columns - 1); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let end_column = ((max_x / self.cell_size).floor().max(0.0) as usize).min(self.columns - 1); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let start_row = ((min_y / self.cell_size).floor().max(0.0) as usize).min(self.rows - 1); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let end_row = ((max_y / self.cell_size).floor().max(0.0) as usize).min(self.rows - 1); for row in start_row..=end_row { for col in start_column..=end_column { @@ -143,18 +154,34 @@ impl SpatialGrid { let min_y = rect.y; let max_y = rect.y + rect.height; - let start_column = ((min_x / self.cell_size).floor() as isize) - .max(0) - .min(self.columns as isize - 1) as usize; - let end_column = ((max_x / self.cell_size).floor() as isize) - .max(0) - .min(self.columns as isize - 1) as usize; - let start_row = ((min_y / self.cell_size).floor() as isize) - .max(0) - .min(self.rows as isize - 1) as usize; - let end_row = ((max_y / self.cell_size).floor() as isize) - .max(0) - .min(self.rows as isize - 1) as usize; + let max_column_idx = if self.columns > 0 { + self.columns - 1 + } else { + 0 + }; + let max_row_idx = if self.rows > 0 { self.rows - 1 } else { 0 }; + + // Safe cast: grid indices are small (< thousands) for typical map sizes, well within f64 precision + // The coordinates are clamped to valid grid bounds before casting to usize + #[allow(clippy::cast_precision_loss)] + let max_column_f64 = max_column_idx as f64; + #[allow(clippy::cast_precision_loss)] + let max_row_f64 = max_row_idx as f64; + + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let start_column = ((min_x / self.cell_size) + .floor() + .max(0.0) + .min(max_column_f64)) as usize; + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let end_column = ((max_x / self.cell_size) + .floor() + .max(0.0) + .min(max_column_f64)) as usize; + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let start_row = ((min_y / self.cell_size).floor().max(0.0).min(max_row_f64)) as usize; + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let end_row = ((max_y / self.cell_size).floor().max(0.0).min(max_row_f64)) as usize; let mut line_indices = Vec::new(); for row in start_row..=end_row { |