use super::bounding_box::BoundingBox;
#[cfg_attr(alef, alef(skip))]
#[derive(Debug, Clone, PartialEq)]
pub struct TextBlock {
pub text: String,
pub bbox: BoundingBox,
pub font_size: f32,
}
#[cfg_attr(alef, alef(skip))]
#[derive(Debug, Clone)]
pub struct SegmentData {
pub text: String,
pub x: f32,
pub y: f32,
pub width: f32,
pub height: f32,
pub font_size: f32,
pub is_bold: bool,
pub is_italic: bool,
pub is_monospace: bool,
pub baseline_y: f32,
pub rotation_degrees: f32,
pub assigned_role: Option<u8>,
}
impl SegmentData {
pub(crate) fn is_unrotated(&self) -> bool {
self.rotation_degrees.abs() <= f32::EPSILON
}
pub(crate) fn has_same_rotation(&self, other: &Self) -> bool {
(self.rotation_degrees - other.rotation_degrees).abs() <= f32::EPSILON
}
pub(crate) fn upright_origin(&self) -> (f32, f32) {
if self.is_unrotated() {
return (self.x, self.y);
}
let (sin, cos) = (-self.rotation_degrees).to_radians().sin_cos();
(self.x * cos - self.y * sin, self.x * sin + self.y * cos)
}
pub(crate) fn upright_advance_extent(&self) -> (f32, f32) {
let (start, _) = self.upright_origin();
(start, start + self.width)
}
pub(crate) fn upright_cross_extent(&self) -> (f32, f32) {
let (_, low) = self.upright_origin();
(low, low + self.height)
}
pub(crate) fn upright_baseline(&self) -> f32 {
if self.is_unrotated() {
self.baseline_y
} else {
self.upright_origin().1
}
}
}
#[cfg(test)]
mod tests {
use super::SegmentData;
fn segment(rotation_degrees: f32) -> SegmentData {
SegmentData {
text: "x".to_string(),
x: 100.0,
y: 700.0,
width: 40.0,
height: 10.0,
font_size: 10.0,
is_bold: false,
is_italic: false,
is_monospace: false,
baseline_y: 700.0,
rotation_degrees,
assigned_role: None,
}
}
#[test]
fn should_leave_unrotated_segment_geometry_unchanged() {
let segment = segment(0.0);
assert_eq!(segment.upright_origin(), (100.0, 700.0));
assert_eq!(segment.upright_advance_extent(), (100.0, 140.0));
assert_eq!(segment.upright_cross_extent(), (700.0, 710.0));
}
#[test]
fn should_rotate_ninety_degree_segment_into_its_reading_frame() {
let segment = segment(90.0);
let (advance, cross) = segment.upright_origin();
assert!((advance - 700.0).abs() < 1e-3, "advance axis was {advance}");
assert!((cross + 100.0).abs() < 1e-3, "cross axis was {cross}");
let (start, end) = segment.upright_advance_extent();
assert!((start - 700.0).abs() < 1e-3 && (end - 740.0).abs() < 1e-3);
}
}