mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
M6.10: Boolean operations hold their area identities on almost-horizontal edges
The sweep compares a curve with another segment over a y-span shorter than its tolerance by bounding boxes only, so an edge rising by less than that tolerance (e.g. a rectangle edge cut through a circle's cap, whose computed intersection end sits ~1e-12 off the horizontal) was mis-ordered and the result lost a corner: xor/difference/area disagreed by up to 10%. Every sweep input now snaps on-curve y values within the tolerance to one level (handles follow and are levelled with their anchor), so such edges become exact horizontals, which the sweep handles exactly. - tests/regressions.rs: the six minimal failures found by the properties, the root cause in isolation, and the self-crossing "star" polygon. - The star-polygon strategy rejected no angular step of half a turn or more, so it sometimes drew self-crossing polygons (the shoelace failure). - Property suites run from a fixed seed (PROPTEST_CASES / PROPTEST_RNG_SEED still override), so CI cannot fail at random. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
bc59c53b5a
commit
be7006ccf5
8 files changed
+301
-10
No files matched your search
@@ -19,9 +19,14 @@ pub fn arb_rect() -> impl Strategy<Value = Rect> {
|
||||
}
|
||||
|
||||
/// A simple (non self-intersecting) star-shaped polygon: points at increasing angles around a
|
||||
/// centre with random radii.
|
||||
/// centre with random radii. Every angular step stays below half a turn: a wider one puts the
|
||||
/// centre outside and can make the polygon cross itself.
|
||||
pub fn arb_star_polygon() -> impl Strategy<Value = Vec<Point>> {
|
||||
(arb_point(40.0, 160.0), prop::collection::vec((0.2f64..1.0, 5.0f64..40.0), 3..12)).prop_map(|(c, v)| {
|
||||
let steps = prop::collection::vec((0.2f64..1.0, 5.0f64..40.0), 3..12).prop_filter("an angular step of half a turn or more", |v| {
|
||||
let total: f64 = v.iter().map(|(a, _)| a).sum();
|
||||
v.iter().all(|(a, _)| 2.0 * a < total)
|
||||
});
|
||||
(arb_point(40.0, 160.0), steps).prop_map(|(c, v)| {
|
||||
let total: f64 = v.iter().map(|(a, _)| a).sum();
|
||||
let mut ang = 0.0;
|
||||
v.iter()
|
||||
|
||||
Reference in new issue
Block a user