omdl  v0.6.1
OpenSCAD Mechanical Design Library
tools_polytope.scad
Go to the documentation of this file.
1 //! Polygon and polyhedron tools.
2 /***************************************************************************//**
3  \file tools_polytope.scad
4  \author Roy Allen Sutton
5  \date 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 tools tools_polytope
31 *******************************************************************************/
32 
33 include <../math/math_polytope.scad>;
34 include <tools_align.scad>;
35 
36 //----------------------------------------------------------------------------//
37 /***************************************************************************//**
38  \addtogroup tools
39  @{
40 
41  \defgroup tools_polytope Polytope
42  \brief Polygon and polyhedron tools.
43  @{
44 *******************************************************************************/
45 //----------------------------------------------------------------------------//
46 
47 //! Label the vertices, paths, and edges of a polytope.
48 /***************************************************************************//**
49  \param c <coords-3d|coords-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  \note Parameter \p f is optional for polygons. When it is not
70  given, the listed order of the coordinates \p c establishes
71  the polygon path.
72  \note When \p e is not specified, it is computed from \p f using
73  polytope_faces2edges().
74 
75  [specification]: \ref dt_index
76 *******************************************************************************/
77 module polytope_number
78 (
79  c,
80  f,
81  e,
82  vi = true,
83  fi = true,
84  ei = true,
85  sp = false,
86  ts,
87  th,
88  to,
89  tr = 0
90 )
91 {
92  fm = defined_or(f, [consts(len(c))]);
93  el = is_defined(e) ? e : polytope_faces2edges(fm);
94 
95  bb = polytope_limits(c, fm, d=[0:2], s=true);
96  pd = all_defined(bb) ? 3 : 2;
97 
98  fs = defined_or(ts, ceil(max(bb)/50));
99  fh = defined_or(th, ceil(min(bb)/100));
100  fo = defined_or(to, [0, 0, fs/2]);
101 
102  // vertex
103  color("green")
104  for (i = get_index(c, vi))
105  {
106  p = c[i];
107  n = polytope_vertex_n(c, fm, i);
108 
109  translate(p)
110  orient_ll(rl=n)
111  translate(fo) rotate(tr)
112  if (pd == 3)
113  linear_extrude(fh, center=true)
114  text(str(i), size=fs, halign="center", valign="center");
115  else
116  text(str(i), size=fs, halign="center", valign="center");
117  }
118 
119  // face
120  color("red")
121  for (i = get_index(fm, fi))
122  {
123  p = polytope_face_m(c, l=fm[i]);
124  n = polytope_face_n(c, l=fm[i]);
125 
126  translate(p)
127  orient_ll(rl=n)
128  translate(fo) rotate(tr)
129  if (pd == 3)
130  linear_extrude(fh, center=true)
131  text(str(i), size=fs, halign="center", valign="center");
132  else
133  text(str(i), size=fs, halign="center", valign="center");
134  }
135 
136  // edge
137  color("blue")
138  for (i = get_index(el, ei))
139  {
140  p = mean([c[first(el[i])], c[second(el[i])]]);
141  n = polytope_edge_n(c, fm, el, i);
142 
143  translate(p)
144  orient_ll(rl=n)
145  translate(fo) rotate(tr)
146  if (pd == 3)
147  linear_extrude(fh, center=true)
148  text(str(i), size=fs, halign="center", valign="center");
149  else
150  text(str(i), size=fs, halign="center", valign="center");
151  }
152 
153  // shape
154  if (sp == true)
155  {
156  if (pd == 3)
157  polyhedron(c, fm);
158 
159  if (pd == 2)
160  polygon(c, fm);
161  }
162 }
163 
164 //! Assemble a polytope skeletal frame using child objects.
165 /***************************************************************************//**
166  \param c <coords-3d|coords-2d> A list of 3d or 2d coordinate points.
167  \param f <integer-list-list> A list of faces (or paths) that enclose
168  the shape where each face is a list of coordinate indexes.
169  \param e <integer-list-2-list> A list of edges where each edge is
170  a list of two coordinate indexes.
171 
172  \param vi <index> Vertex index. An index sequence [specification].
173  \param fi <index> Face index. An index sequence [specification].
174  \param ei <index> Edge index. An index sequence [specification].
175 
176  \param vc <integer> Vertex child index.
177  \param fc <integer> Face child index.
178  \param ec <integer> Edge child index.
179 
180  \details
181 
182  This function constructs a skeletal frame for a given polytope. A
183  2d child object is linearly extruded along specified edges of the
184  polytope to form the frame. Additional 3d child objects can be
185  centered on specified vertices and/or the mean coordinates of
186  specified faces.
187 
188  \b Example
189 
190  \code{.c}
191  include <tools/tools_polytope.scad>;
192 
193  s = second(xy_plane_os) * 25;
194  p = linear_extrude_pp2pf(s, h=50);
195 
196  polytope_frame(first(p), second(p))
197  {
198  circle(r=2);
199  color("grey") sphere(r=4);
200  color("blue") cube(4);
201  }
202  \endcode
203 
204  \note To disable a child assignment to the vertices, faces, or
205  edges, use an index that is less than zero or greater than
206  the number of children.
207  \note Parameter \p f is optional for polygons. When it is not
208  given, the listed order of the coordinates \p c establishes
209  the polygon path.
210  \note When \p e is not specified, it is computed from \p f using
211  polytope_faces2edges().
212 
213  [specification]: \ref dt_index
214 *******************************************************************************/
215 module polytope_frame
216 (
217  c,
218  f,
219  e,
220  vi = true,
221  fi = true,
222  ei = true,
223  vc = 1,
224  fc = 2,
225  ec = 0
226 )
227 {
228  fm = defined_or(f, [consts(len(c))]);
229  el = is_defined(e) ? e : polytope_faces2edges(fm);
230 
231  // vertex
232  if (is_between(vc, 0, $children-1) && ($children > 0))
233  {
234  for (i = get_index(c, vi))
235  {
236  p = c[i];
237  n = polytope_vertex_n(c, fm, i);
238 
239  translate(p)
240  orient_ll(rl=n)
241  children(vc);
242  }
243  }
244 
245  // face
246  if (is_between(fc, 0, $children-1) && ($children > 0))
247  {
248  for (i = get_index(fm, fi))
249  {
250  p = polytope_face_m(c, l=fm[i]);
251  n = polytope_face_n(c, l=fm[i]);
252 
253  translate(p)
254  orient_ll(rl=n)
255  children(fc);
256  }
257  }
258 
259  // edge
260  if (is_between(ec, 0, $children-1) && ($children > 0))
261  {
262  for (i = get_index(el, ei))
263  {
264  p1 = dimension_2to3_v(c[first(el[i])]); // 3d points required for
265  p2 = dimension_2to3_v(c[second(el[i])]); // polygons.
266 
267  translate((p1+p2)/2)
268  orient_ll(rl=[p1, p2])
269  linear_extrude(distance_pp(p1, p2), center=true)
270  children(ec);
271  }
272  }
273 }
274 
275 //! The 3d or 2d bounding box shape for a polytope.
276 /***************************************************************************//**
277  \param c <coords-3d|coords-2d> A list of 3d or 2d cartesian
278  coordinates [[x, y (, z)], ...].
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.
282  A list of 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.
291 
292  \note When \p f is not given, the listed order of the coordinates
293  \p c establishes the path.
294 
295  \sa polytope_limits for warning about secondary shapes.
296 *******************************************************************************/
297 module polytope_bbox
298 (
299  c,
300  f,
301  a
302 )
303 {
304  b = polytope_limits(c=c, f=f, a=a, d=[0:2], s=false);
305  d = len([for (i=b) if (i != [undef, undef]) i]);
306 
307  if (d == 3)
308  translate([b[0][0], b[1][0], b[2][0]])
309  cube([b[0][1]-b[0][0], b[1][1]-b[1][0], b[2][1]-b[2][0]]);
310  else
311  translate([b[0][0], b[1][0]])
312  square([b[0][1]-b[0][0], b[1][1]-b[1][0]]);
313 }
314 
315 //! @}
316 //! @}
317 
318 //----------------------------------------------------------------------------//
319 // end of file
320 //----------------------------------------------------------------------------//
function distance_pp(p1, p2)
Compute the distance between two Euclidean points.
function polytope_edge_n(c, f, e, i)
Get a normal vector for a polytope edge.
function mean(v)
Compute the mean/average of a list of numbers.
function polytope_vertex_n(c, f, i)
Get a normal vector for a polytope vertex.
module orient_ll(l=z_axis3d_ul, rl=z_axis3d_ul, r=0)
Orient a line or vector to a reference line or vector.
function defined_or(v, d)
Return a value when it is defined or a default value when it is not.
function dimension_2to3_v(v)
Return 3d vector unchanged or add a zeroed third dimension to 2d vector.
function second(v)
Return the second element of an iterable value.
function all_defined(v)
Test if no element of a list of values is undefined.
function polytope_face_m(c, f, i, l)
Get the mean coordinate of all vertices of a polytope face.
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.
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.
function is_defined(v)
Test if a value is defined.
function first(v)
Return the first element of an iterable value.
function polytope_faces2edges(f)
List the edge coordinate index pairs of a polytope.
function get_index(l, s=true, rs)
Create a sequence for a list index sequence specification.
function is_between(v, l, u)
Test if a numerical value is between an upper and lower bounds.
function consts(l, v, u=false)
Create a sequence of constant or incrementing elements.
function polytope_face_n(c, f, i, l, cw=true)
Get the normal vector of a polytope face.
module polytope_bbox(c, f, a)
The 3d or 2d bounding box shape for a polytope.
function polytope_limits(c, f, a, d=[0:2], s=true)
Determine the bounding limits of a polytope.