How to write modules with fallback default arguments in OpenSCAD

While refactoring King’s Gambit in OpenSCAD, I wanted to make a rounded-corner cylinder module that also behaved like the regular cylinder module. In the regular cylinder module, you can write arguments in a variety of ways.

cylinder(10, 10, 20);
cylinder(h = 10, r1 = 10, r2 = 20);
cylinder(h = 10, r=20);

As you see above, you can either pass in arguments by order (like most programming languages), or by name (like in Objective-C and passing hashes in Ruby). And if the argument “r” exists, it override the values for “r1” and “r2”.

I wanted to be able to write this kind of module as well. Of note, there is no pattern matching in OpenSCAD, there are no variables and only constants in OpenSCAD, and there is no nil or null in OpenSCAD. There is an undefined state that constants can be in, but no test for their undef state, since it’s unspecified. Thus, we’re left with using default arguments as a work around. This close as I have figured it out:

module rounded_cylinder(h, r1, r2, r = "undefined") {
  module helper(h, r1, r2) {
    // I'm just going to render a regular cylinder here for simplicity. 
    // Pretend this section has multiple lines of code.
    cylinder(h, r1, r2);
  }

  if (r == "undefined") {
    helper(h, r1, r2);
  } else {
    helper(h, r, r);
  }
}

rounded_cylinder(4, 4, 2);
translate([10, 0, 0]) rounded_cylinder(4, r = 4);
translate([20, 0, 0]) rounded_cylinder(4, r1 = 4, r2 = 2);
translate([30, 0, 0]) rounded_cylinder(4, r1 = 4);
translate([40, 0, 0]) rounded_cylinder(4, r2 = 2);
translate([50, 0, 0]) rounded_cylinder(4);

Default_args

As you can see, I set the default value of “r” to “undefined”, and then tested for whether it’s undefined or not, and rendered the correct helper accordingly, since there’s no actual test for whether a variable is undefined or not.

Note that because there are no variables in OpenSCAD, all constants need to be defined in the beginning of a module. Thus, you can’t redefine constants inside the two branches of the if statement.

Also note that you can either repeat the same code twice in each branch of the if statement, or you can define a helper module inside rounded_cylinder and make a call to it in each branch, as shown above. The helper module only exists within the scope of rounded_cylinder and won’t pollute the global namespace.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s