Merge pull request #390 from revarbat/revarbat_dev

Remove apply_list().  Renamed affine_frame_map() to affine3d_frame_map()
This commit is contained in:
Revar Desmera 2021-01-20 13:41:52 -08:00 committed by GitHub
commit d98cd52f2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 88 deletions

View file

@ -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, <reverse>);
// map = affine_frame_map(x=VECTOR1, z=VECTOR2, <reverse>);
// map = affine_frame_map(y=VECTOR1, y=VECTOR2, <reverse>);
// map = affine3d_frame_map(v1, v2, v3);
// map = affine3d_frame_map(x=VECTOR1, y=VECTOR2, <reverse>);
// map = affine3d_frame_map(x=VECTOR1, z=VECTOR2, <reverse>);
// map = affine3d_frame_map(y=VECTOR1, y=VECTOR2, <reverse>);
// 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]]

View file

@ -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
];

View file

@ -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<len(tangents)-1+(closed?1:0)? rot(from=tangents[i],to=tangents[(i+1)%L])*rotation : undef,
@ -1263,7 +1263,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
last_tangent = select(tangents,-1),
lastynormal = last_normal - (last_normal * last_tangent) * last_tangent
)
affine_frame_map(y=lastynormal, z=last_tangent),
affine3d_frame_map(y=lastynormal, z=last_tangent),
mismatch = transpose(select(rotations,-1)) * reference_rot,
correction_twist = atan2(mismatch[1][0], mismatch[0][0]),
// Spread out this extra twist over the whole sweep so that it doesn't occur
@ -1276,7 +1276,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
[for(i=[0:L-(closed?0:1)]) let(
ynormal = relaxed ? normals[i%L] : normals[i%L] - (normals[i%L] * tangents[i%L])*tangents[i%L],
znormal = relaxed ? tangents[i%L] - (normals[i%L] * tangents[i%L])*normals[i%L] : tangents[i%L],
rotation = affine_frame_map(y=ynormal, z=znormal)
rotation = affine3d_frame_map(y=ynormal, z=znormal)
)
assert(approx(ynormal*znormal,0),str("Supplied normal is parallel to the path tangent at point ",i))
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i]),
@ -1288,7 +1288,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
dummy = min(testnormals) < .5 ? echo("WARNING: ***** Abrupt change in normal direction. Consider a different method *****") :0
)
[for(i=[0:L-(closed?0:1)]) let(
rotation = affine_frame_map(x=pathnormal[i%L], z=tangents[i%L])
rotation = affine3d_frame_map(x=pathnormal[i%L], z=tangents[i%L])
)
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i])
] :

View file

@ -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() {
@ -257,18 +257,6 @@ module test_apply() {
test_apply();
module test_apply_list() {
assert(approx(apply_list(25*(BACK+UP), []), 25*(BACK+UP)));
assert(approx(apply_list(25*(BACK+UP), [affine3d_xrot(135)]), 25*sqrt(2)*FWD));
assert(approx(apply_list(25*(RIGHT+UP), [affine3d_yrot(135)]), 25*sqrt(2)*DOWN));
assert(approx(apply_list(25*(BACK+RIGHT), [affine3d_zrot(45)]), 25*sqrt(2)*BACK));
assert(approx(apply_list(25*(BACK+UP), [affine3d_xrot(135), affine3d_translate([30,40,50])]), 25*sqrt(2)*FWD+[30,40,50]));
assert(approx(apply_list(25*(RIGHT+UP), [affine3d_yrot(135), affine3d_translate([30,40,50])]), 25*sqrt(2)*DOWN+[30,40,50]));
assert(approx(apply_list(25*(BACK+RIGHT), [affine3d_zrot(45), affine3d_translate([30,40,50])]), 25*sqrt(2)*BACK+[30,40,50]));
}
test_apply_list();
module test_rot_decode() {
Tlist = [
rot(37),

View file

@ -433,7 +433,7 @@ function turtle3d(commands, state=RIGHT, transforms=false, full_state=false, rep
state = is_matrix(state,4,4) ? [[state],[yrot(90)],1,90,0] :
is_vector(state,3) ?
let( updir = UP - (UP * state) * state / (state*state) )
[[affine_frame_map(x=state, z=approx(norm(updir),0) ? FWD : updir)], [yrot(90)],1, 90, 0]
[[affine3d_frame_map(x=state, z=approx(norm(updir),0) ? FWD : updir)], [yrot(90)],1, 90, 0]
: assert(_turtle3d_state_valid(state), "Supplied state is not valid")
state,
finalstate = _turtle3d_repeat(commands, state, repeat)

View file

@ -6,7 +6,7 @@
//////////////////////////////////////////////////////////////////////
BOSL_VERSION = [2,0,532];
BOSL_VERSION = [2,0,534];
// Section: BOSL Library Version Functions