omdl  v0.5
OpenSCAD Mechanical Design Library
math.scad
Go to the documentation of this file.
1 //! Mathematical functions.
2 /***************************************************************************//**
3  \file math.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  \details
29 
30  \note Include this library file using the \b include statement.
31 
32  \ingroup math math_vector math_ngon math_triangle
33 *******************************************************************************/
34 
35 include <primitives.scad>;
36 
37 //----------------------------------------------------------------------------//
38 /***************************************************************************//**
39  \page tv_math Computations Validation
40  \li \subpage tv_math_vector
41  \li \subpage tv_math_bitwise
42 *******************************************************************************/
43 //----------------------------------------------------------------------------//
44 
45 //----------------------------------------------------------------------------//
46 /***************************************************************************//**
47  \page tv_math_vector Point, Vector and Plane
48  \li \subpage tv_math_vector_s
49  \li \subpage tv_math_vector_r
50  \page tv_math_vector_s Validation Script
51  \dontinclude math_validate_vector.scad
52  \skip include
53  \until end-of-tests
54  \page tv_math_vector_r Validation Results
55  \include math_validate_vector.log
56 *******************************************************************************/
57 //----------------------------------------------------------------------------//
58 
59 //----------------------------------------------------------------------------//
60 /***************************************************************************//**
61  \addtogroup math
62  @{
63 
64  \defgroup math_vector Point, Vector and Plane
65  \brief Point, vector, and plane computations.
66 
67  \details
68 
69  See validation \ref tv_math_vector_r "results".
70  @{
71 *******************************************************************************/
72 //----------------------------------------------------------------------------//
73 
74 //! Compute the distance between two points in a Euclidean 1, 2, or 3D-space.
75 /***************************************************************************//**
76  \param p1 <vector> A 1, 2, or 3-tuple of coordinates.
77  \param p2 <vector> A 1, 2, or 3-tuple of coordinates.
78 
79  \returns <decimal> The distance between the two points.
80  Returns \b 'undef' when x and y do not have same number of terms
81  or for n-tuple where n>3.
82 
83  \details
84 
85  When \p p2 is not given, it is assumed to be at the origin.
86 *******************************************************************************/
87 function distance_pp
88 (
89  p1,
90  p2
91 ) = let
92  (
93  x=p1,
94  y=defined_or( p2, consts(len(p1), 0) )
95  )
96  all_len([x, y], 1) ?
97  abs
98  (
99  x[0] - y[0]
100  )
101  : all_len([x, y], 2) ?
102  sqrt
103  (
104  (x[0] - y[0]) * (x[0] - y[0])
105  + (x[1] - y[1]) * (x[1] - y[1])
106  )
107  : all_len([x, y], 3) ?
108  sqrt
109  (
110  (x[0] - y[0]) * (x[0] - y[0])
111  + (x[1] - y[1]) * (x[1] - y[1])
112  + (x[2] - y[2]) * (x[2] - y[2])
113  )
114  : undef ;
115 
116 //! Compute the dot product of two vectors.
117 /***************************************************************************//**
118  \param v1t <vector> Vector 1 head. An n-tuple of coordinates.
119  \param v2t <vector> Vector 2 head. An n-tuple of coordinates.
120 
121  \param v1i <vector> Vector 1 tail. An n-tuple of coordinates.
122  \param v2i <vector> Vector 2 tail. An n-tuple of coordinates.
123 
124  \returns <decimal> The dot product of the two vectors.
125  Returns \b 'undef' when vector coordinates do not have same
126  number of terms, n.
127 
128  \details
129 
130  Each vector may be specified by both its head and tail coordinates.
131  When specified by head coordinate only, the tail is assumed to
132  be at origin.
133 
134  See [Wikipedia](https://en.wikipedia.org/wiki/Dot_product)
135  for more information.
136 *******************************************************************************/
137 function dot_vv
138 (
139  v1t,
140  v2t,
141  v1i,
142  v2i
143 ) = all_defined([v1i, v2i]) ? ((v1t-v1i) * (v2t-v2i)) : (v1t * v2t);
144 
145 //! Compute the cross product of two vectors in a Euclidean 3D-space (2D).
146 /***************************************************************************//**
147  \param v1t <vector> Vector 1 head. A 2 or 3-tuple of coordinates.
148  \param v2t <vector> Vector 2 head. A 2 or 3-tuple of coordinates.
149 
150  \param v1i <vector> Vector 1 tail. A 2 or 3-tuple of coordinates.
151  \param v2i <vector> Vector 2 tail. A 2 or 3-tuple of coordinates.
152 
153  \returns <decimal> The cross product of the two vectors.
154  Returns \b 'undef' when vector coordinates do not have same
155  number of terms, n.
156 
157  \details
158 
159  Each vector may be specified by both its head and tail coordinates.
160  When specified by head coordinate only, the tail is assumed to
161  be at origin.
162 
163  See Wikipedia [cross](https://en.wikipedia.org/wiki/Cross_product)
164  and [determinant] (https://en.wikipedia.org/wiki/Determinant)
165  for more information.
166 
167  \note Although the cross product of two vectors is defined only in 3D
168  space, this function will return the 2x2 determinant for a 2D
169  vector.
170 
171  \internal
172  The support of 2D vectors by the OpenSCAD \c cross() functions is not
173  documented in the OpenSCAD manual. Its behavior could change in the
174  future.
175  \endinternal
176 *******************************************************************************/
177 function cross_vv
178 (
179  v1t,
180  v2t,
181  v1i,
182  v2i
183 ) = all_defined([v1i, v2i]) ? cross((v1t-v1i), (v2t-v2i)) : cross(v1t, v2t);
184 
185 //! Compute scalar triple product of two vectors in a Euclidean 3D-space.
186 /***************************************************************************//**
187  \param v1t <vector> Vector 1 head. A 2 or 3-tuple of coordinates.
188  \param v2t <vector> Vector 2 head. A 2 or 3-tuple of coordinates.
189  \param v3t <vector> Vector 3 head. A 2 or 3-tuple of coordinates.
190 
191  \param v1i <vector> Vector 1 tail. A 2 or 3-tuple of coordinates.
192  \param v2i <vector> Vector 2 tail. A 2 or 3-tuple of coordinates.
193  \param v3i <vector> Vector 3 tail. A 2 or 3-tuple of coordinates.
194 
195  \returns <decimal> The scalar triple product of the three vectors.
196  Returns \b 'undef' when vector coordinates do not have same
197  number of terms, n.
198 
199  \details
200 
201  Each vector may be specified by both its head and tail coordinates.
202  When specified by head coordinate only, the tail is assumed to
203  be at origin.
204 
205  [v1, v2, v3] = v1 * (v2 x v3)
206 
207  See [Wikipedia] (https://en.wikipedia.org/wiki/Triple_product)
208  for more information.
209 
210  \warning For 2D vectors, this function produces a 2D \e non-scalar
211  vector result. The cross produce function computes the 2x2
212  determinant of the 2D vectors <tt>(v2 x v3)</tt>, which is
213  a scalar value, and this value is \e multiplied by \c v1,
214  which results in a 2D vector.
215 *******************************************************************************/
216 function striple_vvv
217 (
218  v1t,
219  v2t,
220  v3t,
221  v1i,
222  v2i,
223  v3i
224 ) = all_defined([v1i, v2i, v3i]) ? // tails specified
225  dot_vv
226  (
227  v1t=v1t,
228  v2t=cross_vv( v1t=v2t, v2t=v3t, v1i=v2i, v2i=v3i ),
229  v1i=v1i,
230  v2i=all_len([v1t, v2t, v3t, v1i, v2i, v3i], 3) ? origin3d : 0
231  )
232  : dot_vv // heads only
233  (
234  v1t=v1t, v2t=cross_vv( v1t=v2t, v2t=v3t )
235  );
236 
237 //! Compute the angle between two vectors in a Euclidean 2 or 3D-space.
238 /***************************************************************************//**
239  \param v1t <vector> Vector 1 head. A 2 or 3-tuple of coordinates.
240  \param v2t <vector> Vector 2 head. A 2 or 3-tuple of coordinates.
241 
242  \param v1i <vector> Vector 1 tail. A 2 or 3-tuple of coordinates.
243  \param v2i <vector> Vector 2 tail. A 2 or 3-tuple of coordinates.
244 
245  \returns <decimal> The angle between the two vectors in degrees.
246  Returns \b 'undef' when vector coordinates do not have same
247  number of terms or when the vectors do not intersect.
248 
249  \details
250 
251  Each vector may be specified by both its head and tail coordinates.
252  When specified by head coordinate only, the tail is assumed to
253  be at origin.
254 
255  \note For 3D vectors, a normal vector is required to uniquely
256  identify the perpendicular plane and axis of rotation for the
257  two vectors. This function calculates the positive angle, and
258  the plane and axis of rotation will be that which fits this
259  assumed positive angle.
260 
261  \sa angle_vvn().
262 *******************************************************************************/
263 function angle_vv
264 (
265  v1t,
266  v2t,
267  v1i,
268  v2i
269 ) = all_len([v1t, v2t, v1i, v2i], 2) ? // 2D, tails specified
270  atan2
271  (
272  cross_vv( v1t=v1t, v2t=v2t, v1i=v1i, v2i=v2i ),
273  dot_vv( v1t=v1t, v2t=v2t, v1i=v1i, v2i=v2i )
274  )
275  : all_len([v1t, v2t, v1i, v2i], 3) ? // 3D, tails specified
276  atan2
277  (
278  distance_pp( cross_vv( v1t=v1t, v2t=v2t, v1i=v1i, v2i=v2i ) ),
279  dot_vv( v1t=v1t, v2t=v2t, v1i=v1i, v2i=v2i )
280  )
281  : all_len([v1t, v2t], 2) ? // 2D, heads only
282  atan2
283  (
284  cross_vv( v1t=v1t, v2t=v2t ),
285  dot_vv( v1t=v1t, v2t=v2t )
286  )
287  : all_len([v1t, v2t], 3) ? // 3D, heads only
288  atan2
289  (
290  distance_pp( cross_vv( v1t=v1t, v2t=v2t ) ),
291  dot_vv( v1t=v1t, v2t=v2t )
292  )
293  : undef ;
294 
295 //! Compute the angle between two vectors in a Euclidean 3D-space.
296 /***************************************************************************//**
297  \param v1t <vector> Vector 1 head. A 3-tuple of coordinates.
298  \param v2t <vector> Vector 2 head. A 3-tuple of coordinates.
299  \param nvt <vector> Normal vector head. A 3-tuple of coordinates.
300 
301  \param v1i <vector> Vector 1 tail. A 3-tuple of coordinates.
302  \param v2i <vector> Vector 2 tail. A 3-tuple of coordinates.
303  \param nvi <vector> Normal vector tail. A 3-tuple of coordinates.
304 
305  \returns <decimal> The angle between the two vectors in degrees.
306  Returns \b 'undef' when vector coordinates do not have same
307  number of terms or when the vectors do not intersect.
308 
309  \details
310 
311  Each vector may be specified by both its head and tail coordinates.
312  When specified by head coordinate only, the tail is assumed to
313  be at origin.
314 
315  \sa angle_vv().
316 *******************************************************************************/
317 function angle_vvn
318 (
319  v1t,
320  v2t,
321  nvt,
322  v1i,
323  v2i,
324  nvi
325 ) = all_len([v1t, v2t, nvt, v1i, v2i, nvi], 3) ?
326  atan2
327  (
329  (
330  v1t=nvt, v2t=v1t, v3t=v2t, v1i=nvi, v2i=v1i, v3i=v2i
331  ),
332  dot_vv( v1t=v1t, v2t=v2t, v1i=v1i, v2i=v2i )
333  )
334  : undef ;
335 
336 //! Compute the normalized unit vector for a 1, 2, or 3 term vector.
337 /***************************************************************************//**
338  \param vt <vector> Vector head. A 1, 2, or 3-tuple of coordinates.
339  \param vi <vector> Vector tail. A 1, 2, or 3-tuple of coordinates.
340 
341  \returns <vector> The vector normalized to its unit-vector.
342  Returns \b 'undef' when vector coordinates do not have same
343  number of terms or for n-tuple where n>3.
344 
345  \details
346 
347  The vector may be specified by both its head and tail coordinates.
348  When specified by head coordinate only, the tail is assumed to
349  be at origin.
350 *******************************************************************************/
351 function unit_v
352 (
353  vt,
354  vi
355 ) = all_defined([vt, vi]) ? (vt-vi) / distance_pp(vt, vi)
356  : any_equal([1, 2, 3], len(vt)) ? vt / distance_pp(vt)
357  : undef ;
358 
359 //! Test if three vectors are coplanar in Euclidean 3D-space.
360 /***************************************************************************//**
361  \param v1t <vector> Vector 1 head. A 3-tuple of coordinates.
362  \param v2t <vector> Vector 2 head. A 3-tuple of coordinates.
363  \param v3t <vector> Vector 3 head. A 3-tuple of coordinates.
364 
365  \param v1i <vector> Vector 1 tail. A 3-tuple of coordinates.
366  \param v2i <vector> Vector 2 tail. A 3-tuple of coordinates.
367  \param v3i <vector> Vector 3 tail. A 3-tuple of coordinates.
368 
369  \returns <boolean> \b true when all three vectors are coplanar,
370  and \b false otherwise.
371  \details
372 
373  Each vector may be specified by both its head and tail coordinates.
374  When specified by head coordinate only, the tail is assumed to
375  be at origin.
376 
377  See [Wikipedia] (https://en.wikipedia.org/wiki/Coplanarity)
378  for more information.
379 
380  \note Coplanar vectors must all be within the same plane. However,
381  this function can test if vectors are in a plane that is
382  parallel to a coplanar plane by using non-zero vector tails.
383 *******************************************************************************/
384 function are_coplanar_vvv
385 (
386  v1t,
387  v2t,
388  v3t,
389  v1i,
390  v2i,
391  v3i
392 ) = ( striple_vvv( v1t, v2t, v3t, v1i, v2i, v3i ) == 0 );
393 
394 //! @}
395 //! @}
396 
397 //----------------------------------------------------------------------------//
398 /***************************************************************************//**
399  \addtogroup math
400  @{
401 
402  \defgroup math_ngon n-gon Solutions
403  \brief Regular n-sided polygon computations.
404  @{
405 *******************************************************************************/
406 //----------------------------------------------------------------------------//
407 
408 //! Compute the vertices for an n-sided equiangular/equilateral regular polygon.
409 /***************************************************************************//**
410  \param n <decimal> The number of sides.
411  \param r <decimal> The ngon vertex radius.
412  \param vr <decimal> The vertex rounding radius.
413 
414  \returns <vector> A vector [v1, v2, ..., vn] of vectors [x, y] of
415  coordinates.
416 
417  \b Example
418  \code{.C}
419  vr=5;
420 
421  hull()
422  {
423  for ( p = ngon_vp( r=20, n=5, vr=vr ) )
424  translate( p )
425  circle( r=vr );
426  }
427  \endcode
428 *******************************************************************************/
429 function ngon_vp
430 (
431  n,
432  r,
433  vr
434 ) =
435 [
436  for ( a = [0:(360/n):359] )
437  let( v = [r*cos(a), r*sin(a)] )
438  (vr == undef) ? v : v - vr/cos(180/n) * unit_v(vt=v)
439 ];
440 
441 //! @}
442 //! @}
443 
444 //----------------------------------------------------------------------------//
445 /***************************************************************************//**
446  \addtogroup math
447  @{
448 
449  \defgroup math_triangle Triangle Solutions
450  \brief Triangle computations.
451 
452  \details
453 
454  See [Wikipedia](https://en.wikipedia.org/wiki/Triangle)
455  for more information.
456 
457  @{
458 *******************************************************************************/
459 //----------------------------------------------------------------------------//
460 
461 //! Compute the vertices of a plane triangle given its side lengths.
462 /***************************************************************************//**
463  \param s1 <decimal> The length of the side 1.
464  \param s2 <decimal> The length of the side 2.
465  \param s3 <decimal> The length of the side 3.
466 
467  \returns <vector> A vector [v1, v2, v3] of vectors [x, y] of coordinates.
468 
469  \details
470 
471  Vertex \p v1 at the origin. Geometry required that \p s1 + \p s2 is greater
472  then \p s3. Coordinates \p v3:[x, y] will be \b 'nan' when specified
473  triangle does not exists.
474 
475  \note Side length \p s1 is measured along the positive x-axis.
476  \note Sides are numbered counterclockwise.
477 *******************************************************************************/
478 function triangle_lll2vp
479 (
480  s1,
481  s2,
482  s3
483 ) =
484 [
485  origin2d,
486  [s1, 0],
487  [
488  ( s1*s1 + s3*s3 - (s2*s2) ) / ( 2*s1 ),
489  sqrt( s3*s3 - pow( ( s1*s1 + s3*s3 - (s2*s2) ) / ( 2*s1 ), 2 ) )
490  ]
491 ];
492 
493 //! Compute the vertices of a plane triangle given its side lengths.
494 /***************************************************************************//**
495  \param v <vector> of decimal side lengths.
496 
497  \returns <vector> A vector [v1, v2, v3] of vectors [x, y] of coordinates.
498 
499  \details
500 
501  Vertex \p vs[0] at the origin. Geometry required that \p vs[0] + \p vs[1]
502  is greater then \p vs[2]. Coordinates \p v3:[x, y] will be \b 'nan' when
503  specified triangle does not exists.
504 
505  \note Side length \p vs[0] is measured along the positive x-axis.
506  \note Sides are numbered counterclockwise.
507 *******************************************************************************/
508 function triangle_vl2vp
509 (
510  v
511 ) = triangle_lll2vp( s1=v[0], s2=v[1], s3=v[2] );
512 
513 //! Compute the side lengths of a triangle given its vertices.
514 /***************************************************************************//**
515  \param v1 <vector> A vector [x, y] for vertex 1 coordinates.
516  \param v2 <vector> A vector [x, y] for vertex 2 coordinates.
517  \param v3 <vector> A vector [x, y] for vertex 3 coordinates.
518 
519  \returns <vector> A vector [s1, s2, s3] of lengths.
520 
521  \note Vertices are numbered counterclockwise.
522 *******************************************************************************/
523 function triangle_ppp2vl
524 (
525  v1,
526  v2,
527  v3
528 ) = [ distance_pp(v1, v2), distance_pp(v2, v3), distance_pp(v3, v1) ];
529 
530 //! Compute the side lengths of a triangle given its vertices.
531 /***************************************************************************//**
532  \param v <vector> A vector [v1, v2, v3] of vectors [x, y] coordinates.
533 
534  \returns <vector> A vector [s1, s2, s3] of lengths.
535 
536  \note Vertices are numbered counterclockwise.
537 *******************************************************************************/
538 function triangle_vp2vl
539 (
540  v
541 ) = triangle_ppp2vl( v1=v[0], v2=v[1], v3=v[2]);
542 
543 //! Compute the centroid (geometric center) of a triangle.
544 /***************************************************************************//**
545  \param v1 <vector> A vector [x, y] for vertex 1 coordinates.
546  \param v2 <vector> A vector [x, y] for vertex 2 coordinates.
547  \param v3 <vector> A vector [x, y] for vertex 3 coordinates.
548 
549  \returns <vector> A vector [x, y] of coordinates.
550 *******************************************************************************/
551 function triangle_centroid_ppp
552 (
553  v1,
554  v2,
555  v3
556 ) = [ (v1[0] + v2[0] + v3[0])/3, (v1[1] + v2[1] + v3[1])/3 ];
557 
558 //! Compute the centroid (geometric center) of a triangle.
559 /***************************************************************************//**
560  \param v <vector> A vector [v1, v2, v3] of vectors [x, y] coordinates.
561 
562  \returns <vector> A vector [x, y] of coordinates.
563 *******************************************************************************/
564 function triangle_centroid_vp
565 (
566  v
567 ) = triangle_centroid_ppp( v1=v[0], v2=v[1], v3=v[2]);
568 
569 //! Compute the coordinate for the triangle's incircle.
570 /***************************************************************************//**
571  \param v1 <vector> A vector [x, y] for vertex 1 coordinates.
572  \param v2 <vector> A vector [x, y] for vertex 2 coordinates.
573  \param v3 <vector> A vector [x, y] for vertex 3 coordinates.
574 
575  \returns <vector> A vector [x, y] of coordinates.
576 
577  \details
578 
579  The interior point for which distances to the sides of the triangle
580  are equal.
581 *******************************************************************************/
582 function triangle_incenter_ppp
583 (
584  v1,
585  v2,
586  v3
587 ) =
588 [
589  (
590  (
591  v1[0] * distance_pp(v2, v3)
592  + v2[0] * distance_pp(v3, v1)
593  + v3[0] * distance_pp(v1, v2)
594  )
595  / ( distance_pp(v1, v2) + distance_pp(v2, v3) + distance_pp(v3, v1) )
596  ),
597  (
598  (
599  v1[1] * distance_pp(v2, v3)
600  + v2[1] * distance_pp(v3, v1)
601  + v3[1] * distance_pp(v1, v2)
602  )
603  / ( distance_pp(v1, v2) + distance_pp(v2, v3) + distance_pp(v3, v1) )
604  )
605 ];
606 
607 //! Compute the coordinate for the triangle's incircle.
608 /***************************************************************************//**
609  \param v <vector> A vector [v1, v2, v3] of vectors [x, y] coordinates.
610 
611  \returns <vector> A vector [x, y] of coordinates.
612 
613  \details
614 
615  The interior point for which distances to the sides of the triangle
616  are equal.
617 *******************************************************************************/
618 function triangle_incenter_vp
619 (
620  v
621 ) = triangle_incenter_ppp( v1=v[0], v2=v[1], v3=v[2]);
622 
623 //! Compute the inradius of a triangle's incircle.
624 /***************************************************************************//**
625  \param v1 <vector> A vector [x, y] for vertex 1 coordinates.
626  \param v2 <vector> A vector [x, y] for vertex 2 coordinates.
627  \param v3 <vector> A vector [x, y] for vertex 3 coordinates.
628 
629  \returns <decimal> The incircle radius.
630 *******************************************************************************/
631 function triangle_inradius_ppp
632 (
633  v1,
634  v2,
635  v3
636 ) =
637 sqrt
638 (
639  (
640  ( - distance_pp(v1, v2) + distance_pp(v2, v3) + distance_pp(v3, v1) )
641  * ( + distance_pp(v1, v2) - distance_pp(v2, v3) + distance_pp(v3, v1) )
642  * ( + distance_pp(v1, v2) + distance_pp(v2, v3) - distance_pp(v3, v1) )
643  )
644  / ( distance_pp(v1, v2) + distance_pp(v2, v3) + distance_pp(v3, v1) )
645 ) / 2;
646 
647 //! Compute the inradius of a triangle's incircle.
648 /***************************************************************************//**
649  \param v <vector> A vector [v1, v2, v3] of vectors [x, y] coordinates.
650 
651  \returns <decimal> The incircle radius.
652 *******************************************************************************/
653 function triangle_inradius_vp
654 (
655  v
656 ) = triangle_inradius_ppp( v1=v[0], v2=v[1], v3=v[2]);
657 
658 //! @}
659 //! @}
660 
661 //----------------------------------------------------------------------------//
662 // openscad-amu auxiliary scripts
663 //----------------------------------------------------------------------------//
664 
665 /*
666 BEGIN_SCOPE validate;
667  BEGIN_SCOPE vector;
668  BEGIN_OPENSCAD;
669  include <math.scad>;
670  use <table.scad>;
671  use <console.scad>;
672  use <validation.scad>;
673 
674  show_passing = true; // show passing tests
675  show_skipped = true; // show skipped tests
676 
677  echo( str("OpenSCAD Version ", version()) );
678 
679  // test-values columns
680  test_c =
681  [
682  ["id", "identifier"],
683  ["td", "description"],
684  ["tv", "test value"]
685  ];
686 
687  // test-values rows
688  test_r =
689  [
690  ["fac", "Function argument count", undef],
691  ["crp", "Result precision", undef],
692  ["t01", "All undefined", [undef,undef,undef,undef,undef,undef]],
693  ["t02", "All empty vector", [empty_v,empty_v,empty_v,empty_v,empty_v,empty_v]],
694  ["t03", "All scalars", [60, 50, 40, 30, 20, 10]],
695  ["t04", "All 1D vectors", [[99], [58], [12], [42], [15], [1]]],
696  ["t05", "All 2D vectors", [
697  [99,2], [58,16], [12,43],
698  [42,13], [15,59], [1,85]
699  ]],
700  ["t06", "All 3D vectors", [
701  [199,20,55], [158,116,75], [12,43,90],
702  [42,13,34], [15,59,45], [62,33,69]
703  ]],
704  ["t07", "All 4D vectors", [
705  [169,27,35,10], [178,016,25,20], [12,43,90,30],
706  [42,13,34,60], [15,059,45,50], [62,33,69,40]
707  ]],
708  ["t08", "Orthogonal vectors", [
709  +x_axis3d_uv, +y_axis3d_uv, +z_axis3d_uv,
710  -x_axis3d_uv, -y_axis3d_uv, -z_axis3d_uv,
711  ]],
712  ["t09", "Coplanar vectors", [
713  +x_axis3d_uv, +y_axis3d_uv, [2,2,0],
714  origin3d, origin3d, origin3d,
715  ]]
716  ];
717 
718  test_ids = table_get_row_ids( test_r );
719 
720  // expected columns: ("id" + one column for each test)
721  good_c = pmerge([concat("id", test_ids), concat("identifier", test_ids)]);
722 
723  // expected rows: ("golden" test results), use 'skip' to skip test
724  skip = -1; // skip test
725 
726  good_r =
727  [ // function
728  ["distance_pp",
729  2, // fac
730  4, // crp
731  undef, // t01
732  undef, // t02
733  undef, // t03
734  41, // t04
735  43.3244, // t05
736  106.2873, // t06
737  undef, // t07
738  1.4142, // t08
739  1.4142 // t09
740  ],
741  ["dot_vv",
742  4, // fac
743  4, // crp
744  undef, // t01
745  undef, // t02
746  400, // t03
747  1392, // t04
748  1269, // t05
749  17888, // t06
750  22599, // t07
751  1, // t08
752  -2 // t09
753  ],
754  ["cross_vv",
755  4, // fac
756  4, // crp
757  skip, // t01
758  skip, // t02
759  skip, // t03
760  skip, // t04
761  917, // t05
762  [2662,-11727,21929], // t06
763  skip, // t07
764  [1,-1,1], // t08
765  [0,0,-1] // t09
766  ],
767  ["striple_vvv",
768  6, // fac
769  4, // crp
770  skip, // t01
771  skip, // t02
772  skip, // t03
773  skip, // t04
774  [-75981,14663], // t05
775  199188, // t06
776  skip, // t07
777  8, // t08
778  0 // t09
779  ],
780  ["angle_vv",
781  4, // fac
782  4, // crp
783  undef, // t01
784  undef, // t02
785  undef, // t03
786  undef, // t04
787  35.8525, // t05
788  54.4261, // t06
789  undef, // t07
790  60, // t08
791  153.4350 // t09
792  ],
793  ["angle_vvn",
794  6, // fac
795  4, // crp
796  skip, // t01
797  skip, // t02
798  skip, // t03
799  skip, // t04
800  skip, // t05
801  83.2771, // t06 (verify)
802  skip, // t07
803  90, // t08
804  0 // t09
805  ],
806  ["unit_v",
807  2, // fac
808  4, // crp
809  undef, // t01
810  undef, // t02
811  undef, // t03
812  [1], // t04
813  [0.9464,-0.3231], // t05
814  [0.3857,-0.9032,-0.1882], // t06
815  undef, // t07
816  [0.7071,-0.7071,0], // t08
817  [0.7071,-0.7071,0] // t09
818  ],
819  ["are_coplanar_vvv",
820  6, // fac
821  4, // crp
822  skip, // t01
823  skip, // t02
824  skip, // t03
825  skip, // t04
826  skip, // t05
827  false, // t06
828  skip, // t07
829  false, // t08
830  true // t09
831  ]
832  ];
833 
834  // sanity-test tables
835  table_check( test_r, test_c, false );
836  table_check( good_r, good_c, false );
837 
838  // validate helper function and module
839  function get_value( vid ) = table_get(test_r, test_c, vid, "tv");
840  function gv( vid, e ) = get_value( vid )[e];
841  module run( fname, vid )
842  {
843  value_text = table_get(test_r, test_c, vid, "td");
844 
845  if ( table_get(good_r, good_c, fname, vid) != skip )
846  children();
847  else if ( show_skipped )
848  log_info( str("*skip*: ", vid, " '", fname, "(", value_text, ")'") );
849  }
850  module test( fname, fresult, vid )
851  {
852  value_text = table_get(test_r, test_c, vid, "td");
853  fname_argc = table_get(good_r, good_c, fname, "fac");
854  comp_prcsn = table_get(good_r, good_c, fname, "crp");
855  pass_value = table_get(good_r, good_c, fname, vid);
856 
857  test_pass = validate(cv=fresult, t="almost", ev=pass_value, p=comp_prcsn, pf=true);
858  farg_text = vstr(eappend(", ", rselect(get_value(vid), [0:fname_argc-1]), r=false, j=false, l=false));
859  test_text = validate(str(fname, "(", farg_text, ")=~", pass_value), fresult, "almost", pass_value, comp_prcsn);
860 
861  if ( pass_value != skip )
862  {
863  if ( !test_pass )
864  log_warn( str(vid, "(", value_text, ") ", test_text) );
865  else if ( show_passing )
866  log_info( str(vid, " ", test_text) );
867  }
868  else if ( show_skipped )
869  log_info( str(vid, " *skip*: '", fname, "(", value_text, ")'") );
870  }
871 
872  // Indirect function calls would be very useful here!!!
873  run_ids = delete( test_ids, mv=["fac", "crp"] );
874  for (vid=run_ids) run("distance_pp",vid) test( "distance_pp", distance_pp(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
875  for (vid=run_ids) run("dot_vv",vid) test( "dot_vv", dot_vv(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
876  for (vid=run_ids) run("cross_vv",vid) test( "cross_vv", cross_vv(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
877  for (vid=run_ids) run("striple_vvv",vid) test( "striple_vvv", striple_vvv(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
878  for (vid=run_ids) run("angle_vv",vid) test( "angle_vv", angle_vv(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
879  for (vid=run_ids) run("angle_vvn",vid) test( "angle_vvn", angle_vvn(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
880  for (vid=run_ids) run("unit_v",vid) test( "unit_v", unit_v(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
881  for (vid=run_ids) run("are_coplanar_vvv",vid) test( "are_coplanar_vvv", are_coplanar_vvv(gv(vid,0),gv(vid,1),gv(vid,2),gv(vid,3),gv(vid,4),gv(vid,5)), vid );
882 
883  // end-of-tests
884  END_OPENSCAD;
885 
886  BEGIN_MFSCRIPT;
887  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
888  include --path "${INCLUDE_PATH}" script_std.mfs;
889  END_MFSCRIPT;
890  END_SCOPE;
891 END_SCOPE;
892 */
893 
894 //----------------------------------------------------------------------------//
895 // end of file
896 //----------------------------------------------------------------------------//
function defined_or(v, d)
Return a defined or default value.
function angle_vv(v1t, v2t, v1i, v2i)
Compute the angle between two vectors in a Euclidean 2 or 3D-space.
function all_len(v, l)
Test if all elements of a value have a given length.
function dot_vv(v1t, v2t, v1i, v2i)
Compute the dot product of two vectors.
function triangle_centroid_vp(v)
Compute the centroid (geometric center) of a triangle.
function triangle_vl2vp(v)
Compute the vertices of a plane triangle given its side lengths.
function striple_vvv(v1t, v2t, v3t, v1i, v2i, v3i)
Compute scalar triple product of two vectors in a Euclidean 3D-space.
function unit_v(vt, vi)
Compute the normalized unit vector for a 1, 2, or 3 term vector.
function triangle_inradius_vp(v)
Compute the inradius of a triangle's incircle.
function any_equal(v, cv)
Test if any element of a value equals a comparison value.
function triangle_centroid_ppp(v1, v2, v3)
Compute the centroid (geometric center) of a triangle.
function ngon_vp(n, r, vr)
Compute the vertices for an n-sided equiangular/equilateral regular polygon.
function triangle_vp2vl(v)
Compute the side lengths of a triangle given its vertices.
origin3d
The origin coordinates in 3-dimensional Euclidean space.
Definition: constants.scad:114
function triangle_incenter_ppp(v1, v2, v3)
Compute the coordinate for the triangle's incircle.
function distance_pp(p1, p2)
Compute the distance between two points in a Euclidean 1, 2, or 3D-space.
function triangle_inradius_ppp(v1, v2, v3)
Compute the inradius of a triangle's incircle.
origin2d
The origin coordinates in 2-dimensional Euclidean space.
Definition: constants.scad:105
function cross_vv(v1t, v2t, v1i, v2i)
Compute the cross product of two vectors in a Euclidean 3D-space (2D).
function triangle_ppp2vl(v1, v2, v3)
Compute the side lengths of a triangle given its vertices.
function all_defined(v)
Test if no element of a value is undefined.
function consts(l, v)
Create a vector of constant elements.
function angle_vvn(v1t, v2t, nvt, v1i, v2i, nvi)
Compute the angle between two vectors in a Euclidean 3D-space.
function triangle_incenter_vp(v)
Compute the coordinate for the triangle's incircle.
function triangle_lll2vp(s1, s2, s3)
Compute the vertices of a plane triangle given its side lengths.
function are_coplanar_vvv(v1t, v2t, v3t, v1i, v2i, v3i)
Test if three vectors are coplanar in Euclidean 3D-space.