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