diff --git a/arrays.scad b/arrays.scad index d1a008e..5af5b7e 100644 --- a/arrays.scad +++ b/arrays.scad @@ -221,6 +221,31 @@ function in_list(val,list,idx) = : val==list[s][idx]; +// Function: find_first_match() +// Topics: List Handling +// See Also: in_list() +// Usage: +// idx = find_first_match(val, list, , ); +// indices = find_first_match(val, list, all=true, , ); +// Description: +// Finds the first item in `list` that matches `val`, returning the index. +// Arguments: +// val = The value to search for. +// list = The list to search through. +// --- +// start = The index to start searching from. +// all = If true, returns a list of all matching item indices. +// eps = The maximum allowed floating point rounding error for numeric comparisons. +function find_first_match(val, list, start=0, all=false, eps=EPSILON) = + all? [for (i=[start:1:len(list)-1]) if(val==list[i] || approx(val, list[i], eps=eps)) i] : + __find_first_match(val, list, eps=eps, i=start); + +function __find_first_match(val, list, eps, i=0) = + i >= len(list)? undef : + approx(val, list[i], eps=eps)? i : + __find_first_match(val, list, eps=eps, i=i+1); + + // Function: min_index() // Usage: // idx = min_index(vals); diff --git a/regions.scad b/regions.scad index d903177..b4befba 100644 --- a/regions.scad +++ b/regions.scad @@ -121,6 +121,76 @@ function point_in_region(point, region, eps=EPSILON, _i=0, _cnt=0) = ) pip==0? 0 : point_in_region(point, region, eps=eps, _i=_i+1, _cnt = _cnt + (pip>0? 1 : 0)); +// Function: polygons_equal() +// Usage: +// b = polygons_equal(poly1, poly2, ) +// Description: +// Returns true if the components of region1 and region2 are the same polygons +// within given epsilon tolerance. +// Arguments: +// poly1 = first polygon +// poly2 = second polygon +// eps = tolerance for comparison +// Example(NORENDER): +// polygons_equal(pentagon(r=4), +// rot(360/5, p=pentagon(r=4))); // returns true +// polygons_equal(pentagon(r=4), +// rot(90, p=pentagon(r=4))); // returns false +function polygons_equal(poly1, poly2, eps=EPSILON) = + let( + poly1 = cleanup_path(poly1), + poly2 = cleanup_path(poly2), + l1 = len(poly1), + l2 = len(poly2) + ) l1 != l2 ? false : + let( maybes = find_first_match(poly1[0], poly2, eps=eps, all=true) ) + maybes == []? false : + [for (i=maybes) if (__polygons_equal(poly1, poly2, eps, i)) 1] != []; + +function __polygons_equal(poly1, poly2, eps, st) = + max([for(d=poly1-select(poly2,st,st-1)) d*d])= len(polys)? false : + polygons_equal(poly, polys[i])? true : + __poly_in_polygons(poly, polys, i+1); + + +// Function: regions_equal() +// Usage: +// b = regions_equal(region1, region2, ) +// Description: +// Returns true if the components of region1 and region2 are the same polygons +// within given epsilon tolerance. +// Arguments: +// poly1 = first polygon +// poly2 = second polygon +// eps = tolerance for comparison +function regions_equal(region1, region2) = + assert(is_region(region1) && is_region(region2)) + len(region1) != len(region2)? false : + __regions_equal(region1, region2, 0); + +function __regions_equal(region1, region2, i) = + i >= len(region1)? true : + !poly_in_polygons(region1[i], region2)? false : + __regions_equal(region1, region2, i+1); + + // Function: region_path_crossings() // Usage: // region_path_crossings(path, region); @@ -222,64 +292,6 @@ function split_nested_region(region) = ) outs; -function find_first_approx(val, list, start=0, all=false, eps=EPSILON) = - all? [for (i=[start:1:len(list)-1]) if(approx(val, list[i], eps=eps)) i] : - __find_first_approx(val, list, eps=eps, i=start); - -function __find_first_approx(val, list, eps, i=0) = - i >= len(list)? undef : - approx(val, list[i], eps=eps)? i : - __find_first_approx(val, list, eps=eps, i=i+1); - - -// Function: polygons_equal() -// Usage: -// b = polygons_equal(poly1, poly2, ) -// Description: -// Returns true if the components of region1 and region2 are the same polygons -// within given epsilon tolerance. -// Arguments: -// poly1 = first polygon -// poly2 = second polygon -// eps = tolerance for comparison -// Example(NORENDER): -// polygons_equal(pentagon(r=4), -// rot(360/5, p=pentagon(r=4))); // returns true -// polygons_equal(pentagon(r=4), -// rot(90, p=pentagon(r=4))); // returns false -function polygons_equal(poly1, poly2, eps=EPSILON) = - let( l1 = len(poly1), l2 = len(poly2)) - l1 != l2 ? false : - let( maybes = find_first_approx(poly1[0], poly2, eps=eps, all=true) ) - maybes == []? false : - [for (i=maybes) if (__polygons_equal(poly1, poly2, eps, i)) 1] != []; - -function __polygons_equal(poly1, poly2, eps, st) = - max([for(d=poly1-select(poly2,st,st-1)) d*d])) -// Description: -// Returns true if the components of region1 and region2 are the same polygons -// within given epsilon tolerance. -// Arguments: -// poly1 = first polygon -// poly2 = second polygon -// eps = tolerance for comparison -function regions_equal(region1, region2) = - assert(is_region(region1) && is_region(region2)) - len(region1)==len(region2) && - [ - for (a=region1) - if (1!=sum( - [for(b=region2) - if (polygons_equal(path3d(a), path3d(b))) - 1] - ) - ) 1 - ] == []; - // Section: Region Extrusion and VNFs