more error messages for star()

improve speed and flexibility of apply()
fix triangulation bug
add support for single point 2d solutions in polygon_line_intersection
This commit is contained in:
Adrian Mariano 2021-09-14 20:10:55 -04:00
parent 2ea90b7467
commit 4f8ebb2e80
4 changed files with 46 additions and 21 deletions

View file

@ -142,6 +142,9 @@ function affine3d_to_2d(m) =
// Applies the specified transformation matrix to a point, pointlist, bezier patch or VNF.
// Both inputs can be 2D or 3D, and it is also allowed to supply 3D transformations with 2D
// data as long as the the only action on the z coordinate is a simple scaling.
// .
// If you construct your own matrices you can also use a transform that acts like a projection
// with fewer rows to produce lower dimensional output.
// Arguments:
// transform = The 2D or 3D transformation matrix to apply to the point/points.
// points = The point, pointlist, bezier patch, or VNF to apply the transformation to.
@ -173,14 +176,15 @@ function apply(transform,points) =
? /* BezPatch */ [for (x=points) apply(transform,x)] :
let(
tdim = len(transform[0])-1,
datadim = len(points[0])
datadim = len(points[0]),
outdim = min(datadim,len(transform)),
matrix = [for(i=[0:1:tdim]) [for(j=[0:1:outdim-1]) transform[j][i]]]
)
tdim == 3 && datadim == 3 ? [for(p=points) point3d(transform*concat(p,[1]))] :
tdim == 2 && datadim == 2 ? [for(p=points) point2d(transform*concat(p,[1]))] :
tdim == 3 && datadim == 2 ?
tdim==datadim && (datadim==3 || datadim==2) ? [for(p=points) concat(p,1)] * matrix
: tdim == 3 && datadim == 2 ?
assert(is_2d_transform(transform), str("Transforms is 3d but points are 2d"))
[for(p=points) point2d(transform*concat(p,[0,1]))] :
assert(false, str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
[for(p=points) concat(p,[0,1])]*matrix
: assert(false, str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim));
// Function: rot_decode()

View file

