#![deny(
rust_2018_compatibility,
rust_2018_idioms,
rust_2021_compatibility,
nonstandard_style,
unused,
future_incompatible,
non_camel_case_types,
unused_parens,
non_upper_case_globals,
unused_qualifications,
unused_results,
unused_imports,
unused_variables,
bare_trait_objects,
ellipsis_inclusive_range_patterns,
elided_lifetimes_in_paths
)]
#![warn(clippy::explicit_into_iter_loop)]
use crate::prelude::ConvertTo;
use linestring::linestring_2d::convex_hull;
use vector_traits::num_traits::real::Real;
use vector_traits::prelude::{Aabb2, GenericScalar, GenericVector2, GenericVector3, HasXYZ};
#[doc(hidden)]
#[cfg(feature = "debug_probe_code")]
pub mod debug_access;
mod geo;
mod impls;
mod meshanalyzer;
#[doc(hidden)]
pub mod obj;
pub(crate) mod probe;
mod searchpattern;
mod strategyresult;
mod triangulation;
mod util;
pub mod prelude {
pub use crate::{
HronnError, ProbeMode, generate_aabb_then_convex_hull, generate_convex_hull_then_aabb,
geo::{Circle, ConvertTo, RigidTransform2D},
meshanalyzer::{MeshAnalyzer, MeshAnalyzerBuilder, SearchResult},
obj::Obj,
probe::SkipEndpoint,
probe::{BallNoseProbe, Probe, SquareEndProbe, TaperedProbe},
searchpattern::{
AdaptiveSearchConfig, SearchPattern, SearchPatternConfig,
meanderpattern::MeanderPattern, triangulatepattern::TriangulatePattern,
},
strategyresult::{LineData, MeshData, StrategyResult},
triangulation::triangulate_vertices,
util::MaximumTracker,
};
}
#[doc(hidden)]
pub const EPSILON: f64 = 1e-10;
#[doc(hidden)]
#[derive(thiserror::Error, Debug)]
pub enum HronnError {
#[error(transparent)]
KrakelErrr(#[from] krakel::KrakelError),
#[error(transparent)]
LinestringError(#[from] linestring::LinestringError),
#[error(transparent)]
SpaceInsertionError(#[from] spade::InsertionError),
#[error("Could not parse float value.")]
ParseFloatError,
#[error("The vertex indices does not match {0}")]
MismatchedIndex(String),
#[error("Your line-strings are self-intersecting: {0}")]
SelfIntersectingData(String),
#[error("The input data is not 2D: {0}")]
InputNotPLane(String),
#[error("Invalid data: {0}")]
InvalidData(String),
#[error("Aabb error: {0}")]
AabbError(String),
#[error("Transform error: {0}")]
TransformError(String),
#[error("Invalid input data: {0}")]
InvalidParameter(String),
#[error("Missing input data: {0}")]
NoData(String),
#[error("Obj file not triangulated: {0}")]
NotTriangulated(String),
#[error("Missing parameter: {0}")]
MissingParameter(String),
#[error("Mismatched MeshAnalyzer: {0}")]
Mismatch(String),
#[error("Unknown error: {0}")]
InternalError(String),
#[error(transparent)]
IoError(#[from] std::io::Error),
}
#[doc(hidden)]
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum ProbeMode {
SplitTriangles,
OriginalTriangles,
BruteForce,
}
#[doc(hidden)]
#[inline(always)]
pub fn m_factor_from_plane_unit_normal<T: GenericVector3>(unit_norm: T) -> T::Scalar {
let m_sq = (unit_norm.x().powi(2) + unit_norm.y().powi(2)) / unit_norm.z().abs().powi(2);
(T::Scalar::ONE + m_sq).sqrt()
}
#[doc(hidden)]
#[inline(always)]
pub fn m_from_plane_unit_normal<T: GenericVector3>(unit_vector: T) -> T::Scalar {
(unit_vector.x().powi(2) + unit_vector.y().powi(2)).sqrt() / unit_vector.z().abs()
}
#[allow(dead_code)]
#[derive(PartialEq, PartialOrd, Debug, Clone)]
struct GradientAndT {
gradient: f64,
t: f64,
}
#[doc(hidden)]
#[inline(always)]
fn is_inside_2d_triangle<T: GenericVector2>(q: T, p0: T, p1: T, p2: T) -> bool {
let orientation01 = (p1 - p0).perp_dot(q - p0);
let orientation12 = (p2 - p1).perp_dot(q - p1);
let orientation20 = (p0 - p2).perp_dot(q - p2);
orientation01 >= T::Scalar::ZERO
&& orientation12 >= T::Scalar::ZERO
&& orientation20 >= T::Scalar::ZERO
|| (orientation01 <= T::Scalar::ZERO
&& orientation12 <= T::Scalar::ZERO
&& orientation20 <= T::Scalar::ZERO)
}
#[doc(hidden)]
pub fn triangle_normal<T: GenericVector3>(p0: T, p1: T, p2: T) -> T {
let n = (p1.sub(p0)).cross(p2.sub(p0));
if n.z() < T::Scalar::ZERO { n.neg() } else { n }
}
#[doc(hidden)]
pub fn generate_convex_hull_then_aabb<T: GenericVector2, MESH>(
point_cloud: &[MESH],
) -> Result<(<T as GenericVector2>::Aabb, Vec<T>), HronnError>
where
MESH: HasXYZ,
MESH: ConvertTo<T::Vector3>,
{
let mut aabb = <T as GenericVector2>::Aabb::default();
let point_cloud: Vec<T> = point_cloud
.iter()
.map(|v| {
let v = v.to().to_2d();
aabb.add_point(v);
v
})
.collect();
let convex_hull = convex_hull::graham_scan(&point_cloud)?;
Ok((aabb, convex_hull))
}
#[doc(hidden)]
pub fn generate_aabb_then_convex_hull<T: GenericVector2, MESH>(
point_cloud: &[MESH],
) -> Result<(<T as GenericVector2>::Aabb, Vec<T>), HronnError>
where
MESH: HasXYZ,
MESH: ConvertTo<T::Vector3>,
{
let mut aabb = <T as GenericVector2>::Aabb::default();
for v in point_cloud {
let v = v.to().to_2d();
aabb.add_point(v);
}
if aabb.is_empty() {
return Err(HronnError::InvalidData(
"No data found for convex hull".to_string(),
));
}
Ok((aabb, aabb.convex_hull()))
}