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