mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-06 04:09:47 +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:
|
// Usage:
|
||||||
// map = affine_frame_map(v1, v2, v3);
|
// map = affine3d_frame_map(v1, v2, v3);
|
||||||
// map = affine_frame_map(x=VECTOR1, y=VECTOR2, <reverse>);
|
// map = affine3d_frame_map(x=VECTOR1, y=VECTOR2, <reverse>);
|
||||||
// map = affine_frame_map(x=VECTOR1, z=VECTOR2, <reverse>);
|
// map = affine3d_frame_map(x=VECTOR1, z=VECTOR2, <reverse>);
|
||||||
// map = affine_frame_map(y=VECTOR1, y=VECTOR2, <reverse>);
|
// map = affine3d_frame_map(y=VECTOR1, y=VECTOR2, <reverse>);
|
||||||
// Description:
|
// Description:
|
||||||
// Returns a transformation that maps one coordinate frame to another. You must specify two or three of `x`, `y`, and `z`. The specified
|
// Returns a transformation that maps one coordinate frame to another. You must specify two or
|
||||||
// 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.
|
// three of `x`, `y`, and `z`. The specified axes are mapped to the vectors you supplied. If you
|
||||||
// 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
|
// give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand
|
||||||
// to map two arbitrary coordinate systems to each other by using the canonical coordinate system as an intermediary. You cannot use the `reverse` option
|
// coordinate system. If the vectors you give are orthogonal the result will be a rotation and the
|
||||||
// with non-orthogonal inputs.
|
// `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:
|
// Arguments:
|
||||||
// x = Destination vector for x axis
|
// x = Destination 3D vector for x axis.
|
||||||
// y = Destination vector for y axis
|
// y = Destination 3D vector for y axis.
|
||||||
// z = Destination vector for z axis
|
// z = Destination 3D vector for z axis.
|
||||||
// reverse = reverse direction of the map for orthogonal inputs. Default: false
|
// reverse = reverse direction of the map for orthogonal inputs. Default: false
|
||||||
// Examples:
|
// Example:
|
||||||
// T = affine_frame_map(x=[1,1,0], y=[-1,1,0]); // This map is just a rotation around the z axis
|
// T = affine3d_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
|
// 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=[1,0,0], y=[1,1,0]); // This map is not a rotation because x and y aren't orthogonal
|
||||||
// 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);
|
// Example:
|
||||||
function affine_frame_map(x,y,z, reverse=false) =
|
// // 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")
|
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
|
||||||
let(
|
let(
|
||||||
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
|
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));
|
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()
|
// Function: is_2d_transform()
|
||||||
// Usage:
|
// Usage:
|
||||||
// x = is_2d_transform(t);
|
// x = is_2d_transform(t);
|
||||||
// Description:
|
// 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.
|
// 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
|
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 &&
|
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:
|
// Usage:
|
||||||
// info = rot_decode(rotation); // Returns: [angle,axis,cp,translation]
|
// info = rot_decode(rotation); // Returns: [angle,axis,cp,translation]
|
||||||
// Description:
|
// Description:
|
||||||
// Given an input 3d rigid transformation operator (one composed of just rotations and translations)
|
// Given an input 3D rigid transformation operator (one composed of just rotations and translations) represented
|
||||||
// represented as a 4x4 matrix, compute the rotation and translation parameters of the operator.
|
// as a 4x4 matrix, compute the rotation and translation parameters of the operator. Returns a list of the
|
||||||
// Returns a list of the four parameters, the angle, in the interval [0,180], the rotation axis
|
// four parameters, the angle, in the interval [0,180], the rotation axis as a unit vector, a centerpoint for
|
||||||
// as a unit vector, a centerpoint for the rotation, and a translation. If you set `parms=rot_decode(rotation)`
|
// the rotation, and a translation. If you set `parms=rot_decode(rotation)` then the transformation can be
|
||||||
// then the transformation can be reconstructed from parms as `move(parms[3])*rot(a=parms[0],v=parms[1],cp=parms[2])`.
|
// reconstructed from parms as `move(parms[3])*rot(a=parms[0],v=parms[1],cp=parms[2])`. This decomposition
|
||||||
// This decomposition makes it possible to perform interpolation. If you construct a transformation using `rot`
|
// makes it possible to perform interpolation. If you construct a transformation using `rot` the decoding
|
||||||
// the decoding may flip the axis (if you gave an angle outside of [0,180]). The returned axis will be a unit vector,
|
// may flip the axis (if you gave an angle outside of [0,180]). The returned axis will be a unit vector, and
|
||||||
// and the centerpoint lies on the plane through the origin that is perpendicular to the axis. It may be different
|
// 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.
|
// than the centerpoint you used to construct the transformation.
|
||||||
// Example:
|
// Example:
|
||||||
// rot_decode(rot(45)); // Returns [45,[0,0,1], [0,0,0], [0,0,0]]
|
// 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),
|
dx = r*cos(a),
|
||||||
dy = r*sin(a),
|
dy = r*sin(a),
|
||||||
dz = h * (p/steps),
|
dz = h * (p/steps),
|
||||||
pts = apply_list(
|
mat = affine3d_translate([dx, dy, dz-h/2]) *
|
||||||
poly, [
|
affine3d_zrot(a) *
|
||||||
affine3d_xrot(90),
|
affine3d_xrot(90),
|
||||||
affine3d_zrot(a),
|
pts = apply(mat, poly)
|
||||||
affine3d_translate([dx, dy, dz-h/2])
|
|
||||||
]
|
|
||||||
)
|
|
||||||
) for (pt = pts) pt
|
) for (pt = pts) pt
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1244,7 +1244,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
||||||
let(rotations =
|
let(rotations =
|
||||||
[for( i = 0,
|
[for( i = 0,
|
||||||
ynormal = normal - (normal * tangents[0])*tangents[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) ;
|
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,
|
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),
|
last_tangent = select(tangents,-1),
|
||||||
lastynormal = last_normal - (last_normal * last_tangent) * last_tangent
|
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,
|
mismatch = transpose(select(rotations,-1)) * reference_rot,
|
||||||
correction_twist = atan2(mismatch[1][0], mismatch[0][0]),
|
correction_twist = atan2(mismatch[1][0], mismatch[0][0]),
|
||||||
// Spread out this extra twist over the whole sweep so that it doesn't occur
|
// 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(
|
[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],
|
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],
|
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))
|
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]),
|
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
|
dummy = min(testnormals) < .5 ? echo("WARNING: ***** Abrupt change in normal direction. Consider a different method *****") :0
|
||||||
)
|
)
|
||||||
[for(i=[0:L-(closed?0:1)]) let(
|
[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])
|
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i])
|
||||||
] :
|
] :
|
||||||
|
|
|
@ -221,10 +221,10 @@ test_affine3d_chain();
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
|
|
||||||
module test_affine_frame_map() {
|
module test_affine3d_frame_map() {
|
||||||
assert(approx(affine_frame_map(x=[1,1,0], y=[-1,1,0]), affine3d_zrot(45)));
|
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() {
|
module test_apply() {
|
||||||
|
@ -257,18 +257,6 @@ module test_apply() {
|
||||||
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() {
|
module test_rot_decode() {
|
||||||
Tlist = [
|
Tlist = [
|
||||||
rot(37),
|
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] :
|
state = is_matrix(state,4,4) ? [[state],[yrot(90)],1,90,0] :
|
||||||
is_vector(state,3) ?
|
is_vector(state,3) ?
|
||||||
let( updir = UP - (UP * state) * state / (state*state) )
|
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")
|
: assert(_turtle3d_state_valid(state), "Supplied state is not valid")
|
||||||
state,
|
state,
|
||||||
finalstate = _turtle3d_repeat(commands, state, repeat)
|
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
|
// Section: BOSL Library Version Functions
|
||||||
|
|
Loading…
Reference in a new issue