#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum JustificationMode {
LeftJustified,
RightJustified,
CenterJustified,
FullyJustified,
Unjustified,
}
pub struct JustificationDetector;
impl JustificationDetector {
pub fn detect(
_avg_word_spacing: f32,
word_spacing_variance: f32,
start_x: f32,
end_x: f32,
page_width: f32,
page_margin_left: f32,
) -> JustificationMode {
let left_margin = start_x - page_margin_left;
let right_margin = page_width - end_x;
let margin_diff = (left_margin - right_margin).abs();
let is_centered = margin_diff < 10.0;
let aligns_left = left_margin < 5.0; let aligns_right = right_margin < 5.0;
let has_spacing_variance = word_spacing_variance > 0.5;
if aligns_left && aligns_right {
JustificationMode::FullyJustified
} else if is_centered {
JustificationMode::CenterJustified
} else if aligns_right {
JustificationMode::RightJustified
} else if aligns_left {
if has_spacing_variance {
JustificationMode::FullyJustified
} else {
JustificationMode::LeftJustified
}
} else {
JustificationMode::Unjustified
}
}
pub fn calculate_word_spacing_variance(word_spacings: &[f32]) -> f32 {
if word_spacings.is_empty() {
return 0.0;
}
let mean = word_spacings.iter().sum::<f32>() / word_spacings.len() as f32;
let variance = word_spacings
.iter()
.map(|&spacing| (spacing - mean).powi(2))
.sum::<f32>()
/ word_spacings.len() as f32;
variance.sqrt() }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_left_justified_detection() {
let mode = JustificationDetector::detect(
5.0, 0.1, 0.0, 250.0, 500.0, 0.0, );
assert_eq!(mode, JustificationMode::LeftJustified);
}
#[test]
fn test_right_justified_detection() {
let mode = JustificationDetector::detect(
5.0, 0.1, 250.0, 500.0, 500.0, 0.0, );
assert_eq!(mode, JustificationMode::RightJustified);
}
#[test]
fn test_center_justified_detection() {
let mode = JustificationDetector::detect(
5.0, 0.1, 200.0, 300.0, 500.0, 0.0, );
assert_eq!(mode, JustificationMode::CenterJustified);
}
#[test]
fn test_fully_justified_detection() {
let mode = JustificationDetector::detect(
5.0, 2.0, 0.0, 500.0, 500.0, 0.0, );
assert_eq!(mode, JustificationMode::FullyJustified);
}
#[test]
fn test_unjustified_detection() {
let mode = JustificationDetector::detect(
5.0, 0.1, 100.0, 350.0, 500.0, 0.0, );
assert_eq!(mode, JustificationMode::Unjustified);
}
#[test]
fn test_spacing_variance_calculation() {
let spacings = vec![5.0, 5.0, 5.0, 5.0]; let variance = JustificationDetector::calculate_word_spacing_variance(&spacings);
assert!(variance < 0.1, "Uniform spacing should have low variance");
}
#[test]
fn test_spacing_variance_variable() {
let spacings = vec![3.0, 5.0, 7.0, 4.0]; let variance = JustificationDetector::calculate_word_spacing_variance(&spacings);
assert!(variance > 1.0, "Variable spacing should have higher variance");
}
}