omdl  v0.9.5
OpenSCAD Mechanical Design Library
polytope.scad
Go to the documentation of this file.
1 //! Polygon and polyhedron tools.
2 /***************************************************************************//**
3  \file
4  \author Roy Allen Sutton
5  \date 2017-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 (Polytope)
31  \amu_define group_brief (Polygon and polyhedron tools.)
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_define includes_required_add
43  (
44  tools/align.scad
45  )
46  \amu_include (include/amu/includes_required.amu)
47 *******************************************************************************/
48 
49 //----------------------------------------------------------------------------//
50 
51 //! Label the vertices, paths, and edges of a polytope.
52 /***************************************************************************//**
53  \param c <coords-3d | coords-2d> A list of 3d or 2d coordinate points.
54  \param f <<integer-list>-list> A list of faces (or paths) that enclose
55  the shape where each face is a list of coordinate indexes.
56  \param e <<integer-list-2>-list> A list of edges where each edge is
57  a list of two coordinate indexes.
58 
59  \param vi <index> Vertex index. An index sequence [specification].
60  \param fi <index> Face index. An index sequence [specification].
61  \param ei <index> Edge index. An index sequence [specification].
62 
63  \param sp <boolean> Show polyhedron shape.
64 
65  \param ts <decimal> The text size override.
66  \param th <decimal> The text extrusion height override.
67 
68  \param to <vector-3d | vector-2d> The text offset override.
69  \param tr <decimal-list-1:3 | decimal> The text rotation (in degrees).
70 
71  \details
72 
73  Label the vertices, paths, and edges of a polytope. Parameter \p f
74  is optional for polygons. When it is not given, the listed order of
75  the coordinates \p c establishes the polygon path. When \p e is not
76  specified, it is computed from \p f using polytope_faces2edges().
77 
78  \amu_define scope_id (example_number)
79  \amu_define title (Numbering example)
80  \amu_define image_views (top front diag)
81  \amu_define image_size (sxga)
82 
83  \amu_include (include/amu/scope_diagrams_3d.amu)
84 
85  [specification]: \ref dt_index
86 *******************************************************************************/
87 module polytope_number
88 (
89  c,
90  f,
91  e,
92  vi = true,
93  fi = true,
94  ei = true,
95  sp = false,
96  ts,
97  th,
98  to,
99  tr = 0
100 )
101 {
102  fm = defined_or(f, [consts(len(c))]);
103  el = is_defined(e) ? e : polytope_faces2edges(fm);
104 
105  bb = polytope_limits(c=c, f=fm, s=true);
106  pd = len(bb);
107 
108  fs = defined_or(ts, ceil(max(bb)/50));
109  fh = defined_or(th, ceil(min(bb)/100));
110  fo = defined_or(to, [0, 0, fs/2]);
111 
112  // vertex
113  color("green")
114  for (i = index_gen(c, vi))
115  {
116  p = c[i];
117  n = polytope_vertex_normal(c, fm, i);
118 
119  translate(p)
120  orient_ll(r=is_nan(n) ? z_axis3d_uv : n)
121  translate(fo) rotate(tr)
122  if (pd == 3)
123  linear_extrude(fh, center=true)
124  text(str(i), size=fs, halign="center", valign="center");
125  else
126  text(str(i), size=fs, halign="center", valign="center");
127  }
128 
129  // face
130  color("red")
131  for (i = index_gen(fm, fi))
132  {
133  p = polytope_face_mean(c, l=fm[i]);
134  n = polytope_face_normal(c, l=fm[i]);
135 
136  translate(p)
137  orient_ll(r=is_nan(n) ? z_axis3d_uv : n)
138  translate(fo) rotate(tr)
139  if (pd == 3)
140  linear_extrude(fh, center=true)
141  text(str(i), size=fs, halign="center", valign="center");
142  else
143  text(str(i), size=fs, halign="center", valign="center");
144  }
145 
146  // edge
147  color("blue")
148  for (i = index_gen(el, ei))
149  {
150  p = mean([c[first(el[i])], c[second(el[i])]]);
151  n = polytope_edge_normal(c, fm, el, i);
152 
153  translate(p)
154  orient_ll(r=is_nan(n) ? z_axis3d_uv : n)
155  translate(fo) rotate(tr)
156  if (pd == 3)
157  linear_extrude(fh, center=true)
158  text(str(i), size=fs, halign="center", valign="center");
159  else
160  text(str(i), size=fs, halign="center", valign="center");
161  }
162 
163  // shape
164  if (sp == true)
165  {
166  if (pd == 3)
167  polyhedron(c, fm);
168 
169  if (pd == 2)
170  polygon(c, fm);
171  }
172 }
173 
174 //! Assemble a polytope skeletal frame using child objects.
175 /***************************************************************************//**
176  \param c <coords-3d | coords-2d> A list of 3d or 2d coordinate points.
177  \param f <<integer-list>-list> A list of faces (or paths) that enclose
178  the shape where each face is a list of coordinate indexes.
179  \param e <<integer-list-2>-list> A list of edges where each edge is
180  a list of two coordinate indexes.
181 
182  \param vi <index> Vertex index. An index sequence [specification].
183  \param fi <index> Face index. An index sequence [specification].
184  \param ei <index> Edge index. An index sequence [specification].
185 
186  \param vc <integer> Vertex child object index.
187  \param fc <integer> Face child object index.
188  \param ec <integer> Edge child object index.
189 
190  \details
191 
192  Construct a skeletal frame for a given polytope. A 2d child object
193  is linearly extruded along specified edges of the polytope to form
194  the frame. Additional 3d child objects can be centered on specified
195  vertices and/or the mean coordinates of specified faces.
196 
197  To disable a child assignment to the vertices, faces, or edges, use
198  an index that is less than zero or greater than the number of
199  children. Parameter \p f is optional for polygons. When it is not
200  given, the listed order of the coordinates \p c establishes the
201  polygon path. When \p e is not specified, it is computed from \p f
202  using polytope_faces2edges().
203 
204  \amu_define scope_id (example_frame_a)
205  \amu_define title (A. Framing example)
206  \amu_define image_views (top right diag)
207  \amu_define image_size (sxga)
208 
209  \amu_include (include/amu/scope_diagrams_3d.amu)
210 
211  \amu_define scope_id (example_frame_b)
212  \amu_define title (B. Framing example)
213  \amu_define image_views (diag)
214  \amu_define image_size (sxga)
215 
216  \amu_include (include/amu/scope_diagrams_3d.amu)
217 
218  [specification]: \ref dt_index
219 *******************************************************************************/
220 module polytope_frame
221 (
222  c,
223  f,
224  e,
225  vi = true,
226  fi = true,
227  ei = true,
228  vc = 1,
229  fc = 2,
230  ec = 0
231 )
232 {
233  fm = defined_or(f, [consts(len(c))]);
234  el = is_defined(e) ? e : polytope_faces2edges(fm);
235 
236  // vertex
237  if (is_between(vc, 0, $children-1) && ($children > 0))
238  {
239  for (i = index_gen(c, vi))
240  {
241  p = c[i];
242  n = polytope_vertex_normal(c, fm, i);
243 
244  translate(p)
245  orient_ll(r=is_nan(n) ? z_axis3d_uv : n)
246  children(vc);
247  }
248  }
249 
250  // face
251  if (is_between(fc, 0, $children-1) && ($children > 0))
252  {
253  for (i = index_gen(fm, fi))
254  {
255  p = polytope_face_mean(c, l=fm[i]);
256  n = polytope_face_normal(c, l=fm[i]);
257 
258  translate(p)
259  orient_ll(r=is_nan(n) ? z_axis3d_uv : n)
260  children(fc);
261  }
262  }
263 
264  // edge
265  if (is_between(ec, 0, $children-1) && ($children > 0))
266  {
267  for (i = index_gen(el, ei))
268  {
269  p1 = point_to_3d(c[first(el[i])]); // 3d points required for
270  p2 = point_to_3d(c[second(el[i])]); // polygons.
271 
272  translate((p1+p2)/2)
273  orient_ll(r=[p1, p2])
274  linear_extrude(distance_pp(p1, p2), center=true)
275  children(ec);
276  }
277  }
278 }
279 
280 //! The 3d or 2d bounding box shape for a polytope.
281 /***************************************************************************//**
282  \param c <coords-3d | coords-2d> A list of 3d or 2d coordinate points.
283  \param f <<integer-list>-list> A list of faces (or paths) that enclose
284  the shape where each face is a list of coordinate indexes.
285  \param a <decimal-list-1:3 | decimal> The box padding. A list of
286  lengths to equally pad the box dimensions.
287 
288  \details
289 
290  Generates: (1) the 3d box shape that completely encloses the
291  defined 3d polyhedron with the box sides oriented parallel to the
292  coordinate axes. Or: (2) the 2d box shape that exactly encloses the
293  defined 2d polygon with the box sides oriented parallel to the
294  coordinate axes. When \p f is not given, the listed order of the
295  coordinates \p c establishes the path.
296 
297  \amu_define scope_id (example_bbox)
298  \amu_define title (Bounding box example)
299  \amu_define image_views (top front diag)
300  \amu_define image_size (sxga)
301 
302  \amu_include (include/amu/scope_diagrams_3d.amu)
303 
304  \sa polytope_limits for warning about secondary shapes.
305 *******************************************************************************/
307 (
308  c,
309  f,
310  a
311 )
312 {
313  b = polytope_limits(c=c, f=f, a=a, s=false);
314  d = len(b);
315 
316  if (d == 3)
317  translate([b[0][0], b[1][0], b[2][0]])
318  cube([b[0][1]-b[0][0], b[1][1]-b[1][0], b[2][1]-b[2][0]]);
319  else
320  translate([b[0][0], b[1][0]])
321  square([b[0][1]-b[0][0], b[1][1]-b[1][0]]);
322 }
323 
324 //! @}
325 //! @}
326 
327 //----------------------------------------------------------------------------//
328 // openscad-amu auxiliary scripts
329 //----------------------------------------------------------------------------//
330 
331 /*
332 BEGIN_SCOPE example_number;
333  BEGIN_OPENSCAD;
334  include <omdl-base.scad>;
335  include <tools/align.scad>;
336  include <units/coordinate.scad>;
337  include <database/geometry/polyhedra/johnson.scad>;
338  include <tools/polytope.scad>;
339 
340  tc = dtc_polyhedra_johnson;
341  tr = dtr_polyhedra_johnson;
342  id = "metagyrate_diminished_rhombicosidodecahedron";
343 
344  c = table_get_value(tr, tc, id, "c");
345  f = table_get_value(tr, tc, id, "f");
346  v = coordinate_scale3d_csc(c, 100);
347 
348  polytope_number(v, f, sp=true, $fn = 36);
349 
350  // end_include
351  END_OPENSCAD;
352 
353  BEGIN_MFSCRIPT;
354  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
355  table_unset_all sizes;
356 
357  images name "sizes" types "sxga";
358  views name "views" views "top front diag";
359 
360  variables set_opts_combine "sizes views";
361  variables add_opts "--viewall --autocenter --view=axes";
362 
363  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
364  END_MFSCRIPT;
365 END_SCOPE;
366 
367 BEGIN_SCOPE example_frame_a;
368  BEGIN_OPENSCAD;
369  include <omdl-base.scad>;
370  include <tools/align.scad>;
371  include <units/coordinate.scad>;
372  include <database/geometry/polyhedra/cupolas.scad>;
373  include <tools/polytope.scad>;
374 
375  tc = dtc_polyhedra_cupolas;
376  tr = dtr_polyhedra_cupolas;
377  id = "pentagonal_cupola";
378 
379  c = table_get_value(tr, tc, id, "c");
380  f = table_get_value(tr, tc, id, "f");
381 
382  v1 = coordinate_scale3d_csc(c, 100);
383  v2 = coordinate_scale3d_csc(c, 100, true);
384 
385  repeat_grid(2, 225, center=true, $fn=36)
386  {
387  polytope_frame(v1, f) {circle(r=4); color("grey") sphere(r=6);}
388  polytope_frame(v2, f) {circle(r=4); color("grey") sphere(r=6);}
389  }
390 
391  // end_include
392  END_OPENSCAD;
393 
394  BEGIN_MFSCRIPT;
395  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
396  table_unset_all sizes;
397 
398  images name "sizes" types "sxga";
399  views name "views" views "top right diag";
400 
401  variables set_opts_combine "sizes views";
402  variables add_opts "--viewall --autocenter --view=axes";
403 
404  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
405  END_MFSCRIPT;
406 END_SCOPE;
407 
408 BEGIN_SCOPE example_frame_b;
409  BEGIN_OPENSCAD;
410  include <omdl-base.scad>;
411  include <tools/align.scad>;
412  include <units/coordinate.scad>;
413  include <database/geometry/polyhedra/archimedean.scad>;
414  include <tools/polytope.scad>;
415 
416  tc = dtc_polyhedra_archimedean;
417  tr = dtr_polyhedra_archimedean;
418  id = "truncated_cuboctahedron";
419 
420  c = table_get_value(tr, tc, id, "c");
421  f = table_get_value(tr, tc, id, "f");
422  v = coordinate_scale3d_csc(c, 100);
423 
424  polytope_frame(v, f, fi="even", $fn = 36)
425  {
426  circle(r=2);
427  color("grey") sphere(r=4);
428  color("red") star3d(20);
429  }
430 
431  polytope_frame(v, f, fi="odd", fc=0, vc=-1, ec=-1)
432  color("blue") star3d(20);
433 
434  %polyhedron(v, f);
435 
436  // end_include
437  END_OPENSCAD;
438 
439  BEGIN_MFSCRIPT;
440  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
441  table_unset_all sizes;
442 
443  images name "sizes" types "sxga";
444  views name "views" views "diag";
445 
446  variables set_opts_combine "sizes views";
447  variables add_opts "--viewall --autocenter --view=axes";
448 
449  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
450  END_MFSCRIPT;
451 END_SCOPE;
452 
453 BEGIN_SCOPE example_bbox;
454  BEGIN_OPENSCAD;
455  include <omdl-base.scad>;
456  include <database/geometry/polyhedra/archimedean.scad>;
457  include <tools/polytope.scad>;
458 
459  tc = dtc_polyhedra_archimedean;
460  tr = dtr_polyhedra_archimedean;
461  id = "truncated_cuboctahedron";
462 
463  c = table_get_value(tr, tc, id, "c");
464  f = table_get_value(tr, tc, id, "f");
465 
466  polyhedron(c, f);
467  %polytope_bounding_box(c,f );
468 
469  // end_include
470  END_OPENSCAD;
471 
472  BEGIN_MFSCRIPT;
473  include --path "${INCLUDE_PATH}" {var_init,var_gen_png2eps}.mfs;
474  table_unset_all sizes;
475 
476  images name "sizes" types "sxga";
477  views name "views" views "top front diag";
478 
479  variables set_opts_combine "sizes views";
480  variables add_opts "--viewall --autocenter --view=axes";
481 
482  include --path "${INCLUDE_PATH}" scr_make_mf.mfs;
483  END_MFSCRIPT;
484 END_SCOPE;
485 
486 */
487 
488 //----------------------------------------------------------------------------//
489 // end of file
490 //----------------------------------------------------------------------------//
z_axis3d_uv
<vector-3d> The unit vector of the positive z-axis in 3d Euclidean space.
Definition: constants.scad:434
function point_to_3d(p)
Return 3d point unchanged or add a zeroed third dimension to 2d point.
function distance_pp(p1, p2)
Compute the distance between two points.
function second(v)
Return the second element of an iterable value.
function first(v)
Return the first element of an iterable value.
function index_gen(l, s=true, rs)
Create a element selection index list for a given list of values.
function mean(v)
Compute the mean/average of a list of numbers.
function consts(l, v, u=false)
Create a list of constant or incrementing elements.
function defined_or(v, d)
Return given value, if defined, or a secondary value, if primary is not defined.
function is_nan(v)
Test if a numerical value is 'nan' (not a number).
function is_between(v, l, u)
Test if a numerical value is between an upper and lower bounds.
function is_defined(v)
Test if a value is defined.
function polytope_edge_normal(c, f, e, i)
Get a normal vector for a polytope edge.
function polytope_faces2edges(f)
List the edge coordinate index pairs of a polytope.
function polytope_face_normal(c, f, i, l, cw=true)
Get the normal vector of a polytope face.
function polytope_face_mean(c, f, i, l)
Get the mean coordinate of all vertices of a polytope face.
function polytope_limits(c, f, a, d, s=true)
Determine the bounding limits of a polytope.
function polytope_vertex_normal(c, f, i)
Get a normal vector for a polytope vertex.
module orient_ll(l=z_axis3d_ul, r=z_axis3d_ul, ar=0)
Orient a line or vector to a reference line or vector.
Definition: align.scad:164
module polytope_number(c, f, e, vi=true, fi=true, ei=true, sp=false, ts, th, to, tr=0)
Label the vertices, paths, and edges of a polytope.
Definition: polytope.scad:348
module polytope_bounding_box(c, f, a)
The 3d or 2d bounding box shape for a polytope.
Definition: polytope.scad:1029
module polytope_frame(c, f, e, vi=true, fi=true, ei=true, vc=1, fc=2, ec=0)
Assemble a polytope skeletal frame using child objects.
Definition: polytope.scad:789