mirror of
https://github.com/revarbat/BOSL2.git
synced 2025-01-17 06:08:32 +01:00
Optimizations for decompose_path()
This commit is contained in:
parent
fb3475abef
commit
0524194391
@ -75,8 +75,9 @@ function select(list, start, end=undef) =
|
|||||||
// slice([3,4,5,6,7,8,9], 6, -1); // Returns [9]
|
// slice([3,4,5,6,7,8,9], 6, -1); // Returns [9]
|
||||||
// slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
|
// slice([3,4,5,6,7,8,9], 2, -2); // Returns [5,6,7,8]
|
||||||
function slice(arr,st,end) = let(
|
function slice(arr,st,end) = let(
|
||||||
s=st<0?(len(arr)+st):st,
|
l=len(arr),
|
||||||
e=end<0?(len(arr)+end+1):end
|
s=st<0?(l+st):st,
|
||||||
|
e=end<0?(l+end+1):end
|
||||||
) [for (i=[s:1:e-1]) if (e>s) arr[i]];
|
) [for (i=[s:1:e-1]) if (e>s) arr[i]];
|
||||||
|
|
||||||
|
|
||||||
|
65
paths.scad
65
paths.scad
@ -549,8 +549,37 @@ function decompose_path(path, closed=true, eps=EPSILON) =
|
|||||||
path = cleanup_path(path, eps=eps),
|
path = cleanup_path(path, eps=eps),
|
||||||
tagged = _tag_self_crossing_subpaths(path, closed=closed, eps=eps),
|
tagged = _tag_self_crossing_subpaths(path, closed=closed, eps=eps),
|
||||||
kept = [for (sub = tagged) if(sub[0] == "O") sub[1]],
|
kept = [for (sub = tagged) if(sub[0] == "O") sub[1]],
|
||||||
outregion = assemble_path_fragments(kept, eps=eps)
|
completed = [for (frag=kept) if(is_closed_path(frag)) frag],
|
||||||
) outregion;
|
incomplete = [for (frag=kept) if(!is_closed_path(frag)) frag],
|
||||||
|
defrag = _path_fast_defragment(incomplete, eps=eps),
|
||||||
|
completed2 = assemble_path_fragments(defrag, eps=eps)
|
||||||
|
) concat(completed2,completed);
|
||||||
|
|
||||||
|
|
||||||
|
function _path_fast_defragment(fragments, eps=EPSILON, _done=[]) =
|
||||||
|
len(fragments)==0? _done :
|
||||||
|
let(
|
||||||
|
path = fragments[0],
|
||||||
|
endpt = select(path,-1),
|
||||||
|
extenders = [
|
||||||
|
for (i = [1:1:len(fragments)-1]) let(
|
||||||
|
test1 = approx(endpt,fragments[i][0],eps=eps),
|
||||||
|
test2 = approx(endpt,select(fragments[i],-1),eps=eps)
|
||||||
|
) if (test1 || test2) (test1? i : -1)
|
||||||
|
]
|
||||||
|
) len(extenders) == 1 && extenders[0] >= 0? _path_fast_defragment(
|
||||||
|
fragments=[
|
||||||
|
concat(select(path,0,-2),fragments[extenders[0]]),
|
||||||
|
for (i = [1:1:len(fragments)-1])
|
||||||
|
if (i != extenders[0]) fragments[i]
|
||||||
|
],
|
||||||
|
eps=eps,
|
||||||
|
_done=_done
|
||||||
|
) : _path_fast_defragment(
|
||||||
|
fragments=[for (i = [1:1:len(fragments)-1]) fragments[i]],
|
||||||
|
eps=eps,
|
||||||
|
_done=concat(_done,[deduplicate(path,closed=true,eps=eps)])
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
|
function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
|
||||||
@ -596,33 +625,29 @@ function _extreme_angle_fragment(seg, fragments, rightmost=true, eps=EPSILON) =
|
|||||||
// Arguments:
|
// Arguments:
|
||||||
// fragments = List of polylines to be assembled into complete polygons.
|
// fragments = List of polylines to be assembled into complete polygons.
|
||||||
// rightmost = If true, assemble paths using rightmost turns. Leftmost if false.
|
// rightmost = If true, assemble paths using rightmost turns. Leftmost if false.
|
||||||
|
// startfrag = The fragment to start with. Default: 0
|
||||||
// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
// eps = The epsilon error value to determine whether two points coincide. Default: `EPSILON` (1e-9)
|
||||||
function assemble_a_path_from_fragments(fragments, rightmost=true, eps=EPSILON) =
|
function assemble_a_path_from_fragments(fragments, rightmost=true, startfrag=0, eps=EPSILON) =
|
||||||
len(fragments)==0? _finished :
|
len(fragments)==0? _finished :
|
||||||
let(
|
let(
|
||||||
path = fragments[0],
|
path = fragments[startfrag],
|
||||||
newfrags = slice(fragments, 1, -1)
|
newfrags = [for (i=idx(fragments)) if (i!=startfrag) fragments[i]]
|
||||||
) is_closed_path(path, eps=eps)? (
|
) is_closed_path(path, eps=eps)? (
|
||||||
// starting fragment is already closed
|
// starting fragment is already closed
|
||||||
[path, newfrags]
|
[path, newfrags]
|
||||||
) : let(
|
) : let(
|
||||||
// Find rightmost/leftmost continuation fragment
|
// Find rightmost/leftmost continuation fragment
|
||||||
seg = select(path,-2,-1),
|
seg = select(path,-2,-1),
|
||||||
frags = slice(fragments,1,-1),
|
extrema = _extreme_angle_fragment(seg=seg, fragments=newfrags, rightmost=rightmost, eps=eps),
|
||||||
extrema = _extreme_angle_fragment(seg=seg, fragments=frags, rightmost=rightmost, eps=eps),
|
|
||||||
foundfrag = extrema[0],
|
foundfrag = extrema[0],
|
||||||
remainder = extrema[1],
|
remainder = extrema[1]
|
||||||
newfrags = remainder
|
|
||||||
) is_undef(foundfrag)? (
|
) is_undef(foundfrag)? (
|
||||||
// No remaining fragments connect! INCOMPLETE PATH!
|
// No remaining fragments connect! INCOMPLETE PATH!
|
||||||
// Treat it as complete.
|
// Treat it as complete.
|
||||||
[path, newfrags]
|
[path, remainder]
|
||||||
) : is_closed_path(foundfrag, eps=eps)? (
|
) : is_closed_path(foundfrag, eps=eps)? (
|
||||||
let(
|
|
||||||
newfrags = concat([path], remainder)
|
|
||||||
)
|
|
||||||
// Found fragment is already closed
|
// Found fragment is already closed
|
||||||
[foundfrag, newfrags]
|
[foundfrag, concat([path], remainder)]
|
||||||
) : let(
|
) : let(
|
||||||
fragend = select(foundfrag,-1),
|
fragend = select(foundfrag,-1),
|
||||||
hits = [for (i = idx(path,end=-2)) if(approx(path[i],fragend,eps=eps)) i]
|
hits = [for (i = idx(path,end=-2)) if(approx(path[i],fragend,eps=eps)) i]
|
||||||
@ -661,19 +686,15 @@ function assemble_path_fragments(fragments, eps=EPSILON, _finished=[]) =
|
|||||||
minxidx = min_index([
|
minxidx = min_index([
|
||||||
for (frag=fragments) min(subindex(frag,0))
|
for (frag=fragments) min(subindex(frag,0))
|
||||||
]),
|
]),
|
||||||
promoted = [
|
|
||||||
fragments[minxidx],
|
|
||||||
for (i=idx(fragments))
|
|
||||||
if (i!=minxidx)
|
|
||||||
fragments[i]
|
|
||||||
],
|
|
||||||
result_l = assemble_a_path_from_fragments(
|
result_l = assemble_a_path_from_fragments(
|
||||||
fragments=promoted,
|
fragments=fragments,
|
||||||
|
startfrag=minxidx,
|
||||||
rightmost=false,
|
rightmost=false,
|
||||||
eps=eps
|
eps=eps
|
||||||
),
|
),
|
||||||
result_r = assemble_a_path_from_fragments(
|
result_r = assemble_a_path_from_fragments(
|
||||||
fragments=promoted,
|
fragments=fragments,
|
||||||
|
startfrag=minxidx,
|
||||||
rightmost=true,
|
rightmost=true,
|
||||||
eps=eps
|
eps=eps
|
||||||
),
|
),
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
BOSL_VERSION = [2,0,251];
|
BOSL_VERSION = [2,0,252];
|
||||||
|
|
||||||
|
|
||||||
// Section: BOSL Library Version Functions
|
// Section: BOSL Library Version Functions
|
||||||
|
Loading…
x
Reference in New Issue
Block a user