mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-04 03:09:45 +00:00
Merge pull request #390 from revarbat/revarbat_dev
Remove apply_list(). Renamed affine_frame_map() to affine3d_frame_map()
This commit is contained in:
commit
d98cd52f2f
6 changed files with 45 additions and 88 deletions
92
affine.scad
92
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, <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]]
|
||||
|
|
11
paths.scad
11
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
|
||||
];
|
||||
|
||||
|
|
|
@ -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])
|
||||
] :
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BOSL_VERSION = [2,0,532];
|
||||
BOSL_VERSION = [2,0,534];
|
||||
|
||||
|
||||
// Section: BOSL Library Version Functions
|
||||
|
|
Loading…
Reference in a new issue