forked from 1b-agent/opencadstudio-upstream
fix(hatch): close the boundary loop in the fill shader
The point-in-polygon test in both hatch shaders walked edges (v0,v1)…(vn-2,vn-1) but never the closing edge vn-1→v0, so an unclosed boundary miscounted crossings and the fill bled outside the shape. SOLID entities hit this — their four corners are not repeated — making color-wheel fills spike past their bounds. Close each sub-loop (at NaN separators and at the end); already-closed loops get a degenerate closing edge that crosses nothing, so they're unaffected. (#140) Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
e1c5917644
commit
c5ad13d5c7
2 files changed
+34
-4
No files matched your search
+17
-2
@@ -119,19 +119,34 @@ fn in_polygon(p: vec2<f32>) -> bool {
|
||||
var inside = false;
|
||||
let n = h.vcount;
|
||||
var prev = vec2<f32>(0.0, 0.0);
|
||||
var first = vec2<f32>(0.0, 0.0);
|
||||
var have_prev = false;
|
||||
for (var i = 0u; i < n; i++) {
|
||||
let vi = b.verts[i].xy;
|
||||
if !valid_vertex(vi) {
|
||||
// Close the sub-loop that just ended (last → first edge). An
|
||||
// unclosed boundary — e.g. a SOLID's 4 corners, which are not
|
||||
// repeated — otherwise miscounts crossings and the fill bleeds
|
||||
// outside the shape. (#140)
|
||||
if have_prev && edge_crosses(p, prev, first) {
|
||||
inside = !inside;
|
||||
}
|
||||
have_prev = false;
|
||||
continue;
|
||||
}
|
||||
if have_prev && edge_crosses(p, prev, vi) {
|
||||
inside = !inside;
|
||||
if have_prev {
|
||||
if edge_crosses(p, prev, vi) {
|
||||
inside = !inside;
|
||||
}
|
||||
} else {
|
||||
first = vi;
|
||||
}
|
||||
prev = vi;
|
||||
have_prev = true;
|
||||
}
|
||||
if have_prev && edge_crosses(p, prev, first) {
|
||||
inside = !inside;
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
|
||||
@@ -150,19 +150,34 @@ fn edge_crosses(p: vec2<f32>, a: vec2<f32>, c: vec2<f32>) -> bool {
|
||||
fn in_polygon(p: vec2<f32>, offset: u32, count: u32) -> bool {
|
||||
var inside = false;
|
||||
var prev = vec2<f32>(0.0, 0.0);
|
||||
var first = vec2<f32>(0.0, 0.0);
|
||||
var have_prev = false;
|
||||
for (var i = 0u; i < count; i++) {
|
||||
let vi = boundary[offset + i].xy;
|
||||
if !valid_vertex(vi) {
|
||||
// Close the sub-loop that just ended (last → first edge). An
|
||||
// unclosed boundary — e.g. a SOLID's 4 corners, which are not
|
||||
// repeated — otherwise miscounts crossings and the fill bleeds
|
||||
// outside the shape. (#140)
|
||||
if have_prev && edge_crosses(p, prev, first) {
|
||||
inside = !inside;
|
||||
}
|
||||
have_prev = false;
|
||||
continue;
|
||||
}
|
||||
if have_prev && edge_crosses(p, prev, vi) {
|
||||
inside = !inside;
|
||||
if have_prev {
|
||||
if edge_crosses(p, prev, vi) {
|
||||
inside = !inside;
|
||||
}
|
||||
} else {
|
||||
first = vi;
|
||||
}
|
||||
prev = vi;
|
||||
have_prev = true;
|
||||
}
|
||||
if have_prev && edge_crosses(p, prev, first) {
|
||||
inside = !inside;
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user