omdl  v1.0
OpenSCAD Mechanical Design Library
utility.scad
Go to the documentation of this file.
1 //! Miscellaneous mathematical utilities.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2017-2019, 2026
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 (Utilities)
31  \amu_define group_brief (Miscellaneous mathematical utilities.)
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  )
54 *******************************************************************************/
55 
56 // member-wide documentation and conventions
57 /***************************************************************************//**
58  \addtogroup \amu_eval(${group})
59  \details
60  \anchor \amu_eval(${group})_conventions
61  \par Conventions
62 
63  The following conventions apply to all functions in this group.
64  - OpenSCAD special variables \p $fn, \p $fa, and \p $fs are read
65  directly at the call site and are never passed as parameters;
66  their values at the point of call control fragment counts.
67  - \c grid_fine is an omdl library-level constant defining the
68  minimum meaningful geometry size. Inputs below this threshold
69  are treated as degenerate and return safe fallback values.
70  - Bit-field parameters (e.g. \p m in histogram()) are documented
71  with an explicit bit-table in the function's \c \\details block.
72  Bit 0 always selects the primary output mode (0 = numerical,
73  1 = string). Higher bits select sub-modes within the string path.
74  - HTML passthrough parameters (\p cb, \p cp, \p ca, \p cf, \p d)
75  follow the interface of strl_html() exactly; see its documentation
76  for type and semantics. They are ignored in non-html modes.
77  - \c tau is an omdl library constant equal to 2*PI.
78  - No input validation is performed unless an explicit \c assert is
79  present. Out-of-range or wrongly-typed inputs produce \b undef,
80  \b nan, or \b inf without warning.
81 *******************************************************************************/
82 
83 //----------------------------------------------------------------------------//
84 // members
85 //----------------------------------------------------------------------------//
86 
87 //! Return facets number for the given arc radius.
88 /***************************************************************************//**
89  \param r <decimal> The arc radius. Must be >= 0. Defaults to \b 0,
90  which returns \b 3 (the minimum facet count).
91 
92  \returns <integer> The number of facets.
93 
94  \details
95 
96  This function approximates the \c get_fragments_from_r() code that
97  is used by OpenSCAD to calculate the number of fragments in a
98  circle or arc. The arc facets are controlled by the special
99  variables \p $fa, \p $fs, and \p $fn. The three branches are:
100  - \p r < \c grid_fine: returns \b 3 (minimum). \c grid_fine is the
101  library-level constant for the minimum meaningful geometry size;
102  radii below it are treated as degenerate.
103  - \p $fn > 0: returns \p $fn clamped to a minimum of \b 3,
104  respecting the caller's explicit fragment count override.
105  - otherwise: returns \c ceil(max(min(360/\p $fa, r*tau/\p $fs), 5)),
106  where \c tau = 2*PI is an omdl library constant.
107 
108  \note Passing a negative \p r is invalid and caught by an internal
109  assert. If \p $fa is 0, \c 360/$fa produces \c inf; \c min()
110  then selects the \c r*tau/$fs term, which is the correct
111  fallback behaviour.
112 *******************************************************************************/
113 function get_fn
114 (
115  r = 0
116 ) = let
117  (
118  _ = assert( r >= 0, "get_fn: r must be >= 0." )
119  )
120  (r < grid_fine) ? 3
121  : ($fn > 0.0) ? ($fn >= 3) ? $fn : 3
122  : ceil( max( min(360/$fa, r*tau/$fs), 5 ) );
123 
124 //! Generate a histogram for the elements of a list of values.
125 /***************************************************************************//**
126  \param v <data> A list of values.
127  \param m <integer> The output mode (a 5-bit encoded integer).
128 
129  \param cs <string-list-4> A list of strings \c [cs[0], cs[1],
130  cs[2], cs[3]] used only with custom formatting (m =
131  15), mapping to \c s1, \c s2, \c s3, and \c fs
132  respectively in the output template: \c s1, value, \c
133  s2, frequency, \c s3, \c fs.
134 
135  \param cb <string-list> Bold tag specifiers passed to
136  strl_html(). Only used in html and custom string modes.
137  See strl_html() for type and semantics.
138 
139  \param cp <string-list> HTML tag-pair specifiers passed to
140  strl_html(). Only used in html and custom string modes.
141  See strl_html() for type and semantics.
142 
143  \param ca <string-list> HTML attribute specifiers passed to
144  strl_html(). Only used in html and custom string modes.
145  See strl_html() for type and semantics.
146 
147  \param cf <string-list> Font specifiers passed to strl_html().
148  Only used in html and custom string modes. See
149  strl_html() for type and semantics.
150 
151  \param d <boolean> When \b true, emit HTML debug output via
152  strl_html(). Default \b false.
153 
154  \returns <decimal-list | string> The occurrence frequencies of \p v.
155  When \p m bit 0 = \b 0 (numerical mode), returns a list of
156  \c [value, count] pairs. When \p m bit 0 = \b 1 (string
157  mode), returns a single concatenated string, except for m =
158  \b 1 which returns a list of bare \c "NxM" strings.
159 
160  \details
161 
162  The custom formatting strings are inserted in the output stream as
163  follows:
164 
165  \verbatim
166  s1, value, s2, value-frequency, s3, fs
167  \endverbatim
168 
169  See strl_html() for description of the html formatting parameters
170  \p cb, \p cp, \p ca, \p cf, and \p d.
171 
172  Output mode selection:
173 
174  | bit | Description | 0 | 1 |
175  |:---:|:------------------------|:------------|:------------|
176  | 0 | output mode | numerical | string |
177  | 1-3 | string mode format | see table | see table |
178  | 4 | field separator mode | not at end | all |
179 
180  String output modes:
181 
182  | | B3 | B2 | B1 | B0 | Description |
183  |:---:|:---:|:---:|:---:|:---:|:-----------------------------------------|
184  | 1 | 0 | 0 | 0 | 1 | list of bare strings, each "NxM" |
185  | 3 | 0 | 0 | 1 | 1 | text format 1 |
186  | 9 | 1 | 0 | 0 | 1 | html format 1 |
187  | 15 | 1 | 1 | 1 | 1 | custom formatting (uses \p cs) |
188 
189  Example outputs for \c v = ["a","b","a","c","a","b"]:
190  - \c m=0 (numerical): \c [["a",3],["b",2],["c",1]]
191  - \c m=1 (bare strings): \c ["3xa","2xb","1xc"]
192  - \c m=3 (text format): \c "3<a> 2<b> 1<c>"
193  - \c m=9 (html format): formatted as superscript-count + italic-value pairs
194 
195  \note histogram() uses unique() followed by a find() scan per unique
196  value. Both are O(n) per call over the full list, making the
197  combined complexity O(n*k) where k is the number of unique
198  values — effectively O(n^2) in the worst case. Avoid passing
199  very large lists.
200 *******************************************************************************/
201 function histogram
202 (
203  v,
204  m = 0,
205  cs,
206  cb,
207  cp,
208  ca,
209  cf,
210  d = false
211 ) = let
212  (
213  hv = [for (i=unique(v)) [i, len(find(i, v, 0))]]
214  )
215  binary_bit_is(m, 0, 0) ? hv
216  : let
217  (
218  sm = binary_iw2i(m, 1, 3),
219  fm = binary_bit_is(m, 4, 1) ? true : false
220  )
221  (sm == 0) ? [for (i=hv) str(first(i), "x", second(i))]
222  : let
223  (
224  s1 = (sm==1) ? empty_str
225  : (sm==4) ? empty_str
226  : (is_list(cs) && len(cs) > 0 ? cs[0] : empty_str),
227  s2 = (sm==1) ? "<"
228  : (sm==4) ? "x"
229  : (is_list(cs) && len(cs) > 1 ? cs[1] : empty_str),
230  s3 = (sm==1) ? ">"
231  : (sm==4) ? empty_str
232  : (is_list(cs) && len(cs) > 2 ? cs[2] : empty_str),
233  fs = (sm==1) ? " "
234  : (sm==4) ? ", "
235  : (is_list(cs) && len(cs) > 3 ? cs[3] : empty_str),
236  fb = (sm==1) ? undef
237  : (sm==4) ? undef
238  : cb,
239  fp = (sm==1) ? undef
240  : (sm==4) ? [undef, undef, ["i", "sup"], ["b", "sup"], undef]
241  : cp,
242  fa = (sm==1) ? undef
243  : (sm==4) ? [undef, undef, undef, undef, undef, ["br"]]
244  : ca,
245  ff = (sm==1) ? undef
246  : (sm==4) ? undef
247  : cf,
248  n = len(hv)
249  )
250  strl
251  ([
252  for (i=[0:n-1])
253  strl_html
254  (
255  [s1, first(hv[i]), s2, second(hv[i]), s3, if ((i<(n-1)) || fm) fs],
256  b=fb, p=fp, a=fa, f=ff, d=d
257  ),
258  ]);
259 
260 //! @}
261 //! @}
262 
263 //----------------------------------------------------------------------------//
264 // openscad-amu auxiliary scripts
265 //----------------------------------------------------------------------------//
266 
267 /*
268 BEGIN_SCOPE validate;
269  BEGIN_OPENSCAD;
270  include <omdl-base.scad>;
271  include <common/validation.scad>;
272 
273  echo( str("openscad version ", version()) );
274  for (i=[1:2]) echo( "not tested:" );
275 
276  // end_include
277  END_OPENSCAD;
278 
279  BEGIN_MFSCRIPT;
280  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
281  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
282  END_MFSCRIPT;
283 END_SCOPE;
284 */
285 
286 //----------------------------------------------------------------------------//
287 // end of file
288 //----------------------------------------------------------------------------//
tau
<decimal> The ratio of a circle's circumference to its radius.
Definition: constants.scad:201
empty_str
<string> A string with no characters (the empty string).
Definition: constants.scad:301
grid_fine
OpenSCAD fine grid limit.
Definition: constants.scad:310
function binary_iw2i(v, s, w)
Decode the binary bits of a bit window to an integer value.
function binary_bit_is(v, b, t=1)
Test if a binary bit position of an integer value equals a test bit.
function unique(v)
Return a list of the unique elements of an iterable value.
function find(mv, v, c=1, i, i1=0, i2)
Find the occurrences of a match value in an iterable value.
function second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
function strl(v)
Convert a list of values to a concatenated string.
function strl_html(v, b, p, a, f, d=false)
Convert a list of values to a concatenated HTML-formatted string.
function histogram(v, m=0, cs, cb, cp, ca, cf, d=false)
Generate a histogram for the elements of a list of values.
function get_fn(r=0)
Return facets number for the given arc radius.