Skip to content

Commit

Permalink
Merge pull request #599 from chrisprice/support-emf-feedback
Browse files Browse the repository at this point in the history
Improve error handling in `fj_export`
  • Loading branch information
hannobraun authored May 18, 2022
2 parents 59953d0 + c1ed3f0 commit 983ed76
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/fj-export/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories = ["encoding", "mathematics", "rendering"]


[dependencies]
anyhow = "1.0.57"
thiserror = "1.0.31"
threemf = "0.3.0"
stl = "0.2.1"

Expand Down
66 changes: 40 additions & 26 deletions crates/fj-export/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,33 @@

use std::{fs::File, path::Path};

use anyhow::{anyhow, Result};
use thiserror::Error;

use fj_interop::mesh::Mesh;
use fj_math::{Point, Triangle, Vector};
use fj_math::{Point, Triangle};

/// Export the provided mesh to the file at the given path.
///
/// This function will create a file if it does not exist, and will truncate it if it does.
///
/// Currently 3MF & STL file types are supported. The case insensitive file extension of
/// the provided path is used to switch between supported types.
pub fn export(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {
pub fn export(mesh: &Mesh<Point<3>>, path: &Path) -> Result<(), Error> {
match path.extension() {
Some(extension) if extension.to_ascii_uppercase() == "3MF" => {
export_3mf(mesh, path)
}
Some(extension) if extension.to_ascii_uppercase() == "STL" => {
export_stl(mesh, path)
}
Some(extension) => {
Err(anyhow!("Extension not recognised, got {:?}", extension))
}
None => Err(anyhow!("No extension specified")),
Some(extension) => Err(Error::InvalidExtension(
extension.to_str().map(|s| s.to_string()),
)),
None => Err(Error::NoExtension),
}
}

fn export_3mf(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {
fn export_3mf(mesh: &Mesh<Point<3>>, path: &Path) -> Result<(), Error> {
let vertices = mesh.vertices().map(|vertex| vertex.into()).collect();

let indices: Vec<_> = mesh.indices().collect();
Expand All @@ -67,34 +67,21 @@ fn export_3mf(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {
Ok(())
}

fn export_stl(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {
fn export_stl(mesh: &Mesh<Point<3>>, path: &Path) -> Result<(), Error> {
let points = mesh
.triangles()
.map(|triangle| triangle.points)
.collect::<Vec<_>>();

let vertices = points.iter().map(|points| {
points.map(|point| {
[point.x.into_f32(), point.y.into_f32(), point.z.into_f32()]
})
points.map(|point| point.coords.components.map(|s| s.into_f32()))
});

let normals = points
.iter()
.map(|&points| points.into())
.map(|triangle: Triangle<3>| triangle.to_parry().normal())
.collect::<Option<Vec<_>>>()
.ok_or_else(|| anyhow!("Unable to compute normal"))?;

let normals = normals.iter().map(|vector| vector.into_inner().into()).map(
|vector: Vector<3>| {
[
vector.x.into_f32(),
vector.y.into_f32(),
vector.z.into_f32(),
]
},
);
.map(|triangle: Triangle<3>| triangle.normal())
.map(|vector| vector.components.map(|s| s.into_f32()));

let triangles = vertices
.zip(normals)
Expand All @@ -112,7 +99,10 @@ fn export_stl(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {
let binary_stl_file = stl::BinaryStlFile {
header: stl::BinaryStlHeader {
header: [0u8; 80],
num_triangles: triangles.len().try_into()?,
num_triangles: triangles
.len()
.try_into()
.map_err(|_| Error::InvalidTriangleCount)?,
},
triangles,
};
Expand All @@ -121,3 +111,27 @@ fn export_stl(mesh: &Mesh<Point<3>>, path: &Path) -> Result<()> {

Ok(())
}

/// An error that can occur while exporting
#[derive(Debug, Error)]
pub enum Error {
/// No extension specified
#[error("no extension specified")]
NoExtension,

/// Unrecognised extension found `{0:?}`
#[error("unrecognised extension found `{0:?}`")]
InvalidExtension(Option<String>),

/// I/O error whilst exporting to file
#[error("I/O error whilst exporting to file")]
Io(#[from] std::io::Error),

/// Maximum triangle count exceeded
#[error("maximum triangle count exceeded")]
InvalidTriangleCount,

/// Threemf error whilst exporting to 3MF file
#[error("threemf error whilst exporting to 3MF file")]
ThreeMF(#[from] threemf::Error),
}

0 comments on commit 983ed76

Please sign in to comment.