omdl  v0.9.5
OpenSCAD Mechanical Design Library
linear_algebra.scad
Go to the documentation of this file.
1 //! Linear algebra mathematical functions.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2023
6 
7  \copyright
8 
9  This file is part of [omdl] (https://github.com/royasutton/omdl),
10  an OpenSCAD mechanical design library.
11 
12  The \em omdl is free software; you can redistribute it and/or modify
13  it under the terms of the [GNU Lesser General Public License]
14  (http://www.gnu.org/licenses/lgpl.html) as published by the Free
15  Software Foundation; either version 2.1 of the License, or (at
16  your option) any later version.
17 
18  The \em omdl is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with the \em omdl; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26  02110-1301, USA; or see <http://www.gnu.org/licenses/>.
27 
28  \details
29 
30  \amu_define group_name (Linear Algebra)
31  \amu_define group_brief (Euclidean linear algebra functions.)
32 
33  \amu_include (include/amu/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/group_in_parent_start.amu)
42  \amu_include (include/amu/includes_required.amu)
43 *******************************************************************************/
44 
45 //----------------------------------------------------------------------------//
46 
47 //! Multiply all coordinates by a 4x4 transformation matrix in 3D.
48 /***************************************************************************//**
49  \param c <coords-3d> A list of 3d coordinate points.
50  \param m <matrix-4x4> A 4x4 transformation matrix (decimal-list-4-list4).
51 
52  \returns <coords-3d> A list of 3d coordinate points multiplied by the
53  transformation matrix.
54 
55  \details
56 
57  See [Wikipedia] and [multmatrix] for more information.
58 
59  [Wikipedia]: https://en.wikipedia.org/wiki/Transformation_matrix
60  [multmatrix]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#multmatrix
61 *******************************************************************************/
62 function multmatrix_p
63 (
64  c,
65  m
66 ) = let
67  (
68  m11=m[0][0], m12=m[0][1], m13=m[0][2], m14=m[0][3],
69  m21=m[1][0], m22=m[1][1], m23=m[1][2], m24=m[1][3],
70  m31=m[2][0], m32=m[2][1], m33=m[2][2], m34=m[2][3]
71  )
72  [
73  for (ci=c)
74  let
75  (
76  x = ci[0], y = ci[1], z = ci[2]
77  )
78  [m11*x+m12*y+m13*z+m14, m21*x+m22*y+m23*z+m24, m31*x+m32*y+m33*z+m34]
79  ];
80 
81 //! Translate all coordinates dimensions.
82 /***************************************************************************//**
83  \param c <coords-nd> A list of nd coordinate points.
84  \param v <decimal-list-n> A list of translations for each dimension.
85 
86  \returns <coords-nd> A list of translated coordinate points.
87 
88  \details
89 
90  See [Wikipedia] for more information and [transformation matrix].
91 
92  [Wikipedia]: https://en.wikipedia.org/wiki/Translation_(geometry)
93  [transformation matrix]: https://en.wikipedia.org/wiki/Transformation_matrix
94 *******************************************************************************/
95 function translate_p
96 (
97  c,
98  v
99 ) = is_undef(v) ? c
100  : let
101  (
102  d = len(first(c)),
103  u = is_scalar(v) ? v : 0,
104  w = [for (i=[0 : d-1]) defined_e_or(v, i, u)]
105  )
106  [for (ci=c) [for (di=[0 : d-1]) ci[di] + w[di]]];
107 
108 //! Rotate all coordinates about one or more axes in 2D or 3D.
109 /***************************************************************************//**
110  \param c <coords-3d | coords-2d> A list of 3d or 2d coordinate points.
111  \param a <decimal-list-3 | decimal> The axis rotation angle.
112  A list [ax, ay, az] or a single decimal to specify az only.
113  \param v <vector-3d> An arbitrary axis for the rotation. When
114  specified, the rotation angle will be \p a or az about the
115  line \p v that passes through point \p o.
116  \param o <point-3d> A 3d point origin for the rotation.
117  Ignored when \p v is not specified.
118 
119  \returns <coords-3d | coords-2d> A list of 3d or 2d rotated coordinates.
120  Rotation order is rz, ry, rx.
121 
122  \details
123 
124  See [Wikipedia] for more information on [transformation matrix]
125  and [axis rotation].
126 
127  [Wikipedia]: https://en.wikipedia.org/wiki/Rotation_matrix
128  [transformation matrix]: https://en.wikipedia.org/wiki/Transformation_matrix
129  [axis rotation]: http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation
130 *******************************************************************************/
131 function rotate_p
132 (
133  c,
134  a,
135  v,
136  o = origin3d
137 ) = is_undef(a) ? c
138  : let
139  (
140  d = len(first(c)),
141  az = defined_e_or(a, 2, is_scalar(a) ? a : 0),
142 
143  cg = cos(az), sg = sin(az),
144 
145  rc = (d == 2) ? [for (ci=c) [cg*ci[0]-sg*ci[1], sg*ci[0]+cg*ci[1]]]
146  : (d != 3) ? c
147  : (is_undef(v) || is_list(a)) ?
148  let
149  (
150  ax = defined_e_or(a, 0, 0),
151  ay = defined_e_or(a, 1, 0),
152 
153  ca = cos(ax), cb = cos(ay),
154  sa = sin(ax), sb = sin(ay),
155 
156  m11 = cb*cg,
157  m12 = cg*sa*sb-ca*sg,
158  m13 = ca*cg*sb+sa*sg,
159 
160  m21 = cb*sg,
161  m22 = ca*cg+sa*sb*sg,
162  m23 = -cg*sa+ca*sb*sg,
163 
164  m31 = -sb,
165  m32 = cb*sa,
166  m33 = ca*cb
167  )
168  multmatrix_p(c, [[m11,m12,m13,0], [m21,m22,m23,0], [m31,m32,m33,0]])
169  : let
170  (
171  vx = v[0], vy = v[1], vz = v[2],
172  vx2 = vx*vx, vy2 = vy*vy, vz2 = vz*vz,
173  l2 = vx2 + vy2 + vz2
174  )
175  (l2 == 0) ? c
176  : let
177  (
178  ox = o[0], oy = o[1], oz = o[2],
179  ll = sqrt(l2),
180  oc = 1 - cg,
181 
182  m11 = vx2+(vy2+vz2)*cg,
183  m12 = vx*vy*oc-vz*ll*sg,
184  m13 = vx*vz*oc+vy*ll*sg,
185  m14 = (ox*(vy2+vz2)-vx*(oy*vy+oz*vz))*oc+(oy*vz-oz*vy)*ll*sg,
186 
187  m21 = vx*vy*oc+vz*ll*sg,
188  m22 = vy2+(vx2+vz2)*cg,
189  m23 = vy*vz*oc-vx*ll*sg,
190  m24 = (oy*(vx2+vz2)-vy*(ox*vx+oz*vz))*oc+(oz*vx-ox*vz)*ll*sg,
191 
192  m31 = vx*vz*oc-vy*ll*sg,
193  m32 = vy*vz*oc+vx*ll*sg,
194  m33 = vz2+(vx2+vy2)*cg,
195  m34 = (oz*(vx2+vy2)-vz*(ox*vx+oy*vy))*oc+(ox*vy-oy*vx)*ll*sg
196  )
197  multmatrix_p(c, [[m11,m12,m13,m14], [m21,m22,m23,m24], [m31,m32,m33,m34]])/l2
198  )
199  rc;
200 
201 //! Scale all coordinates dimensions.
202 /***************************************************************************//**
203  \param c <coords-nd> A list of nd coordinate points.
204  \param v <decimal-list-n> A list of scalers for each dimension.
205 
206  \returns <coords-nd> A list of scaled coordinate points.
207 *******************************************************************************/
208 function scale_p
209 (
210  c,
211  v
212 ) = is_undef(v) ? c
213  : let
214  (
215  d = len(first(c)),
216  u = is_scalar(v) ? v : 1,
217  w = [for (i=[0 : d-1]) defined_e_or(v, i, u)]
218  )
219  [for (ci=c) [for (di=[0 : d-1]) ci[di] * w[di]]];
220 
221 //! Scale all coordinates dimensions proportionately to fit inside a region.
222 /***************************************************************************//**
223  \param c <coords-nd> A list of nd coordinate points.
224  \param v <decimal-list-n> A list of bounds for each dimension.
225 
226  \returns <coords-nd> A list of proportionately scaled coordinate
227  points which exactly fit the region bounds \p v.
228 *******************************************************************************/
229 function resize_p
230 (
231  c,
232  v
233 ) = is_undef(v) ? c
234  : let
235  (
236  d = len(first(c)),
237  u = is_scalar(v) ? v : 1,
238  w = [for (i=[0 : d-1]) defined_e_or(v, i, u)],
239  m = [for (i=[0 : d-1]) let (cv = [for (ci=c) (ci[i])]) [min(cv), max(cv)]],
240  s = [for (i=[0 : d-1]) second(m[i]) - first(m[i])]
241  )
242  [for (ci=c) [for (di=[0 : d-1]) ci[di]/s[di] * w[di]]];
243 
244 //! @}
245 //! @}
246 
247 //----------------------------------------------------------------------------//
248 // end of file
249 //----------------------------------------------------------------------------//
origin3d
<point-3d> The origin point coordinate in 3-dimensional Euclidean space.
Definition: constants.scad:425
function defined_e_or(v, i, d)
Return an element of an iterable when it exists or a default value otherwise.
function second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
function is_scalar(v)
Test if a value is a single non-iterable value.
function rotate_p(c, a, v, o=origin3d)
Rotate all coordinates about one or more axes in 2D or 3D.
function multmatrix_p(c, m)
Multiply all coordinates by a 4x4 transformation matrix in 3D.
function resize_p(c, v)
Scale all coordinates dimensions proportionately to fit inside a region.
function translate_p(c, v)
Translate all coordinates dimensions.
function scale_p(c, v)
Scale all coordinates dimensions.