mod trait_impl;
use crate::{HronnError, HronnError::InternalError};
use std::{fs::File, io::Write};
use vector_traits::prelude::HasXYZ;
#[derive(Clone, Debug)]
pub enum StrategyResult<MESH: HasXYZ> {
MeshData(MeshData<MESH>),
LineData(LineData<MESH>),
}
#[derive(Clone, Debug)]
pub struct MeshData<MESH: HasXYZ> {
pub vertices: Vec<MESH>,
pub indices: Vec<u32>,
}
#[derive(Clone, Debug)]
pub struct LineData<MESH: HasXYZ> {
pub vertices: Vec<MESH>,
pub lines: Vec<Vec<u32>>,
}
impl<MESH: HasXYZ> StrategyResult<MESH> {
pub fn get_line_data(self) -> Result<LineData<MESH>, HronnError> {
if let StrategyResult::LineData(linedata) = self {
Ok(linedata)
} else {
Err(InternalError(
"Wrong kind of data container found".to_string(),
))
}
}
pub fn get_mesh_data(self) -> Result<MeshData<MESH>, HronnError> {
if let StrategyResult::MeshData(meshdata) = self {
Ok(meshdata)
} else {
Err(InternalError(
"Wrong kind of data container found".to_string(),
))
}
}
}
impl<MESH: HasXYZ> MeshData<MESH> {
pub fn new(vertices: Vec<MESH>, indices: Vec<u32>) -> Self {
Self { vertices, indices }
}
pub fn add_vertex(&mut self, p0: MESH) -> usize {
self.vertices.push(p0);
self.vertices.len() - 1
}
pub fn add_triangle(&mut self, p0: u32, p1: u32, p2: u32) {
self.indices.push(p0);
self.indices.push(p1);
self.indices.push(p2);
}
pub fn add_triangle_as_vertices(&mut self, p0: MESH, p1: MESH, p2: MESH) {
let index = self.vertices.len() as u32;
self.vertices.push(p0);
self.vertices.push(p1);
self.vertices.push(p2);
self.indices.push(index);
self.indices.push(index + 1);
self.indices.push(index + 2);
}
pub fn save_as_obj(
&self,
filename: &std::path::Path,
obj_name: &str,
) -> Result<(), HronnError> {
let mut file = File::create(filename)?;
if self.vertices.is_empty() {
return Ok(());
}
let max_index = (self.vertices.len() - 1) as u32;
writeln!(file, "o {obj_name}")?;
for vertex in &self.vertices {
writeln!(
file,
"v {:+e} {:+e} {:+e}",
vertex.x(),
vertex.y(),
vertex.z()
)?;
}
for face in self.indices.chunks(3) {
write!(file, "f ")?;
for element in face {
if element > &max_index {
return Err(InternalError(format!(
"the vertex index was too high {element} > {max_index}"
)));
}
write!(file, "{} ", element + 1)?;
}
writeln!(file)?;
}
Ok(())
}
}
impl<MESH: HasXYZ> LineData<MESH> {
pub fn add_vertex(&mut self, p0: MESH) -> u32 {
let index = self.vertices.len() as u32;
self.vertices.push(p0);
index
}
pub fn continue_line(&mut self, point: MESH) {
if self.lines.is_empty() {
self.start_new_line(point);
} else {
let index = self.add_vertex(point);
self.lines.last_mut().unwrap().push(index);
}
}
pub fn close_line(&mut self) {
if self.lines.is_empty() {
if let Some(first_index) = self.lines.first().unwrap().first().cloned() {
self.lines.last_mut().unwrap().push(first_index);
}
}
}
pub fn start_new_line(&mut self, point: MESH) {
self.lines.push(Vec::new());
let index = self.add_vertex(point);
self.lines.last_mut().unwrap().push(index);
}
pub fn save_as_obj(
&self,
filename: &std::path::Path,
obj_name: &str,
) -> Result<(), HronnError> {
let mut file = File::create(filename)?;
if self.vertices.is_empty() {
return Ok(());
}
let max_index = (self.vertices.len() - 1) as u32;
writeln!(file, "o {obj_name}")?;
for vertex in &self.vertices {
writeln!(file, "v {} {} {}", vertex.x(), vertex.y(), vertex.z())?;
}
for line in &self.lines {
if !line.is_empty() {
for window in line.windows(2) {
match window {
[a, b] => {
assert!(
a <= &max_index,
"the vertex index was too high {a} > {max_index}",
);
assert!(
b <= &max_index,
"the vertex index was too high {b} > {max_index}",
);
writeln!(file, "f {} {}", a + 1, b + 1)?;
}
_ => unreachable!(),
}
}
}
}
Ok(())
}
}