1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4fn valid_homogeneous_coordinates(coordinates: &[f64]) -> bool {
5 !coordinates.is_empty()
6 && coordinates.iter().all(|coordinate| coordinate.is_finite())
7 && coordinates.iter().any(|coordinate| *coordinate != 0.0)
8}
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct ProjectivePoint {
13 coordinates: Vec<f64>,
14}
15
16impl ProjectivePoint {
17 #[must_use]
19 pub fn new(coordinates: Vec<f64>) -> Option<Self> {
20 if valid_homogeneous_coordinates(&coordinates) {
21 Some(Self { coordinates })
22 } else {
23 None
24 }
25 }
26
27 #[must_use]
29 pub fn coordinates(&self) -> &[f64] {
30 &self.coordinates
31 }
32
33 #[must_use]
35 pub fn dimension(&self) -> usize {
36 self.coordinates.len() - 1
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub struct ProjectiveLine {
43 coefficients: Vec<f64>,
44}
45
46impl ProjectiveLine {
47 #[must_use]
49 pub fn new(coefficients: Vec<f64>) -> Option<Self> {
50 if valid_homogeneous_coordinates(&coefficients) {
51 Some(Self { coefficients })
52 } else {
53 None
54 }
55 }
56
57 #[must_use]
59 pub fn coefficients(&self) -> &[f64] {
60 &self.coefficients
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct ProjectivePlane {
67 order: Option<usize>,
68}
69
70impl ProjectivePlane {
71 #[must_use]
73 pub const fn new(order: Option<usize>) -> Self {
74 Self { order }
75 }
76
77 #[must_use]
79 pub const fn order(self) -> Option<usize> {
80 self.order
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::{ProjectiveLine, ProjectivePlane, ProjectivePoint};
87
88 #[test]
89 fn validates_projective_coordinates() {
90 let point = ProjectivePoint::new(vec![1.0, 2.0, 1.0]).expect("valid point");
91 let line = ProjectiveLine::new(vec![1.0, -1.0, 0.0]).expect("valid line");
92 let plane = ProjectivePlane::new(Some(2));
93
94 assert_eq!(point.dimension(), 2);
95 assert_eq!(point.coordinates(), &[1.0, 2.0, 1.0]);
96 assert_eq!(line.coefficients(), &[1.0, -1.0, 0.0]);
97 assert_eq!(plane.order(), Some(2));
98 assert_eq!(ProjectivePoint::new(vec![0.0, 0.0]), None);
99 }
100}