mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2024-12-29 16:29:40 +00:00
Move affine3d_frame_map to transforms.scad and rename to frame_map.
Add module version. Change all calls.
This commit is contained in:
parent
4fee72f517
commit
0aad39c7e5
7 changed files with 102 additions and 72 deletions
58
affine.scad
58
affine.scad
|
@ -882,64 +882,6 @@ function affine3d_rot_from_to(from, to) =
|
|||
];
|
||||
|
||||
|
||||
// Function: affine3d_frame_map()
|
||||
// Usage:
|
||||
// map = affine3d_frame_map(v1, v2, v3, [reverse=]);
|
||||
// map = affine3d_frame_map(x=VECTOR1, y=VECTOR2, [reverse=]);
|
||||
// map = affine3d_frame_map(x=VECTOR1, z=VECTOR2, [reverse=]);
|
||||
// map = affine3d_frame_map(y=VECTOR1, z=VECTOR2, [reverse=]);
|
||||
// Topics: Affine, Matrices, Transforms, Rotation
|
||||
// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
|
||||
// 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.
|
||||
// Arguments:
|
||||
// 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
|
||||
// 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),
|
||||
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
|
||||
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
|
||||
)
|
||||
assert(xvalid,"Input x must be a length 3 vector")
|
||||
assert(yvalid,"Input y must be a length 3 vector")
|
||||
assert(zvalid,"Input z must be a length 3 vector")
|
||||
let(
|
||||
x = is_undef(x)? undef : unit(x,RIGHT),
|
||||
y = is_undef(y)? undef : unit(y,BACK),
|
||||
z = is_undef(z)? undef : unit(z,UP),
|
||||
map = is_undef(x)? [cross(y,z), y, z] :
|
||||
is_undef(y)? [x, cross(z,x), z] :
|
||||
is_undef(z)? [x, y, cross(x,y)] :
|
||||
[x, y, z]
|
||||
)
|
||||
reverse? (
|
||||
let(
|
||||
ocheck = (
|
||||
approx(map[0]*map[1],0) &&
|
||||
approx(map[0]*map[2],0) &&
|
||||
approx(map[1]*map[2],0)
|
||||
)
|
||||
)
|
||||
assert(ocheck, "Inputs must be orthogonal when reverse==true")
|
||||
[for (r=map) [for (c=r) c, 0], [0,0,0,1]]
|
||||
) : [for (r=transpose(map)) [for (c=r) c, 0], [0,0,0,1]];
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ function project_plane(plane,p) =
|
|||
y = unit(plane[1]-plane[0]), // y axis goes to point b
|
||||
x = unit(v-(v*y)*y) // x axis
|
||||
)
|
||||
affine3d_frame_map(x,y) * move(-plane[0])
|
||||
frame_map(x,y) * move(-plane[0])
|
||||
: is_vector(plane,4) && is_undef(p) ? // no data, plane given in "plane"
|
||||
assert(_valid_plane(plane), "Plane is not valid")
|
||||
let(
|
||||
|
@ -280,7 +280,7 @@ function lift_plane(plane, p) =
|
|||
y = unit(plane[1]-plane[0]), // y axis goes to point b
|
||||
x = unit(v-(v*y)*y) // x axis
|
||||
)
|
||||
move(plane[0]) * affine3d_frame_map(x,y,reverse=true)
|
||||
move(plane[0]) * frame_map(x,y,reverse=true)
|
||||
: is_vector(plane,4) && is_undef(p) ? // no data, plane given in "plane"
|
||||
assert(_valid_plane(plane), "Plane is not valid")
|
||||
let(
|
||||
|
|
|
@ -1630,7 +1630,7 @@ module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=fals
|
|||
if(planar) {
|
||||
rot(from=[0,1],to=cutlist[i][3]) children();
|
||||
} else {
|
||||
multmatrix(affine3d_frame_map(x=cutlist[i][2], z=cutlist[i][3]))
|
||||
frame_map(x=cutlist[i][2], z=cutlist[i][3])
|
||||
children();
|
||||
}
|
||||
} else {
|
||||
|
@ -1777,9 +1777,9 @@ module path_text(path, text, font, size, thickness=1, lettersize, offset=0, reve
|
|||
|
||||
)
|
||||
move(pts[i][0])
|
||||
multmatrix(affine3d_frame_map(x=pts[i][2]-adjustment,
|
||||
frame_map(x=pts[i][2]-adjustment,
|
||||
z=usetop ? undef : normpts[i],
|
||||
y=usetop ? toppts[i] : undef))
|
||||
y=usetop ? toppts[i] : undef)
|
||||
up(offset-thickness/2)
|
||||
linear_extrude(height=thickness)
|
||||
left(lsize[0]/2)text(text[i], font=font, size=size);
|
||||
|
|
|
@ -1355,7 +1355,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 = affine3d_frame_map(y=ynormal, z=tangents[0])
|
||||
rotation = 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,
|
||||
|
@ -1374,7 +1374,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
|
|||
last_tangent = last(tangents),
|
||||
lastynormal = last_normal - (last_normal * last_tangent) * last_tangent
|
||||
)
|
||||
affine3d_frame_map(y=lastynormal, z=last_tangent),
|
||||
frame_map(y=lastynormal, z=last_tangent),
|
||||
mismatch = transpose(last(rotations)) * 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
|
||||
|
@ -1387,7 +1387,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 = affine3d_frame_map(y=ynormal, z=znormal)
|
||||
rotation = 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]),
|
||||
|
@ -1400,7 +1400,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 = affine3d_frame_map(x=pathnormal[i%L], z=tangents[i%L])
|
||||
rotation = frame_map(x=pathnormal[i%L], z=tangents[i%L])
|
||||
)
|
||||
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i])
|
||||
] :
|
||||
|
|
|
@ -918,7 +918,7 @@ module generic_threaded_rod(
|
|||
dummy1 = assert(_r1>depth && _r2>depth, "Screw profile deeper than rod radius");
|
||||
map_threads = right((_r1 + _r2) / 2) // Shift profile out to thread radius
|
||||
* affine3d_skew(sxz=(_r2-_r1)/l) // Skew correction for tapered threads
|
||||
* affine3d_frame_map(x=[0,0,1], y=[1,0,0]) // Map profile to 3d, parallel to z axis
|
||||
* frame_map(x=[0,0,1], y=[1,0,0]) // Map profile to 3d, parallel to z axis
|
||||
* scale(pitch); // scale profile by pitch
|
||||
hig_table = [
|
||||
[-twist/2-0.0001, 0],
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
//////////////////////////////////////////////////////////////////////
|
||||
// LibFile: transforms.scad
|
||||
// Functions and modules that provide shortcuts for translation, rotation, mirror and skew operations. The shortcuts can act on geometry, like the usual OpenSCAD rotate() and translate(). They also work as functions that operate on lists of points in various forms: paths, VNFS and bezier patches. Lastly, the function form of the shortcuts can return a matrix representing the operation the shortcut performs. The rotation and scaling shortcuts accept an optional centerpoint for the rotation or scaling operation.
|
||||
// Functions and modules that provide shortcuts for translation,
|
||||
// rotation and mirror operations. Also provided are skew and frame_map
|
||||
// which remaps the coordinate axes. The shortcuts can act on
|
||||
// geometry, like the usual OpenSCAD rotate() and translate(). They
|
||||
// also work as functions that operate on lists of points in various
|
||||
// forms: paths, VNFS and bezier patches. Lastly, the function form
|
||||
// of the shortcuts can return a matrix representing the operation
|
||||
// the shortcut performs. The rotation and scaling shortcuts accept
|
||||
// an optional centerpoint for the rotation or scaling operation.
|
||||
// Includes:
|
||||
// include <BOSL2/std.scad>
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -771,6 +779,8 @@ module xyzrot(a=0, p, cp)
|
|||
function xyzrot(a=0, p, cp) = rot(a=a, v=[1,1,1], cp=cp, p=p);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Section: Scaling and Mirroring
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -1439,9 +1449,87 @@ function yzflip(p, cp=0) =
|
|||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Section: Skewing
|
||||
// Section: Other Transformations
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Function&Module: frame_map()
|
||||
// Usage: As module
|
||||
// frame_map(v1, v2, v3, [reverse=]) { ... }
|
||||
// Usage: As function to remap points
|
||||
// transformed = frame_map(v1, v2, v3, p=points, [reverse=]);
|
||||
// Usage: As function to return a transformation matrix:
|
||||
// map = frame_map(v1, v2, v3, [reverse=]);
|
||||
// map = frame_map(x=VECTOR1, y=VECTOR2, [reverse=]);
|
||||
// map = frame_map(x=VECTOR1, z=VECTOR2, [reverse=]);
|
||||
// map = frame_map(y=VECTOR1, z=VECTOR2, [reverse=]);
|
||||
// Topics: Affine, Matrices, Transforms, Rotation
|
||||
// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
|
||||
// Description:
|
||||
// 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, so if you
|
||||
// specify x=[1,1] then the x axis will be mapped to the line y=x. 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. Note that only the direction
|
||||
// of the specified vectors matters: the transformation will not apply scaling, though it can
|
||||
// skew if your provide non-orthogonal axes.
|
||||
// Arguments:
|
||||
// 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
|
||||
// Example: Remap axes after linear extrusion
|
||||
// frame_map(x=[0,1,0], y=[0,0,1]) linear_extrude(height=10) square(3);
|
||||
// Example: This map is just a rotation around the z axis
|
||||
// mat = frame_map(x=[1,1,0], y=[-1,1,0]);
|
||||
// Example: This map is not a rotation because x and y aren't orthogonal
|
||||
// mat = frame_map(x=[1,0,0], y=[1,1,0]);
|
||||
// Example: This sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
|
||||
// mat = frame_map(x=[0,1,1], y=[0,-1,1]) * frame_map(x=[1,1,0], y=[-1,1,0],reverse=true);
|
||||
function frame_map(x,y,z, p, reverse=false) =
|
||||
is_def(p)
|
||||
? apply(frame_map(x,y,z,reverse=reverse), p)
|
||||
:
|
||||
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
|
||||
let(
|
||||
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
|
||||
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
|
||||
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
|
||||
)
|
||||
assert(xvalid,"Input x must be a length 3 vector")
|
||||
assert(yvalid,"Input y must be a length 3 vector")
|
||||
assert(zvalid,"Input z must be a length 3 vector")
|
||||
let(
|
||||
x = is_undef(x)? undef : unit(x,RIGHT),
|
||||
y = is_undef(y)? undef : unit(y,BACK),
|
||||
z = is_undef(z)? undef : unit(z,UP),
|
||||
map = is_undef(x)? [cross(y,z), y, z] :
|
||||
is_undef(y)? [x, cross(z,x), z] :
|
||||
is_undef(z)? [x, y, cross(x,y)] :
|
||||
[x, y, z]
|
||||
)
|
||||
reverse? (
|
||||
let(
|
||||
ocheck = (
|
||||
approx(map[0]*map[1],0) &&
|
||||
approx(map[0]*map[2],0) &&
|
||||
approx(map[1]*map[2],0)
|
||||
)
|
||||
)
|
||||
assert(ocheck, "Inputs must be orthogonal when reverse==true")
|
||||
[for (r=map) [for (c=r) c, 0], [0,0,0,1]]
|
||||
) : [for (r=transpose(map)) [for (c=r) c, 0], [0,0,0,1]];
|
||||
|
||||
|
||||
module frame_map(x,y,z,p,reverse=false)
|
||||
{
|
||||
assert(is_undef(p), "Module form `frame_map()` does not accept p= argument.");
|
||||
multmatrix(frame_map(x,y,z,reverse=reverse))
|
||||
children();
|
||||
}
|
||||
|
||||
|
||||
// Function&Module: skew()
|
||||
// Usage: As Module
|
||||
|
|
|
@ -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) )
|
||||
[[affine3d_frame_map(x=state, z=approx(norm(updir),0) ? FWD : updir)], [yrot(90)],1, 90, 0]
|
||||
[[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)
|
||||
|
|
Loading…
Reference in a new issue