From b6cfda0537d2a95df4c81b84f64c533f8f32e6a1 Mon Sep 17 00:00:00 2001 From: Garth Minette Date: Wed, 20 Jan 2021 13:36:41 -0800 Subject: [PATCH 1/2] Remove apply_list(). Renamed affine_frame_map() to affine3d_frame_map() --- affine.scad | 92 +++++++++++++++--------------------------- paths.scad | 11 ++--- skin.scad | 8 ++-- tests/test_affine.scad | 12 ------ turtle3d.scad | 2 +- version.scad | 2 +- 6 files changed, 42 insertions(+), 85 deletions(-) diff --git a/affine.scad b/affine.scad index 35c36e3..666904e 100644 --- a/affine.scad +++ b/affine.scad @@ -264,29 +264,33 @@ function affine3d_rot_from_to(from, to) = ]; -// Function: affine_frame_map() +// Function: affine3d_frame_map() // Usage: -// map = affine_frame_map(v1, v2, v3); -// map = affine_frame_map(x=VECTOR1, y=VECTOR2, ); -// map = affine_frame_map(x=VECTOR1, z=VECTOR2, ); -// map = affine_frame_map(y=VECTOR1, y=VECTOR2, ); +// map = affine3d_frame_map(v1, v2, v3); +// map = affine3d_frame_map(x=VECTOR1, y=VECTOR2, ); +// map = affine3d_frame_map(x=VECTOR1, z=VECTOR2, ); +// map = affine3d_frame_map(y=VECTOR1, y=VECTOR2, ); // Description: -// Returns a transformation that maps one coordinate frame to another. You must specify two or three of `x`, `y`, and `z`. The specified -// axes are mapped to the vectors you supplied. If you give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand coordinate system. -// If the vectors you give are orthogonal the result will be a rotation and the `reverse` parameter will supply the inverse map, which enables you -// to map two arbitrary coordinate systems to each other by using the canonical coordinate system as an intermediary. You cannot use the `reverse` option -// with non-orthogonal inputs. +// Returns a transformation that maps one coordinate frame to another. You must specify two or +// three of `x`, `y`, and `z`. The specified axes are mapped to the vectors you supplied. If you +// give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand +// coordinate system. If the vectors you give are orthogonal the result will be a rotation and the +// `reverse` parameter will supply the inverse map, which enables you to map two arbitrary +// coordinate systems to each other by using the canonical coordinate system as an intermediary. +// You cannot use the `reverse` option with non-orthogonal inputs. // Arguments: -// x = Destination vector for x axis -// y = Destination vector for y axis -// z = Destination vector for z axis +// x = Destination 3D vector for x axis. +// y = Destination 3D vector for y axis. +// z = Destination 3D vector for z axis. // reverse = reverse direction of the map for orthogonal inputs. Default: false -// Examples: -// T = affine_frame_map(x=[1,1,0], y=[-1,1,0]); // This map is just a rotation around the z axis -// T = affine_frame_map(x=[1,0,0], y=[1,1,0]); // This map is not a rotation because x and y aren't orthogonal -// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1] -// T = affine_frame_map(x=[0,1,1], y=[0,-1,1]) * affine_frame_map(x=[1,1,0], y=[-1,1,0],reverse=true); -function affine_frame_map(x,y,z, reverse=false) = +// Example: +// T = affine3d_frame_map(x=[1,1,0], y=[-1,1,0]); // This map is just a rotation around the z axis +// Example: +// T = affine3d_frame_map(x=[1,0,0], y=[1,1,0]); // This map is not a rotation because x and y aren't orthogonal +// Example: +// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1] +// T = affine3d_frame_map(x=[0,1,1], y=[0,-1,1]) * affine3d_frame_map(x=[1,1,0], y=[-1,1,0],reverse=true); +function affine3d_frame_map(x,y,z, reverse=false) = assert(num_defined([x,y,z])>=2, "Must define at least two inputs") let( xvalid = is_undef(x) || (is_vector(x) && len(x)==3), @@ -466,43 +470,11 @@ function apply(transform,points) = assert(false, str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim)); -// Function: apply_list() -// Usage: -// pts = apply_list(points, transform_list); -// Description: -// Transforms the specified point list (or single point) using a list of transformation matrices. Transformations on -// the list are applied in the order they appear in the list (as in right multiplication of matrices). Both inputs can be -// 2d or 3d, and it is also allowed to supply 3d transformations with 2d data as long as the the only action on the z coordinate -// is a simple scaling. All transformations on `transform_list` must have the same dimension: you cannot mix 2d and 3d transformations -// even when acting on 2d data. -// Examples: -// transformed = apply_list(path3d(circle(r=3)),[xrot(45)]); // Rotates 3d circle data around x axis -// transformed = apply_list(circle(r=3), [scale(3), right(4), rot(45)]); // Scales, then translates, and then rotates 2d circle data -function apply_list(points,transform_list) = - transform_list == []? points : - is_vector(points) ? apply_list([points],transform_list)[0] : - let( - tdims = array_dim(transform_list), - datadim = len(points[0]) - ) - assert(len(tdims)==3 || tdims[1]!=tdims[2], "Invalid transformation list") - let( tdim = tdims[1]-1 ) - tdim==2 && datadim == 2 ? apply(affine2d_chain(transform_list), points) : - tdim==3 && datadim == 3 ? apply(affine3d_chain(transform_list), points) : - tdim==3 && datadim == 2 ? - let( - badlist = [for(i=idx(transform_list)) if (!is_2d_transform(transform_list[i])) i] - ) - assert(badlist==[],str("Transforms with indices ",badlist," are 3d but points are 2d")) - apply(affine3d_chain(transform_list), points) : - assert(false,str("Unsupported combination: transform with dimension ",tdim,", data of dimension ",datadim)); - - // Function: is_2d_transform() // Usage: // x = is_2d_transform(t); // Description: -// Checks if the input is a 3d transform that does not act on the z coordinate, except +// Checks if the input is a 3D transform that does not act on the z coordinate, except // possibly for a simple scaling of z. Note that an input which is only a zscale returns false. function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][2]!=1 so scale() works t[2][0]==0 && t[2][1]==0 && t[2][3]==0 && t[0][2] == 0 && t[1][2]==0 && @@ -514,14 +486,14 @@ function is_2d_transform(t) = // z-parameters are zero, except we allow t[2][ // Usage: // info = rot_decode(rotation); // Returns: [angle,axis,cp,translation] // Description: -// Given an input 3d rigid transformation operator (one composed of just rotations and translations) -// represented as a 4x4 matrix, compute the rotation and translation parameters of the operator. -// Returns a list of the four parameters, the angle, in the interval [0,180], the rotation axis -// as a unit vector, a centerpoint for the rotation, and a translation. If you set `parms=rot_decode(rotation)` -// then the transformation can be reconstructed from parms as `move(parms[3])*rot(a=parms[0],v=parms[1],cp=parms[2])`. -// This decomposition makes it possible to perform interpolation. If you construct a transformation using `rot` -// the decoding may flip the axis (if you gave an angle outside of [0,180]). The returned axis will be a unit vector, -// and the centerpoint lies on the plane through the origin that is perpendicular to the axis. It may be different +// Given an input 3D rigid transformation operator (one composed of just rotations and translations) represented +// as a 4x4 matrix, compute the rotation and translation parameters of the operator. Returns a list of the +// four parameters, the angle, in the interval [0,180], the rotation axis as a unit vector, a centerpoint for +// the rotation, and a translation. If you set `parms=rot_decode(rotation)` then the transformation can be +// reconstructed from parms as `move(parms[3])*rot(a=parms[0],v=parms[1],cp=parms[2])`. This decomposition +// makes it possible to perform interpolation. If you construct a transformation using `rot` the decoding +// may flip the axis (if you gave an angle outside of [0,180]). The returned axis will be a unit vector, and +// the centerpoint lies on the plane through the origin that is perpendicular to the axis. It may be different // than the centerpoint you used to construct the transformation. // Example: // rot_decode(rot(45)); // Returns [45,[0,0,1], [0,0,0], [0,0,0]] diff --git a/paths.scad b/paths.scad index a8cfd22..40322c6 100644 --- a/paths.scad +++ b/paths.scad @@ -980,13 +980,10 @@ module spiral_sweep(poly, h, r, twist=360, center, d, anchor, spin=0, orient=UP) dx = r*cos(a), dy = r*sin(a), dz = h * (p/steps), - pts = apply_list( - poly, [ - affine3d_xrot(90), - affine3d_zrot(a), - affine3d_translate([dx, dy, dz-h/2]) - ] - ) + mat = affine3d_translate([dx, dy, dz-h/2]) * + affine3d_zrot(a) * + affine3d_xrot(90), + pts = apply(mat, poly) ) for (pt = pts) pt ]; diff --git a/skin.scad b/skin.scad index 2d95458..07381ca 100644 --- a/skin.scad +++ b/skin.scad @@ -1244,7 +1244,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi let(rotations = [for( i = 0, ynormal = normal - (normal * tangents[0])*tangents[0], - rotation = affine_frame_map(y=ynormal, z=tangents[0]) + rotation = affine3d_frame_map(y=ynormal, z=tangents[0]) ; i < len(tangents) + (closed?1:0) ; rotation = i Date: Wed, 20 Jan 2021 13:40:25 -0800 Subject: [PATCH 2/2] Regressions fix for affine3d_frame_map() --- tests/test_affine.scad | 6 +++--- version.scad | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_affine.scad b/tests/test_affine.scad index 5e4efed..8862f03 100644 --- a/tests/test_affine.scad +++ b/tests/test_affine.scad @@ -221,10 +221,10 @@ test_affine3d_chain(); //////////////////////////// -module test_affine_frame_map() { - assert(approx(affine_frame_map(x=[1,1,0], y=[-1,1,0]), affine3d_zrot(45))); +module test_affine3d_frame_map() { + assert(approx(affine3d_frame_map(x=[1,1,0], y=[-1,1,0]), affine3d_zrot(45))); } -test_affine_frame_map(); +test_affine3d_frame_map(); module test_apply() { diff --git a/version.scad b/version.scad index 87b253d..7b75948 100644 --- a/version.scad +++ b/version.scad @@ -6,7 +6,7 @@ ////////////////////////////////////////////////////////////////////// -BOSL_VERSION = [2,0,533]; +BOSL_VERSION = [2,0,534]; // Section: BOSL Library Version Functions