omdl  v0.9.5
OpenSCAD Mechanical Design Library
coordinate.scad
Go to the documentation of this file.
1 //! Coordinate systems and conversions.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2017-2024
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 (Coordinates Systems)
31  \amu_define group_brief (Coordinate systems and conversions.)
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  \details
45 
46  These functions allow for geometric points in space to be specified
47  using multiple coordinate systems. Some geometric calculations are
48  specified more naturally in one or another coordinate system. These
49  conversion functions allow for the movement between the most
50  convenient for a particular application.
51 
52  For more information see Wikipedia on [coordinate system].
53 
54  The table below enumerates the supported coordinate systems.
55 
56  | system id | description | dimensions | point convention |
57  |:----------:|:--------------:|:-----------:|:-------------------:|
58  | c | [cartesian] | 2d or 3d | [x, y] or [x, y, z] |
59  | p | [polar] | 2d | [r, aa] |
60  | y | [cylindrical] | 3d | [r, aa, z] |
61  | s | [spherical] | 3d | [r, aa, pa] |
62 
63  The symbols used in the convention column are as follows:
64 
65  | symbol | description | units | reference |
66  |:-------:|:------------------------|:-------:|:-------------------:|
67  | x, y, z | coordinate distance | any | xyz-axis |
68  | r | radial distance | any | z-axis / xyz-origin |
69  | aa | [azimuthal] angle | degrees | positive x-axis |
70  | pa | polar / [zenith] angle | degrees | positive z-axis |
71 
72  \note The [azimuthal] angle is a measure of the radial vector orthogonal
73  projection onto the xy-plane measured from the positive x-axis.
74  The polar angle is measured from the z-axis ([zenith]) to the
75  radial vector.
76 
77  \amu_define title (Coordinate system base example)
78  \amu_define scope_id (example)
79  \amu_define output_scad (true)
80  \amu_define output_console (false)
81  \amu_include (include/amu/scope.amu)
82 
83  \amu_define output_scad (false)
84  \amu_define output_console (true)
85 
86  \amu_define title (coordinate_unit_base=c)
87  \amu_define scope_id (example_c)
88  \amu_include (include/amu/scope.amu)
89 
90  \amu_define title (coordinate_unit_base=p)
91  \amu_define scope_id (example_p)
92  \amu_include (include/amu/scope.amu)
93 
94  \amu_define title (coordinate_unit_base=y)
95  \amu_define scope_id (example_y)
96  \amu_include (include/amu/scope.amu)
97 
98  \amu_define title (coordinate_unit_base=s)
99  \amu_define scope_id (example_s)
100  \amu_include (include/amu/scope.amu)
101 
102  [coordinate system]: https://en.wikipedia.org/wiki/Coordinate_system
103  [cartesian]: https://en.wikipedia.org/wiki/Cartesian_coordinate_system
104  [polar]: https://en.wikipedia.org/wiki/Polar_coordinate_system
105  [cylindrical]: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
106  [spherical]: https://en.wikipedia.org/wiki/Spherical_coordinate_system
107  [azimuthal]: https://en.wikipedia.org/wiki/Azimuth
108  [zenith]: https://en.wikipedia.org/wiki/Zenith
109 *******************************************************************************/
110 
111 //----------------------------------------------------------------------------//
112 
113 //! <string> The base units for value storage.
115 
116 //! <string> The default units when unspecified.
118 
119 //! <boolean> When converting to angular measures add 360 to negative angles.
121 
122 //! Return the name of the given coordinate system identifier.
123 /***************************************************************************//**
124  \param s <string> A coordinate system identifier.
125 
126  \returns <string> The system name for the given identifier.
127  Returns \b undef for identifiers that are not defined.
128 *******************************************************************************/
129 function coordinate_unit_name
130 (
132 ) = (s == "c") ? "cartesian"
133  : (s == "p") ? "polar"
134  : (s == "y") ? "cylindrical"
135  : (s == "s") ? "spherical"
136  : undef;
137 
138 //! Convert a point from Cartesian to other coordinate systems.
139 /***************************************************************************//**
140  \param c <point> A point to convert.
141  \param to <string> The coordinate system identifier to which the point
142  should be converted.
143 
144  \returns <point> The converted result.
145  Returns \b undef for identifiers that are not defined.
146 
147  \private
148 *******************************************************************************/
149 function coordinate_unit_c2
150 (
151  c,
152  to
153 ) = !is_point(c) ? undef
154 
155  // cartesian (2d, 3d)
156  : (to == "c") ? c
157 
158  : let( d = line_dim(c) )
159 
160  // polar (2d)
161  (to == "p") ? (d != 2 ) ? undef
162  : (
163  let
164  (
165  r = sqrt(pow(c[0],2) + pow(c[1],2)),
166  aa = atan2(c[1], c[0]),
167  aap = ((aa<0) && (coordinate_positive_angle==true)) ? aa+360 : aa
168  )
169  [r, aap]
170  )
171 
172  // cylindrical (3d)
173  : (to == "y") ? (d != 3 ) ? undef
174  : (
175  let
176  (
177  r = sqrt(pow(c[0],2) + pow(c[1],2)),
178  aa = atan2(c[1], c[0]),
179  aap = ((aa<0) && (coordinate_positive_angle==true)) ? aa+360 : aa,
180  z = (c[2] !=undef) ? c[2] : 0
181  )
182  [r, aap, z]
183  )
184 
185  // spherical (3d)
186  : (to == "s") ? (d != 3 ) ? undef
187  : (
188  let
189  (
190  r = sqrt(pow(c[0],2) + pow(c[1],2) + pow(c[2],2)),
191  aa = atan2(c[1], c[0]),
192  aap = ((aa<0) && (coordinate_positive_angle==true)) ? aa+360 : aa,
193  pa = acos(c[2] / r)
194  )
195  [r, aap, pa]
196  )
197 
198  : undef;
199 
200 //! Convert a point from some coordinate system to the Cartesian coordinate system.
201 /***************************************************************************//**
202  \param c <point> A point to convert.
203  \param from <string> The coordinate system identifier of the point
204  to be converted.
205 
206  \returns <point> The converted result.
207  Returns \b undef for identifiers that are not defined.
208 
209  \private
210 *******************************************************************************/
211 function coordinate_unit_2c
212 (
213  c,
214  from
215 ) = !is_point(c) ? undef
216 
217  // cartesian (2d, 3d)
218  : (from == "c") ? c
219 
220  : let( d = line_dim(c) )
221 
222  // polar (2d)
223  (from == "p") ? (d != 2 ) ? undef
224  : (
225  let
226  (
227  x = c[0]*cos(c[1]),
228  y = c[0]*sin(c[1])
229  )
230  [x, y]
231  )
232 
233  // cylindrical (3d)
234  : (from == "y") ? (d != 3 ) ? undef
235  : (
236  let
237  (
238  x = c[0]*cos(c[1]),
239  y = c[0]*sin(c[1]),
240  z = (c[2] != undef) ? c[2] : 0
241  )
242  [x, y, z]
243  )
244 
245  // spherical (3d)
246  : (from == "s") ? (d != 3 ) ? undef
247  : (
248  let
249  (
250  x = c[0]*sin(c[2])*cos(c[1]),
251  y = c[0]*sin(c[2])*sin(c[1]),
252  z = c[0]*cos(c[2])
253  )
254  [x, y, z]
255  )
256  : undef;
257 
258 //! Convert point from one coordinate system to another.
259 /***************************************************************************//**
260  \param c <point> A point to convert.
261  \param from <string> The coordinate system identifier of the point
262  to be converted.
263  \param to <string> The coordinate system identifier to which the point
264  should be converted.
265 
266  \returns <point> The converted result.
267  Returns \b undef for identifiers that are not defined.
268 *******************************************************************************/
269 function coordinate
270 (
271  c,
274 ) = (from == to) ? c
275  : coordinate_unit_c2( coordinate_unit_2c( c, from ), to );
276 
277 //! Convert point from one coordinate system to another.
278 /***************************************************************************//**
279  \param c <point> A point to convert.
280  \param from <string> The coordinate system identifier of the point
281  to be converted.
282  \param to <string> The coordinate system identifier to which the point
283  should be converted.
284 
285  \returns <point> The converted result.
286  Returns \b undef for identifiers that are not defined.
287 *******************************************************************************/
288 function coordinate_inv
289 (
290  c,
291  from = coordinate_unit_base,
293 ) = (from == to) ? c
294  : coordinate_unit_c2( coordinate_unit_2c( c, from ), to );
295 
296 //! Radially scale a list of 2d cartesian coordinates.
297 /***************************************************************************//**
298  \param c <coords-2d> A list of cartesian coordinates [[x, y], ...].
299  \param r <decimal> A polar radius.
300  \param t <boolean> Translate or scale radius.
301 
302  \returns <coords-2d> A list of scaled cartesian coordinates.
303 
304  \details
305 
306  When \p t is \b true, all coordinates will terminate on a circle of
307  radius \p r. When \p t is \b false, the radius of each coordinate
308  is scaled by \p r.
309 *******************************************************************************/
310 function coordinate_scale2d_cpc
311 (
312  c,
313  r,
314  t = false
315 ) =
316  [
317  for (i = c)
318  let (p = coordinate(i, from="c", to="p"))
319  coordinate([(t == true) ? r : r*p[0], p[1]], from="p", to="c")
320  ];
321 
322 //! Radially scale and convert a list of 2d polar coordinates to cartesian.
323 /***************************************************************************//**
324  \param c <coords-2d> A list of polar coordinates [[r, aa], ...].
325  \param r <decimal> A polar radius.
326  \param t <boolean> Translate or scale radius.
327 
328  \returns <coords-2d> A list of scaled cartesian coordinates.
329 
330  \details
331 
332  When \p t is \b true, all coordinates will terminate on a circle of
333  radius \p r. When \p t is \b false, the radius of each coordinate
334  is scaled by \p r.
335 *******************************************************************************/
336 function coordinate_scale2d_p2c
337 (
338  p,
339  r,
340  t = false
341 ) =
342  [
343  for (i = p)
344  coordinate([(t == true) ? r : r*i[0], i[1]], from="p", to="c")
345  ];
346 
347 //! Spherically scale a list of 3d cartesian coordinates.
348 /***************************************************************************//**
349  \param c <coords-3d> A list of cartesian coordinates [[x, y, z], ...].
350  \param r <decimal> A spherical radius.
351  \param t <boolean> Translate or scale radius.
352 
353  \returns <coords-3d> A list of scaled cartesian coordinates.
354 
355  \details
356 
357  When \p t is \b true, all coordinates will terminate on a sphere of
358  radius \p r. When \p t is \b false, the radius of each coordinate
359  is scaled by \p r.
360 *******************************************************************************/
361 function coordinate_scale3d_csc
362 (
363  c,
364  r,
365  t = false
366 ) =
367  [
368  for (i = c)
369  let (s = coordinate(i, from="c", to="s"))
370  coordinate([(t == true) ? r : r*s[0], s[1], s[2]], from="s", to="c")
371  ];
372 
373 //! Spherically scale and convert a list of 3d spherical coordinates to cartesian.
374 /***************************************************************************//**
375  \param c <coords-3d> A list of spherical coordinates [[r, aa, pa], ...].
376  \param r <decimal> A spherical radius.
377  \param t <boolean> Translate or scale radius.
378 
379  \returns <coords-3d> A list of scaled cartesian coordinates.
380 
381  \details
382 
383  When \p t is \b true, all coordinates will terminate on a sphere of
384  radius \p r. When \p t is \b false, the radius of each coordinate
385  is scaled by \p r.
386 *******************************************************************************/
387 function coordinate_scale3d_s2c
388 (
389  s,
390  r,
391  t = false
392 ) =
393  [
394  for (i = s)
395  coordinate([(t == true) ? r : r*i[0], i[1], i[2]], from="s", to="c")
396  ];
397 
398 //! @}
399 //! @}
400 
401 //----------------------------------------------------------------------------//
402 // openscad-amu auxiliary scripts
403 //----------------------------------------------------------------------------//
404 
405 /*
406 BEGIN_SCOPE example;
407  BEGIN_OPENSCAD;
408  include <omdl-base.scad>;
409  include <units/coordinate.scad>;
410 
411  coordinate_unit_base = "c";
412  coordinate_unit_default = "p";
413 
414  // get unit names
415  bu = coordinate_unit_name(coordinate_unit_base);
416  du = coordinate_unit_name();
417 
418  // absolute coordinates in a specified coordinate system.
419  c1 = coordinate([1, 1, 1], "c");
420  c2 = coordinate([1, 180]);
421  c3 = coordinate([1, 90, -1], "y");
422  c4 = coordinate([1, 5, 50], "s");
423 
424  // convert between system.
425  c5 = coordinate([10*sqrt(2), 45, 45], from="s", to="y");
426  c6 = coordinate([sqrt(2), 45], to="c");
427 
428  // end_include
429 
430  echo( bu=bu );
431  echo( du=du );
432  echo( );
433  echo( c1=c1 );
434  echo( c2=c2 );
435  echo( c3=c3 );
436  echo( c4=c4 );
437  echo( c5=c5 );
438  echo( c6=c6 );
439  END_OPENSCAD;
440 
441  BEGIN_MFSCRIPT;
442  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
443 
444  defines name "system" define "coordinate_unit_base" strings "c p y s";
445  variables add_opts_combine "system";
446 
447  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
448  END_MFSCRIPT;
449 END_SCOPE;
450 */
451 
452 //----------------------------------------------------------------------------//
453 // end of file
454 //----------------------------------------------------------------------------//
function line_dim(l)
Return the number of dimensions of a line or vector.
function is_point(v)
Test if a value defines a point.
coordinate_unit_base
<string> The base units for value storage.
function coordinate(c, from=coordinate_unit_default, to=coordinate_unit_base)
Convert point from one coordinate system to another.
function coordinate_inv(c, from=coordinate_unit_base, to=coordinate_unit_default)
Convert point from one coordinate system to another.
function coordinate_scale2d_cpc(c, r, t=false)
Radially scale a list of 2d cartesian coordinates.
function coordinate_scale3d_csc(c, r, t=false)
Spherically scale a list of 3d cartesian coordinates.
function coordinate_scale2d_p2c(p, r, t=false)
Radially scale and convert a list of 2d polar coordinates to cartesian.
function coordinate_unit_name(s=coordinate_unit_default)
Return the name of the given coordinate system identifier.
function coordinate_scale3d_s2c(s, r, t=false)
Spherically scale and convert a list of 3d spherical coordinates to cartesian.
coordinate_unit_default
<string> The default units when unspecified.
coordinate_positive_angle
<boolean> When converting to angular measures add 360 to negative angles.