@ -654,11 +654,24 @@ function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps
boundedline = [line[0] + (bounded[0]? 0 : -bound) * linevec,
line[1] + (bounded[1]? 0 : bound) * linevec],
parts = split_path_at_region_crossings(boundedline, [poly], closed=false),
inside = [for (part = parts)
if (point_in_polygon(mean(part), poly,nonzero=nonzero,eps=eps)>=0) part
inside = [
if(point_in_polygon(parts[0][0], poly, nonzero=nonzero, eps=eps) == 0)
[parts[0][0]], // Add starting point if it is on the polygon
for(part = parts)
if (point_in_polygon(mean(part), poly, nonzero=nonzero, eps=eps) >=0 )
part
else if(len(part)==2 && point_in_polygon(part[1], poly, nonzero=nonzero, eps=eps) == 0)
[part[1]] // Add segment end if it is on the polygon
]
)
len(inside)==0? undef : _merge_segments(inside, [inside[0]], eps)
(
len(inside)==0 ? undef :
let(
seglist = [for (entry=_merge_segments(inside, [inside[0]], eps))
same_shape(entry,[[0,0]]) ? entry[0]:entry]
)
len(seglist)==1 && is_vector(seglist[0]) ? seglist[0] : seglist
)
: // 3d case
let(indices = noncollinear_triple(poly))
indices==[] ? undef : // Polygon is collinear
@ -681,11 +694,12 @@ function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps
)
segments==undef ? undef : [for(seg=segments) lift_plane(plane,seg)];
function _merge_segments(insegs,outsegs, eps, i=1) = //let(f=echo(insegs=insegs, outsegs=outsegs,lo=last(outsegs[1]), fi=insegs[i][0]))
function _merge_segments(insegs,outsegs, eps, i=1) =
i==len(insegs) ? outsegs :
approx(last(outsegs)[1], insegs[i][0], eps) ? _merge_segments(insegs, [each list_head(outsegs),[last(outsegs)[0],insegs[i][1]]], eps, i+1)
: _merge_segments(insegs, [each outsegs, insegs[i]], eps, i+1);
approx(last(last(outsegs)), insegs[i][0], eps)
? _merge_segments(insegs, [each list_head(outsegs),[last(outsegs)[0],last(insegs[i])]], eps, i+1)
: _merge_segments(insegs, [each outsegs, insegs[i]], eps, i+1);
// Function: plane_intersection()
@ -1443,10 +1457,10 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
) 2*(len(cross)%2)-1;
// Function: polygon_triangulation(poly, [ind], [eps])
// Function: polygon_triangulate(poly, [ind], [eps])
// Usage:
// triangles = polygon_triangulation(poly)
// triangles = polygon_triangulation(poly, ind)
// triangles = polygon_triangulate(poly)
// triangles = polygon_triangulate(poly, ind)
// Description:
// Given a simple polygon in 2D or 3D, triangulates it and returns a list
// of triples indexing into the polygon vertices. When the optional argument `ind` is
@ -1467,7 +1481,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
// eps = A maximum tolerance in geometrical tests. Default: EPSILON
// Example:
// poly = star(id=10, od=15,n=11);
// tris = polygon_triangulation(poly);
// tris = polygon_triangulate(poly);
// polygon(poly);
// up(1)
// color("blue");
@ -1477,11 +1491,11 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
// include<BOSL2/polyhedra.scad>
// vnf = regular_polyhedron_info(name="dodecahedron",side=5,info="vnf");
// %vnf_polyhedron(vnf);
// vnf_tri = [vnf[0], [for(face=vnf[1]) each polygon_triangulation(vnf[0], face) ] ];
// vnf_tri = [vnf[0], [for(face=vnf[1]) each polygon_triangulate(vnf[0], face) ] ];
// color("blue")
// vnf_wireframe(vnf_tri, d=.15);
function polygon_triangulation(poly, ind, eps=EPSILON) =
function polygon_triangulate(poly, ind, eps=EPSILON) =
assert(is_path(poly), "Polygon `poly` should be a list of 2d or 3d points")
assert(is_undef(ind)
|| (is_vector(ind) && min(ind)>=0 && max(ind)<len(poly) ),

View file

@ -1563,7 +1563,9 @@ function star(n, r, ir, d, or, od, id, step, realign=false, align_tip, align_pit
)
assert(is_def(n), "Must specify number of points, n")
assert(count==1, "Must specify exactly one of ir, id, step")
assert(stepOK, str("Parameter 'step' must be between 2 and ",floor(n/2-1/2)," for ",n," point star"))
assert(stepOK, n==4 ? "Parameter 'step' not allowed for 4 point stars"
: n==5 || n==6 ? str("Parameter 'step' must be 2 for ",n," point stars")
: str("Parameter 'step' must be between 2 and ",floor(n/2-1/2)," for ",n," point stars"))
let(
mat = !is_undef(_mat) ? _mat :
( realign? rot(-180/n, planar=true) : affine2d_identity() ) * (

View file

@ -211,7 +211,7 @@ function vnf_triangulate(vnf) =
let(
vnf = is_vnf_list(vnf)? vnf_merge(vnf) : vnf,
verts = vnf[0],
faces = [for (face=vnf[1]) polygon_triangulation(verts, face)]
faces = [for (face=vnf[1]) each polygon_triangulate(verts, face)]
) [verts, faces];
@ -546,6 +546,11 @@ function vnf_volume(vnf) =
])/6;
function vnf_area(vnf) =
let(verts=vnf[0])
sum([for(face=vnf[1]) polygon_area(select(verts,face))]);
// Function: vnf_centroid()
// Usage:
// vol = vnf_centroid(vnf);