Various bugfixes, optimizations, and docs improvements found via regressions.

This commit is contained in:
Revar Desmera 2019-10-25 15:16:48 -07:00
parent 3e278e6a52
commit 50acb3c0b0
3 changed files with 47 additions and 18 deletions

View file

@ -224,14 +224,34 @@ function xy_to_polar(x,y=undef) = let(
// Function: project_plane() // Function: project_plane()
// Usage: // Usage:
// project_plane(point, a, b, c); // xy = project_plane(point, a, b, c);
// xy = project_plane(point, [A,B,C]];
// Description: // Description:
// Given three points defining a plane, returns the projected planar [X,Y] coordinates of the // 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 // 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 // `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 // 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. // 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) = 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( let(
u = normalize(b-a), u = normalize(b-a),
v = normalize(c-a), v = normalize(c-a),
@ -243,12 +263,25 @@ function project_plane(point, a, b, c) =
// Function: lift_plane() // Function: lift_plane()
// Usage: // Usage:
// lift_plane(point, a, b, c); // xyz = lift_plane(point, a, b, c);
// xyz = lift_plane(point, [A,B,C]);
// Description: // Description:
// Given three points defining a plane, converts a planar [X,Y] coordinate to the actual // 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] // 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`. // 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) = 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( let(
u = normalize(b-a), u = normalize(b-a),
v = normalize(c-a), v = normalize(c-a),

View file

@ -758,12 +758,11 @@ function polygon_shift_to_closest_point(path, pt) =
// i1 = The first point. // i1 = The first point.
// i2 = The second point. // i2 = The second point.
// points = The list of points to find a non-collinear point from. // points = The list of points to find a non-collinear point from.
function first_noncollinear(i1, i2, points, _i) = function first_noncollinear(i1, i2, points) =
(_i>=len(points) || !collinear_indexed(points, i1, i2, _i))? _i : [for (j = idx(points)) if (j!=i1 && j!=i2 && !collinear_indexed(points,i1,i2,j)) j][0];
find_first_noncollinear(i1, i2, points, _i=_i+1);
// Function: noncollinear_points() // Function: find_noncollinear_points()
// Usage: // Usage:
// find_noncollinear_points(points); // find_noncollinear_points(points);
// Description: // Description:
@ -771,8 +770,8 @@ function first_noncollinear(i1, i2, points, _i) =
function find_noncollinear_points(points) = function find_noncollinear_points(points) =
let( let(
a = 0, a = 0,
b = furthest_point(a, points), b = furthest_point(points[a], points),
c = first_noncollinear(a, b, points) c = max_index([for (p=points) norm(p-points[a])*norm(p-points[b])])
) [a, b, c]; ) [a, b, c];
@ -987,28 +986,25 @@ function pointlist_bounds(pts) = [
// Usage: // Usage:
// closest_point(pt, points); // closest_point(pt, points);
// Description: // 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: // Arguments:
// pt = The point to find the closest point to. // pt = The point to find the closest point to.
// points = The list of points to search. // points = The list of points to search.
function closest_point(pt, points) = function closest_point(pt, points) =
let( min_index([for (p=points) norm(p-pt)]);
i = min_index([for (j=idx(points)) norm(points[j]-pt)])
) i;
// Function: furthest_point() // Function: furthest_point()
// Usage: // Usage:
// furthest_point(pt, points); // furthest_point(pt, points);
// Description: // 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: // Arguments:
// pt = The point to find the farthest point from. // pt = The point to find the farthest point from.
// points = The list of points to search. // points = The list of points to search.
// Example:
function furthest_point(pt, points) = function furthest_point(pt, points) =
let( max_index([for (p=points) norm(p-pt)]);
i = max_index([for (j=idx(points)) norm(points[j]-pt)])
) i;
// Function: polygon_is_clockwise() // Function: polygon_is_clockwise()

View file

@ -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]); // Returns: 4
// min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7] // min_index([5,3,9,6,2,7,8,2,1],all=true); // Returns: [4,7]
function min_index(vals, all=false) = 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() // Function: max_index()
// Usage: // 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]); // Returns: 2
// max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7] // max_index([5,3,9,6,2,7,8,9,1],all=true); // Returns: [2,7]
function max_index(vals, all=false) = 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() // Function: posmod()