1//////////////////////////////////////////////////////////////////////
2// LibFile: affine.scad
3// Matrix math and affine transformation matrices.
4// Includes:
5// include <BOSL2/std.scad>
6//////////////////////////////////////////////////////////////////////
7
8
9// Section: Affine2d 3x3 Transformation Matrices
10
11
12// Function: affine2d_identity()
13// Usage:
14// mat = affine2d_identify();
15// Topics: Affine, Matrices, Transforms
16// Description:
17// Create a 3x3 affine2d identity matrix.
18// Example:
19// mat = affine2d_identity();
20// // Returns:
21// // [
22// // [1, 0, 0],
23// // [0, 1, 0],
24// // [0, 0, 1]
25// // ]
26function affine2d_identity() = ident(3);
27
28
29// Function: affine2d_translate()
30// Usage:
31// mat = affine2d_translate(v);
32// Topics: Affine, Matrices, Transforms, Translation
33// See Also: move(), affine3d_translate()
34// Description:
35// Returns the 3x3 affine2d matrix to perform a 2D translation.
36// Arguments:
37// v = 2D Offset to translate by. [X,Y]
38// Example:
39// mat = affine2d_translate([30,40]);
40// // Returns:
41// // [
42// // [1, 0, 30],
43// // [0, 1, 40],
44// // [0, 0, 1]
45// // ]
46function affine2d_translate(v=[0,0]) =
47 assert(is_vector(v),2)
48 [
49 [1, 0, v.x],
50 [0, 1, v.y],
51 [0 ,0, 1]
52 ];
53
54
55// Function: affine2d_scale()
56// Usage:
57// mat = affine2d_scale(v);
58// Topics: Affine, Matrices, Transforms, Scaling
59// See Also: scale(), xscale(), yscale(), zscale(), affine3d_scale()
60// Description:
61// Returns the 3x3 affine2d matrix to perform a 2D scaling transformation.
62// Arguments:
63// v = 2D vector of scaling factors. [X,Y]
64// Example:
65// mat = affine2d_scale([3,4]);
66// // Returns:
67// // [
68// // [3, 0, 0],
69// // [0, 4, 0],
70// // [0, 0, 1]
71// // ]
72function affine2d_scale(v=[1,1]) =
73 assert(is_vector(v,2))
74 [
75 [v.x, 0, 0],
76 [ 0, v.y, 0],
77 [ 0, 0, 1]
78 ];
79
80
81// Function: affine2d_zrot()
82// Usage:
83// mat = affine2d_zrot(ang);
84// Topics: Affine, Matrices, Transforms, Rotation
85// See Also: rot(), xrot(), yrot(), zrot(), affine3d_zrot()
86// Description:
87// Returns the 3x3 affine2d matrix to perform a rotation of a 2D vector around the Z axis.
88// Arguments:
89// ang = Number of degrees to rotate.
90// Example:
91// mat = affine2d_zrot(90);
92// // Returns:
93// // [
94// // [0,-1, 0],
95// // [1, 0, 0],
96// // [0, 0, 1]
97// // ]
98function affine2d_zrot(ang=0) =
99 assert(is_finite(ang))
100 [
101 [cos(ang), -sin(ang), 0],
102 [sin(ang), cos(ang), 0],
103 [ 0, 0, 1]
104 ];
105
106
107// Function: affine2d_mirror()
108// Usage:
109// mat = affine2d_mirror(v);
110// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
111// See Also: mirror(), xflip(), yflip(), zflip(), affine3d_mirror()
112// Description:
113// Returns the 3x3 affine2d matrix to perform a reflection of a 2D vector across the line given by its normal vector.
114// Arguments:
115// v = The normal vector of the line to reflect across.
116// Example:
117// mat = affine2d_mirror([0,1]);
118// // Returns:
119// // [
120// // [ 1, 0, 0],
121// // [ 0,-1, 0],
122// // [ 0, 0, 1]
123// // ]
124// Example:
125// mat = affine2d_mirror([1,0]);
126// // Returns:
127// // [
128// // [-1, 0, 0],
129// // [ 0, 1, 0],
130// // [ 0, 0, 1]
131// // ]
132// Example:
133// mat = affine2d_mirror([1,1]);
134// // Returns approximately:
135// // [
136// // [ 0,-1, 0],
137// // [-1, 0, 0],
138// // [ 0, 0, 1]
139// // ]
140function affine2d_mirror(v) =
141 assert(is_vector(v,2))
142 let(v=unit(point2d(v)), a=v.x, b=v.y)
143 [
144 [1-2*a*a, 0-2*a*b, 0],
145 [0-2*a*b, 1-2*b*b, 0],
146 [ 0, 0, 1]
147 ];
148
149
150// Function: affine2d_skew()
151// Usage:
152// mat = affine2d_skew(xa);
153// mat = affine2d_skew(ya=);
154// mat = affine2d_skew(xa, ya);
155// Topics: Affine, Matrices, Transforms, Skewing
156// See Also: skew(), affine3d_skew()
157// Description:
158// Returns the 3x3 affine2d matrix to skew a 2D vector along the XY plane.
159// Arguments:
160// xa = Skew angle, in degrees, in the direction of the X axis. Default: 0
161// ya = Skew angle, in degrees, in the direction of the Y axis. Default: 0
162// Example:
163// mat = affine2d_skew(xa=45,ya=-45);
164// // Returns approximately:
165// // [
166// // [ 1, 1, 0],
167// // [-1, 1, 0],
168// // [ 0, 0, 1]
169// // ]
170function affine2d_skew(xa=0, ya=0) =
171 assert(is_finite(xa))
172 assert(is_finite(ya))
173 [
174 [1, tan(xa), 0],
175 [tan(ya), 1, 0],
176 [0, 0, 1]
177 ];
178
179
180
181// Section: Affine3d 4x4 Transformation Matrices
182
183
184// Function: affine3d_identity()
185// Usage:
186// mat = affine3d_identity();
187// Topics: Affine, Matrices, Transforms
188// Description:
189// Create a 4x4 affine3d identity matrix.
190// Example:
191// mat = affine2d_identity();
192// // Returns:
193// // [
194// // [1, 0, 0, 0],
195// // [0, 1, 0, 0],
196// // [0, 0, 1, 0],
197// // [0, 0, 0, 1]
198// // ]
199function affine3d_identity() = ident(4);
200
201
202// Function: affine3d_translate()
203// Usage:
204// mat = affine3d_translate(v);
205// Topics: Affine, Matrices, Transforms, Translation
206// See Also: move(), affine2d_translate()
207// Description:
208// Returns the 4x4 affine3d matrix to perform a 3D translation.
209// Arguments:
210// v = 3D offset to translate by. [X,Y,Z]
211// Example:
212// mat = affine2d_translate([30,40,50]);
213// // Returns:
214// // [
215// // [1, 0, 0, 30],
216// // [0, 1, 0, 40],
217// // [0, 0, 1, 50]
218// // [0, 0, 0, 1]
219// // ]
220function affine3d_translate(v=[0,0,0]) =
221 assert(is_list(v))
222 let( v = [for (i=[0:2]) default(v[i],0)] )
223 [
224 [1, 0, 0, v.x],
225 [0, 1, 0, v.y],
226 [0, 0, 1, v.z],
227 [0 ,0, 0, 1]
228 ];
229
230
231// Function: affine3d_scale()
232// Usage:
233// mat = affine3d_scale(v);
234// Topics: Affine, Matrices, Transforms, Scaling
235// See Also: scale(), affine2d_scale()
236// Description:
237// Returns the 4x4 affine3d matrix to perform a 3D scaling transformation.
238// Arguments:
239// v = 3D vector of scaling factors. [X,Y,Z]
240// Example:
241// mat = affine3d_scale([3,4,5]);
242// // Returns:
243// // [
244// // [3, 0, 0, 0],
245// // [0, 4, 0, 0],
246// // [0, 0, 5, 0],
247// // [0, 0, 0, 1]
248// // ]
249function affine3d_scale(v=[1,1,1]) =
250 assert(is_list(v))
251 let( v = [for (i=[0:2]) default(v[i],1)] )
252 [
253 [v.x, 0, 0, 0],
254 [ 0, v.y, 0, 0],
255 [ 0, 0, v.z, 0],
256 [ 0, 0, 0, 1]
257 ];
258
259
260// Function: affine3d_xrot()
261// Usage:
262// mat = affine3d_xrot(ang);
263// Topics: Affine, Matrices, Transforms, Rotation
264// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
265// Description:
266// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector around the X axis.
267// Arguments:
268// ang = number of degrees to rotate.
269// Example:
270// mat = affine3d_xrot(90);
271// // Returns:
272// // [
273// // [1, 0, 0, 0],
274// // [0, 0,-1, 0],
275// // [0, 1, 0, 0],
276// // [0, 0, 0, 1]
277// // ]
278function affine3d_xrot(ang=0) =
279 assert(is_finite(ang))
280 [
281 [1, 0, 0, 0],
282 [0, cos(ang), -sin(ang), 0],
283 [0, sin(ang), cos(ang), 0],
284 [0, 0, 0, 1]
285 ];
286
287
288// Function: affine3d_yrot()
289// Usage:
290// mat = affine3d_yrot(ang);
291// Topics: Affine, Matrices, Transforms, Rotation
292// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
293// Description:
294// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector around the Y axis.
295// Arguments:
296// ang = Number of degrees to rotate.
297// Example:
298// mat = affine3d_yrot(90);
299// // Returns:
300// // [
301// // [ 0, 0, 1, 0],
302// // [ 0, 1, 0, 0],
303// // [-1, 0, 0, 0],
304// // [ 0, 0, 0, 1]
305// // ]
306function affine3d_yrot(ang=0) =
307 assert(is_finite(ang))
308 [
309 [ cos(ang), 0, sin(ang), 0],
310 [ 0, 1, 0, 0],
311 [-sin(ang), 0, cos(ang), 0],
312 [ 0, 0, 0, 1]
313 ];
314
315
316// Function: affine3d_zrot()
317// Usage:
318// mat = affine3d_zrot(ang);
319// Topics: Affine, Matrices, Transforms, Rotation
320// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
321// Description:
322// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector around the Z axis.
323// Arguments:
324// ang = number of degrees to rotate.
325// Example:
326// mat = affine3d_zrot(90);
327// // Returns:
328// // [
329// // [ 0,-1, 0, 0],
330// // [ 1, 0, 0, 0],
331// // [ 0, 0, 1, 0],
332// // [ 0, 0, 0, 1]
333// // ]
334function affine3d_zrot(ang=0) =
335 assert(is_finite(ang))
336 [
337 [cos(ang), -sin(ang), 0, 0],
338 [sin(ang), cos(ang), 0, 0],
339 [ 0, 0, 1, 0],
340 [ 0, 0, 0, 1]
341 ];
342
343
344// Function: affine3d_rot_by_axis()
345// Usage:
346// mat = affine3d_rot_by_axis(u, ang);
347// Topics: Affine, Matrices, Transforms, Rotation
348// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
349// Description:
350// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector around an axis.
351// Arguments:
352// u = 3D axis vector to rotate around.
353// ang = number of degrees to rotate.
354// Example:
355// mat = affine3d_rot_by_axis([1,1,1], 120);
356// // Returns approx:
357// // [
358// // [ 0, 0, 1, 0],
359// // [ 1, 0, 0, 0],
360// // [ 0, 1, 0, 0],
361// // [ 0, 0, 0, 1]
362// // ]
363function affine3d_rot_by_axis(u=UP, ang=0) =
364 assert(is_finite(ang))
365 assert(is_vector(u,3))
366 approx(ang,0)? affine3d_identity() :
367 let(
368 u = unit(u),
369 c = cos(ang),
370 c2 = 1-c,
371 s = sin(ang)
372 ) [
373 [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
374 [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
375 [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
376 [ 0, 0, 0, 1]
377 ];
378
379
380// Function: affine3d_rot_from_to()
381// Usage:
382// mat = affine3d_rot_from_to(from, to);
383// Topics: Affine, Matrices, Transforms, Rotation
384// See Also: rot(), xrot(), yrot(), zrot(), affine2d_zrot()
385// Description:
386// Returns the 4x4 affine3d matrix to perform a rotation of a 3D vector from one vector direction to another.
387// Arguments:
388// from = 3D axis vector to rotate from.
389// to = 3D axis vector to rotate to.
390// Example:
391// mat = affine3d_rot_from_to(UP, RIGHT);
392// // Returns:
393// // [
394// // [ 0, 0, 1, 0],
395// // [ 0, 1, 0, 0],
396// // [-1, 0, 0, 0],
397// // [ 0, 0, 0, 1]
398// // ]
399function affine3d_rot_from_to(from, to) =
400 assert(is_vector(from))
401 assert(is_vector(to))
402 assert(len(from)==len(to))
403 let(
404 from = unit(point3d(from)),
405 to = unit(point3d(to))
406 ) approx(from,to)? affine3d_identity() :
407 from.z==0 && to.z==0 ? affine3d_zrot(v_theta(point2d(to)) - v_theta(point2d(from)))
408 :
409 let(
410 u = vector_axis(from,to),
411 ang = vector_angle(from,to),
412 c = cos(ang),
413 c2 = 1-c,
414 s = sin(ang)
415 ) [
416 [u.x*u.x*c2+c , u.x*u.y*c2-u.z*s, u.x*u.z*c2+u.y*s, 0],
417 [u.y*u.x*c2+u.z*s, u.y*u.y*c2+c , u.y*u.z*c2-u.x*s, 0],
418 [u.z*u.x*c2-u.y*s, u.z*u.y*c2+u.x*s, u.z*u.z*c2+c , 0],
419 [ 0, 0, 0, 1]
420 ];
421
422
423
424
425
426// Function: affine3d_mirror()
427// Usage:
428// mat = affine3d_mirror(v);
429// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
430// See Also: mirror(), xflip(), yflip(), zflip(), affine2d_mirror()
431// Description:
432// Returns the 4x4 affine3d matrix to perform a reflection of a 3D vector across the plane given by its normal vector.
433// Arguments:
434// v = The normal vector of the plane to reflect across.
435// Example:
436// mat = affine3d_mirror([1,0,0]);
437// // Returns:
438// // [
439// // [-1, 0, 0, 0],
440// // [ 0, 1, 0, 0],
441// // [ 0, 0, 1, 0],
442// // [ 0, 0, 0, 1]
443// // ]
444// Example:
445// mat = affine3d_mirror([0,1,0]);
446// // Returns:
447// // [
448// // [ 1, 0, 0, 0],
449// // [ 0,-1, 0, 0],
450// // [ 0, 0, 1, 0],
451// // [ 0, 0, 0, 1]
452// // ]
453function affine3d_mirror(v) =
454 assert(is_vector(v))
455 let(
456 v=unit(point3d(v)),
457 a=v.x, b=v.y, c=v.z
458 ) [
459 [1-2*a*a, -2*a*b, -2*a*c, 0],
460 [ -2*b*a, 1-2*b*b, -2*b*c, 0],
461 [ -2*c*a, -2*c*b, 1-2*c*c, 0],
462 [ 0, 0, 0, 1]
463 ];
464
465
466// Function: affine3d_skew()
467// Usage:
468// mat = affine3d_skew([sxy=], [sxz=], [syx=], [syz=], [szx=], [szy=]);
469// Topics: Affine, Matrices, Transforms, Skewing
470// See Also: skew(), affine3d_skew_xy(), affine3d_skew_xz(), affine3d_skew_yz(), affine2d_skew()
471// Description:
472// Returns the 4x4 affine3d matrix to perform a skew transformation.
473// Arguments:
474// sxy = Skew factor multiplier for skewing along the X axis as you get farther from the Y axis. Default: 0
475// sxz = Skew factor multiplier for skewing along the X axis as you get farther from the Z axis. Default: 0
476// syx = Skew factor multiplier for skewing along the Y axis as you get farther from the X axis. Default: 0
477// syz = Skew factor multiplier for skewing along the Y axis as you get farther from the Z axis. Default: 0
478// szx = Skew factor multiplier for skewing along the Z axis as you get farther from the X axis. Default: 0
479// szy = Skew factor multiplier for skewing along the Z axis as you get farther from the Y axis. Default: 0
480// Example:
481// mat = affine3d_skew(sxy=2,szx=3);
482// // Returns:
483// // [
484// // [ 1, 2, 0, 0],
485// // [ 0, 1, 0, 0],
486// // [ 0, 0, 1, 0],
487// // [ 3, 0, 0, 1]
488// // ]
489function affine3d_skew(sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0) = [
490 [ 1, sxy, sxz, 0],
491 [syx, 1, syz, 0],
492 [szx, szy, 1, 0],
493 [ 0, 0, 0, 1]
494];
495
496
497// Function: affine3d_skew_xy()
498// Usage:
499// mat = affine3d_skew_xy(xa);
500// mat = affine3d_skew_xy(ya=);
501// mat = affine3d_skew_xy(xa, ya);
502// Topics: Affine, Matrices, Transforms, Skewing
503// See Also: skew(), affine3d_skew(), affine3d_skew_xz(), affine3d_skew_yz(), affine2d_skew()
504// Description:
505// Returns the 4x4 affine3d matrix to perform a skew transformation along the XY plane.
506// Arguments:
507// xa = Skew angle, in degrees, in the direction of the X axis. Default: 0
508// ya = Skew angle, in degrees, in the direction of the Y axis. Default: 0
509// Example:
510// mat = affine3d_skew_xy(xa=45,ya=-45);
511// // Returns:
512// // [
513// // [ 1, 0, 1, 0],
514// // [ 0, 1,-1, 0],
515// // [ 0, 0, 1, 0],
516// // [ 0, 0, 0, 1]
517// // ]
518function affine3d_skew_xy(xa=0, ya=0) =
519 assert(is_finite(xa))
520 assert(is_finite(ya))
521 [
522 [ 1, tan(xa), 0, 0],
523 [tan(ya), 1, 0, 0],
524 [ 0, 0, 1, 0],
525 [ 0, 0, 0, 1]
526 ];
527
528
529// Function: affine3d_skew_xz()
530// Usage:
531// mat = affine3d_skew_xz(xa);
532// mat = affine3d_skew_xz(za=);
533// mat = affine3d_skew_xz(xa, za);
534// Topics: Affine, Matrices, Transforms, Skewing
535// See Also: skew(), affine3d_skew(), affine3d_skew_xy(), affine3d_skew_yz(), affine2d_skew()
536// Description:
537// Returns the 4x4 affine3d matrix to perform a skew transformation along the XZ plane.
538// Arguments:
539// xa = Skew angle, in degrees, in the direction of the X axis. Default: 0
540// za = Skew angle, in degrees, in the direction of the Z axis. Default: 0
541// Example:
542// mat = affine3d_skew_xz(xa=45,za=-45);
543// // Returns:
544// // [
545// // [ 1, 1, 0, 0],
546// // [ 0, 1, 0, 0],
547// // [ 0,-1, 1, 0],
548// // [ 0, 0, 0, 1]
549// // ]
550function affine3d_skew_xz(xa=0, za=0) =
551 assert(is_finite(xa))
552 assert(is_finite(za))
553 [
554 [ 1, 0, tan(xa), 0],
555 [ 0, 1, 0, 0],
556 [tan(za), 0, 1, 0],
557 [ 0, 0, 0, 1]
558 ];
559
560
561// Function: affine3d_skew_yz()
562// Usage:
563// mat = affine3d_skew_yz(ya);
564// mat = affine3d_skew_yz(za=);
565// mat = affine3d_skew_yz(ya, za);
566// Topics: Affine, Matrices, Transforms, Skewing
567// See Also: skew(), affine3d_skew(), affine3d_skew_xy(), affine3d_skew_xz(), affine2d_skew()
568// Description:
569// Returns the 4x4 affine3d matrix to perform a skew transformation along the YZ plane.
570// Arguments:
571// ya = Skew angle, in degrees, in the direction of the Y axis. Default: 0
572// za = Skew angle, in degrees, in the direction of the Z axis. Default: 0
573// Example:
574// mat = affine3d_skew_yz(ya=45,za=-45);
575// // Returns:
576// // [
577// // [ 1, 0, 0, 0],
578// // [ 1, 1, 0, 0],
579// // [-1, 0, 1, 0],
580// // [ 0, 0, 0, 1]
581// // ]
582function affine3d_skew_yz(ya=0, za=0) =
583 assert(is_finite(ya))
584 assert(is_finite(za))
585 [
586 [1, 0, 0, 0],
587 [0, 1, tan(ya), 0],
588 [0, tan(za), 1, 0],
589 [0, 0, 0, 1]
590 ];
591
592
593
594// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap