test: failing regression test for #261: Rectangular pattern of a hole cut scales super-linearly (#276)
* test: reproduce #261 (Rectangular pattern of a hole cut scales super-linearly) * Patterns of many hole cuts scale near-linearly (#261) Two quadratic costs: - Meshing a face tested every point against every segment of every boundary loop, so a plate face with hundreds of holes meshed in quadratic time. The vendored truck-meshalgo inside test now skips loops whose parameter box is clear of the point (they wind zero times around it). - A pattern cut each copy in turn, rebuilding and re-checking an ever more complex target per copy. Copies whose boxes are clear of each other are now one tool of many pieces (kernel::union_apart, no intersection work), cut once. 512 holes now take ~7 s instead of not finishing. The test's volume tolerance is widened from 1e-6 relative to 0.1 % of each hole: the measure meshes the bores and reads each hole ~0.06 % small, on main too. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Hole-pattern test: a budget CI can meet; coarser apart-box meshes (#261) CI runs every test binary at once and is about ten times slower than a machine running this test alone (15 tests passed 60 s in the last run), so the 512-hole pattern (about 6 s alone) hit the 60 s timeout there. The budget now only has to tell linear from the quadratic hang: 300 s timeout, 120 s budget. union_apart meshes each copy coarsely (2 % of its size, box grown by twice that). Co-Authored-By: Claude Opus 5.5 <[email protected]> * Hole-pattern test checks the scaling, not a wall-clock time (#261) CI runs every test binary at once: the 512-hole pattern (about 6 s alone, 10 s CPU single-threaded) took 177 s there, so no fixed time is reliable. The test now patterns 128 and then 512 holes and requires the second to take under 8x the first (linear is 4x, measured 3.5-4.2x here; the old quadratic cost was 16x or more), each with the volume check and a 900 s hang guard. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: bherbruck <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
6 files changed
+109
-4
No files matched your search
Vendored
+3
@@ -37,6 +37,9 @@ Changes:
|
||||
## truck-meshalgo 0.4.0 (Apache-2.0, © RICOS Co. Ltd., https://github.com/ricosjp/truck)
|
||||
|
||||
Changes:
|
||||
- `tessellation/triangulation.rs`: the inside test of a face's boundary skips loops whose
|
||||
parameter box is clear of the point (it tested every segment of every loop, so a face with
|
||||
hundreds of holes meshed in quadratic time).
|
||||
- `tessellation/triangulation.rs`: meshed faces and edges are built unchecked: faces whose loop
|
||||
runs along a seam edge both ways and closed edges (a full circle on one vertex) are valid,
|
||||
but the debug-build checks rejected them (debug builds could not mesh them).
|
||||
|
||||
+15
-3
@@ -344,8 +344,10 @@ fn get_mindiff(u: f64, u0: f64, up: f64) -> f64 {
|
||||
(-2..=2).map(closure).min_by(abs_diff(u0)).unwrap()
|
||||
}
|
||||
|
||||
/// SolveCraft: the second field holds each loop's parameter box, so `include` skips loops that
|
||||
/// cannot hold the point (a face with hundreds of holes meshed in quadratic time).
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct PolyBoundary(Vec<Vec<Point2>>);
|
||||
struct PolyBoundary(Vec<Vec<Point2>>, Vec<BoundingBox<Point2>>);
|
||||
|
||||
fn normalize_range(curve: &mut Vec<Point2>, compidx: usize, (u0, u1): (f64, f64)) {
|
||||
let p = curve[0];
|
||||
@@ -485,16 +487,26 @@ impl PolyBoundary {
|
||||
closed.push(connect_edges([vec0, vec1, vec2, vec3]));
|
||||
}
|
||||
}
|
||||
Self(closed)
|
||||
let boxes = closed.iter().map(|curve| curve.iter().collect()).collect();
|
||||
Self(closed, boxes)
|
||||
}
|
||||
|
||||
/// whether `c` is included in the domain with boundary = `self`.
|
||||
fn include(&self, c: Point2) -> bool {
|
||||
let t = 2.0 * std::f64::consts::PI * HashGen::hash1(c);
|
||||
let r = Vector2::new(f64::cos(t), f64::sin(t));
|
||||
// SolveCraft: a closed loop whose box is clear of `c` winds zero times around it, and
|
||||
// no crossing with it lies within the tolerance of `c`: it changes nothing here.
|
||||
let margin = 2.0 * TOLERANCE;
|
||||
let near = |bdb: &BoundingBox<Point2>| {
|
||||
let (min, max) = (bdb.min(), bdb.max());
|
||||
!(c.x < min.x - margin || c.x > max.x + margin || c.y < min.y - margin || c.y > max.y + margin)
|
||||
};
|
||||
self.0
|
||||
.iter()
|
||||
.flat_map(|vec| vec.iter().circular_tuple_windows())
|
||||
.zip(&self.1)
|
||||
.filter(|(_, bdb)| near(bdb))
|
||||
.flat_map(|(vec, _)| vec.iter().circular_tuple_windows())
|
||||
.try_fold(0_i32, move |counter, (p0, p1)| {
|
||||
let a = p0 - c;
|
||||
let b = p1 - c;
|
||||
|
||||
Reference in new issue
Block a user