omdl  v0.6.1
OpenSCAD Mechanical Design Library
datatypes_table.scad
Go to the documentation of this file.
1 //! Table data type operations.
2 /***************************************************************************//**
3  \file datatypes_table.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  \ingroup datatypes datatypes_table
31 *******************************************************************************/
32 
33 include <../console.scad>;
34 include <datatypes-base.scad>;
35 
36 //----------------------------------------------------------------------------//
37 /***************************************************************************//**
38  \addtogroup datatypes
39  @{
40 
41  \defgroup datatypes_table Tables
42  \brief Table data type operations.
43 
44  \details
45 
46  \b Example
47 
48  \dontinclude datatypes_table_example.scad
49  \skip use
50  \until ( tsum=tsum );
51 
52  \b Result \include datatypes_table_example.log
53 
54  @{
55 *******************************************************************************/
56 //----------------------------------------------------------------------------//
57 
58 //! Get the table row index that matches a table row identifier.
59 /***************************************************************************//**
60  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
61  \param ri <string> The row identifier.
62 
63  \returns <integer> The row index where the identifier exists.
64  If the identifier does not exists, returns \b empty_lst.
65 *******************************************************************************/
66 function get_table_ri
67 (
68  r,
69  ri
70 ) = first( search( [ri], r, 1, 0 ) );
71 
72 //! Get the table row that matches a table row identifier.
73 /***************************************************************************//**
74  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
75  \param ri <string> The row identifier.
76 
77  \returns <list-C> The table row where the row identifier exists.
78  If the identifier does not exists, returns \b undef.
79 *******************************************************************************/
80 function get_table_r
81 (
82  r,
83  ri
84 ) = r[ get_table_ri(r, ri) ];
85 
86 //! Get the table column index that matches a table column identifier.
87 /***************************************************************************//**
88  \param c <matrix-2xC> The table column matrix (2 x C-columns).
89  \param ci <string> The column identifier.
90 
91  \returns <integer> The column index where the identifier exists.
92  If the identifier does not exists, returns \b empty_lst.
93 *******************************************************************************/
94 function get_table_ci
95 (
96  c,
97  ci
98 ) = first( search( [ci], c, 1, 0 ) );
99 
100 //! Get the table column that matches a table column identifier.
101 /***************************************************************************//**
102  \param c <matrix-2xC> The table column matrix (2 x C-columns).
103  \param ci <string> The column identifier.
104 
105  \returns <list-2> The table column where the column identifier exists.
106  If the identifier does not exists, returns \b undef.
107 *******************************************************************************/
108 function get_table_c
109 (
110  c,
111  ci
112 ) = c[ get_table_ci(c, ci) ];
113 
114 //! Get the table cell value for a specified row and column identifier.
115 /***************************************************************************//**
116  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
117  \param c <matrix-2xC> The table column matrix (2 x C-columns).
118  \param ri <string> The row identifier.
119  \param ci <string> The column identifier.
120 
121  \returns <value> The value of the matrix cell [ri, ci].
122  If either identifier does not exists, returns \b undef.
123 *******************************************************************************/
124 function get_table_v
125 (
126  r,
127  c,
128  ri,
129  ci
130 ) = r[get_table_ri(r,ri)][get_table_ci(c,ci)];
131 
132 //! Form a list of a select column across all table rows.
133 /***************************************************************************//**
134  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
135  \param c <matrix-2xC> The table column matrix (2 x C-columns).
136  \param ci <string> The column identifier.
137 
138  \returns <list> The list of a select column across all rows.
139  If the identifier does not exists, returns \b undef.
140 *******************************************************************************/
141 function get_table_crl
142 (
143  r,
144  c,
145  ci
146 ) = table_exists(r,c,ci=ci) ?
147  eselect(get_table_copy(r,c,cl=[ci]),f=true)
148  : undef;
149 
150 //! Form a list of all table row identifiers.
151 /***************************************************************************//**
152  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
153 
154  \returns <list> The list of all row identifiers.
155 
156  \details
157 
158  \note This functions assumes the first element of each table row
159  to be the row identifier, as enforced by the table_check().
160  As an alternative, the function get_table_crl(), of
161  the form get_table_crl(r, c, "id"), may be used
162  without this assumption.
163 *******************************************************************************/
164 function get_table_ridl
165 (
166  r
167 ) = eselect(r,f=true);
168 
169 //! Form a list of all table column identifiers.
170 /***************************************************************************//**
171  \param c <matrix-2xC> The table column matrix (2 x C-columns).
172 
173  \returns <list> The list of all column identifiers.
174 
175  \details
176 
177  \note This functions assumes the first element of each table column
178  to be the column identifier.
179 *******************************************************************************/
180 function get_table_cidl
181 (
182  c
183 ) = eselect(c,f=true);
184 
185 //! Test the existence of a table row and column identifier.
186 /***************************************************************************//**
187  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
188  \param c <matrix-2xC> The table column matrix (2 x C-columns).
189  \param ri <string> The row identifier.
190  \param ci <string> The column identifier.
191 
192  \returns \b true if the row and column identifier exists, and
193  \b false otherwise.
194 *******************************************************************************/
195 function table_exists
196 (
197  r,
198  c,
199  ri,
200  ci
201 ) = ( is_defined(ri) && is_defined(ci) ) ?
202  is_defined(get_table_v(trows, tcols, ri, ci))
203  : ( is_defined(ri) && not_defined(ci) ) ?
204  !is_empty(get_table_ri(r,ri))
205  : ( not_defined(ri) && is_defined(ci) ) ?
206  !is_empty(get_table_ci(c,ci))
207  : false;
208 
209 //! Get the size of a table.
210 /***************************************************************************//**
211  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
212  \param c <matrix-2xC> The table column matrix (2 x C-columns).
213 
214  \returns <decimal> The table size.
215 
216  \details
217 
218  The size is reported as: (1) The number of rows when only the \p r
219  parameter is specified. (2) The number of columns when only the \p c
220  parameter is specified. (3) The (r * columns) when both parameters
221  are specified.
222 *******************************************************************************/
223 function get_table_size
224 (
225  r,
226  c
227 ) = ( is_defined(r) && not_defined(c) ) ? len( r )
228  : ( not_defined(r) && is_defined(c) ) ? len( c )
229  : len( r ) * len( c );
230 
231 //! Create a new matrix from select rows and columns of a table.
232 /***************************************************************************//**
233  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
234  \param c <matrix-2xC> The table column matrix (2 x C-columns).
235  \param rl <string-list> A list of selected row identifiers.
236  \param cl <string-list> A list of selected column identifiers.
237 
238  \returns <matrix> A matrix of the selected rows and columns.
239 *******************************************************************************/
240 function get_table_copy
241 (
242  r,
243  c,
244  rl,
245  cl
246 ) =
247 [
248  for ( r_iter = r )
249  if
250  (
251  not_defined( rl ) || is_empty( rl ) ||
252  !is_empty( first( search( r_iter, rl, 1, 0 ) ) )
253  )
254  [
255  for ( c_iter = c )
256  if
257  (
258  not_defined( cl ) || is_empty( cl ) ||
259  !is_empty( first( search( c_iter, cl, 1, 0 ) ) )
260  )
261  get_table_v(r, c, r_iter, c_iter)
262  ]
263 ];
264 
265 //! Sum select rows and columns of a table.
266 /***************************************************************************//**
267  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
268  \param c <matrix-2xC> The table column matrix (2 x C-columns).
269  \param rl <string-list> A list of selected row identifiers.
270  \param cl <string-list> A list of selected column identifiers.
271 
272  \returns <list> A list with the sum of each selected rows and columns.
273 *******************************************************************************/
274 function get_table_sum
275 (
276  r,
277  c,
278  rl,
279  cl
280 ) = sum( get_table_copy(r, c, rl, cl) );
281 
282 //! Perform some basic validation/checks on a table.
283 /***************************************************************************//**
284  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
285  \param c <matrix-2xC> The table column matrix (2 x C-columns).
286  \param verbose <boolean> Be verbose during check.
287 
288  \details
289 
290  Check that: (1) the first table column identifier is 'id'. (2) Make
291  sure that each row has the same number of columns as defined in the
292  columns vector. (3) Make sure that there are no repeating column
293  identifiers. (4) Make sure that there are no repeating row
294  identifiers.
295 *******************************************************************************/
296 module table_check
297 (
298  r,
299  c,
300  verbose = false
301 )
302 {
303  if (verbose) log_info("begin table check");
304 
305  // first word of first column should be 'id'
306  if ( first( first(c) ) != "id")
307  {
308  log_warn ("table column 0 should be 'id'");
309  }
310  else
311  {
312  if (verbose) log_info ("row identifier found at column zero.");
313  }
314 
315  // each row has correct column count
316  if (verbose) log_info ("checking row column counts.");
317  col_cnt = get_table_size(c=c);
318  for ( r_iter = r )
319  {
320  if ( col_cnt != len ( r_iter ) )
321  {
322  log_error
323  (
324  str
325  (
326  "row ", get_table_ri(r, r_iter),
327  ", id=[", first(r_iter), "]",
328  ", has incorrect column count=[", len ( r_iter ),"]"
329  )
330  );
331  }
332  }
333 
334  // no repeat column identifiers
335  if (verbose) log_info ("checking for repeat column identifiers.");
336  for (c_iter = c)
337  if ( len(first(search([first(c_iter)], c, 0, 0))) > 1 )
338  log_warn ( str("repeating column identifier [", first(c_iter), "]") );
339 
340  // no repeat row identifiers
341  if (verbose) log_info ("checking for repeat row identifiers.");
342  for (r_iter = r)
343  if ( len(first(search([first(r_iter)], r, 0, 0))) > 1 )
344  log_warn ( str("repeating row identifier [", first(r_iter), "]") );
345 
346  if (verbose)
347  {
348  log_info
349  (
350  str (
351  "table size: ",
352  get_table_size(r=r), " rows by ",
353  get_table_size(c=c), " columns."
354  )
355  );
356 
357  log_info("end table check");
358  }
359 }
360 
361 //! Dump a table to the console.
362 /***************************************************************************//**
363  \param r <matrix-CxR> The table data matrix (C-columns x R-rows).
364  \param c <matrix-2xC> The table column matrix (2 x C-columns).
365  \param rl <string-list> A list of selected row identifiers.
366  \param cl <string-list> A list of selected column identifiers.
367  \param number <boolean> Number the table rows.
368 
369  \details
370 
371  Output each table row to the console. To output only select rows and
372  columns, assign the desired identifiers to \p rl and \p cl.
373  For example to output only the column identifiers 'c1' and 'c2', assign
374  <tt>cl = ["c1", "c2"]</tt>.
375 *******************************************************************************/
376 module table_dump
377 (
378  r,
379  c,
380  rl,
381  cl,
382  number = true
383 )
384 {
385  maxr0 = max( [for (r_iter = r) len( first(r_iter) )] ) + 1;
386  maxc0 = max( [for (c_iter = c) len( first(c_iter) )] ) + 1;
387  maxc1 = max( [for (c_iter = c) len( c_iter[1] )] ) + 1;
388 
389  for ( r_iter = r )
390  {
391  if
392  (
393  not_defined( rl ) || is_empty( rl ) ||
394  !is_empty( first( search( r_iter, rl, 1, 0 ) ) )
395  )
396  {
397  if ( number )
398  {
399  log_echo();
400  log_echo( str("row: ", get_table_ri(r, r_iter)) );
401  }
402  for ( c_iter = c )
403  {
404  if
405  (
406  not_defined( cl ) || is_empty( cl ) ||
407  !is_empty( first( search( c_iter, cl, 1, 0 ) ) )
408  )
409  {
410  log_echo
411  (
412  str
413  (
414  "[", first(r_iter), "]", chr(consts(maxr0-len(first(r_iter)), 32)),
415  "[", first(c_iter), "]", chr(consts(maxc0-len(first(c_iter)), 32)),
416  "(", c_iter[1], ")", chr(consts(maxc1-len(c_iter[1]), 32)),
417  "= [", get_table_v(r, c, r_iter, c_iter), "]"
418  )
419  );
420  }
421  }
422  }
423  }
424 
425  if ( number ) {
426  log_echo();
427  log_echo
428  (
429  str (
430  "table size: ",
431  get_table_size(r=r), " rows by ",
432  get_table_size(c=c), " columns."
433  )
434  );
435  }
436 }
437 
438 //! @}
439 //! @}
440 
441 //----------------------------------------------------------------------------//
442 // openscad-amu auxiliary scripts
443 //----------------------------------------------------------------------------//
444 
445 /*
446 BEGIN_SCOPE example;
447  BEGIN_OPENSCAD;
448  include <units/units_length.scad>;
449  include <datatypes/datatypes_table.scad>;
450 
451  base_unit_length = "mm";
452 
453  table_cols =
454  [ // id, description
455  ["id", "row identifier"],
456  ["ht", "head type [r|h|s]"],
457  ["td", "thread diameter"],
458  ["tl", "thread length"],
459  ["hd", "head diameter"],
460  ["hl", "head length"],
461  ["nd", "hex nut flat-to-flat width"],
462  ["nl", "hex nut length"]
463  ];
464 
465  table_rows =
466  [ // id, ht, td, tl, hd, hl, nd, nl
467  ["m3r08r", "r", 3.000, 8.00, 5.50, 3.000, 5.50, convert_length(1.00, "in")],
468  ["m3r14r", "r", 3.000, 14.00, 5.50, 3.000, 5.50, convert_length(1.25, "in")],
469  ["m3r16r", "r", 3.000, 16.00, 5.50, 3.000, 5.50, convert_length(1.50, "in")],
470  ["m3r20r", "r", 3.000, 20.00, 5.50, 3.000, 5.50, convert_length(1.75, "in")]
471  ];
472 
473  table_check( table_rows, table_cols, true );
474  table_dump( table_rows, table_cols );
475 
476  m3r16r_tl = get_table_v( table_rows, table_cols, "m3r16r", "tl" );
477 
478  if ( table_exists( c=table_cols, ci="nl" ) )
479  echo ( "metric 'nl' available" );
480 
481  table_ids = get_table_ridl( table_rows );
482  table_cols_tl = get_table_crl( table_rows, table_cols, "tl" );
483 
484  echo ( table_ids=table_ids );
485  echo ( table_cols_tl=table_cols_tl );
486 
487  tnew = get_table_copy( table_rows, table_cols, cl=["tl", "nl"] );
488  tsum = get_table_sum( table_rows, table_cols, cl=["tl", "nl"] );
489 
490  echo ( m3r16r_tl=m3r16r_tl );
491  echo ( tnew=tnew );
492  echo ( tsum=tsum );
493  END_OPENSCAD;
494 
495  BEGIN_MFSCRIPT;
496  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
497  include --path "${INCLUDE_PATH}" script_std.mfs;
498  END_MFSCRIPT;
499 END_SCOPE;
500 */
501 
502 //----------------------------------------------------------------------------//
503 // end of file
504 //----------------------------------------------------------------------------//
function get_table_ri(r, ri)
Get the table row index that matches a table row identifier.
module log_echo(m)
Output message to console.
Definition: console.scad:90
function is_empty(v)
Test if an iterable value is empty.
function get_table_ci(c, ci)
Get the table column index that matches a table column identifier.
function table_exists(r, c, ri, ci)
Test the existence of a table row and column identifier.
function sum(v, i1, i2)
Compute the sum of a list of numbers.
module log_warn(m)
Output warning message to console.
Definition: console.scad:137
module log_info(m)
Output information message to console.
Definition: console.scad:122
function get_table_v(r, c, ri, ci)
Get the table cell value for a specified row and column identifier.
function get_table_size(r, c)
Get the size of a table.
function not_defined(v)
Test if a value is not defined.
module log_error(m)
Output error message to console.
Definition: console.scad:166
function is_defined(v)
Test if a value is defined.
function get_table_c(c, ci)
Get the table column that matches a table column identifier.
function get_table_sum(r, c, rl, cl)
Sum select rows and columns of a table.
function first(v)
Return the first element of an iterable value.
function get_table_cidl(c)
Form a list of all table column identifiers.
module table_dump(r, c, rl, cl, number=true)
Dump a table to the console.
function get_table_r(r, ri)
Get the table row that matches a table row identifier.
function consts(l, v, u=false)
Create a sequence of constant or incrementing elements.
function eselect(v, f=true, l=false, i)
Select a specified element from each iterable value of a list.
function get_table_crl(r, c, ci)
Form a list of a select column across all table rows.
module table_check(r, c, verbose=false)
Perform some basic validation/checks on a table.
function get_table_ridl(r)
Form a list of all table row identifiers.
function get_table_copy(r, c, rl, cl)
Create a new matrix from select rows and columns of a table.