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