diff --git a/geometry.scad b/geometry.scad index aee57c5..0b9d240 100644 --- a/geometry.scad +++ b/geometry.scad @@ -11,6 +11,9 @@ // FileFootnotes: STD=Included in std.scad ////////////////////////////////////////////////////////////////////// +_BOSL2_GEOMETRY = is_undef(_BOSL2_STD) && (is_undef(BOSL2_NO_STD_WARNING) || !BOSL2_NO_STD_WARNING) ? + echo("Warning: geometry.scad included without std.scad; dependencies may be missing\nSet BOSL2_NO_STD_WARNING = true to mute this warning.") true : true; + // Section: Lines, Rays, and Segments @@ -29,14 +32,14 @@ // point = The point to test. // line = Array of two points defining the line, ray, or segment to test against. // bounded = boolean or list of two booleans defining endpoint conditions for the line. If false treat the line as an unbounded line. If true treat it as a segment. If [true,false] treat as a ray, based at the first endpoint. Default: false -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function is_point_on_line(point, line, bounded=false, eps=EPSILON) = +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function is_point_on_line(point, line, bounded=false, eps=_EPSILON) = assert(is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." ) assert(is_vector(point), "\nPoint must be a vector.") assert(_valid_line(line, len(point),eps),"\nGiven line is not valid.") _is_point_on_line(point, line, bounded,eps); -function _is_point_on_line(point, line, bounded=false, eps=EPSILON) = +function _is_point_on_line(point, line, bounded=false, eps=_EPSILON) = let( v1 = (line[1]-line[0]), v0 = (point-line[0]), @@ -55,12 +58,12 @@ function _dist2line(d,n) = norm(d-(d * n) * n); ///Internal -function _valid_line(line,dim,eps=EPSILON) = +function _valid_line(line,dim,eps=_EPSILON) = is_matrix(line,2,dim) && norm(line[1]-line[0])>eps*max(norm(line[1]),norm(line[0])); //Internal -function _valid_plane(p, eps=EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps); +function _valid_plane(p, eps=_EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps); /// Internal Function: _is_at_left() @@ -73,7 +76,7 @@ function _valid_plane(p, eps=EPSILON) = is_vector(p,4) && ! approx(norm(p),0,eps /// pt = The 2d point to check position of. /// line = Array of two 2d points forming the line segment to test against. /// eps = Tolerance in the geometrical tests. -function _is_at_left(pt,line,eps=EPSILON) = _tri_class([pt,line[0],line[1]],eps) <= 0; +function _is_at_left(pt,line,eps=_EPSILON) = _tri_class([pt,line[0],line[1]],eps) <= 0; /// Internal Function: _degenerate_tri() @@ -100,7 +103,7 @@ function _degenerate_tri(tri,eps) = /// Arguments: /// tri = A list of the three 2d vertices of a triangle. /// eps = Tolerance in the geometrical tests. -function _tri_class(tri, eps=EPSILON) = +function _tri_class(tri, eps=_EPSILON) = let( crx = cross(tri[1]-tri[2],tri[0]-tri[2]) ) abs( crx ) <= eps*norm(tri[1]-tri[2])*norm(tri[0]-tri[2]) ? 0 : sign( crx ); @@ -118,7 +121,7 @@ function _tri_class(tri, eps=EPSILON) = /// point = The point to check position of. /// tri = A list of the three 2d vertices of a triangle. /// eps = Tolerance in the geometrical tests. -function _pt_in_tri(point, tri, eps=EPSILON) = +function _pt_in_tri(point, tri, eps=_EPSILON) = min( _tri_class([tri[0],tri[1],point],eps), _tri_class([tri[1],tri[2],point],eps), _tri_class([tri[2],tri[0],point],eps) ); @@ -135,7 +138,7 @@ function _pt_in_tri(point, tri, eps=EPSILON) = /// Arguments: /// point = The point to check position of. /// line = Array of two points forming the line segment to test against. -function _point_left_of_line2d(point, line, eps=EPSILON) = +function _point_left_of_line2d(point, line, eps=_EPSILON) = assert( is_vector(point,2) && is_vector(line*point, 2), "\nImproper input." ) // cross(line[0]-point, line[1]-line[0]); _tri_class([point,line[1],line[0]],eps); @@ -153,8 +156,8 @@ function _point_left_of_line2d(point, line, eps=EPSILON) = // a = First point or list of points. // b = Second point or undef; it should be undef if `c` is undef // c = Third point or undef. -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function is_collinear(a, b, c, eps=EPSILON) = +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function is_collinear(a, b, c, eps=_EPSILON) = assert( is_path([a,b,c],dim=undef) || ( is_undef(b) && is_undef(c) && is_path(a,dim=undef) ), "\nInput should be 3 points or a list of points with same dimension.") @@ -205,7 +208,7 @@ function point_line_distance(pt, line, bounded=false) = // Example: // dist = segment_distance([[-14,3], [-15,9]], [[-10,0], [10,0]]); // Returns: 5 // dist2 = segment_distance([[-5,5], [5,-5]], [[-10,3], [10,-3]]); // Returns: 0 -function segment_distance(seg1, seg2,eps=EPSILON) = +function segment_distance(seg1, seg2,eps=_EPSILON) = assert( is_matrix(concat(seg1,seg2),4), "\nInputs should be two valid segments." ) convex_distance(seg1,seg2,eps); @@ -247,7 +250,7 @@ function line_normal(p1,p2) = // the extension of the segment. If lines are parallel or coincident then // it returns undef. -function _general_line_intersection(s1,s2,eps=EPSILON) = +function _general_line_intersection(s1,s2,eps=_EPSILON) = let( denominator = cross(s1[0]-s1[1],s2[0]-s2[1]) ) @@ -281,7 +284,7 @@ function _general_line_intersection(s1,s2,eps=EPSILON) = // bounded2 = boolean or list of two booleans defining which ends are bounded for line2. Default: [false,false] // --- // bounded = boolean or list of two booleans defining which ends are bounded for both lines. The bounded1 and bounded2 parameters override this if both are given. -// eps = tolerance for geometric comparisons. Default: `EPSILON` (1e-9) +// eps = tolerance for geometric comparisons. Default: `_EPSILON` (1e-9) // Example(2D): The segments do not intersect but the lines do in this example. // line1 = 10*[[9, 4], [5, 7]]; // line2 = 10*[[2, 3], [6, 5]]; @@ -302,7 +305,7 @@ function _general_line_intersection(s1,s2,eps=EPSILON) = // stroke(line1); // stroke(line2); // isect = line_intersection(line1, line2, bounded=true); // Returns undef -function line_intersection(line1, line2, bounded1, bounded2, bounded, eps=EPSILON) = +function line_intersection(line1, line2, bounded1, bounded2, bounded, eps=_EPSILON) = assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." ) assert( _valid_line(line1,dim=2,eps=eps), "\nFirst line invalid.") assert( _valid_line(line2,dim=2,eps=eps), "\nSecond line invalid.") @@ -421,7 +424,7 @@ function line_closest_point(line, pt, bounded=false) = // Arguments: // points = The list of points to find the line through. // check_collinear = If true, don't verify that all points are collinear. Default: false -// eps = How much variance is allowed in testing each point against the line. Default: `EPSILON` (1e-9) +// eps = How much variance is allowed in testing each point against the line. Default: `_EPSILON` (1e-9) // Example(FlatSpin,VPD=250): A line fitted to a cloud of points. // points = rot(45, v=[-0.5,1,0], // p=random_points(100,3,scale=[5,5,50],seed=47)); @@ -434,7 +437,7 @@ function _line_greatest_distance(points,line) = // internal function : let(d = [ for(p=points) point_line_distance(p, line) ]) max(d); -function line_from_points(points, check_collinear=false, eps=EPSILON, fast) = +function line_from_points(points, check_collinear=false, eps=_EPSILON, fast) = assert( is_path(points), "\nInvalid point list." ) assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." ) len(points) == 2 @@ -468,8 +471,8 @@ function line_from_points(points, check_collinear=false, eps=EPSILON, fast) = // Returns true if the given 3D points are non-collinear and are on a plane. // Arguments: // points = The points to test. -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function is_coplanar(points, eps=EPSILON) = +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function is_coplanar(points, eps=_EPSILON) = assert( is_path(points,dim=3) , "\nInput should be a list of 3D points." ) assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a non-negative value." ) len(points)<=2 ? false @@ -560,7 +563,7 @@ function plane_from_normal(normal, pt=[0,0,0]) = // Based on: https://en.wikipedia.org/wiki/Eigenvalue_algorithm function _eigenvals_symm_3(M) = let( p1 = pow(M[0][1],2) + pow(M[0][2],2) + pow(M[1][2],2) ) - (p1=0), "\nThe tolerance should be a non-negative value." ) len(points) == 3 @@ -660,14 +663,14 @@ function plane_from_points(points, check_coplanar=false, eps=EPSILON, fast) = // Arguments: // poly = The planar 3D polygon to find the plane of. // check_coplanar = If false, doesn't verify that all points in the polygon are coplanar. Default: true -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) // Example(3D): // xyzpath = rot(45, v=[0,1,0], p=path3d(star(n=5,step=2,d=100), 70)); // plane = plane_from_polygon(xyzpath); // #stroke(xyzpath,closed=true,width=3); // cp = centroid(xyzpath); // move(cp) rot(from=UP,to=plane_normal(plane)) anchor_arrow(45); -function plane_from_polygon(poly, check_coplanar=true, eps=EPSILON, fast) = +function plane_from_polygon(poly, check_coplanar=true, eps=_EPSILON, fast) = assert( is_path(poly,dim=3), "\nInvalid polygon." ) assert( is_finite(eps) && (eps>=0), "\nThe tolerance should be a non-negative value." ) let( @@ -718,7 +721,7 @@ function plane_offset(plane) = // Returns [POINT, U] if line intersects plane at one point, where U is zero at line[0] and 1 at line[1] // Returns [LINE, undef] if the line is on the plane. // Returns undef if line is parallel to, but not on the given plane. -function _general_plane_line_intersection(plane, line, eps=EPSILON) = +function _general_plane_line_intersection(plane, line, eps=_EPSILON) = let( a = plane*[each line[0],-1], // evaluation of the plane expression at line[0] b = plane*[each(line[1]-line[0]),0] // difference between the plane expression evaluation at line[1] and at line[0] @@ -756,8 +759,8 @@ function _normalize_plane(plane) = // plane = The [A,B,C,D] values for the equation of the plane. // line = A list of two distinct 3D points that are 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) -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function plane_line_intersection(plane, line, bounded=false, eps=EPSILON) = +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function plane_line_intersection(plane, line, bounded=false, eps=_EPSILON) = assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." ) assert(_valid_plane(plane,eps=eps) && _valid_line(line,dim=3,eps=eps), "\nInvalid plane and/or 3d line.") assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition.") @@ -912,8 +915,8 @@ function _pointlist_greatest_distance(points,plane) = // Arguments: // plane = The plane to test the points on. // points = The list of 3D points to test. -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function are_points_on_plane(points, plane, eps=EPSILON) = +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function are_points_on_plane(points, plane, eps=_EPSILON) = assert( _valid_plane(plane), "\nInvalid plane." ) assert( is_matrix(points,undef,3) && len(points)>0, "\nInvalid pointlist." ) // using is_matrix it accepts len(points)==1 assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." ) @@ -933,7 +936,7 @@ function are_points_on_plane(points, plane, eps=EPSILON) = /// plane = The [A,B,C,D] coefficients for the first plane equation `Ax+By+Cz=D`. /// point = The 3D point to test. function _is_point_above_plane(plane, point) = - point_plane_distance(plane, point) > EPSILON; + point_plane_distance(plane, point) > _EPSILON; // Module: show_plane() @@ -1028,14 +1031,14 @@ module show_plane(plane, size, offset=0) // color("black") stroke(line, endcaps="arrow2", width=0.5); // isects = circle_line_intersection(r=r, cp=cp, line=line); // color("#f44") move_copies(isects) circle(d=1); -function circle_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) = +function circle_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) = assert(_valid_line(line,2), "\nInvalid 2d line.") assert(is_vector(cp,2), "\nCircle center must be a 2-vector") _circle_or_sphere_line_intersection(r, cp, line, bounded, d, eps); -function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) = +function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) = let(r=get_radius(r=r,d=d,dflt=undef)) assert(is_num(r) && r>0, "\nRadius must be positive") assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition") @@ -1071,7 +1074,7 @@ function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps= // cp1 = Centerpoint of the first circle. // r2 = Radius of the second circle. // cp2 = Centerpoint of the second circle. -// eps = Tolerance for detecting tangent circles. Default: EPSILON +// eps = Tolerance for detecting tangent circles. Default: _EPSILON // --- // d1 = Diameter of the first circle. // d2 = Diameter of the second circle. @@ -1107,7 +1110,7 @@ function _circle_or_sphere_line_intersection(r, cp, line, bounded=false, d, eps= // move(cp1) stroke(circle(r=r1), width=0.2, closed=true); // move(cp2) stroke(circle(r=r2), width=0.2, closed=true); // color("red") move_copies(pts) circle(r=.3); -function circle_circle_intersection(r1, cp1, r2, cp2, eps=EPSILON, d1, d2) = +function circle_circle_intersection(r1, cp1, r2, cp2, eps=_EPSILON, d1, d2) = assert( is_path([cp1,cp2],dim=2), "\nInvalid center point(s)." ) let( r1 = get_radius(r1=r1,d1=d1), @@ -1418,8 +1421,8 @@ function circle_circle_tangents(r1, cp1, r2, cp2, d1, d2) = /// Arguments: /// points = List of input points. /// error = Defines the behaviour for collinear input points. When `true`, produces an error, otherwise returns []. Default: `true`. -/// eps = Tolerance for collinearity test. Default: EPSILON. -function _noncollinear_triple(points,error=true,eps=EPSILON) = +/// eps = Tolerance for collinearity test. Default: _EPSILON. +function _noncollinear_triple(points,error=true,eps=_EPSILON) = assert( is_path(points), "\nInvalid input points." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) len(points)<3 ? [] : @@ -1468,7 +1471,7 @@ function _noncollinear_triple(points,error=true,eps=EPSILON) = // color("cyan") stroke(line); // move(cp) sphere(r=r, $fn=72); // color("red") move_copies(isects) sphere(d=3, $fn=12); -function sphere_line_intersection(r, cp, line, bounded=false, d, eps=EPSILON) = +function sphere_line_intersection(r, cp, line, bounded=false, d, eps=_EPSILON) = assert(_valid_line(line,3), "\nInvalid 3d line.") assert(is_vector(cp,3), "\nSphere center must be a 3-vector") _circle_or_sphere_line_intersection(r, cp, line, bounded, d, eps); @@ -1543,7 +1546,7 @@ function polygon_area(poly, signed=false) = // linear_extrude(height=0.01) polygon(path); // cp = centroid(path); // color("red") move(cp) sphere(d=2); -function centroid(object,eps=EPSILON) = +function centroid(object,eps=_EPSILON) = assert(is_finite(eps) && (eps>=0), "\nThe tolerance should a non-negative value." ) is_vnf(object) ? _vnf_centroid(object,eps) : is_path(object,[2,3]) ? _polygon_centroid(object,eps) @@ -1553,7 +1556,7 @@ function centroid(object,eps=EPSILON) = /// Internal Function: _region_centroid() /// Compute centroid of region -function _region_centroid(region,eps=EPSILON) = +function _region_centroid(region,eps=_EPSILON) = let( region=force_region(region), parts = region_parts(region), @@ -1578,8 +1581,8 @@ function _region_centroid(region,eps=EPSILON) = /// polygons or an error is produced. /// Arguments: /// poly = Points of the polygon from which the centroid is calculated. -/// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) -function _polygon_centroid(poly, eps=EPSILON) = +/// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) +function _polygon_centroid(poly, eps=_EPSILON) = assert( is_path(poly,dim=[2,3]), "\nThe input must be a 2D or 3D polygon." ) let( n = len(poly[0])==2 ? 1 : @@ -1680,7 +1683,7 @@ function polygon_normal(poly) = // point = The 2D point to check // poly = The list of 2D points forming the perimeter of the polygon. // nonzero = The rule to use: true for "Nonzero" rule and false for "Even-Odd". Default: false (Even-Odd) -// eps = Tolerance in geometric comparisons. Default: `EPSILON` (1e-9) +// eps = Tolerance in geometric comparisons. Default: `_EPSILON` (1e-9) // Example(2D): With nonzero set to false (the default), we get this result. Green dots are inside the polygon and red are outside: // a=20*2/3; // b=30*2/3; @@ -1723,7 +1726,7 @@ function _point_above_below_segment(point, edge) = : (edge[1].y <= 0 && cross(edge[0], edge[1]-edge[0]) < 0) ? -1 : 0; -function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) = +function point_in_polygon(point, poly, nonzero=false, eps=_EPSILON) = // Original algorithms from http://geomalgorithms.com/a03-_inclusion.html assert( is_vector(point,2) && is_path(poly,dim=2) && len(poly)>2, "\nThe point and polygon should be in 2D. The polygon should have more that 2 points." ) @@ -1802,7 +1805,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) = // 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) +// 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]]; @@ -1906,7 +1909,7 @@ function point_in_polygon(point, poly, nonzero=false, eps=EPSILON) = // move(part[0]) circle(r=1,$fn=12); // else // stroke(part); -function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=EPSILON) = +function polygon_line_intersection(poly, line, bounded=false, nonzero=false, eps=_EPSILON) = assert( is_finite(eps) && eps>=0, "\nThe tolerance should be a positive number." ) assert(is_path(poly,dim=[2,3]), "\nInvalid polygon." ) assert(is_bool(bounded) || is_bool_list(bounded,2), "\nInvalid bound condition.") @@ -2000,7 +2003,7 @@ function _merge_segments(insegs,outsegs, eps, i=1) = // poly = Array of the polygon vertices. // ind = If given, a list of indices indexing the vertices of the polygon in `poly`. Default: use all the points of poly // error = If false, returns `undef` when the polygon cannot be triangulated; otherwise, issues an assert error. Default: true. -// eps = A maximum tolerance in geometrical tests. Default: EPSILON +// eps = A maximum tolerance in geometrical tests. Default: _EPSILON // Example(2D,NoAxes): a simple polygon; see from above // poly = star(id=10, od=15,n=11); // tris = polygon_triangulate(poly); @@ -2037,7 +2040,7 @@ function _merge_segments(insegs,outsegs, eps, i=1) = // vnf_tri = [vnf[0], [for(face=vnf[1]) each polygon_triangulate(vnf[0], face) ] ]; // color("blue") // vnf_wireframe(vnf_tri, width=.15); -function polygon_triangulate(poly, ind, error=true, eps=EPSILON) = +function polygon_triangulate(poly, ind, error=true, eps=_EPSILON) = assert(is_path(poly) && len(poly)>=3, "\nPolygon `poly` should be a list of at least three 2d or 3d points") assert(is_undef(ind) || (is_vector(ind) && min(ind)>=0 && max(ind)= len(remaining) ? triangles : let ( // pick a point @@ -2632,7 +2635,7 @@ function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let( // evaluate the triangle plane equations at point i planeq_val = planes*[each points[i], -1], // find the triangles that are in conflict with the point (point not inside) - conflicts = [for (i = [0:1:len(planeq_val)-1]) if (planeq_val[i]>EPSILON) i ], + conflicts = [for (i = [0:1:len(planeq_val)-1]) if (planeq_val[i]>_EPSILON) i ], // collect the halfedges of all triangles that are in conflict halfedges = [ for(c = conflicts, i = [0:2]) @@ -2645,12 +2648,12 @@ function _hull3d_iterative(points, triangles, planes, remaining, _i=0) = //let( // add tria2add and remove conflict triangles new_triangles = concat( tri2add, - [ for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=EPSILON) triangles[i] ] + [ for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=_EPSILON) triangles[i] ] ), // add the plane equations of new added triangles and remove the plane equations of the conflict ones new_planes = [ for (t = tri2add) plane3pt_indexed(points, t[0], t[1], t[2]) , - for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=EPSILON) planes[i] ] + for (i = [0:1:len(planes)-1]) if (planeq_val[i]<=_EPSILON) planes[i] ] ) _hull3d_iterative( points, new_triangles, @@ -2692,13 +2695,13 @@ function _find_first_noncoplanar(plane, points, i=0) = // If the points are collinear or not coplanar an error may be generated. // Arguments: // poly = Polygon to check. -// eps = Tolerance for the collinearity and coplanarity tests. Default: EPSILON. +// eps = Tolerance for the collinearity and coplanarity tests. Default: _EPSILON. // Example: // test1 = is_polygon_convex(circle(d=50)); // Returns: true // test2 = is_polygon_convex(rot([50,120,30], p=path3d(circle(1,$fn=50)))); // Returns: true // spiral = [for (i=[0:36]) let(a=-i*10) (10+i)*[cos(a),sin(a)]]; // test = is_polygon_convex(spiral); // Returns: false -function is_polygon_convex(poly,eps=EPSILON) = +function is_polygon_convex(poly,eps=_EPSILON) = assert(is_path(poly), "\nThe input should be a 2D or 3D polygon." ) let( lp = len(poly), @@ -2741,7 +2744,7 @@ function is_polygon_convex(poly,eps=EPSILON) = // Arguments: // points1 = first list of 2d or 3d points. // points2 = second list of 2d or 3d points. -// eps = tolerance in distance evaluations. Default: EPSILON. +// eps = tolerance in distance evaluations. Default: _EPSILON. // Example(2D): // pts1 = move([-3,0], p=square(3,center=true)); // pts2 = rot(a=45, p=square(2,center=true)); @@ -2759,7 +2762,7 @@ function is_polygon_convex(poly,eps=EPSILON) = // vnf_polyhedron(sphr2); // echo(convex_distance(sphr1[0], sphr2[0])); // Returns: 0 // echo(convex_distance(sphr1[0], sphr3[0])); // Returns: 0.5 -function convex_distance(points1, points2, eps=EPSILON) = +function convex_distance(points1, points2, eps=_EPSILON) = assert(is_matrix(points1) && is_matrix(points2,undef,len(points1[0])), "\nThe input lists should be compatible consistent non empty lists of points.") assert(len(points1[0])==2 || len(points1[0])==3 , @@ -2773,7 +2776,7 @@ function convex_distance(points1, points2, eps=EPSILON) = // Finds the vector difference between the hulls of the two pointsets by the GJK algorithm // Based on: // http://www.dtecta.com/papers/jgt98convex.pdf -function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) = +function _GJK_distance(points1, points2, eps=_EPSILON, lbd, d, simplex=[]) = let( nrd = norm(d) ) // distance upper bound nrd eps*eps ? false : // no collision @@ -2847,7 +2850,7 @@ function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) = // given a simplex s, returns a pair: // - the point of the s closest to the origin // - the smallest sub-simplex of s that contains that point -function _closest_simplex(s,eps=EPSILON) = +function _closest_simplex(s,eps=_EPSILON) = len(s)==2 ? _closest_s1(s,eps) : len(s)==3 ? _closest_s2(s,eps) : len(s)==4 ? _closest_s3(s,eps) : @@ -2855,7 +2858,7 @@ function _closest_simplex(s,eps=EPSILON) = // find the point of a 1-simplex closest to the origin -function _closest_s1(s,eps=EPSILON) = +function _closest_s1(s,eps=_EPSILON) = norm(s[1]-s[0])<=eps*(norm(s[0])+norm(s[1]))/2 ? [ s[0], [s[0]] ] : let( c = s[1]-s[0], @@ -2867,7 +2870,7 @@ function _closest_s1(s,eps=EPSILON) = // find the point of a 2-simplex closest to the origin -function _closest_s2(s, eps=EPSILON) = +function _closest_s2(s, eps=_EPSILON) = // considering that s[2] was the last inserted vertex in s by GJK, // the plane orthogonal to the triangle [ origin, s[0], s[1] ] that // contains [s[0],s[1]] have the origin and s[2] on the same side; @@ -2898,7 +2901,7 @@ function _closest_s2(s, eps=EPSILON) = // find the point of a 3-simplex closest to the origin -function _closest_s3(s,eps=EPSILON) = +function _closest_s3(s,eps=_EPSILON) = let( nr = cross(s[1]-s[0],s[2]-s[0]), sz = [ norm(s[0]-s[1]), norm(s[1]-s[2]), norm(s[2]-s[0]) ] ) norm(nr)<=eps*pow(max(sz),2)