diff --git a/coords.scad b/coords.scad index ae9f2e3..ef880e6 100644 --- a/coords.scad +++ b/coords.scad @@ -224,14 +224,34 @@ function xy_to_polar(x,y=undef) = let( // Function: project_plane() // Usage: -// project_plane(point, a, b, c); +// xy = project_plane(point, a, b, c); +// xy = project_plane(point, [A,B,C]]; // Description: // Given three points defining a plane, returns the projected planar [X,Y] coordinates of the // closest point to a 3D `point`. The origin of the planar coordinate system [0,0] will be at point // `a`, and the Y+ axis direction will be towards point `b`. This coordinate system can be useful // in taking a set of nearly coplanar points, and converting them to a pure XY set of coordinates // for manipulation, before convering them back to the original 3D plane. +// Arguments: +// point = The 3D point, or list of 3D points to project into the plane's 2D coordinate system. +// a = A 3D point that the plane passes through. Used to define the plane. +// b = A 3D point that the plane passes through. Used to define the plane. +// c = A 3D point that the plane passes through. Used to define the plane. +// Example: +// pt = [5,-5,5]; +// a=[0,0,0]; b=[10,-10,0]; c=[10,0,10]; +// xy = project_plane(pt, a, b, c); +// xy2 = project_plane(pt, [a,b,c]); +// echo(xy,xy2); function project_plane(point, a, b, c) = + echo(point=point,a=a,b=b,c=c) + is_undef(b) && is_undef(c) && is_list(a)? let( + indices = find_noncollinear_points(a) + ) echo(indices=indices) project_plane(point, a[indices[0]], a[indices[1]], a[indices[2]]) : + assert(is_vector(a)) + assert(is_vector(b)) + assert(is_vector(c)) + assert(is_vector(point)||is_path(point)) let( u = normalize(b-a), v = normalize(c-a), @@ -243,12 +263,25 @@ function project_plane(point, a, b, c) = // Function: lift_plane() // Usage: -// lift_plane(point, a, b, c); +// xyz = lift_plane(point, a, b, c); +// xyz = lift_plane(point, [A,B,C]); // Description: // Given three points defining a plane, converts a planar [X,Y] coordinate to the actual // corresponding 3D point on the plane. The origin of the planar coordinate system [0,0] // will be at point `a`, and the Y+ axis direction will be towards point `b`. +// Arguments: +// point = The 2D point, or list of 2D points in the plane's coordinate system to get the 3D position of. +// a = A 3D point that the plane passes through. Used to define the plane. +// b = A 3D point that the plane passes through. Used to define the plane. +// c = A 3D point that the plane passes through. Used to define the plane. function lift_plane(point, a, b, c) = + is_undef(b) && is_undef(c) && is_list(a)? let( + indices = find_noncollinear_points(a) + ) lift_plane(point, a[indices[0]], a[indices[1]], a[indices[2]]) : + assert(is_vector(a)) + assert(is_vector(b)) + assert(is_vector(c)) + assert(is_vector(point)||is_path(point)) let( u = normalize(b-a), v = normalize(c-a), diff --git a/geometry.scad b/geometry.scad index 9b24e55..d66bfb8 100644 --- a/geometry.scad +++ b/geometry.scad @@ -758,12 +758,11 @@ function polygon_shift_to_closest_point(path, pt) = // i1 = The first point. // i2 = The second point. // points = The list of points to find a non-collinear point from. -function first_noncollinear(i1, i2, points, _i) = - (_i>=len(points) || !collinear_indexed(points, i1, i2, _i))? _i : - find_first_noncollinear(i1, i2, points, _i=_i+1); +function first_noncollinear(i1, i2, points) = + [for (j = idx(points)) if (j!=i1 && j!=i2 && !collinear_indexed(points,i1,i2,j)) j][0]; -// Function: noncollinear_points() +// Function: find_noncollinear_points() // Usage: // find_noncollinear_points(points); // Description: @@ -771,8 +770,8 @@ function first_noncollinear(i1, i2, points, _i) = function find_noncollinear_points(points) = let( a = 0, - b = furthest_point(a, points), - c = first_noncollinear(a, b, points) + b = furthest_point(points[a], points), + c = max_index([for (p=points) norm(p-points[a])*norm(p-points[b])]) ) [a, b, c]; @@ -987,28 +986,25 @@ function pointlist_bounds(pts) = [ // Usage: // closest_point(pt, points); // Description: -// Given a list of `points`, finds the point that is closest to the given point `pt`, and returns the index of it. +// Given a list of `points`, finds the index of the closest point to `pt`. // Arguments: // pt = The point to find the closest point to. // points = The list of points to search. function closest_point(pt, points) = - let( - i = min_index([for (j=idx(points)) norm(points[j]-pt)]) - ) i; + min_index([for (p=points) norm(p-pt)]); // Function: furthest_point() // Usage: // furthest_point(pt, points); // Description: -// Given a list of `points`, finds the point that is farthest from the given point `pt`, and returns the index of it. +// Given a list of `points`, finds the index of the furthest point from `pt`. // Arguments: // pt = The point to find the farthest point from. // points = The list of points to search. +// Example: function furthest_point(pt, points) = - let( - i = max_index([for (j=idx(points)) norm(points[j]-pt)]) - ) i; + max_index([for (p=points) norm(p-pt)]); // Function: polygon_is_clockwise() diff --git a/math.scad b/math.scad index 7cb0c4a..b51c862 100644 --- a/math.scad +++ b/math.scad @@ -153,7 +153,7 @@ function approx(a,b,eps=EPSILON) = let(c=a-b) (is_num(c)? abs(c) : norm(c)) <= e // min_index([5,3,9,6,2,7,8,2,1]); // Returns: 4 // min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7] function min_index(vals, all=false) = - all ? search(min(vals),vals,0) : search(min(vals), vals)[0]; + all ? search(min(vals),vals,0) : search(min(vals), vals)[0]; // Function: max_index() // Usage: @@ -168,7 +168,7 @@ function min_index(vals, all=false) = // max_index([5,3,9,6,2,7,8,9,1]); // Returns: 2 // max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7] function max_index(vals, all=false) = - all ? search(max(vals),vals,0) : search(max(vals), vals)[0]; + all ? search(max(vals),vals,0) : search(max(vals), vals)[0]; // Function: posmod()