1//////////////////////////////////////////////////////////////////////
2// LibFile: compat.scad
3// Backwards Compatability library
4// To use, include this line at the top of your file:
5// ```
6// use <compat.scad>
7// ```
8//////////////////////////////////////////////////////////////////////
9
10
11/*
12BSD 2-Clause License
13
14Copyright (c) 2017, Revar Desmera
15All rights reserved.
16
17Redistribution and use in source and binary forms, with or without
18modification, are permitted provided that the following conditions are met:
19
20* Redistributions of source code must retain the above copyright notice, this
21 list of conditions and the following disclaimer.
22
23* Redistributions in binary form must reproduce the above copyright notice,
24 this list of conditions and the following disclaimer in the documentation
25 and/or other materials provided with the distribution.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
31FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38
39
40// Section: Functions
41
42
43// Function: default()
44// Description:
45// Returns the value given as `v` if it is not `undef`.
46// Otherwise, returns the value of `dflt`.
47// Arguments:
48// v = Value to pass through if not `undef`.
49// dflt = Value to return if `v` *is* `undef`.
50function default(v,dflt=undef) = v==undef? dflt : v;
51
52
53// Function: is_def()
54// Description: Returns true if given value is not `undef`.
55function is_def(v) = (version_num() > 20190100)? !is_undef(v) : (v != undef);
56
57
58// Function: is_str()
59// Description: Given a value, returns true if it is a string.
60function is_str(v) = (version_num() > 20190100)? is_string(v) : (v=="" || (is_def(v) && is_def(v[0]) && (len(str(v,v)) == len(v)*2)));
61
62
63// Function: is_boolean()
64// Description: Given a value, returns true if it is a boolean.
65function is_boolean(v) = (version_num() > 20190100)? is_bool(v) : (!is_str(v) && (str(v) == "true" || str(v) == "false"));
66
67
68// Function: is_scalar()
69// Description: Given a value, returns true if it is a scalar number.
70function is_scalar(v) = (version_num() > 20190100)? is_num(v) : (!is_boolean(v) && is_def(v+0));
71
72
73// Function: is_array()
74// Description: Given a value, returns true if it is an array/list/vector.
75function is_array(v) = (version_num() > 20190100)? is_list(v) : (v==[] || (is_def(v[0]) && !is_str(v) ));
76
77
78// Function: get_radius()
79// Description:
80// Given various radii and diameters, returns the most specific radius.
81// If a diameter is most specific, returns half its value, giving the radius.
82// If no radii or diameters are defined, returns the value of dflt.
83// Value specificity order is r1, d1, r, d, then dflt
84// Arguments:
85// r1 = Most specific radius.
86// d1 = Most specific Diameter.
87// r = Most general radius.
88// d = Most general diameter.
89// dflt = Value to return if all other values given are `undef`.
90function get_radius(r1=undef, r=undef, d1=undef, d=undef, dflt=undef) = (
91 is_def(r1)? r1 :
92 is_def(d1)? d1/2 :
93 is_def(r)? r :
94 is_def(d)? d/2 :
95 dflt
96);
97
98
99// Function: Len()
100// Description:
101// Given an array, returns number of items in array. Otherwise returns `undef`.
102function Len(v) = is_array(v)? len(v) : undef;
103
104
105// Function: remove_undefs()
106// Description: Removes all `undef`s from a list.
107function remove_undefs(v) = [for (x = v) if (is_def(x)) x];
108
109
110// Function: first_defined()
111// Description:
112// Returns the first item in the list that is not `undef`.
113// If all items are `undef`, or list is empty, returns `undef`.
114function first_defined(v) = remove_undefs(v)[0];
115
116
117// Function: any_defined()
118// Description:
119// Returns true if any item in the given array is not `undef`.
120function any_defined(v) = len(remove_undefs(v))>0;
121
122
123// Function: scalar_vec3()
124// Usage:
125// scalar_vec3(v, [dflt]);
126// Description:
127// If `v` is a scalar, and `dflt==undef`, returns `[v, v, v]`.
128// If `v` is a scalar, and `dflt!=undef`, returns `[v, dflt, dflt]`.
129// If `v` is a vector, returns the first 3 items, with any missing values replaced by `dflt`.
130// If `v` is `undef`, returns `undef`.
131// Arguments:
132// v = Value to return vector from.
133// dflt = Default value to set empty vector parts from.
134function scalar_vec3(v, dflt=undef) =
135 !is_def(v)? undef :
136 is_array(v)? [for (i=[0:2]) default(v[i], default(dflt, 0))] :
137 is_def(dflt)? [v,dflt,dflt] : [v,v,v];
138
139
140
141// Function: f_echo()
142// Description: If possible, echo a message from a function.
143function f_echo(msg) = (version_num() > 20190100)? echo(msg) : 0;
144
145
146// Section: Modules
147
148
149// Module: assert_in_list()
150// Usage:
151// assert_in_list(argname, val, l, [idx]);
152// Description:
153// Emulates the newer OpenSCAD `assert()` with an `in_list()` test.
154// You can also use this as a function call from a function.
155// Arguments:
156// argname = The name of the argument value being tested.
157// val = The value to test if it exists in the list.
158// l = The list to look for `val` in.
159// idx = If given, and `l` is a list of lists, look for `val` in the given index of each sublist.
160module assert_in_list(argname, val, l, idx=undef) {
161 succ = search([val], l, num_returns_per_match=1, index_col_num=idx) != [[]];
162 if (!succ) {
163 msg = str(
164 "In argument '", argname, "', ",
165 (is_str(val)? str("\"", val, "\"") : val),
166 " must be one of ",
167 (is_def(idx)? [for (v=l) v[idx]] : l)
168 );
169 assertion(succ, msg);
170 }
171}
172
173function assert_in_list(argname, val, l, idx=undef) =
174 let(succ = search([val], l, num_returns_per_match=1, index_col_num=idx) != [[]])
175 succ? 0 : let(
176 msg = str(
177 "In argument '", argname, "', ",
178 (is_str(val)? str("\"", val, "\"") : val),
179 " must be one of ",
180 (is_def(idx)? [for (v=l) v[idx]] : l)
181 )
182 ) assertion(succ, msg);
183
184
185// Module: assertion()
186// Usage:
187// assertion(succ, msg);
188// Description:
189// Backwards compatible assert() semi-replacement.
190// If `succ` is false, then print an error with `msg`.
191// You can also use this as a function call from a function.
192// Arguments:
193// succ = If this is `false`, trigger the assertion.
194// msg = The message to emit if `succ` is `false`.
195module assertion(succ, msg) {
196 if (version_num() > 20190100) {
197 // assert() will echo the variable name, and `succ` looks confusing there. So we store it in FAILED.
198 FAILED = succ;
199 assert(FAILED, msg);
200 } else if (!succ) {
201 echo_error(msg);
202 }
203}
204
205function assertion(succ, msg) =
206 (version_num() > 20190100)? let(FAILED=succ) assert(FAILED, msg) : 0;
207
208
209// Module: echo_error()
210// Usage:
211// echo_error(msg, [pfx]);
212// Description:
213// Emulates printing of an error message. The text will be shaded red.
214// You can also use this as a function call from a function.
215// Arguments:
216// msg = The message to print.
217// pfx = The prefix to print before `msg`. Default: `ERROR`
218module echo_error(msg, pfx="ERROR") {
219 echo(str("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
220}
221
222function echo_error(msg, pfx="ERROR") =
223 f_echo(str("<p style=\"background-color: #ffb0b0\"><b>", pfx, ":</b> ", msg, "</p>"));
224
225
226// Module: echo_warning()
227// Usage:
228// echo_warning(msg, [pfx]);
229// Description:
230// Emulates printing of a warning message. The text will be shaded yellow.
231// You can also use this as a function call from a function.
232// Arguments:
233// msg = The message to print.
234// pfx = The prefix to print before `msg`. Default: `WARNING`
235module echo_warning(msg, pfx="WARNING") {
236 echo(str("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
237}
238
239function echo_warning(msg, pfx="WARNING") =
240 f_echo(str("<p style=\"background-color: #ffffb0\"><b>", pfx, ":</b> ", msg, "</p>"));
241
242
243// Module: deprecate()
244// Usage:
245// deprecate(name, [suggest]);
246// Description:
247// Show module deprecation warnings.
248// You can also use this as a function call from a function.
249// Arguments:
250// name = The name of the module that is deprecated.
251// suggest = If given, the module to recommend using instead.
252module deprecate(name, suggest=undef) {
253 echo_warning(pfx="DEPRECATED",
254 str(
255 "`<code>", name, "</code>` is deprecated and should not be used.",
256 !is_def(suggest)? "" : str(
257 " You should use `<code>", suggest, "</code>` instead."
258 )
259 )
260 );
261}
262
263function deprecate(name, suggest=undef) =
264 echo_warning(pfx="DEPRECATED",
265 str(
266 "`<code>", name, "</code>` is deprecated and should not be used.",
267 !is_def(suggest)? "" : str(
268 " You should use `<code>", suggest, "</code>` instead."
269 )
270 )
271 );
272
273
274// Module: deprecate_argument()
275// Usage:
276// deprecate(name, arg, [suggest]);
277// Description:
278// Show argument deprecation warnings.
279// You can also use this as a function call from a function.
280// Arguments:
281// name = The name of the module/function the deprecated argument is used in.
282// arg = The name of the deprecated argument.
283// suggest = If given, the argument to recommend using instead.
284module deprecate_argument(name, arg, suggest=undef) {
285 echo_warning(pfx="DEPRECATED ARG", str(
286 "In `<code>", name, "</code>`, ",
287 "the argument `<code>", arg, "</code>` ",
288 "is deprecated and should not be used.",
289 !is_def(suggest)? "" : str(
290 " You should use `<code>", suggest, "</code>` instead."
291 )
292 ));
293}
294
295function deprecate_argument(name, arg, suggest=undef) =
296 echo_warning(pfx="DEPRECATED ARG", str(
297 "In `<code>", name, "</code>`, ",
298 "the argument `<code>", arg, "</code>` ",
299 "is deprecated and should not be used.",
300 !is_def(suggest)? "" : str(
301 " You should use `<code>", suggest, "</code>` instead."
302 )
303 ));
304
305
306
307// vim: noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap