fix align_polygon & examples

This commit is contained in:
Adrian Mariano 2021-10-15 16:01:01 -04:00
parent 315a1021df
commit 544bb5883e
2 changed files with 49 additions and 66 deletions

View file

@ -1888,26 +1888,7 @@ function polygon_shift(poly, i) =
// move_copies(concat(circ,pent)) circle(r=.1,$fn=32); // move_copies(concat(circ,pent)) circle(r=.1,$fn=32);
// color("red") move_copies([pent[0],circ[0]]) circle(r=.1,$fn=32); // color("red") move_copies([pent[0],circ[0]]) circle(r=.1,$fn=32);
// color("blue") translate(reindexed[0])circle(r=.1,$fn=32); // color("blue") translate(reindexed[0])circle(r=.1,$fn=32);
function old_reindex_polygon(reference, poly, return_error=false) = function reindex_polygon(reference, poly, return_error=false) =
assert(is_path(reference) && is_path(poly,dim=len(reference[0])),
"Invalid polygon(s) or incompatible dimensions. " )
assert(len(reference)==len(poly), "The polygons must have the same length.")
let(
dim = len(reference[0]),
N = len(reference),
fixpoly = dim != 2? poly :
is_polygon_clockwise(reference)
? clockwise_polygon(poly)
: ccw_polygon(poly),
I = [for(i=reference) 1],
val = [ for(k=[0:N-1])
[for(i=[0:N-1])
(reference[i]*poly[(i+k)%N]) ] ]*I,
optimal_poly = polygon_shift(fixpoly, max_index(val))
)
return_error? [optimal_poly, min(poly*(I*poly)-2*val)] :
optimal_poly;
function reindex_polygon(reference, poly, return_error=false) =
assert(is_path(reference) && is_path(poly,dim=len(reference[0])), assert(is_path(reference) && is_path(poly,dim=len(reference[0])),
"Invalid polygon(s) or incompatible dimensions. " ) "Invalid polygon(s) or incompatible dimensions. " )
assert(len(reference)==len(poly), "The polygons must have the same length.") assert(len(reference)==len(poly), "The polygons must have the same length.")
@ -1929,68 +1910,70 @@ function reindex_polygon(reference, poly, return_error=false) =
optimal_poly; optimal_poly;
// Function: align_polygon() // Function: align_polygon()
// Usage: // Usage:
// newpoly = align_polygon(reference, poly, angles, [cp]); // newpoly = align_polygon(reference, poly, [angles], [cp], [tran], [return_ind]);
// Topics: Geometry, Polygons // Topics: Geometry, Polygons
// Description: // Description:
// Tries the list or range of angles to find a rotation of the specified 2D polygon that best aligns // Find the best alignment of a specified 2D polygon with a reference 2D polygon over a set of
// with the reference 2D polygon. For each angle, the polygon is reindexed, which is a costly operation // transformations. You can specify a list or range of angles and a centerpoint or you can
// so if run time is a problem, use a smaller sampling of angles. Returns the rotated and reindexed // give a list of arbitrary 2d transformation matrices. For each transformation or angle, the polygon is
// polygon. // reindexed, which is a costly operation so if run time is a problem, use a smaller sampling of angles or
// transformations. By default returns the rotated and reindexed polygon. You can also request that
// the best angle or the index into the transformation list be returned. When you specify an angle
// Arguments: // Arguments:
// reference = reference polygon // reference = reference polygon
// poly = polygon to rotate into alignment with the reference // poly = polygon to rotate into alignment with the reference
// angles = list or range of angles to test // angles = list or range of angles to test
// cp = centerpoint for rotations // cp = centerpoint for rotations
// Example(2D): The original hexagon in yellow is not well aligned with the pentagon. Turning it so the faces line up gives an optimal alignment, shown in red. // ---
// $fn=32; // tran = list of 2D transformation matrices to optimize over
// pentagon = subdivide_path(pentagon(side=2),60); // return_ind = if true, return the best angle (if you specified angles) or the index into tran otherwise of best alignment
// hexagon = subdivide_path(hexagon(side=2.7),60); // Example(2D): Rotating the poorly aligned light gray triangle by 105 degrees produces the best alignment, shown in blue:
// color("red") move_copies(scale(1.4,p=align_polygon(pentagon,hexagon,[0:10:359]))) circle(r=.1); // ellipse = yscale(3,circle(r=10, $fn=32));
// move_copies(concat(pentagon,hexagon))circle(r=.1); // tri = move([-50/3,-9],
function old_align_polygon(reference, poly, angles, cp) = // subdivide_path([[0,0], [50,0], [0,27]], 32));
// aligned = align_polygon(ellipse,tri, [0:5:180]);
// color("white")stroke(tri,width=.5,closed=true);
// stroke(ellipse, width=.5, closed=true);
// color("blue")stroke(aligned,width=.5,closed=true);
// Example(2D,NoAxes): Translating a triangle (light gray) to the best alignment (blue)
// ellipse = yscale(2,circle(r=10, $fn=32));
// tri = subdivide_path([[0,0], [27,0], [-7,50]], 32);
// T = [for(x=[-10:0], y=[-30:-15]) move([x,y])];
// aligned = align_polygon(ellipse,tri, trans=T);
// color("white")stroke(tri,width=.5,closed=true);
// stroke(ellipse, width=.5, closed=true);
// color("blue")stroke(aligned,width=.5,closed=true);
function align_polygon(reference, poly, angles, cp, trans, return_ind=false) =
assert(is_undef(trans) || (is_undef(angles) && is_undef(cp)), "Cannot give both angles/cp and trans as input")
let(
trans = is_def(trans) ? trans :
assert( (is_vector(angles) && len(angles)>0) || valid_range(angles),
"The `angle` parameter must be a range or a non void list of numbers.")
[for(angle=angles) zrot(angle,cp=cp)]
)
assert(is_path(reference,dim=2) && is_path(poly,dim=2), assert(is_path(reference,dim=2) && is_path(poly,dim=2),
"Invalid polygon(s). " ) "Invalid polygon(s). " )
assert(len(reference)==len(poly), "The polygons must have the same length.") assert(len(reference)==len(poly), "The polygons must have the same length.")
assert( (is_vector(angles) && len(angles)>0) || valid_range(angles),
"The `angle` parameter must be a range or a non void list of numbers.")
let( // alignments is a vector of entries of the form: [polygon, error] let( // alignments is a vector of entries of the form: [polygon, error]
alignments = [ alignments = [
for(angle=angles) for(T=trans)
reindex_polygon( reindex_polygon(
reference, reference,
zrot(angle,p=poly,cp=cp), apply(T,poly),
return_error=true return_error=true
) )
],
best = min_index(subindex(alignments,1))
) alignments[best][0];
function align_polygon(reference, poly, angles, cp) =
assert(is_path(reference,dim=2) && is_path(poly,dim=2),
"Invalid polygon(s). " )
assert(len(reference)==len(poly), "The polygons must have the same length.")
assert( (is_vector(angles) && len(angles)>0) || valid_range(angles),
"The `angle` parameter must be a range or a non void list of numbers.")
let( // alignments is a vector of entries of the form: [polygon, error]
alignments = [
for(angle=angles)
reindex_polygon(
reference,
zrot(angle,p=poly,cp=cp),
return_error=true
)
], ],
scores = subindex(alignments,1), scores = subindex(alignments,1),
minscore = min(scores), minscore = min(scores),
minind = [for(i=idx(scores)) if (scores[i]<minscore+EPSILON) i], minind = [for(i=idx(scores)) if (scores[i]<minscore+EPSILON) i],
f=echo(best_angles = select(list(angles), minind)), dummy = is_def(angles) ? echo(best_angles = select(list(angles), minind)):0,
best = minind[0] best = minind[0]
) alignments[best][0]; )
return_ind ? (is_def(angles) ? list(angles)[best] : best)
: alignments[best][0];
// Function: are_polygons_equal() // Function: are_polygons_equal()
// Usage: // Usage:

View file

@ -287,9 +287,9 @@ function vnf_tri_array(points, row_wrap=false, reverse=false, vnf=EMPTY_VNF) =
// and eliminates any faces with fewer than 3 vertices. // and eliminates any faces with fewer than 3 vertices.
// (Unreferenced vertices of the input VNFs are not dropped.) // (Unreferenced vertices of the input VNFs are not dropped.)
// Arguments: // Arguments:
// vnfs - a list of the VNFs to merge in one VNF. // vnfs = a list of the VNFs to merge in one VNF.
// cleanup - when true, consolidates the duplicate vertices of the merge. Default: false // cleanup = when true, consolidates the duplicate vertices of the merge. Default: false
// eps - the tolerance in finding duplicates when cleanup=true. Default: EPSILON // eps = the tolerance in finding duplicates when cleanup=true. Default: EPSILON
function vnf_merge(vnfs, cleanup=false, eps=EPSILON) = function vnf_merge(vnfs, cleanup=false, eps=EPSILON) =
is_vnf(vnfs) ? vnf_merge([vnfs], cleanup, eps) : is_vnf(vnfs) ? vnf_merge([vnfs], cleanup, eps) :
assert( is_vnf_list(vnfs) , "Improper vnf or vnf list")   assert( is_vnf_list(vnfs) , "Improper vnf or vnf list")