Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions crates/difftest/src/units/boolean_merge_p1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,16 +923,17 @@ fn run_rust(i: &Inputs, b: &mut Brep, other: &Brep) -> Result<Vec<f64>, SolidErr
7 => {
let mut other = other.clone();
// The native probe constructs and immediately destroys its shift.
let transform = |_: &mut Brep, _: bool, _: &_, _: Option<_>, _: bool| {
// UNPORTED(topology.brep_p5): SmBrep::Transform
Err(SolidError::unported(
"SmBrep::Transform",
"topology.brep_p5",
))
};
port::temporary_brep_transform(&k, &k, b, &other)?
.apply(b, &mut other, transform)?
.restore(Some(b), Some(&mut other), transform)?;
let shift = port::temporary_brep_transform(&k, &k, b, &other)?;
// SmBrep::Transform, both operands in the one kernel
let mut transform =
|brep: &mut Brep, _: bool, xfm: &_, scale: Option<_>, scale_tol: bool| {
solidcore::topology::brep::p5::transform(&mut k, brep, xfm, scale, scale_tol)
};
shift.apply(b, &mut other, &mut transform)?.restore(
Some(b),
Some(&mut other),
&mut transform,
)?;
}
8 | 9 => {
let sec = EdgeuseId::from_index(u32::from(a) % b.edgeuses().len() as u32);
Expand Down
133 changes: 101 additions & 32 deletions crates/difftest/src/units/boolean_topology_intersector_p3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
//! Both sides produce one flat record: the pre-relation statuses, the merge's status
//! and outputs (only on success: the port returns none with an error), then the state
//! (counts, every vertex and edge tolerance, and the vertex, edge and face mates sorted
//! by handle). Handles are the p1 runner's `brep kind index` triples.
//! by handle). Handles are the p1 runner's `brep kind index` triples, numbered after the
//! merge by both sides' re-walk of the B-reps (the shim's `walk_all`, `Walk` here), so
//! records the merge deleted (kept unlinked in the Rust arena) are unknown on both.
//!
//! **Selectors.** Generated handles are selectors taken modulo the entity count of
//! their kind; classification parameters are fractions of the classified edge's
Expand Down Expand Up @@ -55,7 +57,9 @@ use solidcore::topology::edgeuse::p1 as eu1;
use solidcore::topology::face::p4 as fp4;
use solidcore::topology::loopuse as lu;
use solidcore::topology::proto_topology::ProtoBrep;
use solidcore::topology::{Brep, EdgeId, EdgeuseId, FaceuseId, LoopuseId, VertexId, VertexuseId};
use solidcore::topology::{
Brep, EdgeId, EdgeuseId, FaceId, FaceuseId, LoopuseId, VertexId, VertexuseId,
};
use solidcore::{EntityRef, SolidError};
use solidcore_ffi::units::boolean_topology_intersector_p1 as ffi1;
use solidcore_ffi::units::boolean_topology_intersector_p3::{self as ffi, Op};
Expand All @@ -65,6 +69,7 @@ use super::boolean_topology_intersector_p1::{
Two, H, K_BREP, K_EDGE, K_EDGE_CURVE, K_FACE, K_FACE_SURFACE, K_NULL, K_TRIM_CURVE, K_VERTEX,
NULL_DEREF, TI_HANDLE,
};
use super::boolean_merge_p1::Canon;
use super::topology_vertexuse::import;
use crate::case::{CaseContext, CaseSource};
use crate::runner::default_cases;
Expand Down Expand Up @@ -491,10 +496,58 @@ fn status<T>(r: Result<T, SolidError>, o: &mut Vec<f64>) -> Result<Option<T>, So
}
}

fn put_list(o: &mut Vec<f64>, hs: &[H]) {
fn put_list(o: &mut Vec<f64>, walk: &Walk, hs: &[H]) {
o.push(hs.len() as f64);
for &h in hs {
put_h(o, Some(h));
walk.put(o, Some(h));
}
}

/// The shim's `walk_all` after the merge: both B-reps re-walked
/// ([`Canon::reachable`], the shim's `walk`), so a vertex, edge or face handle (and an
/// edge curve's or face surface's) is its position in that walk, and a record the merge
/// deleted (unlinked, but kept in the Rust arena) is unknown, `-1 -3 -1`, as a deleted
/// object upstream. Without deletions the walk is the import order (the identity).
struct Walk([Option<Canon>; 2]);

impl Walk {
fn of(two: &Two) -> Self {
Self([0i8, 1].map(|b| two.brep(brep_h(b)).map(Canon::reachable)))
}

/// The post-merge triple of `h` (see [`Walk`]).
fn triple(&self, h: Option<H>) -> [f64; 3] {
let mut o = Vec::with_capacity(3);
self.put(&mut o, h);
[
o.first().copied().unwrap_or(-1.0),
o.get(1).copied().unwrap_or(-3.0),
o.get(2).copied().unwrap_or(-1.0),
]
}

fn put(&self, o: &mut Vec<f64>, h: Option<H>) {
let Some(h) = h else {
put_h(o, None);
return;
};
let canon = usize::try_from(h.b)
.ok()
.and_then(|b| self.0.get(b))
.and_then(Option::as_ref);
let at = match (canon, h.kind) {
(Some(c), K_VERTEX) => c.vertices.of(Some(VertexId::from_index(h.i))),
(Some(c), K_EDGE | K_EDGE_CURVE) => c.edges.of(Some(EdgeId::from_index(h.i))),
(Some(c), K_FACE | K_FACE_SURFACE) => c.faces.of(Some(FaceId::from_index(h.i))),
_ => {
put_h(o, Some(h));
return;
}
};
match u32::try_from(at) {
Ok(i) => put_h(o, Some(hd(h.b, h.kind, i))),
Err(_) => o.extend([-1.0, -3.0, -1.0]),
}
}
}

Expand Down Expand Up @@ -575,50 +628,63 @@ fn new_class(k: &Kernel, c: &ClassR) -> Result<CurveClassification<H>, SolidErro
Ok(cc)
}

