From dcae838b82998504572251dacc24a1dcaee30f32 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Wed, 23 Jun 2021 16:24:59 +0100 Subject: [PATCH 1/4] Minor tweaks --- geometry.scad | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/geometry.scad b/geometry.scad index 91c42db..2610abd 100644 --- a/geometry.scad +++ b/geometry.scad @@ -1110,7 +1110,7 @@ function plane_offset(plane) = // } function projection_on_plane(plane, points) = assert( _valid_plane(plane), "Invalid plane." ) - assert( is_path(points), "Invalid list of points or dimension." ) + assert( is_matrix(points,undef,3), "Invalid list of points or dimension." ) let( p = len(points[0])==2 ? [for(pi=points) point3d(pi) ] @@ -1752,6 +1752,7 @@ function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) = function noncollinear_triple(points,error=true,eps=EPSILON) = assert( is_path(points), "Invalid input points." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) + len(pts)<3 ? [] : let( pa = points[0], b = furthest_point(pa, points), @@ -2092,6 +2093,7 @@ function polygon_is_clockwise(poly) = // Usage: // newpoly = clockwise_polygon(poly); // Topics: Geometry, Polygons, Clockwise +// See Also: polygon_is_clockwise(), ccw_polygon(), reverse_polygon() // Description: // Given a 2D polygon path, returns the clockwise winding version of that path. // Arguments: @@ -2104,6 +2106,7 @@ function clockwise_polygon(poly) = // Function: ccw_polygon() // Usage: // newpoly = ccw_polygon(poly); +// See Also: polygon_is_clockwise(), clockwise_polygon(), reverse_polygon() // Topics: Geometry, Polygons, Clockwise // Description: // Given a 2D polygon poly, returns the counter-clockwise winding version of that poly. @@ -2118,6 +2121,7 @@ function ccw_polygon(poly) = // Usage: // newpoly = reverse_polygon(poly) // Topics: Geometry, Polygons, Clockwise +// See Also: polygon_is_clockwise(), ccw_polygon(), clockwise_polygon() // Description: // Reverses a polygon's winding direction, while still using the same start point. // Arguments: @@ -2369,7 +2373,7 @@ function is_convex_polygon(poly,eps=EPSILON) = // echo(convex_distance(sphr1[0], sphr3[0])); // Returns: 0.5 function convex_distance(points1, points2, eps=EPSILON) = assert(is_matrix(points1) && is_matrix(points2,undef,len(points1[0])), - "The input list should be a consistent non empty list of points of same dimension.") + "The input lists should be compatible consistent non empty lists of points.") assert(len(points1[0])==2 || len(points1[0])==3 , "The input points should be 2d or 3d points.") let( d = points1[0]-points2[0] ) @@ -2431,7 +2435,7 @@ function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) = // function convex_collision(points1, points2, eps=EPSILON) = assert(is_matrix(points1) && is_matrix(points2,undef,len(points1[0])), - "The input list should be a consistent non empty list of points of same dimension.") + "The input lists should be compatible consistent non empty lists of points.") assert(len(points1[0])==2 || len(points1[0])==3 , "The input points should be 2d or 3d points.") let( d = points1[0]-points2[0] ) From e63c1680a6a0fc288491480f26c482a484e419b6 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 25 Jun 2021 14:40:03 +0100 Subject: [PATCH 2/4] Better cides for _closest_s --- geometry.scad | 85 +++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/geometry.scad b/geometry.scad index 92d474f..a61298f 100644 --- a/geometry.scad +++ b/geometry.scad @@ -1,4 +1,4 @@ -////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// // LibFile: geometry.scad // Geometry helpers. // Includes: @@ -1778,7 +1778,7 @@ function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) = function noncollinear_triple(points,error=true,eps=EPSILON) = assert( is_path(points), "Invalid input points." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) - len(pts)<3 ? [] : + len(pts)<3 ? [] : let( pa = points[0], b = furthest_point(pa, points), @@ -2106,6 +2106,7 @@ function point_in_polygon(point, poly, nonzero=true, eps=EPSILON) = // Usage: // test = polygon_is_clockwise(poly); // Topics: Geometry, Polygons, Clockwise +// See Also: clockwise_polygon(), ccw_polygon(), reverse_polygon() // Description: // Return true if the given 2D simple polygon is in clockwise order, false otherwise. // Results for complex (self-intersecting) polygon are indeterminate. @@ -2489,16 +2490,15 @@ function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) = // - 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) = - assert(len(s)>=2 && len(s)<=4, "Internal error.") len(s)==2 ? _closest_s1(s,eps) : - len(s)==3 ? _closest_s2(s,eps) - : _closest_s3(s,eps); + len(s)==3 ? _closest_s2(s,eps) : + len(s)==4 ? _closest_s3(s,eps) : + assert(false, "Internal error."); // find the point of a 1-simplex closest to the origin -// Based on: http://uu.diva-portal.org/smash/get/diva2/FFULLTEXT01.pdf function _closest_s1(s,eps=EPSILON) = - norm(s[1]-s[0]) 0 ? _closest_s1([s[0],s[1]]) : _closest_s1([s[0],s[2]]) : - class==3 ? _closest_s1([s[0],s[2]],eps) : -// class==5 ? b*(b-c)<=0 ? _closest_s1([s[0],s[1]]) : _closest_s1([s[1],s[2]]) : - class==5 ? _closest_s1([s[1],s[2]],eps) : - c*(c-a)>0 ? _closest_s1([s[0],s[2]],eps) : _closest_s1([s[1],s[2]],eps); - + // all have the same signal -> origin projects inside the tri + max(crx1, crx0, crx2) < 0 || min(crx1, crx0, crx2) > 0 + ? // baricentric coords of projection + [ [abs(crx0),abs(crx1),abs(crx2)]*s/area2, s ] + : let( + cl12 = _closest_s1([s[1],s[2]]), + cl02 = _closest_s1([s[0],s[2]]) + ) + norm(cl12[0]) Date: Fri, 25 Jun 2021 14:43:38 +0100 Subject: [PATCH 3/4] Better codes for _closest_s --- geometry.scad | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geometry.scad b/geometry.scad index a61298f..4122c30 100644 --- a/geometry.scad +++ b/geometry.scad @@ -1778,7 +1778,7 @@ function circle_line_intersection(c,r,d,line,bounded=false,eps=EPSILON) = function noncollinear_triple(points,error=true,eps=EPSILON) = assert( is_path(points), "Invalid input points." ) assert( is_finite(eps) && (eps>=0), "The tolerance should be a non-negative value." ) - len(pts)<3 ? [] : + len(points)<3 ? [] : let( pa = points[0], b = furthest_point(pa, points), @@ -2493,7 +2493,7 @@ 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) : - assert(false, "Internal error."); + assert(false, "Internal error."); // find the point of a 1-simplex closest to the origin @@ -2517,7 +2517,7 @@ function _closest_s2(s, eps=EPSILON) = // outcomes are s, [s[0],s[2]] and [s[1],s[2]] let( area = cross(s[2]-s[0], s[1]-s[0]), - area2 = area*area // tri area squared + area2 = area*area // tri area squared ) area2<=eps*max([for(si=s) pow(si*si,2)]) // degenerate tri ? norm(s[2]-s[0]) < norm(s[2]-s[1]) From fee433f6549cc0d022dd764bae9f253273a1a6d3 Mon Sep 17 00:00:00 2001 From: RonaldoCMP Date: Fri, 25 Jun 2021 16:32:28 +0100 Subject: [PATCH 4/4] Tweaks to deal with some coner case --- geometry.scad | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/geometry.scad b/geometry.scad index 4122c30..049dfdb 100644 --- a/geometry.scad +++ b/geometry.scad @@ -2423,9 +2423,7 @@ function _GJK_distance(points1, points2, eps=EPSILON, lbd, d, simplex=[]) = lbd = max(lbd, d*v/nrd), // distance lower bound close = (nrd-lbd <= eps*nrd) ) - // v already in the simplex is a degenerence due to numerical errors - // and may produce a non-stopping loop - close || [for(nv=norm(v), s=simplex) if(norm(s-v)<=eps*nv) 1]!=[] ? d : + close ? d : let( newsplx = _closest_simplex(concat(simplex,[v]),eps) ) _GJK_distance(points1, points2, eps, lbd, newsplx[0], newsplx[1]); @@ -2480,9 +2478,10 @@ function convex_collision(points1, points2, eps=EPSILON) = // http://www.dtecta.com/papers/jgt98convex.pdf function _GJK_collide(points1, points2, d, simplex, eps=EPSILON) = norm(d) < eps ? true : // does collide - let( v = _support_diff(points1,points2,-d) ) - v*d > eps ? false : // no collision + let( v = _support_diff(points1,points2,-d) ) + v*d > eps*eps ? false : // no collision let( newsplx = _closest_simplex(concat(simplex,[v]),eps) ) + norm(v-newsplx[0])