omdl  v0.5
OpenSCAD Mechanical Design Library
resolution.scad
Go to the documentation of this file.
1 //! Arc rendering resolution abstraction.
2 /***************************************************************************//**
3  \file resolution.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  \note Include this library file using the \b include statement.
31 
32  \todo Review model for accuracy.
33 
34  \ingroup units units_resolution
35 *******************************************************************************/
36 
37 use <console.scad>;
38 include <constants.scad>;
39 include <units_length.scad>;
40 
41 //----------------------------------------------------------------------------//
42 /***************************************************************************//**
43  \addtogroup units
44  @{
45 
46  \defgroup units_resolution Resolution
47  \brief Arch rendering resolution management.
48 
49  \details
50 
51  Functions, global variables, and configuration presets to provide a
52  common mechanism for managing arc rendering resolution.
53  Specifically, the number of fragments/facets with which arcs
54  (circles, spheres, and cylinders, etc.) are rendered in OpenSCAD.
55 
56  \b Example
57 
58  \dontinclude resolution_example.scad
59  \skip include
60  \until f));
61 
62  \b Result (base_unit_length = \b mm): \include resolution_example_mm.log
63  \b Result (base_unit_length = \b cm): \include resolution_example_cm.log
64  \b Result (base_unit_length = \b mil): \include resolution_example_mil.log
65  \b Result (base_unit_length = \b in): \include resolution_example_in.log
66 
67  @{
68 *******************************************************************************/
69 //----------------------------------------------------------------------------//
70 
71 //! <string> Global special variable that configures the arc resolution mode.
73 
74 //! <decimal> Global special variable for modes that use custom resolutions.
76 
77 //! Return facets number for the given arc radius.
78 /***************************************************************************//**
79  \param radius <decimal> An arc radius.
80  \returns <decimal> The number of facets to be assigned to $fn.
81 
82  \details
83 
84  The return result of this function can be assigned to the special
85  variables \p $fn to render arcs according to the resolution mode set
86  by \ref $resolution_mode and \ref $resolution_value.
87 
88  The following table shows the modes that require \ref $resolution_value
89  to be set prior to specify the custom values used during resolution
90  calculation.
91 
92  $resolution_mode | $resolution_value sets | radius dependent
93  :----------------:|:----------------------:|:----------------:
94  set | fixed value | no
95  upf | units per facet | yes
96  fpu | facets per unit | yes
97  fpi | facets per inch | yes
98 
99  The following table has common resolution presets. Equivalent
100  configuration can be obtained using \ref resolution_mode and
101  \ref resolution_value as described in the preview table.
102 
103  $resolution_mode | preset description | radius dependent
104  :----------------:|:--------------------------|:----------------:
105  fast | fast rendering mode | no
106  low | low resolution | yes
107  medium | medium resolution | yes
108  high | high resolution | yes
109  50um | 50 micron per facets | yes
110  100um | 100 micron per facets | yes
111  200um | 200 micron per facets | yes
112  300um | 300 micron per facets | yes
113  400um | 400 micron per facets | yes
114  500um | 500 micron per facets | yes
115  50mil | 50 thousandth per facets | yes
116  100mil | 100 thousandth per facets | yes
117  200mil | 200 thousandth per facets | yes
118  300mil | 300 thousandth per facets | yes
119  400mil | 400 thousandth per facets | yes
120  500mil | 500 thousandth per facets | yes
121 *******************************************************************************/
122 function resolution_fn
123 (
124  radius
125 ) = $resolution_mode == "set"
126  ? ceil(max(3, $resolution_value))
127 
128  // custom resolutions
129  : $resolution_mode == "upf"
130  ? ceil(max(3, radius*tau / $resolution_value))
131  : $resolution_mode == "fpu"
132  ? ceil(max(3, radius*tau * $resolution_value))
133  : $resolution_mode == "fpi"
134  ? ceil(max(3, unit_length_convert(radius, to="in")*tau * $resolution_value))
135 
136  // common resolutions per unit (base_units)
137  : $resolution_mode == "fast"
138  ? 18
139  : $resolution_mode == "low"
140  ? ceil(max(3, radius*tau * 1))
141  : $resolution_mode == "medium"
142  ? ceil(max(3, radius*tau * 10))
143  : $resolution_mode == "high"
144  ? ceil(max(3, radius*tau * 100))
145 
146  // common resolutions in microns
147  : $resolution_mode == "50um"
148  ? ceil(max(3, radius*tau / unit_length_convert( 50, "um")))
149  : $resolution_mode == "100um"
150  ? ceil(max(3, radius*tau / unit_length_convert( 100, "um")))
151  : $resolution_mode == "200um"
152  ? ceil(max(3, radius*tau / unit_length_convert( 200, "um")))
153  : $resolution_mode == "300um"
154  ? ceil(max(3, radius*tau / unit_length_convert( 300, "um")))
155  : $resolution_mode == "400um"
156  ? ceil(max(3, radius*tau / unit_length_convert( 400, "um")))
157  : $resolution_mode == "500um"
158  ? ceil(max(3, radius*tau / unit_length_convert( 500, "um")))
159 
160  // common resolutions in thousands
161  : $resolution_mode == "50mil"
162  ? ceil(max(3, radius*tau / unit_length_convert( 50, "mil")))
163  : $resolution_mode == "100mil"
164  ? ceil(max(3, radius*tau / unit_length_convert( 100, "mil")))
165  : $resolution_mode == "200mil"
166  ? ceil(max(3, radius*tau / unit_length_convert( 200, "mil")))
167  : $resolution_mode == "300mil"
168  ? ceil(max(3, radius*tau / unit_length_convert( 300, "mil")))
169  : $resolution_mode == "400mil"
170  ? ceil(max(3, radius*tau / unit_length_convert( 400, "mil")))
171  : $resolution_mode == "500mil"
172  ? ceil(max(3, radius*tau / unit_length_convert( 500, "mil")))
173 
174  // otherwise
175  : undef;
176 
177 //! Return minimum facets size.
178 /***************************************************************************//**
179  \returns <decimal> Minimum facet size to be assigned to $fs.
180 
181  \details
182 
183  The return result of this function can be assigned to the OpenSCAD
184  special variables \p $fs to render arcs according to the resolution
185  mode set by \ref $resolution_mode and \ref $resolution_value.
186 
187  The following table shows the modes that require \ref $resolution_value
188  to be set prior to calling this function in order to specify the
189  custom values used during resolution calculation.
190 
191  $resolution_mode | $resolution_value sets | radius dependent
192  :----------------:|:----------------------:|:----------------:
193  set | fixed value | no
194  upf | units per facet | no
195  fpu | facets per unit | no
196  fpi | facets per inch | no
197 
198  The following table has common resolution presets. Equivalent
199  configuration can be obtained using \ref resolution_mode and
200  \ref resolution_value as described in the preview table.
201 
202  $resolution_mode | preset description | radius dependent
203  :----------------:|:--------------------------|:----------------:
204  fast | fast rendering mode | no
205  low | low resolution | no
206  medium | medium resolution | no
207  high | high resolution | no
208  50um | 50 micron per facets | no
209  100um | 100 micron per facets | no
210  200um | 200 micron per facets | no
211  300um | 300 micron per facets | no
212  400um | 400 micron per facets | no
213  500um | 500 micron per facets | no
214  50mil | 50 thousandth per facets | no
215  100mil | 100 thousandth per facets | no
216  200mil | 200 thousandth per facets | no
217  300mil | 300 thousandth per facets | no
218  400mil | 400 thousandth per facets | no
219  500mil | 500 thousandth per facets | no
220 *******************************************************************************/
221 function resolution_fs ( )
222  // OpenSCAD's minimum allowed value for $fa and $fs is 0.01
223  = $resolution_mode == "set"
224  ? max(0.01, $resolution_value)
225 
226  // custom resolutions
227  : $resolution_mode == "upf"
228  ? max(0.01, $resolution_value)
229  : $resolution_mode == "fpu"
230  ? max(0.01, 1 / $resolution_value)
231  : $resolution_mode == "fpi"
232  ? max(0.01, unit_length_convert(1, "in") / $resolution_value)
233 
234  // common resolutions per unit (base_units)
235  : $resolution_mode == "fast"
236  ? 10
237  : $resolution_mode == "low"
238  ? 1/001
239  : $resolution_mode == "medium"
240  ? 1/010
241  : $resolution_mode == "high"
242  ? 1/100
243 
244  // common resolutions in microns
245  : $resolution_mode == "50um"
246  ? unit_length_convert( 50, "um")
247  : $resolution_mode == "100um"
248  ? unit_length_convert( 100, "um")
249  : $resolution_mode == "200um"
250  ? unit_length_convert( 200, "um")
251  : $resolution_mode == "300um"
252  ? unit_length_convert( 300, "um")
253  : $resolution_mode == "400um"
254  ? unit_length_convert( 400, "um")
255  : $resolution_mode == "500um"
256  ? unit_length_convert( 500, "um")
257 
258  // common resolutions in thousands
259  : $resolution_mode == "50mil"
260  ? unit_length_convert( 50, "mil")
261  : $resolution_mode == "100mil"
262  ? unit_length_convert( 100, "mil")
263  : $resolution_mode == "200mil"
264  ? unit_length_convert( 200, "mil")
265  : $resolution_mode == "300mil"
266  ? unit_length_convert( 300, "mil")
267  : $resolution_mode == "400mil"
268  ? unit_length_convert( 400, "mil")
269  : $resolution_mode == "500mil"
270  ? unit_length_convert( 500, "mil")
271 
272  // otherwise
273  : undef;
274 
275 //! Return the minimum facets angle.
276 /***************************************************************************//**
277  \param radius <decimal> An arc radius.
278  \returns <decimal> Minimum facet angle to be assigned to $fa.
279 
280  \details
281 
282  The return result of this function can be assigned to the OpenSCAD
283  special variables \p $fa to render arcs.
284 *******************************************************************************/
285 function resolution_fa
286 (
287  radius
288 ) = max(0.01, (360*$fs)/(tau*radius));
289 
290 //! Return the radius at which arc resolution will begin to degrade.
291 /***************************************************************************//**
292  \returns <decimal> Transition radius where resolution reduction begins.
293 
294  \details
295 
296  The OpenSCAD special variables \p $fs and \p $fa work together when
297  \p $fn=0. For a given \p $fs, the fragment angle of a drawn arc gets
298  smaller with increasing radius. In other words, the fragment angle is
299  inversely proportional to the arc radius for a given fragment size.
300  The special variable \p $fa enforces a minimum fragment angle limit
301  and at some radius, the fragment angle would becomes smaller than this
302  limit. At this point, OpenSCAD limits further reduction in the facet
303  angle which forces the use of increased fragment size. This in effect
304  begins the gradual reduction of arc resolution with increasing radius.
305 
306  The return result of this function indicates the radius at which this
307  enforced limiting begins. When \p $fn != 0, returns \b 'undef'.
308 *******************************************************************************/
309 function resolution_reduced ( )
310  = ($fn == 0.0)
311  ? (360*$fs)/(tau*$fa)
312  : undef;
313 
314 //! Echo resolution information to the console for given radius.
315 /***************************************************************************//**
316  \param radius <decimal> An arc radius.
317 *******************************************************************************/
318 module resolution_info
319 (
320  radius
321 )
322 {
323  log_echo
324  (
325  str
326  (
327  "$resolution_mode = [", $resolution_mode,
328  "], $resolution_value = ", $resolution_value,
329  ", base_unit_length = ", unit_length_name()
330  )
331  );
332 
333  log_echo
334  (
335  str
336  (
337  "$fn = ", $fn,
338  ", $fa = ", $fa,
339  ", $fs = ", $fs
340  )
341  );
342 
343  if ($fn == 0.0)
344  log_echo
345  (
346  str
347  (
348  "resolution reduction at radius > ",
350  )
351  );
352 
353  if ($fn > 0.0)
354  log_echo
355  (
356  str
357  (
358  "for radius = ", radius, " ", unit_length_name()," facets limited to ",
359  max(3, $fn), " by $fn=", $fn
360  )
361  );
362  else if (360.0/$fa < radius*tau/$fs)
363  log_echo
364  (
365  str
366  (
367  "for radius = ", radius, " ", unit_length_name()," facets limited to ",
368  max(5, ceil(360.0/$fa)), " by $fa=", $fa
369  )
370  );
371  else
372  log_echo
373  (
374  str
375  (
376  "for radius = ", radius, " ", unit_length_name()," facets limited to ",
377  max(5, ceil(radius*tau/$fs)), " by $fs=", $fs, " ", unit_length_name()
378  )
379  );
380 }
381 
382 //! Return facet count used to render a radius.
383 /***************************************************************************//**
384  \param radius <decimal> An arc radius.
385  \returns <decimal> The number of fragments/facets that will be used to
386  render a radius given the current values for \p $fn, \p $fa,
387  and \p $fs.
388 *******************************************************************************/
389 function resolution_facets
390 (
391  radius
392 ) = ($fn > 0.0) ? max(3, $fn)
393  : (360.0/$fa < radius*tau/$fs) ? max(5, ceil(360.0/$fa))
394  : max(5, ceil(radius*tau/$fs));
395 
396 //! Return facet count used to render a radius as vector triple.
397 /***************************************************************************//**
398  \param radius <decimal> An arc radius.
399  \returns A vector triple:
400  [\b facets <decimal>,\b limiter <string>,\b value <decimal>].
401 
402  \details
403 
404  Where \p facets is the number of fragments/facets that will be used to
405  render the \p radius given the current values for \p $fn, \p $fa, and
406  \p $fs. \p limiter identifies the special variable that currently limits
407  the facets, and \p value is the current value assigned to the limiter.
408 *******************************************************************************/
409 function resolution_facetsv
410 (
411  radius
412 ) = ($fn > 0.0) ? [max(3, $fn), "$fn", $fn]
413  : (360.0/$fa < radius*tau/$fs) ? [max(5, ceil(360.0/$fa)), "$fa", $fa]
414  : [max(5, ceil(radius*tau/$fs)), "$fs", $fs ];
415 
416 //! @}
417 //! @}
418 
419 //----------------------------------------------------------------------------//
420 // openscad-amu auxiliary scripts
421 //----------------------------------------------------------------------------//
422 
423 /*
424 BEGIN_SCOPE example;
425  BEGIN_OPENSCAD;
426  include <resolution.scad>;
427 
428  base_unit_length = "in";
429 
430  // set resolution to 25 fpi
431  $resolution_mode = "fpi";
432  $resolution_value = 25;
433 
434  // use radius length of 1 inch
435  r = convert_length(1, "in");
436 
437  $fs=resolution_fs();
438  $fa=resolution_fa( r );
439 
440  resolution_info( r );
441 
442  f = resolution_facets( r );
443  echo(str("for r = ", r, " ", unit_length_name(), ", facets = ", f));
444  END_OPENSCAD;
445 
446  BEGIN_MFSCRIPT;
447  include --path "${INCLUDE_PATH}" {config_base,config_csg}.mfs;
448 
449  defines name "units" define "base_unit_length" strings "mm cm mil in";
450  variables add_opts_combine "units";
451 
452  include --path "${INCLUDE_PATH}" script_std.mfs;
453  END_MFSCRIPT;
454 END_SCOPE;
455 */
456 
457 //----------------------------------------------------------------------------//
458 // end of file
459 //----------------------------------------------------------------------------//
function resolution_fn(radius)
Return facets number for the given arc radius.
module resolution_info(radius)
Echo resolution information to the console for given radius.
function resolution_fa(radius)
Return the minimum facets angle.
tau
The ratio of a circle's circumference to its radius
Definition: constants.scad:53
$resolution_value
Global special variable for modes that use custom resolutions.
Definition: resolution.scad:75
module log_echo(m)
Output message to console.
Definition: console.scad:61
function resolution_fs()
Return minimum facets size.
$resolution_mode
Global special variable that configures the arc resolution mode.
Definition: resolution.scad:72
function resolution_reduced()
Return the radius at which arc resolution will begin to degrade.
function resolution_facets(radius)
Return facet count used to render a radius.
function resolution_facetsv(radius)
Return facet count used to render a radius as vector triple.
function unit_length_name(units=base_unit_length, d=1, w=false)
Return the name of the given unit identifier with dimension.