omdl  v1.0
OpenSCAD Mechanical Design Library
scalar_test.scad
Go to the documentation of this file.
1 //! Scalar data type tests.
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 (Scalar Tests)
31  \amu_define group_brief (Tests to differentiate scalar data types.)
32 
33  \amu_include (include/amu/doxyg_init_pd_gds_ipg.amu)
34 *******************************************************************************/
35 
36 // auto-tests (add to test results page)
37 /***************************************************************************//**
38  \amu_include (include/amu/validate_log.amu)
39  \amu_include (include/amu/validate_results.amu)
40 *******************************************************************************/
41 
42 // group(s) begin (test summary and includes-required)
43 /***************************************************************************//**
44  \amu_include (include/amu/doxyg_define_in_parent_open.amu)
45  \amu_include (include/amu/validate_summary.amu)
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 // member-wide reference definitions
50 /***************************************************************************//**
51  \amu_define group_references
52  (
53  [ottf]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Type_Test_Functions "OpenSCAD Type Test Functions"
54  )
55 *******************************************************************************/
56 
57 // member-wide documentation and conventions
58 /***************************************************************************//**
59  \addtogroup \amu_eval(${group})
60  \details
61  \anchor \amu_eval(${group})_conventions
62  \par Conventions
63 
64  - The primary parameter is always \p v (the value under test).
65  - All functions whose name begins with \c is_ return \b <boolean>.
66  - \p empty_str and \p empty_lst are treated as iterable, not scalar.
67  - is_integer() and is_decimal() are mutually exclusive; a value cannot
68  satisfy both. is_decimal() requires (v % 1) != 0 (not > 0) so that
69  negative decimals such as -1.5 are correctly identified.
70  - is_between() uses \b inclusive bounds at both ends.
71  - The parameters \p l and \p u in is_between() denote the lower and
72  upper bounds respectively. They are unrelated to \p l = list-length
73  used in other groups; prefer \p vmin / \p vmax in future revisions.
74 *******************************************************************************/
75 
76 //----------------------------------------------------------------------------//
77 // members
78 //----------------------------------------------------------------------------//
79 
80 //! Test if a value is a single non-iterable value.
81 /***************************************************************************//**
82  \param v <value> A value.
83 
84  \returns <boolean> \b true when the value is a single non-iterable
85  value and \b false otherwise.
86 
87  \details
88 
89  input value | function return
90  :-----------:|:-----------------:
91  number | true
92  boolean | true
93  string | false
94  list | false
95  range | true
96  undef | true
97  inf | true
98  nan | true
99 
100  \note The empty list and empty string return \b true.
101 *******************************************************************************/
102 function is_scalar
103 (
104  v
105 ) = !is_string(v) && !is_list(v);
106 
107 //! Test if a value is defined.
108 /***************************************************************************//**
109  \param v <value> A value.
110 
111  \returns <boolean> \b true when the value is defined
112  and \b false otherwise.
113 
114  \details
115 
116  \note Starting with version 2019.05, this function is now
117  provided directly by OpenSCAD via a built-in [type test
118  function][ottf] \c is_undef().
119 
120  \amu_eval (${group_references})
121 *******************************************************************************/
122 function is_defined
123 (
124  v
125 ) = is_undef(v) ? false : true;
126 
127 //! Test if a numerical value is 'nan' (not a number).
128 /***************************************************************************//**
129  \param v <value> A numerical value.
130 
131  \returns <boolean> \b true when the value is determined to be
132  \b nan (Not A Number) and \b false otherwise.
133 *******************************************************************************/
134 function is_nan
135 (
136  v
137 ) = (v != v);
138 
139 //! Test if a numerical value is infinite.
140 /***************************************************************************//**
141  \param v <value> A numerical value.
142 
143  \returns <boolean> \b true when the value is determined to be
144  \b inf (greater than the largest OpenSCAD representable
145  number) and \b false otherwise.
146 *******************************************************************************/
147 function is_inf
148 (
149  v
150 ) = ( v == (number_max * number_max) );
151 
152 //! Test if a value is a number.
153 /***************************************************************************//**
154  \param v <value> A value.
155 
156  \returns <boolean> \b true when the value is a number
157  and \b false otherwise.
158 
159  \details
160 
161  \note Starting with version 2019.05, this function is now
162  provided directly by OpenSCAD via a built-in [type test
163  function][ottf] \c is_num().
164 
165  \amu_eval (${group_references})
166 *******************************************************************************/
167 function is_number
168 (
169  v
170 ) = is_num(v);
171 
172 //! Test if a value is an integer.
173 /***************************************************************************//**
174  \param v <value> A value.
175 
176  \returns <boolean> \b true when the value is an integer and \b false
177  otherwise.
178 *******************************************************************************/
179 function is_integer
180 (
181  v
182 ) = !is_num(v) ? false
183  : ((v % 1) == 0);
184 
185 //! Test if a value is a decimal.
186 /***************************************************************************//**
187  \param v <value> A value.
188 
189  \returns <boolean> \b true when the value is a decimal and \b false
190  otherwise.
191 *******************************************************************************/
192 function is_decimal
193 (
194  v
195 ) = !is_num(v) ? false
196  : is_inf(v) ? false // catch infinite numbers
197  : ((v % 1) != 0);
198 
199 //! Test if a value is a range definition.
200 /***************************************************************************//**
201  \param v <value> A value.
202 
203  \returns <boolean> \b true when the value is a range definition
204  and \b false otherwise.
205 
206  \details
207 
208  \note A range is determined to be a value which does not fit in
209  any other category. Specifically, It is a value that is not
210  {\b undef, \b nan or \b inf}, and is neither of {\em list,
211  \em number, \em bool, or \em string}.
212 
213  \internal
214  This exclusion test should be replaced by a suitable inclusion test
215  when possible.
216  \endinternal
217 *******************************************************************************/
218 function is_range
219 (
220  v
221 ) = !is_undef(v) &&
222  !is_nan(v) &&
223  !is_inf(v) &&
224  !is_list(v) &&
225  !is_num(v) &&
226  !is_bool(v) &&
227  !is_string(v);
228 
229 //! Test if a numerical value is even.
230 /***************************************************************************//**
231  \param v <value> A numerical value.
232 
233  \returns <boolean> \b true when the value is determined to be an \em even
234  integer and \b false otherwise (The value may be positive or
235  negative).
236 *******************************************************************************/
237 function is_even
238 (
239  v
240 ) = !is_integer(v) ? false
241  : ((v % 2) == 0);
242 
243 //! Test if a numerical value is odd.
244 /***************************************************************************//**
245  \param v <value> A numerical value.
246 
247  \returns <boolean> \b true when the value is determined to be an \em odd
248  integer and \b false otherwise (The value may be positive or
249  negative).
250 *******************************************************************************/
251 function is_odd
252 (
253  v
254 ) = !is_integer(v) ? false
255  : ((v % 2) != 0);
256 
257 //! Test if a numerical value is between an upper and lower bounds.
258 /***************************************************************************//**
259  \param v <number> A numerical value.
260  \param l <number> The minimum value.
261  \param u <number> The maximum value.
262 
263  \returns <boolean> \b true when the value is equal to or between the
264  upper and lower bounds and \b false otherwise. Returns \b false
265  when either of \p v, \p l, or \p u is not a number.
266 *******************************************************************************/
267 function is_between
268 (
269  v,
270  l,
271  u
272 ) = !(is_num(v) && is_num(l) && is_num(u)) ? false
273  : ((v >= l) && (v <=u));
274 
275 //! @}
276 //! @}
277 
278 //----------------------------------------------------------------------------//
279 // openscad-amu auxiliary scripts
280 //----------------------------------------------------------------------------//
281 
282 /*
283 BEGIN_SCOPE validate;
284  BEGIN_OPENSCAD;
285  include <omdl-base.scad>;
286  include <common/validation.scad>;
287 
288  function fmt( id, td, v1, v2, v3 ) = table_validate_fmt(id, td, v1, v2, v3);
289  function v1(db, id) = table_validate_get_v1(db, id);
290  t = true; f = false; u = undef; s = validation_skip;
291 
292  tbl_test_values =
293  [
294  fmt("t01", "The undefined value", undef),
295  fmt("t02", "An odd integer", 1),
296  fmt("t03", "An small even integer", 10),
297  fmt("t04", "A large integer", 100000000),
298  fmt("t05", "A small decimal (epsilon)", eps),
299  fmt("t06", "The max number", number_max),
300  fmt("t07", "The min number", number_min),
301  fmt("t08", "The max number^2", number_max * number_max),
302  fmt("t09", "The invalid number nan", 0 / 0),
303  fmt("t10", "The boolean true", true),
304  fmt("t11", "The boolean false", false),
305  fmt("t12", "A character string", "a"),
306  fmt("t13", "A string", "This is a longer string"),
307  fmt("t14", "The empty string", empty_str),
308  fmt("t15", "The empty list", empty_lst),
309  fmt("t16", "A 1-tuple list of undef", [undef]),
310  fmt("t17", "A 1-tuple list", [10]),
311  fmt("t18", "A 3-tuple list", [1, 2, 3]),
312  fmt("t19", "A list of lists", [[1,2,3], [4,5,6], [7,8,9]]),
313  fmt("t20", "A shorthand range", [0:9]),
314  fmt("t21", "A range", [0:0.5:9])
315  ];
316 
317  tbl_test_answers =
318  [ // function 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21
319  ["is_scalar", t, t, t, t, t, t, t, t, t, t, t, f, f, f, f, f, f, f, f, t, t],
320  ["is_defined", f, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t, t],
321  ["is_nan", f, f, f, f, f, f, f, f, t, f, f, f, f, f, f, f, f, f, f, f, f],
322  ["is_inf", f, f, f, f, f, f, f, t, f, f, f, f, f, f, f, f, f, f, f, f, f],
323  ["is_number", f, t, t, t, t, t, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f],
324  ["is_integer", f, t, t, t, f, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
325  ["is_decimal", f, f, f, f, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
326  ["is_range", f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, t],
327  ["is_even", f, f, t, t, f, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
328  ["is_odd", f, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
329  ["is_between_MM", f, t, t, t, t, t, t, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
330 
331  ["is_undef", t, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f, f],
332  ["is_bool", f, f, f, f, f, f, f, f, f, t, t, f, f, f, f, f, f, f, f, f, f],
333  ["is_string", f, f, f, f, f, f, f, f, f, f, f, t, t, t, f, f, f, f, f, f, f],
334  ["is_list", f, f, f, f, f, f, f, f, f, f, f, f, f, f, t, t, t, t, t, f, f]
335  ];
336 
337  db = table_validate_init( tbl_test_values, tbl_test_answers );
338 
339  table_validate_start( db );
340  test_ids = table_validate_get_ids( db );
341 
342  for (id=test_ids) table_validate( db, id, "is_scalar", 1, is_scalar( v1(db,id)) );
343  for (id=test_ids) table_validate( db, id, "is_defined", 1, is_defined( v1(db,id)) );
344  for (id=test_ids) table_validate( db, id, "is_nan", 1, is_nan( v1(db,id)) );
345  for (id=test_ids) table_validate( db, id, "is_inf", 1, is_inf( v1(db,id)) );
346  for (id=test_ids) table_validate( db, id, "is_number", 1, is_number( v1(db,id)) );
347  for (id=test_ids) table_validate( db, id, "is_integer", 1, is_integer( v1(db,id)) );
348  for (id=test_ids) table_validate( db, id, "is_decimal", 1, is_decimal( v1(db,id)) );
349  for (id=test_ids) table_validate( db, id, "is_range", 1, is_range( v1(db,id)) );
350  for (id=test_ids) table_validate( db, id, "is_even", 1, is_even( v1(db,id)) );
351  for (id=test_ids) table_validate( db, id, "is_odd", 1, is_odd( v1(db,id)) );
352  for (id=test_ids) table_validate( db, id, "is_between_MM", 1, is_between( v1(db,id), number_min, number_max ) );
353 
354  // OpenSCAD built-in functions: is_undef() and is_num() are tested above
355  for (id=test_ids) table_validate( db, id, "is_undef", 1, is_undef( v1(db,id)) );
356  for (id=test_ids) table_validate( db, id, "is_bool", 1, is_bool( v1(db,id)) );
357  for (id=test_ids) table_validate( db, id, "is_string", 1, is_string( v1(db,id)) );
358  for (id=test_ids) table_validate( db, id, "is_list", 1, is_list( v1(db,id)) );
359 
360  // end_include
361  END_OPENSCAD;
362 
363  BEGIN_MFSCRIPT;
364  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
365  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
366  END_MFSCRIPT;
367 END_SCOPE;
368 */
369 
370 //----------------------------------------------------------------------------//
371 // end of file
372 //----------------------------------------------------------------------------//
number_max
<decimal> The largest representable number in OpenSCAD scripts.
Definition: constants.scad:289
function is_nan(v)
Test if a numerical value is 'nan' (not a number).
function is_scalar(v)
Test if a value is a single non-iterable value.
function is_between(v, l, u)
Test if a numerical value is between an upper and lower bounds.
function is_inf(v)
Test if a numerical value is infinite.
function is_defined(v)
Test if a value is defined.
function is_integer(v)
Test if a value is an integer.
function is_number(v)
Test if a value is a number.
function is_even(v)
Test if a numerical value is even.
function is_decimal(v)
Test if a value is a decimal.
function is_odd(v)
Test if a numerical value is odd.
function is_range(v)
Test if a value is a range definition.