omdl  v0.6.1
OpenSCAD Mechanical Design Library
math_linear_algebra.scad
Go to the documentation of this file.
1 //! Linear algebra mathematical functions.
2 /***************************************************************************//**
3  \file math_linear_algebra.scad
4  \author Roy Allen Sutton
5  \date 2015-2017
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 *******************************************************************************/
29 
30 //----------------------------------------------------------------------------//
31 /***************************************************************************//**
32  \addtogroup math
33  @{
34 
35  \defgroup math_linear_algebra Linear Algebra
36  \brief Linear algebra transformations on Euclidean coordinates.
37  @{
38 *******************************************************************************/
39 //----------------------------------------------------------------------------//
40 
41 //! Multiply all coordinates by a 4x4 3d-transformation matrix.
42 /***************************************************************************//**
43  \param c <coords-3d> A list of 3d coordinate points.
44  \param m <matrix-4x4> A 4x4 transformation matrix (decimal-list-4-list4).
45 
46  \returns <coords-3d> A list of 3d coordinate points multiplied by the
47  transformation matrix.
48 
49  \details
50 
51  See [Wikipedia] and [multmatrix] for more information.
52 
53  [Wikipedia]: https://en.wikipedia.org/wiki/Transformation_matrix
54  [multmatrix]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Transformations#multmatrix
55 *******************************************************************************/
56 function multmatrix_lp
57 (
58  c,
59  m
60 ) =
61  let
62  (
63  m11=m[0][0], m12=m[0][1], m13=m[0][2], m14=m[0][3],
64  m21=m[1][0], m22=m[1][1], m23=m[1][2], m24=m[1][3],
65  m31=m[2][0], m32=m[2][1], m33=m[2][2], m34=m[2][3]
66  )
67  [
68  for (ci=c)
69  let
70  (
71  x = ci[0], y = ci[1], z = ci[2]
72  )
73  [m11*x+m12*y+m13*z+m14, m21*x+m22*y+m23*z+m24, m31*x+m32*y+m33*z+m34]
74  ];
75 
76 //! Translate all coordinates dimensions.
77 /***************************************************************************//**
78  \param c <coords-nd> A list of nd coordinate points.
79  \param v <decimal-list-n> A list of translations for each dimension.
80 
81  \returns <coords-nd> A list of translated coordinate points.
82 
83  \details
84 
85  See [Wikipedia] for more information and [transformation matrix].
86 
87  [Wikipedia]: https://en.wikipedia.org/wiki/Translation_(geometry)
88  [transformation matrix]: https://en.wikipedia.org/wiki/Transformation_matrix
89 *******************************************************************************/
90 function translate_lp
91 (
92  c,
93  v
94 ) = not_defined(v) ? c
95  : let
96  (
97  d = len(first(c)),
98  u = is_scalar(v) ? v : 0,
99  w = [for (i=[0 : d-1]) edefined_or(v, i, u)]
100  )
101  [for (ci=c) [for (di=[0 : d-1]) ci[di] + w[di]]];
102 
103 //! Rotate all coordinates about one or more axes in Euclidean 2d or 3d space.
104 /***************************************************************************//**
105  \param c <coords-3d|coords-2d> A list of 3d or 2d coordinate points.
106  \param a <decimal-list-3|decimal> The axis rotation angle.
107  A list [ax, ay, az] or a single decimal to specify az only.
108  \param v <vector-3d> An arbitrary axis for the rotation. When
109  specified, the rotation angle will be \p a or az about the
110  line \p v that passes through point \p o.
111  \param o <point-3d> A 3d point origin for the rotation.
112  Ignored when \p v is not specified.
113 
114  \returns <coords-3d|coords-2d> A list of 3d or 2d rotated coordinates.
115  Rotation order is rz, ry, rx.
116 
117  \details
118 
119  See [Wikipedia] for more information on [transformation matrix]
120  and [axis rotation].
121 
122  [Wikipedia]: https://en.wikipedia.org/wiki/Rotation_matrix
123  [transformation matrix]: https://en.wikipedia.org/wiki/Transformation_matrix
124  [axis rotation]: http://inside.mines.edu/fs_home/gmurray/ArbitraryAxisRotation
125 *******************************************************************************/
126 function rotate_lp
127 (
128  c,
129  a,
130  v,
131  o = origin3d
132 ) = not_defined(a) ? c
133  : let
134  (
135  d = len(first(c)),
136  az = edefined_or(a, 2, is_scalar(a) ? a : 0),
137 
138  cg = cos(az), sg = sin(az),
139 
140  rc = (d == 2) ? [for (ci=c) [cg*ci[0]-sg*ci[1], sg*ci[0]+cg*ci[1]]]
141  : (d != 3) ? c
142  : (not_defined(v) || is_list(a)) ?
143  let
144  (
145  ax = edefined_or(a, 0, 0),
146  ay = edefined_or(a, 1, 0),
147 
148  ca = cos(ax), cb = cos(ay),
149  sa = sin(ax), sb = sin(ay),
150 
151  m11 = cb*cg,
152  m12 = cg*sa*sb-ca*sg,
153  m13 = ca*cg*sb+sa*sg,
154 
155  m21 = cb*sg,
156  m22 = ca*cg+sa*sb*sg,
157  m23 = -cg*sa+ca*sb*sg,
158 
159  m31 = -sb,
160  m32 = cb*sa,
161  m33 = ca*cb
162  )
163  multmatrix_lp(c, [[m11,m12,m13,0], [m21,m22,m23,0], [m31,m32,m33,0]])
164  : let
165  (
166  vx = v[0], vy = v[1], vz = v[2],
167  vx2 = vx*vx, vy2 = vy*vy, vz2 = vz*vz,
168  l2 = vx2 + vy2 + vz2
169  )
170  (l2 == 0) ? c
171  : let
172  (
173  ox = o[0], oy = o[1], oz = o[2],
174  ll = sqrt(l2),
175  oc = 1 - cg,
176 
177  m11 = vx2+(vy2+vz2)*cg,
178  m12 = vx*vy*oc-vz*ll*sg,
179  m13 = vx*vz*oc+vy*ll*sg,
180  m14 = (ox*(vy2+vz2)-vx*(oy*vy+oz*vz))*oc+(oy*vz-oz*vy)*ll*sg,
181 
182  m21 = vx*vy*oc+vz*ll*sg,
183  m22 = vy2+(vx2+vz2)*cg,
184  m23 = vy*vz*oc-vx*ll*sg,
185  m24 = (oy*(vx2+vz2)-vy*(ox*vx+oz*vz))*oc+(oz*vx-ox*vz)*ll*sg,
186 
187  m31 = vx*vz*oc-vy*ll*sg,
188  m32 = vy*vz*oc+vx*ll*sg,
189  m33 = vz2+(vx2+vy2)*cg,
190  m34 = (oz*(vx2+vy2)-vz*(ox*vx+oy*vy))*oc+(ox*vy-oy*vx)*ll*sg
191  )
192  multmatrix_lp(c, [[m11,m12,m13,m14], [m21,m22,m23,m24], [m31,m32,m33,m34]])/l2
193  )
194  rc;
195 
196 //! Scale all coordinates dimensions.
197 /***************************************************************************//**
198  \param c <coords-nd> A list of nd coordinate points.
199  \param v <decimal-list-n> A list of scalers for each dimension.
200 
201  \returns <coords-nd> A list of scaled coordinate points.
202 *******************************************************************************/
203 function scale_lp
204 (
205  c,
206  v
207 ) = not_defined(v) ? c
208  : let
209  (
210  d = len(first(c)),
211  u = is_scalar(v) ? v : 1,
212  w = [for (i=[0 : d-1]) edefined_or(v, i, u)]
213  )
214  [for (ci=c) [for (di=[0 : d-1]) ci[di] * w[di]]];
215 
216 //! Scale all coordinates dimensions proportionately to fit inside a region.
217 /***************************************************************************//**
218  \param c <coords-nd> A list of nd coordinate points.
219  \param v <decimal-list-n> A list of bounds for each dimension.
220 
221  \returns <coords-nd> A list of proportionately scaled coordinate
222  points which exactly fit the region bounds \p v.
223 *******************************************************************************/
224 function resize_lp
225 (
226  c,
227  v
228 ) = not_defined(v) ? c
229  : let
230  (
231  d = len(first(c)),
232  u = is_scalar(v) ? v : 1,
233  w = [for (i=[0 : d-1]) edefined_or(v, i, u)],
234  m = [for (i=[0 : d-1]) let (cv = [for (ci=c) (ci[i])]) [min(cv), max(cv)]],
235  s = [for (i=[0 : d-1]) second(m[i]) - first(m[i])]
236  )
237  [for (ci=c) [for (di=[0 : d-1]) ci[di]/s[di] * w[di]]];
238 
239 //! @}
240 //! @}
241 
242 //----------------------------------------------------------------------------//
243 // end of file
244 //----------------------------------------------------------------------------//
function rotate_lp(c, a, v, o=origin3d)
Rotate all coordinates about one or more axes in Euclidean 2d or 3d space.
function scale_lp(c, v)
Scale all coordinates dimensions.
function second(v)
Return the second element of an iterable value.
function is_scalar(v)
Test if a value is a single non-iterable value.
function edefined_or(v, i, d)
Return an iterable element when it exists or a default value when it does not.
function not_defined(v)
Test if a value is not defined.
origin3d
The origin point coordinate in 3-dimensional Euclidean space.
Definition: constants.scad:127
function is_list(v)
Test if a value is an iterable list of values.
function first(v)
Return the first element of an iterable value.
function resize_lp(c, v)
Scale all coordinates dimensions proportionately to fit inside a region.
function multmatrix_lp(c, m)
Multiply all coordinates by a 4x4 3d-transformation matrix.
function translate_lp(c, v)
Translate all coordinates dimensions.