omdl  v0.9.5
OpenSCAD Mechanical Design Library
table.scad
Go to the documentation of this file.
1 //! Table data structure and operations.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2015-2024
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 (Tables)
31  \amu_define group_brief (Table data type and operations.)
32 
33  \amu_include (include/amu/pgid_path_pstem_pg.amu)
34 *******************************************************************************/
35 
36 //----------------------------------------------------------------------------//
37 // group.
38 //----------------------------------------------------------------------------//
39 
40 /***************************************************************************//**
41  \amu_include (include/amu/group_in_parent_start.amu)
42  \amu_include (include/amu/includes_required.amu)
43 
44  \details
45 
46  The table functions were originally coded with the row and column
47  data as separate parameters. Some equivalent functions are provided
48  that accept the row and column data as a single combined parameter,
49  where <tt>t = [r, c];</tt> for convenience and are prefaced with
50  the letter 'c'.
51 
52  \amu_define title (Table use)
53  \amu_define scope_id (example_use)
54  \amu_include (include/amu/scope.amu)
55 *******************************************************************************/
56 
57 //----------------------------------------------------------------------------//
58 // Separate
59 //----------------------------------------------------------------------------//
60 
61 //! \name Separate table data
62 //! @{
63 
64 //! Get the table row index that matches a table row identifier.
65 /***************************************************************************//**
66  \param r <table> The table row data matrix (C-columns x R-rows).
67  \param ri <string> The row identifier.
68 
69  \returns <integer> The row index where the identifier exists.
70  Returns \b undef if the identifier does not exists.
71 *******************************************************************************/
72 function table_get_row_index
73 (
74  r,
75  ri
76 ) = let(i = first( search( [ri], r, 1, 0 ) ) )
77  (i == empty_lst) ? undef : i;
78 
79 //! Get the table row that matches a table row identifier.
80 /***************************************************************************//**
81  \param r <table> The table row data matrix (C-columns x R-rows).
82  \param ri <string> The row identifier.
83 
84  \returns <list-C> The table row where the row identifier exists.
85  If the identifier does not exists, returns \b undef.
86 *******************************************************************************/
87 function table_get_row
88 (
89  r,
90  ri
91 ) = r[ table_get_row_index(r, ri) ];
92 
93 //! Get the table column index that matches a table column identifier.
94 /***************************************************************************//**
95  \param c <map> The table column identifier matrix (2 x C-columns).
96  \param ci <string> The column identifier.
97 
98  \returns <integer> The column index where the identifier exists.
99  Returns \b undef if the identifier does not exists.
100 *******************************************************************************/
101 function table_get_column_index
102 (
103  c,
104  ci
105 ) = let(i = first( search( [ci], c, 1, 0 ) ) )
106  (i == empty_lst) ? undef : i;
107 
108 //! Get the table column that matches a table column identifier.
109 /***************************************************************************//**
110  \param c <map> The table column identifier matrix (2 x C-columns).
111  \param ci <string> The column identifier.
112 
113  \returns <list-2> The table column where the column identifier exists.
114  If the identifier does not exists, returns \b undef.
115 *******************************************************************************/
116 function table_get_column
117 (
118  c,
119  ci
120 ) = c[ table_get_column_index(c, ci) ];
121 
122 //! Get the table cell value for a specified row and column identifier.
123 /***************************************************************************//**
124  \param r <table> The table row data matrix (C-columns x R-rows).
125  \param c <map> The table column identifier matrix (2 x C-columns).
126  \param ri <string> The row identifier.
127  \param ci <string> The column identifier.
128 
129  \returns <value> The value of the table cell <tt>[ri, ci]</tt>.
130  If either identifier does not exists, returns \b undef.
131 *******************************************************************************/
132 function table_get_value
133 (
134  r,
135  c,
136  ri,
137  ci
138 ) = r[table_get_row_index(r,ri)][table_get_column_index(c,ci)];
139 
140 //! Form a list of a select column across all table rows.
141 /***************************************************************************//**
142  \param r <table> The table row data matrix (C-columns x R-rows).
143  \param c <map> The table column identifier matrix (2 x C-columns).
144  \param ci <string> The column identifier.
145 
146  \returns <list> The list of a select column across all rows.
147  If the identifier does not exists, returns \b undef.
148 *******************************************************************************/
149 function table_get_columns
150 (
151  r,
152  c,
153  ci
154 ) = table_exists(r,c,ci=ci) ?
155  select_e(table_get_copy(r,c,cs=[ci]),f=true)
156  : undef;
157 
158 //! Get a row, a column, or a specific cell value from a table.
159 /***************************************************************************//**
160  \param r <table> The table row data matrix (C-columns x R-rows).
161  \param c <map> The table column identifier matrix (2 x C-columns).
162  \param ri <string> The row identifier.
163  \param ci <string> The column identifier.
164 
165  \returns (1) <value> The value of the table cell <tt>[ri, ci]</tt>
166  when both \p ri and \p ci are defined. (2) The row <list-R>
167  when only \p ri is defined. (3) The column <list-C> when
168  only \p ci is defined. (4) Returns \b undef when the
169  specified row or column identifier is not present in the
170  table or when both are undefined.
171 
172  \details
173 
174  This function combines the behavior of several other table access
175  functions dependent on the supplied parameters.
176 
177  \b Example
178  \code
179  rows = table_get( r, c, ri );
180  cols = table_get( r, c, ci=ci );
181  cell = table_get( r, c, ri, ci );
182  \endcode
183 *******************************************************************************/
184 function table_get
185 (
186  r,
187  c,
188  ri,
189  ci
190 ) = let ( dr = is_defined(ri), dc = is_defined(ci) )
191  ( dr && dc ) ? table_get_value(r, c, ri, ci)
192  : dr ? table_get_row(r, ri)
193  : dc ? table_get_columns(r, c, ci)
194  : undef;
195 
196 //! Form a list of all table row identifiers.
197 /***************************************************************************//**
198  \param r <table> The table row data matrix (C-columns x R-rows).
199 
200  \returns <list> The list of all row identifiers.
201 
202  \details
203 
204  This functions assumes the first element of each table row to be
205  the row identifier, as enforced by the table_check(). As an
206  alternative, the function table_get_columns(), of the form
207  table_get_columns(r, c, id), may be used without this assumption.
208 *******************************************************************************/
209 function table_get_row_ids
210 (
211  r
212 ) = select_e(r,f=true);
213 
214 //! Form a list of all table column identifiers.
215 /***************************************************************************//**
216  \param c <map> The table column identifier matrix (2 x C-columns).
217 
218  \returns <list> The list of all column identifiers.
219 
220  \details
221 
222  This functions assumes the first element of each table column to be
223  the column identifier.
224 *******************************************************************************/
225 function table_get_column_ids
226 (
227  c
228 ) = select_e(c,f=true);
229 
230 //! Test the existence of a table row identifier, table column identifier, or both.
231 /***************************************************************************//**
232  \param r <table> The table row data matrix (C-columns x R-rows).
233  \param c <map> The table column identifier matrix (2 x C-columns).
234  \param ri <string> The row identifier.
235  \param ci <string> The column identifier.
236 
237  \returns \b true if the specified row and/or column identifier
238  exists, and \b false otherwise.
239 
240  \details
241 
242  The functions can be used to check for a row or a column identifier
243  alone, or can be use to check for the existence of a specific row
244  and column combination.
245 *******************************************************************************/
246 function table_exists
247 (
248  r,
249  c,
250  ri,
251  ci
252 ) = let ( dr = is_defined(ri), dc = is_defined(ci) )
253  ( dr && dc ) ? is_defined(table_get_value(r, c, ri, ci))
254  : dr ? is_number(table_get_row_index(r,ri))
255  : dc ? is_number(table_get_column_index(c,ci))
256  : false;
257 
258 //! Get the size of a table.
259 /***************************************************************************//**
260  \param r <table> The table row data matrix (C-columns x R-rows).
261  \param c <map> The table column identifier matrix (2 x C-columns).
262 
263  \returns <integer> The table size.
264 
265  \details
266 
267  The size is reported as: (1) The number of rows when only the \p r
268  parameter is specified. (2) The number of columns when only the \p c
269  parameter is specified. (3) The (r * columns) when both parameters
270  are specified.
271 *******************************************************************************/
273 (
274  r,
275  c
276 ) = ( is_defined(r) && is_undef(c) ) ? len( r )
277  : ( is_undef(r) && is_defined(c) ) ? len( c )
278  : len( r ) * len( c );
279 
280 //! Create a new matrix from select rows and columns of a table.
281 /***************************************************************************//**
282  \param r <table> The table row data matrix (C-columns x R-rows).
283  \param c <map> The table column identifier matrix (2 x C-columns).
284  \param rs <string-list> A list of selected row identifiers.
285  \param cs <string-list> A list of selected column identifiers.
286 
287  \returns <matrix> A matrix of the selected rows and columns.
288 *******************************************************************************/
289 function table_get_copy
290 (
291  r,
292  c,
293  rs,
294  cs
295 ) =
296 [
297  for ( r_iter = r )
298  if
299  (
300  is_undef( rs ) ||
301  is_number( first( search( r_iter, rs, 1, 0 ) ) )
302  )
303  [
304  for ( c_iter = c )
305  if
306  (
307  is_undef( cs ) ||
308  is_number( first( search( c_iter, cs, 1, 0 ) ) )
309  )
310  table_get_value(r, c, r_iter, c_iter)
311 
312  ]
313 ];
314 
315 //! Sum select rows and columns of a table.
316 /***************************************************************************//**
317  \param r <table> The table row data matrix (C-columns x R-rows).
318  \param c <map> The table column identifier matrix (2 x C-columns).
319  \param rs <string-list> A list of selected row identifiers.
320  \param cs <string-list> A list of selected column identifiers.
321 
322  \returns <list> A list with the sum of each selected rows and columns.
323 *******************************************************************************/
324 function table_get_sum
325 (
326  r,
327  c,
328  rs,
329  cs
330 ) = sum( table_get_copy(r, c, rs, cs) );
331 
332 //! Perform basic format checks on a table and return errors.
333 /***************************************************************************//**
334  \param r <table> The table row data matrix (C-columns x R-rows).
335  \param c <map> The table column identifier matrix (2 x C-columns).
336 
337  \returns <list-N> A list of table format errors.
338 
339  \details
340 
341  Check that: (1) the first table column identifier is 'id'. (2) Make
342  sure that each row has the same number of columns as defined in the
343  columns vector. (3) Make sure that there are no repeating column
344  identifiers. (4) Make sure that there are no repeating row
345  identifiers. When there are no errors, the \b empty_lst is
346  returned.
347 *******************************************************************************/
348 function table_errors
349 (
350  r,
351  c
352 ) =
353  let
354  (
355  // (1) first word of first column should be 'id'
356  ec1 =
357  [
358  if ( first( first(c) ) != "id")
359  str ("table column 0 should be 'id'")
360  ],
361 
362  // (2) each row has correct column count
363  ec2 =
364  [
365  let (col_cnt = table_get_size(c=c))
366  for ( r_iter = r )
367  if ( col_cnt != len ( r_iter ) )
368  str
369  (
370  "row ", table_get_row_index(r, r_iter),
371  ", id=[", first(r_iter), "]",
372  ", has incorrect column count=[", len ( r_iter ),"]"
373  )
374  ],
375 
376  // (3) no repeat column identifiers
377  ec3 =
378  [
379  for ( c_iter = c )
380  if ( len(first(search([first(c_iter)], c, 0, 0))) > 1 )
381  str("repeating column identifier [", first(c_iter), "]")
382  ],
383 
384  // (4) no repeat row identifiers
385  ec4 =
386  [
387  for ( r_iter = r )
388  if ( len(first(search([first(r_iter)], r, 0, 0))) > 1 )
389  str("repeating row identifier [", first(r_iter), "]")
390  ]
391  )
392  concat(ec1, ec2, ec3, ec4);
393 
394 
395 //! Perform basic format checks on a table and output errors to console.
396 /***************************************************************************//**
397  \param r <table> The table row data matrix (C-columns x R-rows).
398  \param c <map> The table column identifier matrix (2 x C-columns).
399  \param verbose <boolean> Be verbose during check.
400 
401  \details
402 
403  Check that: (1) the first table column identifier is 'id'. (2) Make
404  sure that each row has the same number of columns as defined in the
405  columns vector. (3) Make sure that there are no repeating column
406  identifiers. (4) Make sure that there are no repeating row
407  identifiers.
408 *******************************************************************************/
409 module table_check
410 (
411  r,
412  c,
413  verbose = false
414 )
415 {
416  if (verbose) log_info("begin table check");
417 
418  // (1) first word of first column should be 'id'
419  if ( first( first(c) ) != "id")
420  {
421  log_warn ("table column 0 should be 'id'");
422  }
423  else
424  {
425  if (verbose) log_info ("row identifier found at column zero.");
426  }
427 
428  // (2) each row has correct column count
429  if (verbose) log_info ("checking row column counts.");
430  col_cnt = table_get_size(c=c);
431  for ( r_iter = r )
432  {
433  assert
434  (
435  col_cnt == len ( r_iter ),
436  str
437  (
438  "row ", table_get_row_index(r, r_iter),
439  ", id=[", first(r_iter), "]",
440  ", has incorrect column count=[", len ( r_iter ),"]",
441  ", expecting=[", col_cnt, "]"
442  )
443  );
444  }
445 
446  // (3) no repeat column identifiers
447  if (verbose) log_info ("checking for repeat column identifiers.");
448  for ( c_iter = c )
449  if ( len(first(search([first(c_iter)], c, 0, 0))) > 1 )
450  log_warn ( str("repeating column identifier [", first(c_iter), "]") );
451 
452  // (4) no repeat row identifiers
453  if (verbose) log_info ("checking for repeat row identifiers.");
454  for ( r_iter = r )
455  if ( len(first(search([first(r_iter)], r, 0, 0))) > 1 )
456  log_warn ( str("repeating row identifier [", first(r_iter), "]") );
457 
458  if (verbose)
459  {
460  log_info
461  (
462  str (
463  "table size: ",
464  table_get_size(r=r), " rows by ",
465  table_get_size(c=c), " columns."
466  )
467  );
468 
469  log_info("end table check");
470  }
471 }
472 
473 //! Dump a table to the console.
474 /***************************************************************************//**
475  \param r <table> The table row data matrix (C-columns x R-rows).
476  \param c <map> The table column identifier matrix (2 x C-columns).
477  \param rs <string-list> A list of selected row identifiers.
478  \param cs <string-list> A list of selected column identifiers.
479  \param number <boolean> Number the rows.
480 
481  \details
482 
483  Output each table row to the console. To output only select rows and
484  columns, assign the desired identifiers to \p rs and \p cs.
485  For example to output only the column identifiers 'c1' and 'c2', assign
486  <tt>cs = ["c1", "c2"]</tt>.
487 *******************************************************************************/
488 module table_dump
489 (
490  r,
491  c,
492  rs,
493  cs,
494  number = true
495 )
496 {
497  // determine maximum field lengths
498  maxr0 = max( [for (r_iter = r) len( first(r_iter) )] ) + 1;
499  maxc0 = max( [for (c_iter = c) len( first(c_iter) )] ) + 1;
500  maxc1 = max( [for (c_iter = c) len( c_iter[1] )] ) + 1;
501 
502  for ( r_iter = r )
503  {
504  if
505  (
506  is_undef( rs ) ||
507  is_number( first( search( r_iter, rs, 1, 0 ) ) )
508  )
509  {
510  if ( number )
511  {
512  log_echo();
513  log_echo( str("row: ", table_get_row_index(r, r_iter)) );
514  }
515  for ( c_iter = c )
516  {
517  if
518  (
519  is_undef( cs ) ||
520  is_number( first( search( c_iter, cs, 1, 0 ) ) )
521  )
522  {
523  log_echo
524  (
525  str
526  (
527  "[", first(r_iter), "]", chr(consts(maxr0-len(first(r_iter)), 32)),
528  "[", first(c_iter), "]", chr(consts(maxc0-len(first(c_iter)), 32)),
529  "(", c_iter[1], ")", chr(consts(maxc1-len(c_iter[1]), 32)),
530  "= [", table_get_value(r, c, r_iter, c_iter), "]"
531  )
532  );
533  }
534  }
535  }
536  }
537 
538  if ( number )
539  {
540  log_echo();
541  log_echo
542  (
543  str (
544  "table size: ",
545  table_get_size(r=r), " rows by ",
546  table_get_size(c=c), " columns."
547  )
548  );
549  }
550 }
551 
552 //! Dump table getter functions to the console.
553 /***************************************************************************//**
554  \param r <table> The table row data matrix (C-columns x R-rows).
555  \param c <map> The table column identifier matrix (2 x C-columns).
556  \param tr <string> The table row data matrix variable name.
557  \param tc <string> The table column identifier matrix variable name.
558  \param ri <string | value> The row identifier variable name or value.
559  \param ci <string | value> The column identifier variable name or value.
560  \param vri <boolean> The row identifier \p ri is a value.
561  \param vci <boolean> The column identifier \p ci is a value.
562  \param name <string> The getter function name.
563  \param append <boolean> Append id to names.
564  \param comment <integer> Output comment mode {0, 1, 2}.
565  \param verbose <boolean> Be verbose.
566 
567  \details
568 
569  Output getter functions for a table to the console. The resulting
570  functions can be used within scripts to access table data.
571 
572  \b Example
573  \code
574  table_dump_getters
575  (
576  r=my_config_tr, c=my_config_tc, tr="my_config_tr", tc="my_config_tc",
577  ri="my_config", vri=true, name="my_get_function", comment=2
578  );
579  \endcode
580 *******************************************************************************/
581 module table_dump_getters
582 (
583 r,
584 c,
585 
586 tr = "table_rows",
587 tc = "table_cols",
588 
589 ri = "ri",
590 ci = "ci",
591 
592 vri = false,
593 vci = false,
594 
595 name = "get_helper",
596 append = false,
597 comment = 0,
598 verbose = false
599 )
600 {
601  function qri(ri) = (ri == "ri") ? ri : (vri == true) ? ri : str("\"", ri, "\"");
602  function qci(ci) = (ci == "ci") ? ci : (vci == true) ? ci : str("\"", ci, "\"");
603  function gfn(fn) =
604  str
605  (
606  fn,
607  (ri == "ri")?"":(append?str("_", ri):""),
608  (ci == "ci")?"":(append?str("_", ci):"")
609  );
610 
611  //
612  // check table
613  //
614  echo();
615  echo("Checking table...");
616  table_check(r=r, c=c, verbose=verbose);
617 
618  if ( table_errors(r=r, c=c) == empty_lst )
619  {
620  //
621  // output helper function
622  //
623  echo();
624 
625  // getter function comment
626  gct =
627  str
628  (
629  "// table value getter function",
630  (ri == "ri")?"":str(", constant row ri=", qri(ri)),
631  (ci == "ci")?"":str(", constant column ci=", qci(ci)),
632  "."
633  );
634  if (comment > 0) echo (str(gct));
635 
636  // getter function
637  echo
638  (
639  str
640  (
641  "function ", gfn(name),
642  "(",
643  (ri == "ri")?"ri":"",
644  (ri == "ri") && (ci == "ci")?", ":"",
645  (ci == "ci")?"ci":"",
646  ") = table_get_value (r=", tr,
647  ", c=", tc,
648  ", ri=", qri(ri),
649  ", ci=", qci(ci),
650  ");"
651  )
652  );
653 
654  //
655  // output value functions
656  //
657  echo();
658 
659  // constant row (ri)
660  if ( (ri != "ri") && (ci == "ci") )
661  {
662  if ( vri || table_exists( r=r, c=c, ri=ri ) )
663  {
664  for ( i = table_get_column_ids (c=c) )
665  {
666  cic = table_get_column( c=c, ci=i );
667 
668  gct = str("// get ci=", qci(i), " (", second(cic), ") & ri=", qri(ri), ".");
669  if (comment == 1) echo (str(gct));
670 
671  echo
672  (
673  str
674  (
675  (append?str(ri, "_"):""), i, " = ",
676  gfn(name), "(ci=", qci(i), ");",
677  (comment == 2)?str("\t", gct):""
678  )
679  );
680  }
681  }
682  else
683  {
684  echo( str( "row ri=", qri(ri), " does not exist in table." ) );
685  }
686  }
687 
688  // constant col (ci)
689  else if ( (ri == "ri") && (ci != "ci") )
690  {
691  if ( vci || table_exists( r=r, c=c, ci=ci ) )
692  {
693  for ( i = table_get_row_ids (r=r) )
694  {
695  gct = str("// get ri=", qri(i), " & ci=", qci(ci), ".");
696  if (comment == 1) echo (str(gct));
697 
698  echo
699  (
700  str
701  (
702  i, (append?str("_", ci):""), " = ",
703  gfn(name), "(ri=", qri(i), ");",
704  (comment == 2)?str("\t", gct):""
705  )
706  );
707  }
708  }
709  else
710  {
711  echo( str( "column ci=", qci(ci), " does not exist in table." ) );
712  }
713  }
714 
715  // constant row and col (ri & ci)
716  else if ( (ri != "ri") && (ci != "ci") )
717  {
718  if ( vri || vci || table_exists( r=r, c=c, ri=ri, ci=ci ) )
719  { gct = str("// get ri=", qri(ri), " & ci=", qci(ci), ".");
720  if (comment == 1) echo (str(gct));
721 
722  echo
723  (
724  str
725  (
726  ri, "_", ci, " = ",
727  gfn(name), "(ri=", qri(ri), ", ci=", qci(ci), ");",
728  (comment == 2)?str("\t", gct):""
729  )
730  );
731  }
732  else
733  {
734  echo
735  (
736  str
737  (
738  "row ri=", qri(ri), ", column ci=", qci(ci),
739  " does not exist in table."
740  )
741  );
742  }
743  }
744  }
745  else
746  {
747  echo ( "Table has errors." );
748  }
749 }
750 
751 //! Write formatted map entries to the console.
752 /***************************************************************************//**
753  \param r <table> The table row data matrix (C-columns x R-rows).
754  \param c <map> The table column identifier matrix (2 x C-columns).
755  \param rs <string-list> A list of selected row identifiers.
756  \param cs <string-list> A list of selected column identifiers.
757  \param number <boolean> Number the rows.
758  \param heading_id <boolean> Output table heading identifiers.
759  \param heading_text <boolean> Output table heading description text.
760  \param fs <string> A field separator.
761  \param thn <string> Column heading for numbered row output.
762  \param index_tags <string-list> List of html formatting tags.
763  \param row_id_tags <string-list> List of html formatting tags.
764  \param value_tags <string-list> List of html formatting tags.
765 
766  \details
767 
768  Output each table row to the console. To output only select rows
769  and columns, assign the desired identifiers to \p rs and \p cs. For
770  example to output only the column identifiers 'c1' and 'c2', assign
771  <tt>cs = ["c1", "c2"]</tt>. The output can then be processed to
772  produce documentation tables as shown in the example below.
773 
774  \amu_define title (Table write)
775  \amu_define scope_id (example_table)
776 
777  \amu_define th_line (1)
778  \amu_define td_line_begin (2)
779  \amu_define td_line_end (9)
780  \amu_include (include/amu/scope_table.amu)
781 
782  \amu_define output_scad (false)
783  \amu_define output_console (false)
784  \amu_define th_line (10)
785  \amu_define td_line_begin (11)
786  \amu_define td_line_end (0)
787  \amu_include (include/amu/scope_table.amu)
788 *******************************************************************************/
789 module table_write
790 (
791  r,
792  c,
793  rs,
794  cs,
795  number = false,
796  heading_id = true,
797  heading_text = false,
798  fs = "^",
799  thn = "idx",
800  index_tags = empty_lst,
801  row_id_tags = ["b"],
802  value_tags = empty_lst
803 )
804 {
805  // heading identifiers and/or text descriptions
806  th_text =
807  [
808  if(number == true)
809  thn,
810 
811  for ( c_iter = c )
812  if
813  ( // when column selected
814  is_undef( cs ) ||
815  is_number( first( search( c_iter, cs, 1, 0 ) ) )
816  )
817  (heading_id && heading_text) ? str(second(c_iter)," (", first(c_iter), ")")
818  : (heading_id ) ? first(c_iter)
819  : ( heading_text) ? second(c_iter)
820  : empty_str
821  ];
822 
823  if ( heading_id || heading_text )
824  // reformat so that 'fs' exists only between fields
825  log_echo ( strl([for ( i = headn(th_text) ) str(i,fs), last(th_text)]) );
826 
827  // row data
828  for ( r_iter = r )
829  {
830  if
831  ( // when row selected
832  is_undef( rs ) ||
833  is_number( first( search( r_iter, rs, 1, 0 ) ) )
834  )
835  {
836  tdr_text =
837  [
838  if (number == true)
839  str(strl_html([table_get_row_index(r, r_iter)], p=[index_tags]),fs),
840 
841  strl_html(first(r_iter), p=[row_id_tags]), fs,
842  for ( c_iter = tailn(c, n=1) )
843  if
844  ( // when column selected
845  is_undef( cs ) ||
846  is_number( first( search( c_iter, cs, 1, 0 ) ) )
847  )
848  str(strl_html([table_get_value(r, c, r_iter, c_iter)], p=[value_tags]),fs)
849  ];
850 
851  log_echo ( strl(tdr_text) );
852  }
853  }
854 }
855 
856 //! @}
857 
858 //----------------------------------------------------------------------------//
859 // Combined
860 //----------------------------------------------------------------------------//
861 
862 //! \name Combined table data
863 //! @{
864 
865 /***************************************************************************//**
866  \param t <datastruct-list-2> A list [<table>, <map>], [r, c], of
867  the row data matrix (C-columns x R-rows) and column
868  identifier matrix (2 x C-columns).
869 
870  \copydoc table_get()
871 *******************************************************************************/
872 function ctable_get( t, ri, ci ) = table_get( first(t), second(t), ri, ci );
873 
874 /***************************************************************************//**
875  \param t <datastruct-list-2> A list [<table>, <map>], [r, c], of
876  the row data matrix (C-columns x R-rows) and column
877  identifier matrix (2 x C-columns).
878 
879  \copydoc table_exists()
880 *******************************************************************************/
881 function ctable_exists( t, ri, ci ) = table_exists( first(t), second(t), ri, ci );
882 
883 /***************************************************************************//**
884  \param t <datastruct-list-2> A list [<table>, <map>], [r, c], of
885  the row data matrix (C-columns x R-rows) and column
886  identifier matrix (2 x C-columns).
887 
888  \copydoc table_get_size()
889 *******************************************************************************/
890 function ctable_get_size( t ) = table_get_size( first(t), second(t) );
891 
892 /***************************************************************************//**
893  \param t <datastruct-list-2> A list [<table>, <map>], [r, c], of
894  the row data matrix (C-columns x R-rows) and column
895  identifier matrix (2 x C-columns).
896 
897  \copydoc table_errors()
898 *******************************************************************************/
899 function ctable_errors( t ) = table_errors( first(t), second(t) );
900 
901 //! @}
902 
903 //! @}
904 //! @}
905 
906 //----------------------------------------------------------------------------//
907 // openscad-amu auxiliary scripts
908 //----------------------------------------------------------------------------//
909 
910 /*
911 BEGIN_SCOPE example_use;
912  BEGIN_OPENSCAD;
913  include <omdl-base.scad>;
914 
915  base_unit_length = "mm";
916 
917  table_cols =
918  [ // id, description
919  ["id", "row identifier"],
920  ["ht", "head type [r|h|s]"],
921  ["td", "thread diameter"],
922  ["tl", "thread length"],
923  ["hd", "head diameter"],
924  ["hl", "head length"],
925  ["nd", "hex nut flat-to-flat width"],
926  ["nl", "hex nut length"]
927  ];
928 
929  table_rows =
930  [ // id, ht, td, tl, hd, hl, nd, nl
931  ["m3r08r", "r", 3.000, 8.00, 5.50, 3.000, 5.50, length(1.00, "in")],
932  ["m3r14r", "r", 3.000, 14.00, 5.50, 3.000, 5.50, length(1.25, "in")],
933  ["m3r16r", "r", 3.000, 16.00, 5.50, 3.000, 5.50, length(1.50, "in")],
934  ["m3r20r", "r", 3.000, 20.00, 5.50, 3.000, 5.50, length(1.75, "in")]
935  ];
936 
937  echo( "### table_check ###" );
938  table_check( table_rows, table_cols, true );
939 
940  echo( "### table_dump ###" );
941  table_dump( table_rows, table_cols );
942 
943  echo( "### table_get_value ###" );
944  m3r16r_tl = table_get_value( table_rows, table_cols, "m3r16r", "tl" );
945  echo ( m3r16r_tl=m3r16r_tl );
946 
947  echo( "### table_exists ###" );
948  if ( table_exists( c=table_cols, ci="nl" ) )
949  echo ( "metric 'nl' available" );
950  else
951  echo ( "metric 'nl' not available" );
952 
953  echo( "### table_get_row_ids ###" );
954  table_ids = table_get_row_ids( table_rows );
955  echo ( table_ids=table_ids );
956 
957  echo( "### table_get_columns 'tl' ###" );
958  table_cols_tl = table_get_columns( table_rows, table_cols, "tl" );
959  echo ( table_cols_tl=table_cols_tl );
960 
961  echo( "### table_get_copy ['tl, 'nl'] ###" );
962  tnew = table_get_copy( table_rows, table_cols, cs=["tl", "nl"] );
963  echo ( tnew=tnew );
964 
965  echo( "### table_get_sum ['tl, 'nl'] ###" );
966  tsum = table_get_sum( table_rows, table_cols, cs=["tl", "nl"] );
967  echo ( tsum=tsum );
968 
969  echo( "### table_dump_getters ###" );
970  table_dump_getters( r=table_rows, c=table_cols,
971  tr="table_rows", tc="table_cols",
972  ri="my_config", vri=true, name="get_my_value", comment=2 );
973 
974  // end_include
975  END_OPENSCAD;
976 
977  BEGIN_MFSCRIPT;
978  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
979  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
980  END_MFSCRIPT;
981 END_SCOPE;
982 
983 BEGIN_SCOPE example_table;
984  BEGIN_OPENSCAD;
985  include <omdl-base.scad>;
986 
987  base_unit_length = "mm";
988 
989  table_cols =
990  [ // id, description
991  ["id", "row identifier"],
992  ["ht", "head type"],
993  ["td", "thread diameter"],
994  ["tl", "thread length"],
995  ["hd", "head diameter"],
996  ["hl", "head length"],
997  ["nd", "nut width"],
998  ["nl", "nut length"]
999  ];
1000 
1001  table_rows =
1002  [ // id, ht, td, tl, hd, hl, nd, nl
1003  ["m3r08r", "r", 3.000, 8.00, 5.50, 3.000, 5.50, length(1.00, "in")],
1004  ["m3r14r", "r", 3.000, 14.00, 5.50, 3.000, 5.50, length(1.25, "in")],
1005  ["m4r16s", "s", 4.000, 16.00, 4.50, 4.000, 5.50, length(1.50, "in")],
1006  ["m5r20h", "h", 5.000, 20.00, 6.00, 5.000, 5.50, length(1.75, "in")]
1007  ];
1008 
1009  map_write(table_cols, value_tags=["i"]);
1010  table_write(table_rows, table_cols);
1011 
1012  // end_include
1013  END_OPENSCAD;
1014 
1015  BEGIN_MFSCRIPT;
1016  include --path "${INCLUDE_PATH}" {var_init,var_gen_term}.mfs;
1017  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
1018  END_MFSCRIPT;
1019 END_SCOPE;
1020 */
1021 
1022 //----------------------------------------------------------------------------//
1023 // end of file
1024 //----------------------------------------------------------------------------//
module log_warn(m)
Output warning message to console.
Definition: console.scad:333
module log_echo(m)
Output message to console.
Definition: console.scad:272
module log_info(m)
Output information message to console.
Definition: console.scad:318
empty_str
<string> A string with no characters (the empty string).
Definition: constants.scad:301
empty_lst
<list> A list with no values (the empty list).
Definition: constants.scad:304
function headn(v, n=1)
Return a list containing all but the last n elements of an iterable value.
function last(v)
Return the last element of 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 tailn(v, n=1)
Return a list containing all but the first n elements of an iterable value.
function consts(l, v, u=false)
Create a list of constant or incrementing elements.
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 sum(v, i1, i2)
Compute the sum of a list of numbers.
function select_e(v, i, f, l)
Select each element at an index position of a list of iterable values.
function is_defined(v)
Test if a value is defined.
function is_number(v)
Test if a value is a number.
function ctable_exists(t, ri, ci)
Test the existence of a table row identifier, table column identifier, or both.
function table_get_size(r, c)
Get the size of a table.
function table_get_copy(r, c, rs, cs)
Create a new matrix from select rows and columns of a table.
function table_exists(r, c, ri, ci)
Test the existence of a table row identifier, table column identifier, or both.
module table_dump_getters(r, c, tr="table_rows", tc="table_cols", ri="ri", ci="ci", vri=false, vci=false, name="get_helper", append=false, comment=0, verbose=false)
Dump table getter functions to the console.
Definition: table.scad:767
function table_get_columns(r, c, ci)
Form a list of a select column across all table rows.
function table_get_row(r, ri)
Get the table row that matches a table row identifier.
function table_get_row_index(r, ri)
Get the table row index that matches a table row identifier.
function table_get_column_index(c, ci)
Get the table column index that matches a table column identifier.
module table_check(r, c, verbose=false)
Perform basic format checks on a table and output errors to console.
Definition: table.scad:595
module table_write(r, c, rs, cs, number=false, heading_id=true, heading_text=false, fs="^", thn="idx", index_tags=empty_lst, row_id_tags=["b"], value_tags=empty_lst)
Write formatted map entries to the console.
Definition: table.scad:1183
function table_get_sum(r, c, rs, cs)
Sum select rows and columns of a table.
function table_get_row_ids(r)
Form a list of all table row identifiers.
function ctable_get_size(t)
Get the size of a table.
function table_get_column_ids(c)
Form a list of all table column identifiers.
module table_dump(r, c, rs, cs, number=true)
Dump a table to the console.
Definition: table.scad:674
function table_get(r, c, ri, ci)
Get a row, a column, or a specific cell value from a table.
function table_errors(r, c)
Perform basic format checks on a table and return errors.
function ctable_errors(t)
Perform basic format checks on a table and return errors.
function ctable_get(t, ri, ci)
Get a row, a column, or a specific cell value from a table.
function table_get_column(c, ci)
Get the table column that matches a table column identifier.
function table_get_value(r, c, ri, ci)
Get the table cell value for a specified row and column identifier.