fn put_class_out(o: &mut Vec<f64>, cc: &CurveClassification<H>) -> Result<(), SolidError> {
fn put_class_out(
o: &mut Vec<f64>,
walk: &Walk,
cc: &CurveClassification<H>,
) -> Result<(), SolidError> {
o.push(cc.size() as f64);
for i in 0..cc.size() {
let ivl = cc.at(i)?;
o.push(ivl.interval.min());
o.push(ivl.interval.max());
for pc in [&ivl.start, &ivl.mid, &ivl.end] {
o.push(f64::from(pc.point_class().code()));
put_h(o, pc.object());
walk.put(o, pc.object());
}
}
Ok(())
}

/// The state after the merge (see the module docs).
fn put_state(o: &mut Vec<f64>, two: &Two, ti: &TopologyIntersector<H>) -> Result<(), SolidError> {
/// The state after the merge (see the module docs), in the post-merge walk ([`Walk`]):
/// the records it reaches, in its order; mates sorted by their post-merge handles.
fn put_state(
o: &mut Vec<f64>,
two: &Two,
walk: &Walk,
ti: &TopologyIntersector<H>,
) -> Result<(), SolidError> {
for b in 0..2i8 {
let Some(br) = two.brep(brep_h(b)) else {
let canon = usize::try_from(b).ok().and_then(|i| walk.0.get(i));
let (Some(br), Some(Some(c))) = (two.brep(brep_h(b)), canon) else {
o.extend([0.0, 0.0, 0.0]);
continue;
};
o.push(br.vertices().len() as f64);
o.push(br.edges().len() as f64);
o.push(br.faces().len() as f64);
for v in 0..br.vertices().len() {
let id = VertexId::from_index(u32::try_from(v).unwrap_or(u32::MAX));
o.push(br.vertex(id)?.tolerance);
o.push(c.vertices.items.len() as f64);
o.push(c.edges.items.len() as f64);
o.push(c.faces.items.len() as f64);
for &v in &c.vertices.items {
o.push(br.vertex(v)?.tolerance);
}
for e in 0..br.edges().len() {
let id = EdgeId::from_index(u32::try_from(e).unwrap_or(u32::MAX));
o.push(br.edge(id)?.tolerance);
for &e in &c.edges.items {
o.push(br.edge(e)?.tolerance);
}
}
for kind in [
ClassObjectKind::Vertex,
ClassObjectKind::Edge,
ClassObjectKind::Face,
] {
let mut objs = ti.mapped_brep_objects(kind)?;
objs.sort();
let mut objs: Vec<_> = ti
.mapped_brep_objects(kind)?
.into_iter()
.map(|h| (walk.triple(Some(h)), walk.triple(ti.other_mate(Some(h)))))
.collect();
objs.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
o.push(objs.len() as f64);
for h in objs {
put_h(o, Some(h));
put_h(o, ti.other_mate(Some(h)));
for (h, mate) in objs {
o.extend(h);
o.extend(mate);
}
}
Ok(())
Expand Down Expand Up @@ -702,9 +768,10 @@ fn run_rust_merge(i: &Inputs, p: Prepared) -> Result<Vec<f64>, SolidError> {
};
let r = ti.merge_curve_on_surfaces(&mut k, &mut two, &input);
if let Some(m) = status(r, &mut o)? {
let walk = Walk::of(&two);
o.push(flag(m.deleted_topology));
put_list(&mut o, &m.deleted_edges.unwrap_or_default());
put_list(&mut o, &m.deleted_vertices.unwrap_or_default());
put_list(&mut o, &walk, &m.deleted_edges.unwrap_or_default());
put_list(&mut o, &walk, &m.deleted_vertices.unwrap_or_default());
}
}
MergeR::CurveClasses {
Expand All @@ -722,11 +789,12 @@ fn run_rust_merge(i: &Inputs, p: Prepared) -> Result<Vec<f64>, SolidError> {
let r =
ti.merge_curve_classes(&mut k, &mut two, &mut cc1, &mut cc2, merge_singularities);
if let Some(m) = status(r, &mut o)? {
let walk = Walk::of(&two);
o.push(flag(m.topology_was_deleted));
put_list(&mut o, &m.deleted_edges.unwrap_or_default());
put_list(&mut o, &m.deleted_vertices.unwrap_or_default());
put_class_out(&mut o, &cc1)?;
put_class_out(&mut o, &cc2)?;
put_list(&mut o, &walk, &m.deleted_edges.unwrap_or_default());
put_list(&mut o, &walk, &m.deleted_vertices.unwrap_or_default());
put_class_out(&mut o, &walk, &cc1)?;
put_class_out(&mut o, &walk, &cc2)?;
}
}
MergeR::CoincidentSurfaces { s1, s2 } => {
Expand All @@ -741,12 +809,13 @@ fn run_rust_merge(i: &Inputs, p: Prepared) -> Result<Vec<f64>, SolidError> {
}
let r = ti.merge_coincident_surfaces(&mut k, &mut two, s1, s2, Some(TI_HANDLE));
if let Some(m) = status(r, &mut o)? {
put_list(&mut o, &m.faces);
put_list(&mut o, &m.other_faces);
let walk = Walk::of(&two);
put_list(&mut o, &walk, &m.faces);
put_list(&mut o, &walk, &m.other_faces);
}
}
}
put_state(&mut o, &two, &ti)?;
put_state(&mut o, &two, &Walk::of(&two), &ti)?;
Ok(o)
}

Expand Down
19 changes: 12 additions & 7 deletions crates/difftest/src/units/sweep_topology_sweep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,14 +847,19 @@ mod tests {
assert_ne!(model.k.context.current_mark(MarkType::Mark), old_mark);
assert!(!model.k.context.is_mark_locked(MarkType::Mark));
model.transform(b, Axis2Placement::default())?;
// This fixture reaches HCR's separate, still-unavailable transform adapter.
// HCR's scene transform is wired (topology::brep::p5::transform_with_notifications):
// the scene is built, then this fixture has no service to retain it in.
let hcr = model.hcr(b, Axis2Placement::default(), 0.001, 0.1, false, false, true);
assert!(matches!(
hcr,
Err(SolidError::Unported {
upstream: "SmBrep::Transform", unit: "topology.brep_p5"
})
), "{hcr:?}");
assert!(
matches!(
hcr,
Err(SolidError::InvalidInput {
reason: "fixture has no retained HCR service",
..
})
),
"{hcr:?}"
);
model.b[0].set_editing_enabled(false);
model.k.context.set_doing_boolean(false);
// query.brep (CalculateBoundingBox) is ported: the stitch now fails later,
Expand Down
40 changes: 23 additions & 17 deletions crates/solidcore/src/blend/hcr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@
//! `topology::brep::p3::copy_brep`) notifies through the caller's notification
//! environment, naming the copy's objects by its `key_of` and `brep`'s by `source_key`
//! (upstream objects are known by address), so [`Hcr::new`] and [`Hcr::with_transform`]
//! take the kernel mutably with both. The scene's transformation (`Transform`) and
//! its bounding box
//! (`SmBrep::CalculateBoundingBox`) belong to unported units, so [`Hcr::with_transform`]
//! stops there; [`Hcr::from_scene`] is the rest of `ConstructorInit` for a caller that
//! take the kernel mutably with both. The scene's transformation (`SmBrep::Transform`,
//! `topology::brep::p5::transform_with_notifications`) notifies through the same
//! environment. [`Hcr::from_scene`] is the rest of `ConstructorInit` for a caller that
//! already holds the transformed scene and its box.
//! - The pointer maps `m_pSilVertices`, `m_pSilEdges` and `m_pBackFacingEdges` are id
//! sets; [`Hcr::silhouette_edges`] returns the ids in ascending order (upstream
Expand Down Expand Up @@ -224,16 +223,22 @@ fn copy_brep(
crate::topology::brep::p3::copy_brep(k, env, brep, source_key, None, None, true, true)
}

// ---- unported callees ---------------------------------------------------------------------

/// `SmBrep::Transform` (unit `topology.brep_p5`).
fn transform_brep(brep: &mut Brep, transform: &Axis2Placement) -> Result<()> {
let _ = (brep, transform);
// UNPORTED(topology.brep_p5): SmBrep::Transform
Err(SolidError::unported(
"SmBrep::Transform",
"topology.brep_p5",
))
/// `SmBrep::Transform(crRotateNMove)` with its defaults (no scale, `bScaleTol` `TRUE`),
/// notifying through the scene copy's environment `env`.
fn transform_brep(
k: &mut Kernel,
env: &mut edge::NotifyEnv<'_>,
brep: &mut Brep,
transform: &Axis2Placement,
) -> Result<()> {
crate::topology::brep::p5::transform_with_notifications(
k,
brep,
transform,
None,
true,
Some(env),
)
}

/// `SmBrep::FindAndSetInfiniteRegion()` with upstream's default arguments (no shell to
Expand Down Expand Up @@ -529,8 +534,9 @@ impl Hcr {
///
/// # Errors
///
/// Those of the scene copy (`topology::brep::p3::copy_brep`); [`SolidError::Unported`]
/// from the transform and box (units `topology.brep_p5`, `query.brep`).
/// Those of the scene copy (`topology::brep::p3::copy_brep`); the transform's and
/// `FindAndSetInfiniteRegion`'s failures are ignored as upstream, apart from
/// [`SolidError::Unported`] from their callees.
pub fn with_transform(
k: &mut Kernel,
env: &mut edge::NotifyEnv<'_>,
Expand All @@ -544,7 +550,7 @@ impl Hcr {
let mut scene = copy_brep(k, env, brep, source_key)?;
scene.set_editing_enabled(true);
// transform the copied Brep to place the eye looking up the Z axis
ignore_status(transform_brep(&mut scene, &vt))?;
ignore_status(transform_brep(k, env, &mut scene, &vt))?;
ignore_status(find_and_set_infinite_region(k, &mut scene))?; // [B23]
// its status is ignored upstream (the box then stays empty)
let scene_box = ignored(qbrep::calculate_bounding_box(
Expand Down
10 changes: 3 additions & 7 deletions crates/solidcore/src/topology/brep/p5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,15 +416,16 @@ pub fn combine_with_notifications(
notifications.as_deref_mut(),
))?;
}
set_vertex_point(k, b, survivor, target.point, notifications)?;
set_vertex_point(k, b, survivor, target.point, notifications.as_deref_mut())?;
crate::error::ignore_status(vertex::set_tolerance(
b,
survivor,
target.tolerance,
true,
true,
))?;
update_vertex_edge_intervals(b, survivor)
let env = notifications.ok_or_else(|| SolidError::null_pointer(OP))?;
crate::topology::brep::p1::update_vertex_edge_intervals(k, b, env, survivor)
}

/// `Notify(SM_NO_MERGE_IN_BREP, pSurvivingVertex, pVertexToDelete, this)`
Expand Down Expand Up @@ -553,11 +554,6 @@ fn set_vertex_point(
)
}

fn update_vertex_edge_intervals(_b: &mut Brep, _vertex: VertexId) -> Result<()> {
// UNPORTED(topology.brep_p1): SmBrep::UpdateVertexEdgeIntervals
missing("SmBrep::UpdateVertexEdgeIntervals", "topology.brep_p1")
}

/// Makes a wire edge over the caller's curve interval. Evaluates start before end,
/// then needs the owning B-rep's infinite region; the owned curve drops on error.
pub fn create_wire_edge_from_curve(
Expand Down
Loading
Loading