Tweaked offset() to work on regions as well as paths.

This commit is contained in:
Revar Desmera 2019-06-26 18:56:33 -07:00
parent 83e6eb24ee
commit d64b836e8b

View file

@ -8,6 +8,10 @@
//////////////////////////////////////////////////////////////////////
// CommonCode:
// include <BOSL2/roundcorners.scad>
// Section: Lines and Triangles
// Function: point_on_segment2d()
@ -392,7 +396,14 @@ function path_subselect(path,s1,u1,s2,u2) =
function assemble_path_fragments(subpaths,eps=EPSILON,_finished=[]) =
len(subpaths)<=1? concat(_finished, subpaths) :
let(
path = subpaths[0],
path = subpaths[0]
) is_closed_path(path, eps=eps)? (
assemble_path_fragments(
[for (i=[1:1:len(subpaths)-1]) subpaths[i]],
eps=eps,
_finished=concat(_finished, [path])
)
) : let(
matches = [
for (i=[1:1:len(subpaths)-1], rev1=[0,1], rev2=[0,1]) let(
idx1 = rev1? 0 : len(path)-1,
@ -589,14 +600,17 @@ function _offset_chamfer(center, points, delta) =
line_intersection(endline, select(points,[1,2]))
];
function _shift_segment(segment, d) =
move(d*line_normal(segment),segment);
// Extend to segments to their intersection point. First check if the segments already have a point in common,
// which can happen if two colinear segments are input to the path variant of `offset()`
function _segment_extension(s1,s2) =
norm(s1[1]-s2[0])<1e-6 ? s1[1] : line_intersection(s1,s2);
function _makefaces(direction, startind, good, pointcount, closed) =
let(
lenlist = list_bset(good, pointcount),
@ -636,6 +650,7 @@ function _makefaces_recurse(startind1, startind2, numfirst, numsecond, lenlist,
)
);
// Determine which of the shifted segments are good
function _good_segments(path, d, shiftsegs, closed, quality) =
let(
@ -684,6 +699,42 @@ function _point_dist(path,pathseg_unit,pathseg_len,pt) =
]);
function _offset_region(
paths, r, delta, chamfer, closed,
maxstep, check_valid, quality,
return_faces, firstface_index,
flip_faces, _acc=[], _i=0
) =
_i>=len(paths)? _acc :
_offset_region(
paths, _i=_i+1,
_acc = (paths[_i].x % 2 == 0)? (
union(_acc, [
offset(
paths[_i].y,
r=r, delta=delta, chamfer=chamfer, closed=closed,
maxstep=maxstep, check_valid=check_valid, quality=quality,
return_faces=return_faces, firstface_index=firstface_index,
flip_faces=flip_faces
)
])
) : (
difference(_acc, [
offset(
paths[_i].y,
r=-r, delta=-delta, chamfer=chamfer, closed=closed,
maxstep=maxstep, check_valid=check_valid, quality=quality,
return_faces=return_faces, firstface_index=firstface_index,
flip_faces=flip_faces
)
])
),
r=r, delta=delta, chamfer=chamfer, closed=closed,
maxstep=maxstep, check_valid=check_valid, quality=quality,
return_faces=return_faces, firstface_index=firstface_index, flip_faces=flip_faces
);
// Function: offset()
//
// Description:
@ -753,13 +804,36 @@ function _point_dist(path,pathseg_unit,pathseg_len,pt) =
// sinpath = 2*[for(theta=[-180:5:180]) [theta/4,45*sin(theta)]];
// #stroke(sinpath);
// stroke(offset(sinpath, r=17.5));
// Example(2D): Region
// rgn = difference(circle(d=100), union(square([20,40], center=true), square([40,20], center=true)));
// #linear_extrude(height=1.1) for (p=rgn) stroke(close=true, width=0.5, p);
// region(offset(rgn, r=-5));
function offset(
path, r=undef, delta=undef, chamfer=false,
maxstep=0.1, closed=false, check_valid=true,
quality=1, return_faces=false, firstface_index=0,
flip_faces=false
) =
let(rcount = num_defined([r,delta]))
is_region(path)? (
let(
path = [for (p=path) polygon_clockwise(p)? p : reverse(p)],
rgn = exclusive_or([for (p = path) [p]]),
pathlist = sort(idx=0,[
for (i=[0:1:len(rgn)-1]) [
sum([
for (j=[0:1:len(rgn)-1]) if (i!=j)
point_in_polygon(rgn[i][0],rgn[j])>=0? 1 : 0
]),
rgn[i]
]
])
) _offset_region(
pathlist, r=r, delta=delta, chamfer=chamfer, closed=true,
maxstep=maxstep, check_valid=check_valid, quality=quality,
return_faces=return_faces, firstface_index=firstface_index,
flip_faces=flip_faces
)
) : let(rcount = num_defined([r,delta]))
assert(rcount==1,"Must define exactly one of 'delta' and 'r'")
let(
chamfer = is_def(r) ? false : chamfer,
@ -1187,5 +1261,4 @@ module region(r)
// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap