dailp/geometry.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
use serde::{Deserialize, Serialize};
/// A rectangle slice of something, usually a large document image.
///
/// Units are a percentage of the containing document.
/// This is more useful than pixels because we can more easily compare
/// geometries between images of different resolutions. For example, we could identify
/// all items in any bottom-right corner with Geometry(90%, 90%, 100%, 100%).
/// Physical units would be better, but IIIF only allows pixels and percentages.
///
/// Potential use case:
/// Each document is represented by an ordered list of [AnnotatedForm]s. Each
/// form has some geometry on the source image. There are a bunch of other
/// annotations on the source image that are unordered. These may be specific
/// syllabary characters, notes about the handwriting, etc. Using MongoDB
/// comparison queries, we can request a list of all spatial annotations
/// on the same document that lie within or around the geometry of this specific word.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, async_graphql::SimpleObject)]
#[serde(rename_all = "camelCase")]
pub struct Geometry {
x_min: Scalar,
y_min: Scalar,
x_max: Scalar,
y_max: Scalar,
}
type Scalar = f64;
impl Geometry {
/// Make a new rectangle with coordinates in percentage units of the
/// containing document.
pub fn new(x_min: Scalar, y_min: Scalar, x_max: Scalar, y_max: Scalar) -> Self {
Self {
x_min,
y_min,
x_max,
y_max,
}
}
/// Total width of the rectangle in percentage points
pub fn width(&self) -> Scalar {
(self.x_max - self.x_min).abs()
}
/// Total height of the rectangle in percentage points
pub fn height(&self) -> Scalar {
(self.y_max - self.y_min).abs()
}
/// Usable in IIIF URL queries.
pub fn to_iiif_string(&self) -> String {
format!(
"pct:{},{},{},{}",
self.x_min,
self.y_min,
self.width(),
self.height()
)
}
/// Usable in IIIF API calls.
pub fn to_selector_string(&self) -> String {
format!(
"xywh={},{},{},{}",
self.x_min,
self.y_min,
self.width(),
self.height()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iiif_string() {
let g = Geometry::new(90.0, 91.0, 100.0, 99.0);
let s = g.to_iiif_string();
assert_eq!(s, "pct:90,91,10,8");
}
}