mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-06 04:09:47 +00:00
commit
d57d2f006c
3 changed files with 224 additions and 186 deletions
406
geometry.scad
406
geometry.scad
|
@ -701,186 +701,6 @@ function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) =
|
||||||
res[0];
|
res[0];
|
||||||
|
|
||||||
|
|
||||||
// Function: polygon_line_intersection()
|
|
||||||
// Usage:
|
|
||||||
// pt = polygon_line_intersection(poly, line, [bounded], [nonzero], [eps]);
|
|
||||||
// Topics: Geometry, Polygons, Lines, Intersection
|
|
||||||
// Description:
|
|
||||||
// Takes a possibly bounded line, and a 2D or 3D planar polygon, and finds their intersection.
|
|
||||||
// If the line does not intersect the polygon then `undef` returns `undef`.
|
|
||||||
// In 3D if the line is not on the plane of the polygon but intersects it then you get a single intersection point.
|
|
||||||
// Otherwise the polygon and line are in the same plane, or when your input is 2D, ou will get a list of segments and
|
|
||||||
// single point lists. Use `is_vector` to distinguish these two cases.
|
|
||||||
// .
|
|
||||||
// In the 2D case, when single points are in the intersection they appear on the segment list as lists of a single point
|
|
||||||
// (like single point segments) so a single point intersection in 2D has the form `[[[x,y,z]]]` as compared
|
|
||||||
// to a single point intersection in 3D which has the form `[x,y,z]`. You can identify whether an entry in the
|
|
||||||
// segment list is a true segment by checking its length, which will be 2 for a segment and 1 for a point.
|
|
||||||
// Arguments:
|
|
||||||
// poly = The 3D planar polygon to find the intersection with.
|
|
||||||
// line = A list of two distinct 3D points on the line.
|
|
||||||
// bounded = If false, the line is considered unbounded. If true, it is treated as a bounded line segment. If given as `[true, false]` or `[false, true]`, the boundedness of the points are specified individually, allowing the line to be treated as a half-bounded ray. Default: false (unbounded)
|
|
||||||
// nonzero = set to true to use the nonzero rule for determining it points are in a polygon. See point_in_polygon. Default: false.
|
|
||||||
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
|
||||||
// Example(3D): The line intersects the 3d hexagon in a single point.
|
|
||||||
// hex = zrot(140,p=rot([-45,40,20],p=path3d(hexagon(r=15))));
|
|
||||||
// line = [[5,0,-13],[-3,-5,13]];
|
|
||||||
// isect = polygon_line_intersection(hex,line);
|
|
||||||
// stroke(hex,closed=true);
|
|
||||||
// stroke(line);
|
|
||||||
// color("red")move(isect)sphere(r=1,$fn=12);
|
|
||||||
// Example(2D): In 2D things are more complicated. The output is a list of intersection parts, in the simplest case a single segment.
|
|
||||||
// hex = hexagon(r=15);
|
|
||||||
// line = [[-20,10],[25,-7]];
|
|
||||||
// isect = polygon_line_intersection(hex,line);
|
|
||||||
// stroke(hex,closed=true);
|
|
||||||
// stroke(line,endcaps="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) sphere(r=1);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Here the line is treated as a ray.
|
|
||||||
// hex = hexagon(r=15);
|
|
||||||
// line = [[0,0],[25,-7]];
|
|
||||||
// isect = polygon_line_intersection(hex,line,RAY);
|
|
||||||
// stroke(hex,closed=true);
|
|
||||||
// stroke(line,endcap2="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Here the intersection is a single point, which is returned as a single point "path" on the path list.
|
|
||||||
// hex = hexagon(r=15);
|
|
||||||
// line = [[15,-10],[15,13]];
|
|
||||||
// isect = polygon_line_intersection(hex,line,RAY);
|
|
||||||
// stroke(hex,closed=true);
|
|
||||||
// stroke(line,endcap2="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Another way to get a single segment
|
|
||||||
// hex = hexagon(r=15);
|
|
||||||
// line = rot(30,p=[[15,-10],[15,25]],cp=[15,0]);
|
|
||||||
// isect = polygon_line_intersection(hex,line,RAY);
|
|
||||||
// stroke(hex,closed=true);
|
|
||||||
// stroke(line,endcap2="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Single segment again
|
|
||||||
// star = star(r=15,n=8,step=2);
|
|
||||||
// line = [[20,-5],[-5,20]];
|
|
||||||
// isect = polygon_line_intersection(star,line,RAY);
|
|
||||||
// stroke(star,closed=true);
|
|
||||||
// stroke(line,endcap2="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Solution is two points
|
|
||||||
// star = star(r=15,n=8,step=3);
|
|
||||||
// line = rot(22.5,p=[[15,-10],[15,20]],cp=[15,0]);
|
|
||||||
// isect = polygon_line_intersection(star,line,SEGMENT);
|
|
||||||
// stroke(star,closed=true);
|
|
||||||
// stroke(line);
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Solution is list of three segments
|
|
||||||
// star = star(r=25,ir=9,n=8);
|
|
||||||
// line = [[-25,12],[25,12]];
|
|
||||||
// isect = polygon_line_intersection(star,line);
|
|
||||||
// stroke(star,closed=true);
|
|
||||||
// stroke(line,endcaps="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
// Example(2D): Solution is a mixture of segments and points
|
|
||||||
// star = star(r=25,ir=9,n=7);
|
|
||||||
// line = [left(10,p=star[8]), right(50,p=star[8])];
|
|
||||||
// isect = polygon_line_intersection(star,line);
|
|
||||||
// stroke(star,closed=true);
|
|
||||||
// stroke(line,endcaps="arrow2");
|
|
||||||
// color("red")
|
|
||||||
// for(part=isect)
|
|
||||||
// if(len(part)==1)
|
|
||||||
// move(part[0]) circle(r=1,$fn=12);
|
|
||||||
// else
|
|
||||||
// stroke(part);
|
|
||||||
function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=EPSILON) =
|
|
||||||
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
|
||||||
assert(is_path(poly,dim=[2,3]), "Invalid polygon." )
|
|
||||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "Invalid bound condition.")
|
|
||||||
assert(_valid_line(line,dim=len(poly[0]),eps=eps), "Line invalid or does not match polygon dimension." )
|
|
||||||
let(
|
|
||||||
bounded = force_list(bounded,2),
|
|
||||||
poly = deduplicate(poly)
|
|
||||||
)
|
|
||||||
len(poly[0])==2 ? // planar case
|
|
||||||
let(
|
|
||||||
linevec = unit(line[1] - line[0]),
|
|
||||||
bound = 100*max(v_abs(flatten(pointlist_bounds(poly)))),
|
|
||||||
boundedline = [line[0] + (bounded[0]? 0 : -bound) * linevec,
|
|
||||||
line[1] + (bounded[1]? 0 : bound) * linevec],
|
|
||||||
parts = split_region_at_region_crossings(boundedline, [poly], closed1=false)[0][0],
|
|
||||||
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))
|
|
||||||
: // 3d case
|
|
||||||
let(indices = _noncollinear_triple(poly))
|
|
||||||
indices==[] ? undef : // Polygon is collinear
|
|
||||||
let(
|
|
||||||
plane = plane3pt(poly[indices[0]], poly[indices[1]], poly[indices[2]]),
|
|
||||||
plane_isect = plane_line_intersection(plane, line, bounded, eps)
|
|
||||||
)
|
|
||||||
is_undef(plane_isect) ? undef :
|
|
||||||
is_vector(plane_isect,3) ?
|
|
||||||
let(
|
|
||||||
poly2d = project_plane(plane,poly),
|
|
||||||
pt2d = project_plane(plane, plane_isect)
|
|
||||||
)
|
|
||||||
(point_in_polygon(pt2d, poly2d, nonzero=nonzero, eps=eps) < 0 ? undef : plane_isect)
|
|
||||||
: // Case where line is on the polygon plane
|
|
||||||
let(
|
|
||||||
poly2d = project_plane(plane, poly),
|
|
||||||
line2d = project_plane(plane, line),
|
|
||||||
segments = polygon_line_intersection(poly2d, line2d, bounded=bounded, nonzero=nonzero, eps=eps)
|
|
||||||
)
|
|
||||||
segments==undef ? undef
|
|
||||||
: [for(seg=segments) len(seg)==2 ? lift_plane(plane,seg) : [lift_plane(plane,seg[0])]];
|
|
||||||
|
|
||||||
function _merge_segments(insegs,outsegs, eps, i=1) =
|
|
||||||
i==len(insegs) ? outsegs :
|
|
||||||
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()
|
// Function: plane_intersection()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
@ -1048,15 +868,20 @@ function _is_point_above_plane(plane, point) =
|
||||||
// Arguments:
|
// Arguments:
|
||||||
// c = center of circle
|
// c = center of circle
|
||||||
// r = radius of circle
|
// r = radius of circle
|
||||||
// ---
|
|
||||||
// d = diameter of circle
|
|
||||||
// line = two points defining the line
|
// line = two points defining the line
|
||||||
// bounded = false for unbounded line, true for a segment, or a vector [false,true] or [true,false] to specify a ray with the first or second end unbounded. Default: false
|
// bounded = false for unbounded line, true for a segment, or a vector [false,true] or [true,false] to specify a ray with the first or second end unbounded. Default: false
|
||||||
|
// ---
|
||||||
|
// d = diameter of circle
|
||||||
// eps = epsilon used for identifying the case with one solution. Default: 1e-9
|
// eps = epsilon used for identifying the case with one solution. Default: 1e-9
|
||||||
function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) =
|
function circle_line_intersection(c,r,line,bounded=false,d,eps=EPSILON) =
|
||||||
let(r=get_radius(r=r,d=d,dflt=undef))
|
|
||||||
assert(_valid_line(line,2), "Invalid 2d line.")
|
assert(_valid_line(line,2), "Invalid 2d line.")
|
||||||
assert(is_vector(c,2), "Circle center must be a 2-vector")
|
assert(is_vector(c,2), "Circle center must be a 2-vector")
|
||||||
|
_circle_or_sphere_line_intersection(c,r,line,bounded,d,eps);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function _circle_or_sphere_line_intersection(c,r,line,bounded=false,d,eps=EPSILON) =
|
||||||
|
let(r=get_radius(r=r,d=d,dflt=undef))
|
||||||
assert(is_num(r) && r>0, "Radius must be positive")
|
assert(is_num(r) && r>0, "Radius must be positive")
|
||||||
assert(is_bool(bounded) || is_bool_list(bounded,2), "Invalid bound condition")
|
assert(is_bool(bounded) || is_bool_list(bounded,2), "Invalid bound condition")
|
||||||
let(
|
let(
|
||||||
|
@ -1491,6 +1316,34 @@ function _noncollinear_triple(points,error=true,eps=EPSILON) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Section: Sphere Calculations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: sphere_line_intersection()
|
||||||
|
// Usage:
|
||||||
|
// isect = sphere_line_intersection(c,<r|d>,[line],[bounded],[eps]);
|
||||||
|
// Topics: Geometry, Spheres, Lines, Intersection
|
||||||
|
// Description:
|
||||||
|
// Find intersection points between a sphere and a line, ray or segment specified by two points.
|
||||||
|
// By default the line is unbounded.
|
||||||
|
// Arguments:
|
||||||
|
// c = center of sphere
|
||||||
|
// r = radius of sphere
|
||||||
|
// line = two points defining the line
|
||||||
|
// bounded = false for unbounded line, true for a segment, or a vector [false,true] or [true,false] to specify a ray with the first or second end unbounded. Default: false
|
||||||
|
// ---
|
||||||
|
// d = diameter of sphere
|
||||||
|
// eps = epsilon used for identifying the case with one solution. Default: 1e-9
|
||||||
|
function sphere_line_intersection(c,r,line,bounded=false,d,eps=EPSILON) =
|
||||||
|
assert(_valid_line(line,3), "Invalid 3d line.")
|
||||||
|
assert(is_vector(c,3), "Sphere center must be a 3-vector")
|
||||||
|
_circle_or_sphere_line_intersection(c,r,line,bounded,d,eps);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Polygons
|
// Section: Polygons
|
||||||
|
|
||||||
// Function: polygon_area()
|
// Function: polygon_area()
|
||||||
|
@ -1762,6 +1615,191 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function: polygon_line_intersection()
|
||||||
|
// Usage:
|
||||||
|
// pt = polygon_line_intersection(poly, line, [bounded], [nonzero], [eps]);
|
||||||
|
// Topics: Geometry, Polygons, Lines, Intersection
|
||||||
|
// Description:
|
||||||
|
// Takes a possibly bounded line, and a 2D or 3D planar polygon, and finds their intersection. Note the polygon is
|
||||||
|
// treated as its boundary and interior, so the intersection may include both points and line segments.
|
||||||
|
// If the line does not intersect the polygon returns `undef`.
|
||||||
|
// In 3D if the line is not on the plane of the polygon but intersects it then you get a single intersection point.
|
||||||
|
// Otherwise the polygon and line are in the same plane, or when your input is 2D, you will get a list of segments and
|
||||||
|
// single point lists. Use `is_vector` to distinguish these two cases.
|
||||||
|
// .
|
||||||
|
// In the 2D case, a common result is a list containing a single segment, which lists the two intersection points
|
||||||
|
// with the boundary of the polygon.
|
||||||
|
// When single points are in the intersection (the line just touches a polygon corner) they appear on the segment
|
||||||
|
// list as lists of a single point
|
||||||
|
// (like single point segments) so a single point intersection in 2D has the form `[[[x,y,z]]]` as compared
|
||||||
|
// to a single point intersection in 3D which has the form `[x,y,z]`. You can identify whether an entry in the
|
||||||
|
// segment list is a true segment by checking its length, which will be 2 for a segment and 1 for a point.
|
||||||
|
// Arguments:
|
||||||
|
// poly = The 3D planar polygon to find the intersection with.
|
||||||
|
// line = A list of two distinct 3D points on the line.
|
||||||
|
// bounded = If false, the line is considered unbounded. If true, it is treated as a bounded line segment. If given as `[true, false]` or `[false, true]`, the boundedness of the points are specified individually, allowing the line to be treated as a half-bounded ray. Default: false (unbounded)
|
||||||
|
// nonzero = set to true to use the nonzero rule for determining it points are in a polygon. See point_in_polygon. Default: false.
|
||||||
|
// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9)
|
||||||
|
// Example(3D): The line intersects the 3d hexagon in a single point.
|
||||||
|
// hex = zrot(140,p=rot([-45,40,20],p=path3d(hexagon(r=15))));
|
||||||
|
// line = [[5,0,-13],[-3,-5,13]];
|
||||||
|
// isect = polygon_line_intersection(hex,line);
|
||||||
|
// stroke(hex,closed=true);
|
||||||
|
// stroke(line);
|
||||||
|
// color("red")move(isect)sphere(r=1,$fn=12);
|
||||||
|
// Example(2D): In 2D things are more complicated. The output is a list of intersection parts, in the simplest case a single segment.
|
||||||
|
// hex = hexagon(r=15);
|
||||||
|
// line = [[-20,10],[25,-7]];
|
||||||
|
// isect = polygon_line_intersection(hex,line);
|
||||||
|
// stroke(hex,closed=true);
|
||||||
|
// stroke(line,endcaps="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) sphere(r=1);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Here the line is treated as a ray.
|
||||||
|
// hex = hexagon(r=15);
|
||||||
|
// line = [[0,0],[25,-7]];
|
||||||
|
// isect = polygon_line_intersection(hex,line,RAY);
|
||||||
|
// stroke(hex,closed=true);
|
||||||
|
// stroke(line,endcap2="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Here the intersection is a single point, which is returned as a single point "path" on the path list.
|
||||||
|
// hex = hexagon(r=15);
|
||||||
|
// line = [[15,-10],[15,13]];
|
||||||
|
// isect = polygon_line_intersection(hex,line,RAY);
|
||||||
|
// stroke(hex,closed=true);
|
||||||
|
// stroke(line,endcap2="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Another way to get a single segment
|
||||||
|
// hex = hexagon(r=15);
|
||||||
|
// line = rot(30,p=[[15,-10],[15,25]],cp=[15,0]);
|
||||||
|
// isect = polygon_line_intersection(hex,line,RAY);
|
||||||
|
// stroke(hex,closed=true);
|
||||||
|
// stroke(line,endcap2="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Single segment again
|
||||||
|
// star = star(r=15,n=8,step=2);
|
||||||
|
// line = [[20,-5],[-5,20]];
|
||||||
|
// isect = polygon_line_intersection(star,line,RAY);
|
||||||
|
// stroke(star,closed=true);
|
||||||
|
// stroke(line,endcap2="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Solution is two points
|
||||||
|
// star = star(r=15,n=8,step=3);
|
||||||
|
// line = rot(22.5,p=[[15,-10],[15,20]],cp=[15,0]);
|
||||||
|
// isect = polygon_line_intersection(star,line,SEGMENT);
|
||||||
|
// stroke(star,closed=true);
|
||||||
|
// stroke(line);
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Solution is list of three segments
|
||||||
|
// star = star(r=25,ir=9,n=8);
|
||||||
|
// line = [[-25,12],[25,12]];
|
||||||
|
// isect = polygon_line_intersection(star,line);
|
||||||
|
// stroke(star,closed=true);
|
||||||
|
// stroke(line,endcaps="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
// Example(2D): Solution is a mixture of segments and points
|
||||||
|
// star = star(r=25,ir=9,n=7);
|
||||||
|
// line = [left(10,p=star[8]), right(50,p=star[8])];
|
||||||
|
// isect = polygon_line_intersection(star,line);
|
||||||
|
// stroke(star,closed=true);
|
||||||
|
// stroke(line,endcaps="arrow2");
|
||||||
|
// color("red")
|
||||||
|
// for(part=isect)
|
||||||
|
// if(len(part)==1)
|
||||||
|
// move(part[0]) circle(r=1,$fn=12);
|
||||||
|
// else
|
||||||
|
// stroke(part);
|
||||||
|
function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=EPSILON) =
|
||||||
|
assert( is_finite(eps) && eps>=0, "The tolerance should be a positive number." )
|
||||||
|
assert(is_path(poly,dim=[2,3]), "Invalid polygon." )
|
||||||
|
assert(is_bool(bounded) || is_bool_list(bounded,2), "Invalid bound condition.")
|
||||||
|
assert(_valid_line(line,dim=len(poly[0]),eps=eps), "Line invalid or does not match polygon dimension." )
|
||||||
|
let(
|
||||||
|
bounded = force_list(bounded,2),
|
||||||
|
poly = deduplicate(poly)
|
||||||
|
)
|
||||||
|
len(poly[0])==2 ? // planar case
|
||||||
|
let(
|
||||||
|
linevec = unit(line[1] - line[0]),
|
||||||
|
bound = 100*max(v_abs(flatten(pointlist_bounds(poly)))),
|
||||||
|
boundedline = [line[0] + (bounded[0]? 0 : -bound) * linevec,
|
||||||
|
line[1] + (bounded[1]? 0 : bound) * linevec],
|
||||||
|
parts = split_region_at_region_crossings(boundedline, [poly], closed1=false)[0][0],
|
||||||
|
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))
|
||||||
|
: // 3d case
|
||||||
|
let(indices = _noncollinear_triple(poly))
|
||||||
|
indices==[] ? undef : // Polygon is collinear
|
||||||
|
let(
|
||||||
|
plane = plane3pt(poly[indices[0]], poly[indices[1]], poly[indices[2]]),
|
||||||
|
plane_isect = plane_line_intersection(plane, line, bounded, eps)
|
||||||
|
)
|
||||||
|
is_undef(plane_isect) ? undef :
|
||||||
|
is_vector(plane_isect,3) ?
|
||||||
|
let(
|
||||||
|
poly2d = project_plane(plane,poly),
|
||||||
|
pt2d = project_plane(plane, plane_isect)
|
||||||
|
)
|
||||||
|
(point_in_polygon(pt2d, poly2d, nonzero=nonzero, eps=eps) < 0 ? undef : plane_isect)
|
||||||
|
: // Case where line is on the polygon plane
|
||||||
|
let(
|
||||||
|
poly2d = project_plane(plane, poly),
|
||||||
|
line2d = project_plane(plane, line),
|
||||||
|
segments = polygon_line_intersection(poly2d, line2d, bounded=bounded, nonzero=nonzero, eps=eps)
|
||||||
|
)
|
||||||
|
segments==undef ? undef
|
||||||
|
: [for(seg=segments) len(seg)==2 ? lift_plane(plane,seg) : [lift_plane(plane,seg[0])]];
|
||||||
|
|
||||||
|
function _merge_segments(insegs,outsegs, eps, i=1) =
|
||||||
|
i==len(insegs) ? outsegs :
|
||||||
|
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: polygon_triangulate()
|
// Function: polygon_triangulate()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
|
|
@ -817,7 +817,7 @@ function list_remove_values(list,values=[],all=false) =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Section: Iteration Helpers
|
// Section: Lists of Subsets
|
||||||
|
|
||||||
// Function: idx()
|
// Function: idx()
|
||||||
// Usage:
|
// Usage:
|
||||||
|
|
|
@ -351,7 +351,7 @@ module robertson_mask(size, extra=1) {
|
||||||
Fmin = [0.032, 0.057, 0.065, 0.085, 0.090][size];
|
Fmin = [0.032, 0.057, 0.065, 0.085, 0.090][size];
|
||||||
Fmax = [0.038, 0.065, 0.075, 0.095, 0.100][size];
|
Fmax = [0.038, 0.065, 0.075, 0.095, 0.100][size];
|
||||||
F = (Fmin + Fmax) / 2 * INCH;
|
F = (Fmin + Fmax) / 2 * INCH;
|
||||||
ang = 2;
|
ang = 4;
|
||||||
h = T + extra;
|
h = T + extra;
|
||||||
down(T) {
|
down(T) {
|
||||||
intersection(){
|
intersection(){
|
||||||
|
|
Loading…
Reference in a new issue