diff --git a/crates/solidcore/src/query/brep.rs b/crates/solidcore/src/query/brep.rs index f640885cb..abde0a1ed 100644 --- a/crates/solidcore/src/query/brep.rs +++ b/crates/solidcore/src/query/brep.rs @@ -79,6 +79,7 @@ mod ray; +pub(crate) use ray::solve_mutable_brep_point; #[cfg(test)] pub(crate) use ray::PreparationRequest; pub use ray::RayPreparation; @@ -453,7 +454,7 @@ impl<'a> BrepQuery<'a> { tolerance, None, |b, point, options| { - ray::solve_mutable_brep_point(k, b, &self.identity, cache, point, options) + solve_mutable_brep_point(k, b, &self.identity, cache, point, options) }, ) } @@ -511,30 +512,39 @@ impl<'a> BrepQuery<'a> { // Intersect the point with the boundary elements of the Brep if do_boundary_intersections { - let b = target.shared(); - let objects = BrepObjects { - preparation: None, - brep: b, - brep_id, - cache: Some(self.cache(k, b)?), - keys, - owner_of, + let options = TopologySolveOptions { + operation: SolverOperation::Intersect, + requested: SolutionRequested::Single, + tolerance_3d: point_zone_tol_3d, + best_answer_so_far_sq: 0.0, + opt_vectors: &[], }; // XSects point with the Brep verts, edges, and faces returning lowest dim // topology intersection found. - let solutions = TopologySolver::brep_point_solve( - k, - &objects, - Some(CacheObject::Brep), - point, - TopologySolveOptions { - operation: SolverOperation::Intersect, - requested: SolutionRequested::Single, - tolerance_3d: point_zone_tol_3d, - best_answer_so_far_sq: 0.0, - opt_vectors: &[], - }, - )?; + let solutions = match &mut target { + Target::Own(b) => { + let cache = self.cache(k, b)?; + solve_mutable_brep_point(k, b, &self.identity, cache, point, options)? + } + Target::Shared { .. } => { + let b = target.shared(); + let objects = BrepObjects { + preparation: None, + brep: b, + brep_id, + cache: Some(self.cache(k, b)?), + keys, + owner_of, + }; + TopologySolver::brep_point_solve( + k, + &objects, + Some(CacheObject::Brep), + point, + options, + )? + } + }; // when the point is on a Brep Face if let Some(sol) = solutions.get(0) { @@ -1128,6 +1138,59 @@ mod tests { assert_eq!(format!("{b:?}"), before); } + /// A unit box from `create_box` without its UV trims (upstream's classification + /// makes the ones its loop walks reach), and a query under the box's own keys + /// (`notify_ref`, as `create_box` owns its geometry). + fn box_without_trims(k: &mut Kernel) -> (Brep, BrepQuery<'static>) { + fn keys(o: CacheObject) -> ObjectRef { + use crate::topology::loopuse::notify_ref; + match o { + CacheObject::Edge(e) | CacheObject::Curve(e) => notify_ref(EntityRef::Edge(e)), + CacheObject::Face(f) | CacheObject::Surface(f) => notify_ref(EntityRef::Face(f)), + CacheObject::Vertex(v) => notify_ref(EntityRef::Vertex(v)), + _ => notify_ref(EntityRef::Brep(BrepId::from_index(0))), + } + } + fn no_owner(_: ObjectRef) -> Option { + None + } + let mut b = + crate::primitive::api_primitives::create_box(k, Point3::ZERO, 1.0, 1.0, 1.0).unwrap(); + let uses: Vec<_> = b.edgeuses().ids().collect(); + for u in uses { + b.edgeuse_mut(u).unwrap().uv_trim_curve = None; + } + let query = BrepQuery::new(BrepIdentity { + brep_id: BrepId::from_index(0), + keys: &keys, + owner_of: &no_owner, + }); + (b, query) + } + + fn trim_count(b: &Brep) -> usize { + b.edgeuses() + .iter() + .filter(|(_, u)| u.uv_trim_curve.is_some()) + .count() + } + + #[test] + fn ray_fires_make_missing_uv_trims_on_the_callers_brep() { + let mut k = Kernel::default(); + let (mut b, query) = box_without_trims(&mut k); + let solid = b + .regions() + .ids() + .find(|&r| Some(r) != b.infinite_region()) + .map(EntityRef::Region); + let inside = query + .point_3d_classify(&k, &mut b, Point3::new(0.5, 0.5, 0.5), 1e-6, false) + .unwrap(); + assert_eq!(inside.object(), solid); + assert!(trim_count(&b) > 0, "the trims are made on the box itself"); + } + #[test] fn lazy_brep_edits_the_callers_brep_or_a_copy() { let mut b = Brep::new(); diff --git a/crates/solidcore/src/topology/brep/p2.rs b/crates/solidcore/src/topology/brep/p2.rs index 3829d927e..560fe4889 100644 --- a/crates/solidcore/src/topology/brep/p2.rs +++ b/crates/solidcore/src/topology/brep/p2.rs @@ -91,7 +91,6 @@ use crate::intersect::curve_class::ClassificationInit; use crate::intersect::point_class::{ ClassGeometry, ClassObject, PointClassType, PointClassification, }; -use crate::intersect::topology_solver::p1::TopologySolver; use crate::intersect::topology_solver::p2::TopologySolveOptions; use crate::kernel::Kernel; use crate::math::{Point2, Point3, Vec3, BIG_DOUBLE, EFF_ZERO, EFF_ZERO_SQRT, PI}; @@ -105,7 +104,7 @@ use crate::query::face::p2::{curve_on_classify, CurveOnClassifyObjects}; use crate::surface::surface::{Surface, SurfaceKind}; use crate::surface::trim_srf_cache::TrimSrfCache; use crate::topology::brep::p1; -use crate::topology::brep_cache::{self, BrepCache, BrepObjects, CacheObject, CacheSource}; +use crate::topology::brep_cache::{self, BrepCache, CacheObject, CacheSource}; use crate::topology::edge::{self, AttributeFilter, NotifyEnv, SetCurveOptions}; use crate::topology::edgeuse::p1::{self as eu1, UvTrimCurveArg}; use crate::topology::edgeuse::p2 as eu2; @@ -1347,15 +1346,12 @@ pub fn ray_fire( ray_zone_tol_3d, answer_limit, |b, point, options| { - let objects = BrepObjects { - preparation: None, - brep: b, + let identity = crate::query::brep::BrepIdentity { brep_id, - cache: Some(cache), keys, owner_of, }; - TopologySolver::brep_point_solve(k, &objects, Some(CacheObject::Brep), point, options) + crate::query::brep::solve_mutable_brep_point(k, b, &identity, cache, point, options) }, ) }