omdl  v0.6.1
OpenSCAD Mechanical Design Library
math_vector_algebra.scad
Go to the documentation of this file.
1 //! Vector algebra mathematical functions.
2 /***************************************************************************//**
3  \file math_vector_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  \page tv_math_vector_algebra Vector Algebra
33  \li \subpage tv_math_vector_algebra_s
34  \li \subpage tv_math_vector_algebra_r
35  \page tv_math_vector_algebra_s Script
36  \dontinclude math_vector_algebra_validate.scad
37  \skip include
38  \until end-of-tests
39  \page tv_math_vector_algebra_r Results
40  \include math_vector_algebra_validate.log
41 *******************************************************************************/
42 //----------------------------------------------------------------------------//
43 
44 //----------------------------------------------------------------------------//
45 /***************************************************************************//**
46  \addtogroup math
47  @{
48 
49  \defgroup math_vector_algebra Vector Algebra
50  \brief Algebraic operations on Euclidean vectors.
51 
52  \details
53 
54  See validation \ref tv_math_vector_algebra_r "results".
55  @{
56 *******************************************************************************/
57 //----------------------------------------------------------------------------//
58 
59 //----------------------------------------------------------------------------//
60 // group 1: point
61 //----------------------------------------------------------------------------//
62 
63 //! Compute the distance between two Euclidean points.
64 /***************************************************************************//**
65  \param p1 <point> A point coordinate 1.
66  \param p2 <point> A point coordinate 2.
67 
68  \returns <decimal> The distance between the two points.
69  Returns \b undef when points do not have equal dimensions.
70 
71  \details
72 
73  When \p p2 is not given, it is assumed to be at the origin. This
74  function is similar to [norm].
75 
76  [norm]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Mathematical_Functions#norm
77 *******************************************************************************/
78 function distance_pp
79 (
80  p1,
81  p2
82 ) = let(d = len(p1))
83  !(d > 0) ? abs(p1 - defined_or(p2, 0))
84  : is_defined(p2) ?
85  sqrt(sum([for (i=[0:d-1]) (p1[i]-p2[i])*(p1[i]-p2[i])]))
86  : sqrt(sum([for (i=[0:d-1]) p1[i]*p1[i]]));
87 
88 //! Test if a point is left, on, or right of an infinite line in a Euclidean 2d-space.
89 /***************************************************************************//**
90  \param p1 <point-2d> A 2d point coordinate 1.
91  \param p2 <point-2d> A 2d point coordinate 2.
92  \param p3 <point-2d> A 2d point coordinate 3.
93 
94  \returns <decimal> (\b > 0) for \p p3 \em left of the line through
95  \p p1 and \p p2, (\b = 0) for p3 \em on the line, and
96  (\b < 0) for p3 right of the line.
97 
98  \details
99 
100  Function patterned after [Dan Sunday, 2012].
101 
102  [Dan Sunday, 2012]: http://geomalgorithms.com/a01-_area.html
103 *******************************************************************************/
104 function is_left_ppp
105 (
106  p1,
107  p2,
108  p3
109 ) = ((p2[0]-p1[0]) * (p3[1]-p1[1]) - (p3[0]-p1[0]) * (p2[1]-p1[1]));
110 
111 //----------------------------------------------------------------------------//
112 // group 2: vector
113 //----------------------------------------------------------------------------//
114 
115 //! Return 3d vector unchanged or add a zeroed third dimension to 2d vector.
116 /***************************************************************************//**
117  \param v <vector-3d|vector-2d> A vector.
118 
119  \returns <vector-3d> The 3d vector or the 2d vector converted to 3d
120  with its third dimension assigned zero.
121 
122  \warning To reduce overhead, this function assumes any vector that is
123  not 3d to be 2d.
124 *******************************************************************************/
125 function dimension_2to3_v
126 (
127  v
128 ) = (len(v) == 3) ? v : [v[0], v[1], 0];
129 
130 //----------------------------------------------------------------------------//
131 // group 3: line (or vector)
132 //----------------------------------------------------------------------------//
133 
134 //! Return the number of dimensions of a Euclidean line (or vector).
135 /***************************************************************************//**
136  \param l <line> A line (or vector).
137 
138  \returns <integer> The number of dimensions for the line (or vector).
139 
140  \details
141 
142  See \ref dt_line for argument specification and conventions.
143 *******************************************************************************/
144 function get_line_dim
145 (
146  l
147 ) = is_defined(len(l[0])) ? len(l[0]) : len(l);
148 
149 //! Return the terminal point of a Euclidean line (or vector).
150 /***************************************************************************//**
151  \param l <line> A line (or vector).
152 
153  \returns <point> The terminal point of the line (or vector).
154 
155  \details
156 
157  See \ref dt_line for argument specification and conventions.
158 *******************************************************************************/
159 function get_line_tp
160 (
161  l
162 ) = is_iterable(l[0]) ? (len(l)>1) ? l[1] : l[0] : l;
163 
164 //! Return the initial point of a Euclidean line (or vector).
165 /***************************************************************************//**
166  \param l <line> A line (or vector).
167 
168  \returns <point> The initial point of the line (or vector).
169 
170  \details
171 
172  See \ref dt_line for argument specification and conventions.
173 *******************************************************************************/
174 function get_line_ip
175 (
176  l
177 ) = is_iterable(l[0]) ? (len(l)>1) ? l[0] : consts(len(l[0]), 0)
178  : is_iterable(l) ? consts(len(l), 0) : 0;
179 
180 //! Shift a Euclidean line (or vector) to the origin.
181 /***************************************************************************//**
182  \param l <line> A line (or vector).
183 
184  \returns <vector> The line (or vector) shifted to the origin.
185 
186  \details
187 
188  See \ref dt_line for argument specification and conventions.
189 *******************************************************************************/
190 function get_line2origin
191 (
192  l
193 ) = not_defined(len(l[0])) ? l
194  : (len(l) == 1) ? l[0]
195  : (len(l) == 2) ? (l[1]-l[0])
196  : undef;
197 
198 //! Compute the dot product of two lines (or vectors).
199 /***************************************************************************//**
200  \param l1 <line> A n-dimensional line (or vector) 1.
201  \param l2 <line> A n-dimensional line (or vector) 2.
202 
203  \returns <decimal> The dot product of \p l1 with \p l2.
204  Returns \b undef when lines (or vectors) have different
205  dimensions.
206 
207  \details
208 
209  This function supports the abstraction outlined in \ref dt_line.
210  The built-in operation will be more efficient in situations that do
211  not make use of the aforementioned abstraction.
212 
213  See \ref dt_line for argument specification and conventions.
214  See [Wikipedia] for more information.
215 
216  [Wikipedia]: https://en.wikipedia.org/wiki/Dot_product
217 *******************************************************************************/
218 function dot_ll
219 (
220  l1,
221  l2
222 ) = (get_line2origin(l1) * get_line2origin(l2));
223 
224 //! Compute the cross product of two lines (or vectors) in a Euclidean 3d or 2d-space.
225 /***************************************************************************//**
226  \param l1 <line-3d|line-2d> A 3d or 2d line (or vector) 1.
227  \param l2 <line-3d|line-2d> A 3d or 2d line (or vector) 2.
228 
229  \returns <decimal|vector-2d> The cross product of \p l1 with \p l2.
230  Returns \b undef when lines (or vectors) have different
231  dimensions.
232 
233  \details
234 
235  This function supports the abstraction outlined in \ref dt_line.
236  The built-in operation will be more efficient in situations that do
237  not make use of the aforementioned abstraction.
238 
239  See \ref dt_line for argument specification and conventions.
240  See Wikipedia [cross] and [determinant] for more information.
241 
242  \note This function returns the 2x2 determinant for 2d vectors.
243 
244  [cross]: https://en.wikipedia.org/wiki/Cross_product
245  [determinant]: https://en.wikipedia.org/wiki/Determinant
246 *******************************************************************************/
247 function cross_ll
248 (
249  l1,
250  l2
251 ) = cross(get_line2origin(l1), get_line2origin(l2));
252 
253 //! Compute the scalar triple product of three lines (or vectors) in a Euclidean 3d or 2d-space.
254 /***************************************************************************//**
255  \param l1 <line-3d|line-2d> A 3d or 2d line (or vector) 1.
256  \param l2 <line-3d|line-2d> A 3d or 2d line (or vector) 2.
257  \param l3 <line-3d|line-2d> A 3d or 2d line (or vector) 3.
258 
259  \returns <decimal|vector-2d> The scalar triple product.
260  Returns \b undef when lines (or vectors) have different
261  dimensions.
262 
263  \details
264 
265  [l1, l2, l3] = l1 * (l2 x l3)
266 
267  See \ref dt_line for argument specification and conventions.
268  See [Wikipedia] for more information.
269 
270  \warning Returns a 2d vector result for 2d vectors. The cross product
271  computes the 2x2 determinant of the vectors <tt>(l2 x l3)</tt>,
272  a scalar value, which is then \e multiplied by \c l1.
273 
274  [Wikipedia]: https://en.wikipedia.org/wiki/Triple_product
275 *******************************************************************************/
276 function striple_lll
277 (
278  l1,
279  l2,
280  l3
281 ) = (get_line2origin(l1) * cross_ll(l2, l3));
282 
283 //! Compute the angle between two lines (or vectors) in a Euclidean 3d or 2d-space.
284 /***************************************************************************//**
285  \param l1 <line-3d|line-2d> A 3d or 2d line (or vector) 1.
286  \param l2 <line-3d|line-2d> A 3d or 2d line (or vector) 2.
287 
288  \returns <decimal> The angle between the two lines (or vectors) in
289  degrees. Returns \b undef when lines (or vectors) have
290  different dimensions or when they do not intersect.
291 
292  \details
293 
294  See \ref dt_line for argument specification and conventions.
295 
296  \note For 3d lines (or vectors), a normal is required to uniquely
297  identify the perpendicular plane and axis of rotation. This
298  function calculates the positive angle, and the plane and
299  axis of rotation will be that which fits this assumed
300  positive angle.
301 
302  \sa angle_lll().
303 *******************************************************************************/
304 function angle_ll
305 (
306  l1,
307  l2
308 ) = let(d = get_line_dim(l1))
309  (d == 2) ? atan2(cross_ll(l1, l2), dot_ll(l1, l2))
310  : (d == 3) ? atan2(distance_pp(cross_ll(l1, l2)), dot_ll(l1, l2))
311  : undef;
312 
313 //! Compute the angle between two lines (or vectors) in a Euclidean 3d-space.
314 /***************************************************************************//**
315  \param l1 <line-3d> A 3d line (or vector) 1.
316  \param l2 <line-3d> A 3d line (or vector) 2.
317  \param n <line-3d> A 3d normal line (or vector).
318 
319  \returns <decimal> The angle between the two lines (or vectors) in
320  degrees. Returns \b undef when lines (or vectors) have
321  different dimensions or when they do not intersect.
322 
323  \details
324 
325  See \ref dt_line for argument specification and conventions.
326 
327  \sa angle_ll().
328 *******************************************************************************/
329 function angle_lll
330 (
331  l1,
332  l2,
333  n
334 ) = atan2(striple_lll(n, l1, l2), dot_ll(l1, l2));
335 
336 //! Compute the normalized unit vector of a Euclidean line (or vector).
337 /***************************************************************************//**
338  \param l <line> A line (or vector).
339 
340  \returns <vector> The normalized unit vector.
341 
342  \details
343 
344  See \ref dt_line for argument specification and conventions.
345 *******************************************************************************/
346 function unit_l
347 (
348  l
350 
351 //! Test if three lines (or vectors) are coplanar in Euclidean 3d-space.
352 /***************************************************************************//**
353  \param l1 <line-3d> A 3d line (or vector) 1.
354  \param l2 <line-3d> A 3d line (or vector) 2.
355  \param l3 <line-3d> A 3d line (or vector) 3.
356  \param d <integer> The number of decimal places to consider.
357 
358  \returns <boolean> \b true when all three lines (or vectors) are
359  coplanar, and \b false otherwise.
360 
361  \details
362 
363  See \ref dt_line for argument specification and conventions.
364  See [Wikipedia] for more information.
365 
366  \note When lines (or vectors) are specified with start and end
367  points, this function tests if they are in a planes
368  parallel to the coplanar.
369 
370  [Wikipedia]: https://en.wikipedia.org/wiki/Coplanarity
371 *******************************************************************************/
372 function are_coplanar_lll
373 (
374  l1,
375  l2,
376  l3,
377  d = 6
378 ) = (dround(striple_lll(l1, l2, l3), d) == 0);
379 
380 //----------------------------------------------------------------------------//
381 // group 4: plane and pnorm
382 //----------------------------------------------------------------------------//
383 
384 //! Convert a planes' normal specification into a normal vector.
385 /***************************************************************************//**
386  \param pn <pnorm> A plane normal \ref dt_pnorm "specification".
387 
388  \param cw <boolean> Point ordering. When the plane specified as
389  non-collinear points, this indicates ordering.
390 
391  \returns <normal> A vector-3d normal to the plane.
392 
393  \details
394 
395  See \ref dt_pnorm for argument specification and conventions.
396 *******************************************************************************/
397 function get_pnorm2nv
398 (
399  pn,
400  cw = true
401 ) = not_defined(len(pn[0])) ?
402  (
403  (len(pn) == 3) ? pn : (len(pn) == 2) ? [pn[0], pn[1], 0]: undef
404  )
405  : let
406  (
407  q = [for (i=pn) (len(i) == 3) ? i : (len(i) == 2) ? [i[0], i[1], 0]: undef]
408  )
409  (len(pn) == 1) ? q[0]
410  : (len(pn) == 2) ? cross(q[0], q[1])
411  : cross(q[0]-q[1], q[2]-q[1]) * ((cw == true) ? 1 : -1);
412 
413 //! @}
414 //! @}
415 
416 //----------------------------------------------------------------------------//
417 // openscad-amu auxiliary scripts
418 //----------------------------------------------------------------------------//
419 
420 /*
421 BEGIN_SCOPE validate;
422  BEGIN_OPENSCAD;
423  include <console.scad>;
424  include <datatypes/datatypes_table.scad>;
425  include <math/math_vector_algebra.scad>;
426  include <validation.scad>;
427 
428  show_passing = true; // show passing tests
429  show_skipped = true; // show skipped tests
430 
431  echo( str("OpenSCAD Version ", version()) );
432 
433  // test-values columns
434  test_c =
435  [
436  ["id", "identifier"],
437  ["td", "description"],
438  ["tv", "test value"]
439  ];
440 
441  // test-values rows
442  test_r =
443  [
444  ["fac", "Function argument count", undef],
445  ["crp", "Result precision", undef],
446  ["t01", "All undefined", [undef,undef,undef,undef,undef,undef]],
447  ["t02", "All empty lists", [empty_lst,empty_lst,empty_lst,empty_lst,empty_lst,empty_lst]],
448  ["t03", "All scalars", [60, 50, 40, 30, 20, 10]],
449  ["t04", "All 1d vectors", [[99], [58], [12], [42], [15], [1]]],
450  ["t05", "All 2d vectors", [
451  [99,2], [58,16], [12,43],
452  [42,13], [15,59], [1,85]
453  ]],
454  ["t06", "All 3d vectors", [
455  [199,20,55], [158,116,75], [12,43,90],
456  [42,13,34], [15,59,45], [62,33,69]
457  ]],
458  ["t07", "All 4d vectors", [
459  [169,27,35,10], [178,016,25,20], [12,43,90,30],
460  [42,13,34,60], [15,059,45,50], [62,33,69,40]
461  ]],
462  ["t08", "Orthogonal vectors", [
463  +x_axis3d_uv, +y_axis3d_uv, +z_axis3d_uv,
464  -x_axis3d_uv, -y_axis3d_uv, -z_axis3d_uv,
465  ]],
466  ["t09", "Coplanar vectors", [
467  +x_axis3d_uv, +y_axis3d_uv, [2,2,0],
468  origin3d, origin3d, origin3d,
469  ]]
470  ];
471 
472  test_ids = get_table_ridl( test_r );
473 
474  // expected columns: ("id" + one column for each test)
475  good_c = pmerge([concat("id", test_ids), concat("identifier", test_ids)]);
476 
477  // expected rows: ("golden" test results), use 'skip' to skip test
478  skip = -1; // skip test
479 
480  good_r =
481  [ // function
482  ["distance_pp",
483  2, // fac
484  4, // crp
485  undef, // t01
486  undef, // t02
487  10, // t03
488  41, // t04
489  43.3244, // t05
490  106.2873, // t06
491  20.0499, // t07
492  1.4142, // t08
493  1.4142 // t09
494  ],
495  ["is_left_ppp",
496  3, // fac
497  4, // crp
498  undef, // t01
499  undef, // t02
500  undef, // t03
501  undef, // t04
502  -463, // t05
503  17009, // t06
504  -1583, // t07
505  1, // t08
506  -3 // t09
507  ],
508  ["dimension_2to3_v",
509  1, // fac
510  4, // crp
511  [undef,undef,0], // t01
512  [undef,undef,0], // t02
513  [undef,undef,0], // t03
514  [99,undef,0], // t04
515  [99,2,0], // t05
516  [199,20,55], // t06
517  [169,27,0], // t07
518  x_axis3d_uv, // t08
519  x_axis3d_uv // t09
520  ],
521  ["get_line_dim",
522  2, // fac
523  4, // crp
524  2, // t01
525  0, // t02
526  2, // t03
527  1, // t04
528  2, // t05
529  3, // t06
530  4, // t07
531  3, // t08
532  3 // t09
533  ],
534  ["get_line_tp",
535  2, // fac
536  4, // crp
537  [undef,undef], // t01
538  empty_lst, // t02
539  [60,50], // t03
540  [58], // t04
541  [58,16], // t05
542  [158,116,75], // t06
543  [178,16,25,20], // t07
544  y_axis3d_uv, // t08
545  y_axis3d_uv // t09
546  ],
547  ["get_line_ip",
548  2, // fac
549  4, // crp
550  origin2d, // t01
551  empty_lst, // t02
552  origin2d, // t03
553  [99], // t04
554  [99,2], // t05
555  [199,20,55], // t06
556  [169,27,35,10], // t07
557  x_axis3d_uv, // t08
558  x_axis3d_uv // t09
559  ],
560  ["get_line2origin",
561  2, // fac
562  4, // crp
563  [undef, undef], // t01
564  empty_lst, // t02
565  [60,50], // t03
566  [-41], // t04
567  [-41,14], // t05
568  [-41,96,20], // t06
569  [9,-11,-10,10], // t07
570  [-1,1,0], // t08
571  [-1,1,0] // t09
572  ],
573  ["dot_ll",
574  4, // fac
575  4, // crp
576  undef, // t01
577  undef, // t02
578  3900, // t03
579  -1230, // t04
580  -1650, // t05
581  -5230, // t06
582  1460, // t07
583  1, // t08
584  0 // t09
585  ],
586  ["cross_ll",
587  4, // fac
588  4, // crp
589  skip, // t01
590  skip, // t02
591  skip, // t03
592  skip, // t04
593  810, // t05
594  [-4776,-1696,-1650], // t06
595  skip, // t07
596  [-1,-1,1], // t08
597  [0,0,4] // t09
598  ],
599  ["striple_lll",
600  6, // fac
601  4, // crp
602  skip, // t01
603  skip, // t02
604  skip, // t03
605  skip, // t04
606  [-14760,5040], // t05
607  -219976, // t06
608  skip, // t07
609  -2, // t08
610  0 // t09
611  ],
612  ["angle_ll",
613  4, // fac
614  4, // crp
615  undef, // t01
616  undef, // t02
617  -2.9357, // t03
618  undef, // t04
619  153.8532, // t05
620  134.4573, // t06
621  undef, // t07
622  60, // t08
623  90 // t09
624  ],
625  ["angle_lll",
626  6, // fac
627  4, // crp
628  skip, // t01
629  skip, // t02
630  skip, // t03
631  skip, // t04
632  skip, // t05
633  -91.362, // t06
634  skip, // t07
635  -63.4349, // t08
636  0 // t09
637  ],
638  ["unit_l",
639  2, // fac
640  4, // crp
641  undef, // t01
642  undef, // t02
643  [.7682,0.6402], // t03
644  [-1], // t04
645  [-0.9464,0.3231], // t05
646  [-0.3857,0.9032,0.1882], // t06
647  [0.44888,-0.5486,-0.4988,0.4988], // t07
648  [-0.7071,0.7071,0], // t08
649  [-0.7071,0.7071,0] // t09
650  ],
651  ["are_coplanar_lll",
652  6, // fac
653  4, // crp
654  skip, // t01
655  skip, // t02
656  skip, // t03
657  skip, // t04
658  skip, // t05
659  false, // t06
660  skip, // t07
661  false, // t08
662  true // t09
663  ],
664  ["get_pnorm2nv",
665  2, // fac
666  4, // crp
667  skip, // t01
668  skip, // t02
669  [60,50,0], // t03
670  skip, // t04
671  [0,0,1468], // t05
672  [-4880,-6235,19924], // t06
673  skip, // t07
674  z_axis3d_uv, // t08
675  z_axis3d_uv // t09
676  ]
677  ];
678 
679  // sanity-test tables
680  table_check( test_r, test_c, false );
681  table_check( good_r, good_c, false );
682 
683  // validate helper function and module
684  function get_value( vid ) = get_table_v(test_r, test_c, vid, "tv");
685  function gv( vid, e ) = get_value( vid )[e];
686  module run( fname, vid )
687  {
688  value_text = get_table_v(test_r, test_c, vid, "td");
689 
690  if ( get_table_v(good_r, good_c, fname, vid) != skip )
691  children();
692  else if ( show_skipped )
693  log_info( str("*skip*: ", vid, " '", fname, "(", value_text, ")'") );
694  }
695  module test( fname, fresult, vid, pair )
696  {
697  value_text = get_table_v(test_r, test_c, vid, "td");
698  fname_argc = get_table_v(good_r, good_c, fname, "fac");
699  comp_prcsn = get_table_v(good_r, good_c, fname, "crp");
700  pass_value = get_table_v(good_r, good_c, fname, vid);
701 
702  test_pass = validate(cv=fresult, t="almost", ev=pass_value, p=comp_prcsn, pf=true);
703  farg_text = (pair == true)
704  ? lstr(eappend(", ", nssequence(rselect(get_value(vid), [0:fname_argc-1]), n=2, s=2), r=false, j=false, l=false))
705  : lstr(eappend(", ", rselect(get_value(vid), [0:fname_argc-1]), r=false, j=false, l=false));
706  test_text = validate(str(fname, "(", farg_text, ")=~", pass_value), fresult, "almost", pass_value, comp_prcsn);
707 
708  if ( pass_value != skip )
709  {
710  if ( !test_pass )
711  log_warn( str(vid, "(", value_text, ") ", test_text) );
712  else if ( show_passing )
713  log_info( str(vid, " ", test_text) );
714  }
715  else if ( show_skipped )
716  log_info( str(vid, " *skip*: '", fname, "(", value_text, ")'") );
717  }
718 
719  // Indirect function calls would be very useful here!!!
720  run_ids = delete( test_ids, mv=["fac", "crp"] );
721 
722  // group 1: point
723  for (vid=run_ids) run("distance_pp",vid) test( "distance_pp", distance_pp(gv(vid,0),gv(vid,1)), vid, false );
724  for (vid=run_ids) run("is_left_ppp",vid) test( "is_left_ppp", is_left_ppp(gv(vid,0),gv(vid,1),gv(vid,2)), vid, false );
725 
726  // group 2: vector
727  for (vid=run_ids) run("dimension_2to3_v",vid) test( "dimension_2to3_v", dimension_2to3_v(gv(vid,0)), vid, false );
728 
729  // group 3: line (or vector)
730  for (vid=run_ids) run("get_line_dim",vid) test( "get_line_dim", get_line_dim([gv(vid,0),gv(vid,1)]), vid, true );
731  for (vid=run_ids) run("get_line_tp",vid) test( "get_line_tp", get_line_tp([gv(vid,0),gv(vid,1)]), vid, true );
732  for (vid=run_ids) run("get_line_ip",vid) test( "get_line_ip", get_line_ip([gv(vid,0),gv(vid,1)]), vid, true );
733  for (vid=run_ids) run("get_line2origin",vid) test( "get_line2origin", get_line2origin([gv(vid,0),gv(vid,1)]), vid, true );
734  for (vid=run_ids) run("dot_ll",vid) test( "dot_ll", dot_ll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)]), vid, true );
735  for (vid=run_ids) run("cross_ll",vid) test( "cross_ll", cross_ll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)]), vid, true );
736  for (vid=run_ids) run("striple_lll",vid) test( "striple_lll", striple_lll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)],[gv(vid,4),gv(vid,5)]), vid, true );
737  for (vid=run_ids) run("angle_ll",vid) test( "angle_ll", angle_ll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)]), vid, true );
738  for (vid=run_ids) run("angle_lll",vid) test( "angle_lll", angle_lll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)],[gv(vid,4),gv(vid,5)]), vid, true );
739  for (vid=run_ids) run("unit_l",vid) test( "unit_l", unit_l([gv(vid,0),gv(vid,1)]), vid, true );
740  for (vid=run_ids) run("are_coplanar_lll",vid) test( "are_coplanar_lll", are_coplanar_lll([gv(vid,0),gv(vid,1)],[gv(vid,2),gv(vid,3)],[gv(vid,4),gv(vid,5)]), vid, true );
741 
742  // group 4: plane and pnorm
743  for (vid=run_ids) run("get_pnorm2nv",vid) test( "get_pnorm2nv", get_pnorm2nv([gv(vid,0),gv(vid,1)]), vid, true );
744 
745  // end-of-tests
746  END_OPENSCAD;
747 
748  BEGIN_MFSCRIPT;
749  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
750  include --path "${INCLUDE_PATH}" script_std.mfs;
751  END_MFSCRIPT;
752 END_SCOPE;
753 */
754 
755 //----------------------------------------------------------------------------//
756 // end of file
757 //----------------------------------------------------------------------------//
function get_pnorm2nv(pn, cw=true)
Convert a planes' normal specification into a normal vector.
function is_left_ppp(p1, p2, p3)
Test if a point is left, on, or right of an infinite line in a Euclidean 2d-space.
function distance_pp(p1, p2)
Compute the distance between two Euclidean points.
function cross_ll(l1, l2)
Compute the cross product of two lines (or vectors) in a Euclidean 3d or 2d-space.
function dot_ll(l1, l2)
Compute the dot product of two lines (or vectors).
function are_coplanar_lll(l1, l2, l3, d=6)
Test if three lines (or vectors) are coplanar in Euclidean 3d-space.
function defined_or(v, d)
Return a value when it is defined or a default value when it is not.
function dimension_2to3_v(v)
Return 3d vector unchanged or add a zeroed third dimension to 2d vector.
function sum(v, i1, i2)
Compute the sum of a list of numbers.
function get_line_ip(l)
Return the initial point of a Euclidean line (or vector).
function get_line_dim(l)
Return the number of dimensions of a Euclidean line (or vector).
function not_defined(v)
Test if a value is not defined.
function unit_l(l)
Compute the normalized unit vector of a Euclidean line (or vector).
function get_line_tp(l)
Return the terminal point of a Euclidean line (or vector).
function is_defined(v)
Test if a value is defined.
function angle_ll(l1, l2)
Compute the angle between two lines (or vectors) in a Euclidean 3d or 2d-space.
function consts(l, v, u=false)
Create a sequence of constant or incrementing elements.
function striple_lll(l1, l2, l3)
Compute the scalar triple product of three lines (or vectors) in a Euclidean 3d or 2d-space...
function angle_lll(l1, l2, n)
Compute the angle between two lines (or vectors) in a Euclidean 3d-space.
function is_iterable(v)
Test if a value has multiple parts and is iterable.
function get_line2origin(l)
Shift a Euclidean line (or vector) to the origin.
function dround(v, d=6)
Round all numerical values of a list to a fixed number of decimal point digits.