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// Function: affine3d_mirror()
454// Synopsis: Returns a 3D (4x4) reflection transformation matrix.
455// SynTags: Mat
456// Topics: Affine, Matrices, Transforms, Reflection, Mirroring
457// See Also: mirror(), xflip(), yflip(), zflip(), affine2d_mirror()
458// Usage:
459// mat = affine3d_mirror(v);
460// Description:
461// Returns the 4x4 affine3d matrix to perform a reflection of a 3D vector across the plane given by its normal vector.
462// Arguments:
463// v = The normal vector of the plane to reflect across.
464// Example:
465// mat = affine3d_mirror([1,0,0]);
466// // Returns:
467// // [
468// // [-1, 0, 0, 0],
469// // [ 0, 1, 0, 0],
470// // [ 0, 0, 1, 0],
471// // [ 0, 0, 0, 1]
472// // ]
473// Example:
474// mat = affine3d_mirror([0,1,0]);
475// // Returns:
476// // [
477// // [ 1, 0, 0, 0],
478// // [ 0,-1, 0, 0],
479// // [ 0, 0, 1, 0],
480// // [ 0, 0, 0, 1]
481// // ]
482function affine3d_mirror(v) =
483 assert(is_vector(v))
484 let(
485 v=unit(point3d(v)),
486 a=v.x, b=v.y, c=v.z
487 ) [
488 [1-2*a*a, -2*a*b, -2*a*c, 0],
489 [ -2*b*a, 1-2*b*b, -2*b*c, 0],
490 [ -2*c*a, -2*c*b, 1-2*c*c, 0],
491 [ 0, 0, 0, 1]
492 ];
493
494
495// Function: affine3d_skew()
496// Synopsis: Returns a 3D (4x4) skewing transformation matrix.
497// SynTags: Mat
498// Topics: Affine, Matrices, Transforms, Skewing
499// See Also: skew(), affine3d_skew_xy(), affine3d_skew_xz(), affine3d_skew_yz(), affine2d_skew()
500// Usage:
501// mat = affine3d_skew([sxy=], [sxz=], [syx=], [syz=], [szx=], [szy=]);
502// Description:
503// Returns the 4x4 affine3d matrix to perform a skew transformation.
504// Arguments:
505// sxy = Skew factor multiplier for skewing along the X axis as you get farther from the Y axis. Default: 0
506// sxz = Skew factor multiplier for skewing along the X axis as you get farther from the Z axis. Default: 0
507// syx = Skew factor multiplier for skewing along the Y axis as you get farther from the X axis. Default: 0
508// syz = Skew factor multiplier for skewing along the Y axis as you get farther from the Z axis. Default: 0
509// szx = Skew factor multiplier for skewing along the Z axis as you get farther from the X axis. Default: 0
510// szy = Skew factor multiplier for skewing along the Z axis as you get farther from the Y axis. Default: 0
511// Example:
512// mat = affine3d_skew(sxy=2,szx=3);
513// // Returns:
514// // [
515// // [ 1, 2, 0, 0],
516// // [ 0, 1, 0, 0],
517// // [ 0, 0, 1, 0],
518// // [ 3, 0, 0, 1]
519// // ]
520function affine3d_skew(sxy=0, sxz=0, syx=0, syz=0, szx=0, szy=0) = [
521 [ 1, sxy, sxz, 0],
522 [syx, 1, syz, 0],
523 [szx, szy, 1, 0],
524 [ 0, 0, 0, 1]
525];
526
527
528// Function: affine3d_skew_xy()
529// Synopsis: Returns a 3D (4x4) XY-plane skewing transformation matrix.
530// SynTags: Mat
531// Topics: Affine, Matrices, Transforms, Skewing
532// See Also: skew(), affine3d_skew(), affine3d_skew_xz(), affine3d_skew_yz(), affine2d_skew()
533// Usage:
534// mat = affine3d_skew_xy(xa);
535// mat = affine3d_skew_xy(ya=);
536// mat = affine3d_skew_xy(xa, ya);
537// Description:
538// Returns the 4x4 affine3d matrix to perform a skew transformation along the XY plane.
539// Arguments:
540// xa = Skew angle, in degrees, in the direction of the X axis. Default: 0
541// ya = Skew angle, in degrees, in the direction of the Y axis. Default: 0
542// Example:
543// mat = affine3d_skew_xy(xa=45,ya=-45);
544// // Returns:
545// // [
546// // [ 1, 0, 1, 0],
547// // [ 0, 1,-1, 0],
548// // [ 0, 0, 1, 0],
549// // [ 0, 0, 0, 1]
550// // ]
551function affine3d_skew_xy(xa=0, ya=0) =
552 assert(is_finite(xa))
553 assert(is_finite(ya))
554 [
555 [ 1, tan(xa), 0, 0],
556 [tan(ya), 1, 0, 0],
557 [ 0, 0, 1, 0],
558 [ 0, 0, 0, 1]
559 ];
560
561
562// Function: affine3d_skew_xz()
563// Synopsis: Returns a 3D (4x4) XZ-plane skewing transformation matrix.
564// SynTags: Mat
565// Topics: Affine, Matrices, Transforms, Skewing
566// See Also: skew(), affine3d_skew(), affine3d_skew_xy(), affine3d_skew_yz(), affine2d_skew()
567// Usage:
568// mat = affine3d_skew_xz(xa);
569// mat = affine3d_skew_xz(za=);
570// mat = affine3d_skew_xz(xa, za);
571// Description:
572// Returns the 4x4 affine3d matrix to perform a skew transformation along the XZ plane.
573// Arguments:
574// xa = Skew angle, in degrees, in the direction of the X axis. Default: 0
575// za = Skew angle, in degrees, in the direction of the Z axis. Default: 0
576// Example:
577// mat = affine3d_skew_xz(xa=45,za=-45);
578// // Returns:
579// // [
580// // [ 1, 1, 0, 0],
581// // [ 0, 1, 0, 0],
582// // [ 0,-1, 1, 0],
583// // [ 0, 0, 0, 1]
584// // ]
585function affine3d_skew_xz(xa=0, za=0) =
586 assert(is_finite(xa))
587 assert(is_finite(za))
588 [
589 [ 1, 0, tan(xa), 0],
590 [ 0, 1, 0, 0],
591 [tan(za), 0, 1, 0],
592 [ 0, 0, 0, 1]
593 ];
594
595
596// Function: affine3d_skew_yz()
597// Synopsis: Returns a 3D (4x4) YZ-plane skewing transformation matrix.
598// SynTags: Mat
599// Topics: Affine, Matrices, Transforms, Skewing
600// See Also: skew(), affine3d_skew(), affine3d_skew_xy(), affine3d_skew_xz(), affine2d_skew()
601// Usage:
602// mat = affine3d_skew_yz(ya);
603// mat = affine3d_skew_yz(za=);
604// mat = affine3d_skew_yz(ya, za);
605// Description:
606// Returns the 4x4 affine3d matrix to perform a skew transformation along the YZ plane.
607// Arguments:
608// ya = Skew angle, in degrees, in the direction of the Y axis. Default: 0
609// za = Skew angle, in degrees, in the direction of the Z axis. Default: 0
610// Example:
611// mat = affine3d_skew_yz(ya=45,za=-45);
612// // Returns:
613// // [
614// // [ 1, 0, 0, 0],
615// // [ 1, 1, 0, 0],
616// // [-1, 0, 1, 0],
617// // [ 0, 0, 0, 1]
618// // ]
619function affine3d_skew_yz(ya=0, za=0) =
620 assert(is_finite(ya))
621 assert(is_finite(za))
622 [
623 [1, 0, 0, 0],
624 [0, 1, tan(ya), 0],
625 [0, tan(za), 1, 0],
626 [0, 0, 0, 1]
627 ];
628
629
630
631// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap