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