#![cfg(feature = "application")]
use axiolid::application::ApplicationBuilder;
use axiolid::contracts::{
capability_ids, CapabilityRequirement, Exactness, ExecutionOptions, Representation,
};
use axiolid::core::{BooleanOperator, Point3, Ray3, Tolerance, Vec3};
use axiolid::mesh::TriMesh;
use axiolid::profile::{Profile, RectangleProfile};
fn cube(min: [f64; 3], max: [f64; 3]) -> TriMesh {
let [x0, y0, z0] = min;
let [x1, y1, z1] = max;
let positions = vec![
Point3::new(x0, y0, z0),
Point3::new(x1, y0, z0),
Point3::new(x1, y1, z0),
Point3::new(x0, y1, z0),
Point3::new(x0, y0, z1),
Point3::new(x1, y0, z1),
Point3::new(x1, y1, z1),
Point3::new(x0, y1, z1),
];
let indices = vec![
0, 2, 1, 0, 3, 2, 4, 5, 6, 4, 6, 7, 0, 1, 5, 0, 5, 4, 1, 2, 6, 1, 6, 5, 2, 3, 7, 2, 7, 6,
3, 0, 4, 3, 4, 7,
];
TriMesh::new(positions, indices)
}
#[test]
fn portable_application_executes_the_reference_workflows() {
let application = ApplicationBuilder::new()
.with_portable_boolean()
.expect("boolmesh passes registration conformance")
.with_portable_section()
.expect("scalar section passes registration conformance")
.build();
let tolerance = Tolerance::new(1.0e-9, 1.0e-12).expect("valid tolerance");
let options = ExecutionOptions::new(tolerance);
let subject = cube([0.0, 0.0, 0.0], [2.0, 2.0, 2.0]);
let tool = cube([1.0, 1.0, 0.5], [3.0, 3.0, 1.5]);
let health = application
.validate_mesh(&subject, tolerance)
.expect("mesh audit");
assert!(health.is_closed_two_manifold());
let measurements = application
.measure_mesh(&subject, tolerance)
.expect("measurement");
assert!((measurements.volume.signed_volume - 8.0).abs() < 1.0e-10);
let difference = application
.boolean(&subject, &tool, BooleanOperator::Difference, &options)
.expect("boolean difference");
assert!(!difference.mesh.indices.is_empty());
let batched = application
.subtract_many(&subject, std::slice::from_ref(&tool), &options)
.expect("batched subtraction");
assert!(!batched.mesh.indices.is_empty());
let ray = Ray3 {
origin: Point3::new(-1.0, 1.0, 1.0),
direction: Vec3::X,
};
let hit = application
.nearest_mesh_hit(&subject, &ray, tolerance)
.expect("spatial query")
.expect("ray intersects cube");
assert!((hit.point.x - 0.0).abs() < 1.0e-10);
let profile = Profile::Rectangle(RectangleProfile {
x: 2.0,
y: 3.0,
thickness: None,
outer_radius: None,
inner_radius: None,
});
let exact = application
.extrude_profile_exact(&profile, Vec3::Z, 4.0, tolerance)
.expect("exact rectangle extrusion");
assert!(!exact.topology().faces().is_empty());
}
#[test]
fn descriptor_reports_selected_providers_and_exactness() {
let application = ApplicationBuilder::new()
.with_portable_boolean()
.expect("conformant provider")
.with_portable_section()
.expect("scalar section passes registration conformance")
.build();
let descriptor = application.descriptor();
let mesh_boolean = descriptor
.require(CapabilityRequirement {
id: capability_ids::MESH_BOOLEAN,
output: Representation::TriangleMesh,
exactness: Exactness::ToleranceBounded,
deterministic: true,
})
.expect("mesh boolean advertised");
assert_eq!(mesh_boolean.provider.as_str(), "boolmesh");
descriptor
.require(CapabilityRequirement {
id: capability_ids::EXACT_EXTRUDE,
output: Representation::ExactBrep,
exactness: Exactness::Exact,
deterministic: true,
})
.expect("exact extrusion advertised");
}