Merge pull request #1765 from adrianVmariano/master

fix offset_sweep bug with disjoint region components
This commit is contained in:
adrianVmariano
2025-07-29 21:39:08 -04:00
committed by GitHub
2 changed files with 37 additions and 43 deletions

View File

@@ -1614,51 +1614,40 @@ module _offset_sweep_region(region, height,
spin=0, orient=UP, atype="hull")
{
connected_reg = region_parts(region);
vnf_h_list = [for(reg=connected_reg)
offset_sweep(path=reg[0], height=height, h=h, l=l, length=length, bot=bot, top=top, bottom=bottom, ends=ends,
offset=offset, r=r, steps=steps,
quality=quality, check_valid=check_valid, extra=extra, cut=cut, chamfer_width=chamfer_width,
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle, _return_height=true)];
vnf_list = column(vnf_h_list,0);
height = vnf_h_list[0][1];
holes = [for(reg=connected_reg, i=[1:1:len(reg)-1]) reg[i]];
final_height = vnf_h_list[0][1]; // Need height for anchoring. All heights are the same, so take the first one.
vnf_list = column(vnf_h_list,0);
holes = [for(reg=connected_reg) slice(reg,1,-1)];
anchors = [
named_anchor("zcenter", [0,0,0], UP),
named_anchor("base", [0,0,-height/2], UP),
named_anchor("top", [0,0,height/2], UP)
named_anchor("base", [0,0,-final_height/2], UP),
named_anchor("top", [0,0,final_height/2], UP)
];
bottom_hole=first_defined([bottom_hole, bot_hole, ends_hole, bottom, ends]);
bottom_hole=first_defined([bottom_hole, bot_hole, ends_hole, bottom, bot, ends]);
top_hole = first_defined([top_hole,ends_hole,top,ends]);
if (in_list(atype,["hull","intersect"]))
attachable(anchor,spin,orient,region=region,h=height,cp=cp,anchors=anchors,extent=atype=="hull"){
down(height/2)
difference(){
for(vnf=vnf_list)
polyhedron(vnf[0],vnf[1],convexity=convexity);
for(path=holes)
offset_sweep(path=path, height=height, h=h, l=l, length=length, bot=bot, top=top_hole, bottom=bottom_hole,
offset=offset, r=r, steps=steps,
quality=quality, check_valid=check_valid, extra=extra+0.1, cut=cut, chamfer_width=chamfer_width,
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle, _flipdir=true,convexity=convexity);
}
geom = in_list(atype,["hull","intersect"]) ? attach_geom(region=region,h=final_height,cp=cp,anchors=anchors,extent=atype=="hull")
: attach_geom(vnf=vnf_join(vnf_list), cp=cp,anchors=anchors, extent = atype=="surf_hull");
attachable(anchor,spin,orient,geom=geom){
down(final_height/2)
for(i=idx(holes))
difference(){
polyhedron(vnf_list[i][0],vnf_list[i][1],convexity=convexity);
for(path=holes[i])
offset_sweep(path=path, height=height, h=h, l=l, length=length, top=top_hole, bottom=bottom_hole,
offset=offset, r=r, steps=steps,
quality=quality, check_valid=check_valid, extra=extra+0.2, cut=cut, chamfer_width=chamfer_width,
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle, _flipdir=true,convexity=convexity);
}
children();
}
else {
allvnf=vnf_join(vnf_list);
attachable(anchor,spin.orient,vnf=allvnf, cp=cp,anchors=anchors, extent = atype=="surf_hull"){
difference(){
for(vnf=vnf_list)
vnf_polyhedron(vnf,convexity=convexity);
for(path=holes)
offset_sweep(path=path, height=height, h=h, l=l, length=length, bot=bot, top=top_hole, bottom=bottom_hole,
offset=offset, r=r, steps=steps,
quality=quality, check_valid=check_valid, extra=extra+0.1, cut=cut, chamfer_width=chamfer_width,
chamfer_height=chamfer_height, joint=joint, k=k, angle=angle, _flipdir=true,convexity=convexity);
}
children();
}
}
}

View File

@@ -1372,7 +1372,7 @@ function _slice_3dpolygons(polys, dir, cuts) =
for (poly = polys)
let(
polyarea = polygon_area(poly),
err = assert(!is_undef(polyarea), "\nFound non-coplanar face.")
err=assert(!is_undef(polyarea), "\nvnf_slice encountered non-coplanar face.")
)
if (polyarea > EPSILON) // Discard zero area polygons
let(
@@ -2395,7 +2395,7 @@ module debug_vnf(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// See Also: debug_vnf()
//
// Usage:
// vnf_validate(vnf, [size], [show_warns=], [check_isects=], [opacity=], [adjacent=], [label_verts=], [label_faces=], [wireframe=]);
// vnf_validate(vnf, [size], [show_warns=], [check_isects=], [big_face=], [opacity=], [adjacent=], [label_verts=], [label_faces=], [wireframe=]);
// Description:
// When called as a module, echoes the non-manifold errors to the console, and color hilites the
// bad edges and vertices, overlaid on a transparent gray polyhedron of the VNF.
@@ -2423,6 +2423,7 @@ module debug_vnf(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// ---
// show_warns = If true show warnings for non-triangular faces. Default: true
// check_isects = If true, performs slow checks for intersecting faces. Default: false
// big_false = If true report faces with more than 3 vertices even though these may not cause problems. Default: true
// opacity = The opacity level to show the polyhedron itself with. Default: 0.67
// label_verts = If true, shows labels at each vertex that show the vertex number. Default: false
// label_faces = If true, shows labels at the center of each face that show the face number. Default: false
@@ -2488,7 +2489,7 @@ module debug_vnf(vnf, faces=true, vertices=true, opacity=0.5, size=1, convexity=
// Returns a list of non-manifold errors with the given VNF.
// Each error has the format `[ERR_OR_WARN,CODE,MESG,POINTS,COLOR]`.
function _vnf_validate(vnf, show_warns=true, check_isects=false) =
function _vnf_validate(vnf, show_warns=true, check_isects=false, big_face=false) =
assert(is_vnf(vnf), "\nInvalid VNF.")
let(
varr = vnf[0],
@@ -2515,9 +2516,10 @@ function _vnf_validate(vnf, show_warns=true, check_isects=false) =
)
let(
big_faces = !show_warns? [] : [
for (face = faces)
if (len(face) > 3)
_vnf_validate_err("BIG_FACE", face)
for (i = idx(faces))
if (len(faces[i]) > 3)
if(is_undef(face_areas[i])) _vnf_validate_err("NONPLANAR",faces[i])
else if(big_face) _vnf_validate_err("BIG_FACE", faces[i])
],
null_faces = !show_warns? [] : [
for (i = idx(faces)) let(
@@ -2652,7 +2654,9 @@ function _vnf_validate(vnf, show_warns=true, check_isects=false) =
_vnf_validate_err("HOLE_EDGE", uniq_edges[i])
]),
issues = concat(issues, hole_edges)
) hole_edges? issues :
) issues;
/*:
let(
nonplanars = unique([
for (i = idx(faces))
@@ -2661,7 +2665,7 @@ function _vnf_validate(vnf, show_warns=true, check_isects=false) =
]),
issues = concat(issues, nonplanars)
) issues;
*/
_vnf_validate_errs = [
["BIG_FACE", "WARNING", "yellow", "Face has more than 3 vertices, and may confuse CGAL"],
@@ -2700,14 +2704,15 @@ function _edge_not_reported(edge, varr, reports) =
] == [];
module vnf_validate(vnf, size=1, show_warns=true, check_isects=false, opacity=0.67, adjacent=false, label_verts=false, label_faces=false, wireframe=false) {
module vnf_validate(vnf, size=1, show_warns=true, check_isects=false, big_face=true, opacity=0.67, adjacent=false, label_verts=false, label_faces=false, wireframe=false) {
no_children($children);
vcount = len(vnf[0]);
fcount = len(vnf[1]);
vnf = vnf_merge_points(vnf);
faults = _vnf_validate(
vnf, show_warns=show_warns,
check_isects=check_isects
check_isects=check_isects,
big_face=big_face
);
verts = vnf[0];
vnf_changed = len(verts)!=vcount || len(vnf[1])!=fcount;