Skip to content

Commit 0aad39c

Browse files
Move affine3d_frame_map to transforms.scad and rename to frame_map.
Add module version. Change all calls.
1 parent 4fee72f commit 0aad39c

7 files changed

Lines changed: 102 additions & 72 deletions

File tree

affine.scad

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -882,64 +882,6 @@ function affine3d_rot_from_to(from, to) =
882882
];
883883

884884

885-
// Function: affine3d_frame_map()
886-
// Usage:
887-
// map = affine3d_frame_map(v1, v2, v3, [reverse=]);
888-
// map = affine3d_frame_map(x=VECTOR1, y=VECTOR2, [reverse=]);
889-
// map = affine3d_frame_map(x=VECTOR1, z=VECTOR2, [reverse=]);
890-
// map = affine3d_frame_map(y=VECTOR1, z=VECTOR2, [reverse=]);
891-
// Topics: Affine, Matrices, Transforms, Rotation
892-
// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
893-
// Description:
894-
// Returns a transformation that maps one coordinate frame to another. You must specify two or
895-
// three of `x`, `y`, and `z`. The specified axes are mapped to the vectors you supplied. If you
896-
// give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand
897-
// coordinate system. If the vectors you give are orthogonal the result will be a rotation and the
898-
// `reverse` parameter will supply the inverse map, which enables you to map two arbitrary
899-
// coordinate systems to each other by using the canonical coordinate system as an intermediary.
900-
// You cannot use the `reverse` option with non-orthogonal inputs.
901-
// Arguments:
902-
// x = Destination 3D vector for x axis.
903-
// y = Destination 3D vector for y axis.
904-
// z = Destination 3D vector for z axis.
905-
// reverse = reverse direction of the map for orthogonal inputs. Default: false
906-
// Example:
907-
// T = affine3d_frame_map(x=[1,1,0], y=[-1,1,0]); // This map is just a rotation around the z axis
908-
// Example:
909-
// 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
910-
// Example:
911-
// // The next map sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
912-
// 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);
913-
function affine3d_frame_map(x,y,z, reverse=false) =
914-
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
915-
let(
916-
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
917-
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
918-
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
919-
)
920-
assert(xvalid,"Input x must be a length 3 vector")
921-
assert(yvalid,"Input y must be a length 3 vector")
922-
assert(zvalid,"Input z must be a length 3 vector")
923-
let(
924-
x = is_undef(x)? undef : unit(x,RIGHT),
925-
y = is_undef(y)? undef : unit(y,BACK),
926-
z = is_undef(z)? undef : unit(z,UP),
927-
map = is_undef(x)? [cross(y,z), y, z] :
928-
is_undef(y)? [x, cross(z,x), z] :
929-
is_undef(z)? [x, y, cross(x,y)] :
930-
[x, y, z]
931-
)
932-
reverse? (
933-
let(
934-
ocheck = (
935-
approx(map[0]*map[1],0) &&
936-
approx(map[0]*map[2],0) &&
937-
approx(map[1]*map[2],0)
938-
)
939-
)
940-
assert(ocheck, "Inputs must be orthogonal when reverse==true")
941-
[for (r=map) [for (c=r) c, 0], [0,0,0,1]]
942-
) : [for (r=transpose(map)) [for (c=r) c, 0], [0,0,0,1]];
943885

944886

945887

coords.scad

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ function project_plane(plane,p) =
224224
y = unit(plane[1]-plane[0]), // y axis goes to point b
225225
x = unit(v-(v*y)*y) // x axis
226226
)
227-
affine3d_frame_map(x,y) * move(-plane[0])
227+
frame_map(x,y) * move(-plane[0])
228228
: is_vector(plane,4) && is_undef(p) ? // no data, plane given in "plane"
229229
assert(_valid_plane(plane), "Plane is not valid")
230230
let(
@@ -280,7 +280,7 @@ function lift_plane(plane, p) =
280280
y = unit(plane[1]-plane[0]), // y axis goes to point b
281281
x = unit(v-(v*y)*y) // x axis
282282
)
283-
move(plane[0]) * affine3d_frame_map(x,y,reverse=true)
283+
move(plane[0]) * frame_map(x,y,reverse=true)
284284
: is_vector(plane,4) && is_undef(p) ? // no data, plane given in "plane"
285285
assert(_valid_plane(plane), "Plane is not valid")
286286
let(

paths.scad

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@ module path_spread(path, n, spacing, sp=undef, rotate_children=true, closed=fals
16301630
if(planar) {
16311631
rot(from=[0,1],to=cutlist[i][3]) children();
16321632
} else {
1633-
multmatrix(affine3d_frame_map(x=cutlist[i][2], z=cutlist[i][3]))
1633+
frame_map(x=cutlist[i][2], z=cutlist[i][3])
16341634
children();
16351635
}
16361636
} else {
@@ -1777,9 +1777,9 @@ module path_text(path, text, font, size, thickness=1, lettersize, offset=0, reve
17771777

17781778
)
17791779
move(pts[i][0])
1780-
multmatrix(affine3d_frame_map(x=pts[i][2]-adjustment,
1781-
z=usetop ? undef : normpts[i],
1782-
y=usetop ? toppts[i] : undef))
1780+
frame_map(x=pts[i][2]-adjustment,
1781+
z=usetop ? undef : normpts[i],
1782+
y=usetop ? toppts[i] : undef)
17831783
up(offset-thickness/2)
17841784
linear_extrude(height=thickness)
17851785
left(lsize[0]/2)text(text[i], font=font, size=size);

skin.scad

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
13551355
let(rotations =
13561356
[for( i = 0,
13571357
ynormal = normal - (normal * tangents[0])*tangents[0],
1358-
rotation = affine3d_frame_map(y=ynormal, z=tangents[0])
1358+
rotation = frame_map(y=ynormal, z=tangents[0])
13591359
;
13601360
i < len(tangents) + (closed?1:0) ;
13611361
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
13741374
last_tangent = last(tangents),
13751375
lastynormal = last_normal - (last_normal * last_tangent) * last_tangent
13761376
)
1377-
affine3d_frame_map(y=lastynormal, z=last_tangent),
1377+
frame_map(y=lastynormal, z=last_tangent),
13781378
mismatch = transpose(last(rotations)) * reference_rot,
13791379
correction_twist = atan2(mismatch[1][0], mismatch[0][0]),
13801380
// 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
13871387
[for(i=[0:L-(closed?0:1)]) let(
13881388
ynormal = relaxed ? normals[i%L] : normals[i%L] - (normals[i%L] * tangents[i%L])*tangents[i%L],
13891389
znormal = relaxed ? tangents[i%L] - (normals[i%L] * tangents[i%L])*normals[i%L] : tangents[i%L],
1390-
rotation = affine3d_frame_map(y=ynormal, z=znormal)
1390+
rotation = frame_map(y=ynormal, z=znormal)
13911391
)
13921392
assert(approx(ynormal*znormal,0),str("Supplied normal is parallel to the path tangent at point ",i))
13931393
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i]),
@@ -1400,7 +1400,7 @@ function path_sweep(shape, path, method="incremental", normal, closed=false, twi
14001400
dummy = min(testnormals) < .5 ? echo("WARNING: ***** Abrupt change in normal direction. Consider a different method *****") :0
14011401
)
14021402
[for(i=[0:L-(closed?0:1)]) let(
1403-
rotation = affine3d_frame_map(x=pathnormal[i%L], z=tangents[i%L])
1403+
rotation = frame_map(x=pathnormal[i%L], z=tangents[i%L])
14041404
)
14051405
translate(path[i%L])*rotation*zrot(-twist*pathfrac[i])
14061406
] :

threading.scad

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ module generic_threaded_rod(
918918
dummy1 = assert(_r1>depth && _r2>depth, "Screw profile deeper than rod radius");
919919
map_threads = right((_r1 + _r2) / 2) // Shift profile out to thread radius
920920
* affine3d_skew(sxz=(_r2-_r1)/l) // Skew correction for tapered threads
921-
* affine3d_frame_map(x=[0,0,1], y=[1,0,0]) // Map profile to 3d, parallel to z axis
921+
* frame_map(x=[0,0,1], y=[1,0,0]) // Map profile to 3d, parallel to z axis
922922
* scale(pitch); // scale profile by pitch
923923
hig_table = [
924924
[-twist/2-0.0001, 0],

transforms.scad

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
//////////////////////////////////////////////////////////////////////
22
// LibFile: transforms.scad
3-
// 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.
3+
// Functions and modules that provide shortcuts for translation,
4+
// rotation and mirror operations. Also provided are skew and frame_map
5+
// which remaps the coordinate axes. The shortcuts can act on
6+
// geometry, like the usual OpenSCAD rotate() and translate(). They
7+
// also work as functions that operate on lists of points in various
8+
// forms: paths, VNFS and bezier patches. Lastly, the function form
9+
// of the shortcuts can return a matrix representing the operation
10+
// the shortcut performs. The rotation and scaling shortcuts accept
11+
// an optional centerpoint for the rotation or scaling operation.
412
// Includes:
513
// include <BOSL2/std.scad>
614
//////////////////////////////////////////////////////////////////////
@@ -771,6 +779,8 @@ module xyzrot(a=0, p, cp)
771779
function xyzrot(a=0, p, cp) = rot(a=a, v=[1,1,1], cp=cp, p=p);
772780

773781

782+
783+
774784
//////////////////////////////////////////////////////////////////////
775785
// Section: Scaling and Mirroring
776786
//////////////////////////////////////////////////////////////////////
@@ -1439,9 +1449,87 @@ function yzflip(p, cp=0) =
14391449

14401450

14411451
//////////////////////////////////////////////////////////////////////
1442-
// Section: Skewing
1452+
// Section: Other Transformations
14431453
//////////////////////////////////////////////////////////////////////
14441454

1455+
// Function&Module: frame_map()
1456+
// Usage: As module
1457+
// frame_map(v1, v2, v3, [reverse=]) { ... }
1458+
// Usage: As function to remap points
1459+
// transformed = frame_map(v1, v2, v3, p=points, [reverse=]);
1460+
// Usage: As function to return a transformation matrix:
1461+
// map = frame_map(v1, v2, v3, [reverse=]);
1462+
// map = frame_map(x=VECTOR1, y=VECTOR2, [reverse=]);
1463+
// map = frame_map(x=VECTOR1, z=VECTOR2, [reverse=]);
1464+
// map = frame_map(y=VECTOR1, z=VECTOR2, [reverse=]);
1465+
// Topics: Affine, Matrices, Transforms, Rotation
1466+
// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
1467+
// Description:
1468+
// Maps one coordinate frame to another. You must specify two or
1469+
// three of `x`, `y`, and `z`. The specified axes are mapped to the vectors you supplied, so if you
1470+
// specify x=[1,1] then the x axis will be mapped to the line y=x. If you
1471+
// give two inputs, the third vector is mapped to the appropriate normal to maintain a right hand
1472+
// coordinate system. If the vectors you give are orthogonal the result will be a rotation and the
1473+
// `reverse` parameter will supply the inverse map, which enables you to map two arbitrary
1474+
// coordinate systems to each other by using the canonical coordinate system as an intermediary.
1475+
// You cannot use the `reverse` option with non-orthogonal inputs. Note that only the direction
1476+
// of the specified vectors matters: the transformation will not apply scaling, though it can
1477+
// skew if your provide non-orthogonal axes.
1478+
// Arguments:
1479+
// x = Destination 3D vector for x axis.
1480+
// y = Destination 3D vector for y axis.
1481+
// z = Destination 3D vector for z axis.
1482+
// reverse = reverse direction of the map for orthogonal inputs. Default: false
1483+
// Example: Remap axes after linear extrusion
1484+
// frame_map(x=[0,1,0], y=[0,0,1]) linear_extrude(height=10) square(3);
1485+
// Example: This map is just a rotation around the z axis
1486+
// mat = frame_map(x=[1,1,0], y=[-1,1,0]);
1487+
// Example: This map is not a rotation because x and y aren't orthogonal
1488+
// mat = frame_map(x=[1,0,0], y=[1,1,0]);
1489+
// Example: This sends [1,1,0] to [0,1,1] and [-1,1,0] to [0,-1,1]
1490+
// mat = frame_map(x=[0,1,1], y=[0,-1,1]) * frame_map(x=[1,1,0], y=[-1,1,0],reverse=true);
1491+
function frame_map(x,y,z, p, reverse=false) =
1492+
is_def(p)
1493+
? apply(frame_map(x,y,z,reverse=reverse), p)
1494+
:
1495+
assert(num_defined([x,y,z])>=2, "Must define at least two inputs")
1496+
let(
1497+
xvalid = is_undef(x) || (is_vector(x) && len(x)==3),
1498+
yvalid = is_undef(y) || (is_vector(y) && len(y)==3),
1499+
zvalid = is_undef(z) || (is_vector(z) && len(z)==3)
1500+
)
1501+
assert(xvalid,"Input x must be a length 3 vector")
1502+
assert(yvalid,"Input y must be a length 3 vector")
1503+
assert(zvalid,"Input z must be a length 3 vector")
1504+
let(
1505+
x = is_undef(x)? undef : unit(x,RIGHT),
1506+
y = is_undef(y)? undef : unit(y,BACK),
1507+
z = is_undef(z)? undef : unit(z,UP),
1508+
map = is_undef(x)? [cross(y,z), y, z] :
1509+
is_undef(y)? [x, cross(z,x), z] :
1510+
is_undef(z)? [x, y, cross(x,y)] :
1511+
[x, y, z]
1512+
)
1513+
reverse? (
1514+
let(
1515+
ocheck = (
1516+
approx(map[0]*map[1],0) &&
1517+
approx(map[0]*map[2],0) &&
1518+
approx(map[1]*map[2],0)
1519+
)
1520+
)
1521+
assert(ocheck, "Inputs must be orthogonal when reverse==true")
1522+
[for (r=map) [for (c=r) c, 0], [0,0,0,1]]
1523+
) : [for (r=transpose(map)) [for (c=r) c, 0], [0,0,0,1]];
1524+
1525+
1526+
module frame_map(x,y,z,p,reverse=false)
1527+
{
1528+
assert(is_undef(p), "Module form `frame_map()` does not accept p= argument.");
1529+
multmatrix(frame_map(x,y,z,reverse=reverse))
1530+
children();
1531+
}
1532+
14451533

14461534
// Function&Module: skew()
14471535
// Usage: As Module

turtle3d.scad

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ function turtle3d(commands, state=RIGHT, transforms=false, full_state=false, rep
433433
state = is_matrix(state,4,4) ? [[state],[yrot(90)],1,90,0] :
434434
is_vector(state,3) ?
435435
let( updir = UP - (UP * state) * state / (state*state) )
436-
[[affine3d_frame_map(x=state, z=approx(norm(updir),0) ? FWD : updir)], [yrot(90)],1, 90, 0]
436+
[[frame_map(x=state, z=approx(norm(updir),0) ? FWD : updir)], [yrot(90)],1, 90, 0]
437437
: assert(_turtle3d_state_valid(state), "Supplied state is not valid")
438438
state,
439439
finalstate = _turtle3d_repeat(commands, state, repeat)

0 commit comments

Comments
 (0)