discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Help combining bits into an object

GH
George Hartzell
Fri, Feb 2, 2018 10:20 PM

Hi All,

I'm a very new OpenSCAD user.  I'm having a practical (and apparently
a conceptual...) problem and hope all y'all can set me straight.

I'd like to build of a library of modules, like the doohickey below
that create things like tabs and clips and ....

Some of the features (like doohickey) carve bits out of one part of
space and add bits to another.

I'd like to "drop" them onto a board and have the feature from the
doohickey take precedence over the feature in the base object.  If
something's carved out by the doohickey then it's carved out in the
result.  If somethings added by the doohickey, then it's added in the
result.  If there's nothing in the doohickey, then the base object
expresses itself.

I'd like the example below to do something like this:

+-----------+
|          |
|          +-+
|            |
|          +-+
|          |
|        +--+
|        |
|        |
|        +--+
|          |
|          |
+-----------+

I haven't been able to figure out a way to composite them.  union
doesn't work, it fills in the hole in the C.  intersection doesn't
work, it drops off the dingus.

// A little C shaped thingy with a dingus hanging off the top.
module doohickey () {
     /*  the C shaped bit */
     difference() {
          translate([-4, -3, 0]) cube([4, 6, 1]);
          translate([-3, -1, 0]) cube([3,2,1]);
     }
     /* the dingus */
     translate([0,3,0]) cube([2,1,1]);
}

cube([10, 20, 1]);
translate([10,10,0]) doohickey();

What's the right OpenSCAD approach to this?

Thanks,

g.

Hi All, I'm a very new OpenSCAD user. I'm having a practical (and apparently a conceptual...) problem and hope all y'all can set me straight. I'd like to build of a library of modules, like the `doohickey` below that create things like tabs and clips and .... Some of the features (like doohickey) carve bits out of one part of space and add bits to another. I'd like to "drop" them onto a board and have the feature from the doohickey take precedence over the feature in the base object. If something's carved out by the doohickey then it's carved out in the result. If somethings added by the doohickey, then it's added in the result. If there's nothing in the doohickey, then the base object expresses itself. I'd like the example below to do something like this: +-----------+ | | | +-+ | | | +-+ | | | +--+ | | | | | +--+ | | | | +-----------+ I haven't been able to figure out a way to composite them. `union` doesn't work, it fills in the hole in the C. `intersection` doesn't work, it drops off the dingus. ```scad // A little C shaped thingy with a dingus hanging off the top. module doohickey () { /* the C shaped bit */ difference() { translate([-4, -3, 0]) cube([4, 6, 1]); translate([-3, -1, 0]) cube([3,2,1]); } /* the dingus */ translate([0,3,0]) cube([2,1,1]); } cube([10, 20, 1]); translate([10,10,0]) doohickey(); ``` What's the right OpenSCAD approach to this? Thanks, g.
N
NateTG
Sat, Feb 3, 2018 12:03 AM

If I understand what you want correctly, one way to do what you want is to
fill the 'free' area for each component instead of leaving it open.  Then
when you intersect things you get the stuff you want.

Another possibility is to make a 'positive' by subtracting the base from
your component, and a 'negative' by subtracting the component from from the
base.  Then you can modify the base by adding the positive and subtracting
the negative.

--
Sent from: http://forum.openscad.org/

If I understand what you want correctly, one way to do what you want is to fill the 'free' area for each component instead of leaving it open. Then when you intersect things you get the stuff you want. Another possibility is to make a 'positive' by subtracting the base from your component, and a 'negative' by subtracting the component from from the base. Then you can modify the base by adding the positive and subtracting the negative. -- Sent from: http://forum.openscad.org/
GH
George Hartzell
Sat, Feb 3, 2018 1:07 AM

NateTG writes:

If I understand what you want correctly, one way to do what you want is to
fill the 'free' area for each component instead of leaving it open.  Then
when you intersect things you get the stuff you want.

I'm not quite sure that I get what you're suggesting here, but it
might be related to my "riff" below.

Another possibility is to make a 'positive' by subtracting the base from
your component, and a 'negative' by subtracting the component from from the
base.  Then you can modify the base by adding the positive and subtracting
the negative.

After thinking about this a bit, I think that's it's basically what's
happening in the lasercut library.

Here's an example that pulls the def'n of clipTab (your "positive",
above) and clipInner (your "negative", above) and sticks them onto a
flat plate:

module clipTab(angle, x, y, thickness)
{
     translate([x,y,0]) rotate([0,0,angle]) union()
     {
          // make off-center
          translate([-thickness/2-1,0,0])
          {
               difference()
               {
                    translate([0,thickness/2,thickness/2]) cube([thickness+1,thickness,thickness], center=true);
                    translate([(1+thickness)/2+1,-thickness*8,0])  linear_extrude(height = thickness*3, center = true)  polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]);
               }
               translate([-thickness,thickness,0])  linear_extrude(height = thickness)  polygon(points=[[0,0],[thickness+1,0],[thickness,thickness-1],[1,thickness-1]]);
          }
          translate([0.5,0,0]) cube([thickness,thickness,thickness]);
          *       cube([thickness*2+1,thickness,thickness], center=true);
     }
}

module clipInner(angle, x, y, thickness)
{
     translate([x,y,0]) rotate([0,0,angle]) union()
     {
          translate([-thickness/2-1,0,0])
          {
               translate([-(1+thickness)/2,-thickness*10,-thickness]) cube([1, thickness*11, thickness*3]);
               translate([(1+thickness)/2+1,-thickness*8,0])  linear_extrude(height = thickness*3, center = true)  polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]);
               translate([(1+thickness)/2+1-thickness+1,thickness-1,-thickness]) cube([thickness/2, thickness, thickness*3]);
               translate([-thickness*3/2,0,-thickness]) cube([thickness, thickness, thickness*3]);
          }
     }
}

difference () {
     union() {
          translate([-10, -40, 0]) cube([20, 40, 3]);
          clipTab(0, 0, 0, 3);
     }
     clipInner(0, 0, 0, 3);
}

It doesn't seem like a very general approach.

As a riff on what I think you're suggesting, I guess that I could
write a pair of modules, one of which defines a bounding box for a
doohickey and one of which defines the doohickey itself.  I could
delete the bounding box (basically making a "slot") and then add the
doohickey into the resulting emptiness.

I feel like this has to be well trod ground and would appreciate
points to how other libraries/designs have approached it.

THANKS!,

g.

NateTG writes: > If I understand what you want correctly, one way to do what you want is to > fill the 'free' area for each component instead of leaving it open. Then > when you intersect things you get the stuff you want. I'm not quite sure that I get what you're suggesting here, but it might be related to my "riff" below. > Another possibility is to make a 'positive' by subtracting the base from > your component, and a 'negative' by subtracting the component from from the > base. Then you can modify the base by adding the positive and subtracting > the negative. After thinking about this a bit, I think that's it's basically what's happening in the [lasercut] library. Here's an example that pulls the def'n of `clipTab` (your "positive", above) and `clipInner` (your "negative", above) and sticks them onto a flat plate: ```scad module clipTab(angle, x, y, thickness) { translate([x,y,0]) rotate([0,0,angle]) union() { // make off-center translate([-thickness/2-1,0,0]) { difference() { translate([0,thickness/2,thickness/2]) cube([thickness+1,thickness,thickness], center=true); translate([(1+thickness)/2+1,-thickness*8,0]) linear_extrude(height = thickness*3, center = true) polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]); } translate([-thickness,thickness,0]) linear_extrude(height = thickness) polygon(points=[[0,0],[thickness+1,0],[thickness,thickness-1],[1,thickness-1]]); } translate([0.5,0,0]) cube([thickness,thickness,thickness]); * cube([thickness*2+1,thickness,thickness], center=true); } } module clipInner(angle, x, y, thickness) { translate([x,y,0]) rotate([0,0,angle]) union() { translate([-thickness/2-1,0,0]) { translate([-(1+thickness)/2,-thickness*10,-thickness]) cube([1, thickness*11, thickness*3]); translate([(1+thickness)/2+1,-thickness*8,0]) linear_extrude(height = thickness*3, center = true) polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]); translate([(1+thickness)/2+1-thickness+1,thickness-1,-thickness]) cube([thickness/2, thickness, thickness*3]); translate([-thickness*3/2,0,-thickness]) cube([thickness, thickness, thickness*3]); } } } difference () { union() { translate([-10, -40, 0]) cube([20, 40, 3]); clipTab(0, 0, 0, 3); } clipInner(0, 0, 0, 3); } ``` It doesn't seem like a very general approach. As a riff on what I think you're suggesting, I guess that I could write a pair of modules, one of which defines a bounding box for a doohickey and one of which defines the doohickey itself. I could delete the bounding box (basically making a "slot") and then add the doohickey into the resulting emptiness. I feel like this has to be well trod ground and would appreciate points to how other libraries/designs have approached it. **THANKS!**, g. [lasercut]: https://github.com/rogerclarkmelbourne/lasercut > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
HL
Hans L
Sat, Feb 3, 2018 2:26 AM

Hi George, how about this solution?

// A little C shaped thingy with a dingus hanging off the top.
module doohickey () {
     /*  the C shaped bit */
   if ($negative) {
          translate([-4, -3, 0]) cube([4, 6, 1]);
          translate([-3, -1, 0]) cube([3,2,1]);
   } else {
     /* the dingus */
     translate([0,3,0]) cube([2,1,1]);
  }
}

// applies positive and negative features to the first child from all
subsequent children
module apply_features() {
  union() {
    difference() {
      children(0);
      for (i = [1:$children-1]) let($negative = true) {
        children(i);
      }
    }
    for (i = [1:$children-1]) let($negative = false) {
      children(i);
    }
  }
}

apply_features() {
  cube([10, 20, 1]);
  translate([10,10,0]) doohickey();
}

On Fri, Feb 2, 2018 at 7:07 PM, George Hartzell hartzell@alerce.com wrote:

NateTG writes:

If I understand what you want correctly, one way to do what you want is to
fill the 'free' area for each component instead of leaving it open.  Then
when you intersect things you get the stuff you want.

I'm not quite sure that I get what you're suggesting here, but it
might be related to my "riff" below.

Another possibility is to make a 'positive' by subtracting the base from
your component, and a 'negative' by subtracting the component from from the
base.  Then you can modify the base by adding the positive and subtracting
the negative.

After thinking about this a bit, I think that's it's basically what's
happening in the lasercut library.

Here's an example that pulls the def'n of clipTab (your "positive",
above) and clipInner (your "negative", above) and sticks them onto a
flat plate:

module clipTab(angle, x, y, thickness)
{
     translate([x,y,0]) rotate([0,0,angle]) union()
     {
          // make off-center
          translate([-thickness/2-1,0,0])
          {
               difference()
               {
                    translate([0,thickness/2,thickness/2]) cube([thickness+1,thickness,thickness], center=true);
                    translate([(1+thickness)/2+1,-thickness*8,0])  linear_extrude(height = thickness*3, center = true)  polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]);
               }
               translate([-thickness,thickness,0])  linear_extrude(height = thickness)  polygon(points=[[0,0],[thickness+1,0],[thickness,thickness-1],[1,thickness-1]]);
          }
          translate([0.5,0,0]) cube([thickness,thickness,thickness]);
          *       cube([thickness*2+1,thickness,thickness], center=true);
     }
}

module clipInner(angle, x, y, thickness)
{
     translate([x,y,0]) rotate([0,0,angle]) union()
     {
          translate([-thickness/2-1,0,0])
          {
               translate([-(1+thickness)/2,-thickness*10,-thickness]) cube([1, thickness*11, thickness*3]);
               translate([(1+thickness)/2+1,-thickness*8,0])  linear_extrude(height = thickness*3, center = true)  polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]);
               translate([(1+thickness)/2+1-thickness+1,thickness-1,-thickness]) cube([thickness/2, thickness, thickness*3]);
               translate([-thickness*3/2,0,-thickness]) cube([thickness, thickness, thickness*3]);
          }
     }
}

difference () {
     union() {
          translate([-10, -40, 0]) cube([20, 40, 3]);
          clipTab(0, 0, 0, 3);
     }
     clipInner(0, 0, 0, 3);
}

It doesn't seem like a very general approach.

As a riff on what I think you're suggesting, I guess that I could
write a pair of modules, one of which defines a bounding box for a
doohickey and one of which defines the doohickey itself.  I could
delete the bounding box (basically making a "slot") and then add the
doohickey into the resulting emptiness.

I feel like this has to be well trod ground and would appreciate
points to how other libraries/designs have approached it.

THANKS!,

g.

Hi George, how about this solution? ``` // A little C shaped thingy with a dingus hanging off the top. module doohickey () { /* the C shaped bit */ if ($negative) { translate([-4, -3, 0]) cube([4, 6, 1]); translate([-3, -1, 0]) cube([3,2,1]); } else { /* the dingus */ translate([0,3,0]) cube([2,1,1]); } } // applies positive and negative features to the first child from all subsequent children module apply_features() { union() { difference() { children(0); for (i = [1:$children-1]) let($negative = true) { children(i); } } for (i = [1:$children-1]) let($negative = false) { children(i); } } } apply_features() { cube([10, 20, 1]); translate([10,10,0]) doohickey(); } ``` On Fri, Feb 2, 2018 at 7:07 PM, George Hartzell <hartzell@alerce.com> wrote: > NateTG writes: > > If I understand what you want correctly, one way to do what you want is to > > fill the 'free' area for each component instead of leaving it open. Then > > when you intersect things you get the stuff you want. > > I'm not quite sure that I get what you're suggesting here, but it > might be related to my "riff" below. > > > Another possibility is to make a 'positive' by subtracting the base from > > your component, and a 'negative' by subtracting the component from from the > > base. Then you can modify the base by adding the positive and subtracting > > the negative. > > After thinking about this a bit, I think that's it's basically what's > happening in the [lasercut] library. > > Here's an example that pulls the def'n of `clipTab` (your "positive", > above) and `clipInner` (your "negative", above) and sticks them onto a > flat plate: > > ```scad > module clipTab(angle, x, y, thickness) > { > translate([x,y,0]) rotate([0,0,angle]) union() > { > // make off-center > translate([-thickness/2-1,0,0]) > { > difference() > { > translate([0,thickness/2,thickness/2]) cube([thickness+1,thickness,thickness], center=true); > translate([(1+thickness)/2+1,-thickness*8,0]) linear_extrude(height = thickness*3, center = true) polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]); > } > translate([-thickness,thickness,0]) linear_extrude(height = thickness) polygon(points=[[0,0],[thickness+1,0],[thickness,thickness-1],[1,thickness-1]]); > } > translate([0.5,0,0]) cube([thickness,thickness,thickness]); > * cube([thickness*2+1,thickness,thickness], center=true); > } > } > > module clipInner(angle, x, y, thickness) > { > translate([x,y,0]) rotate([0,0,angle]) union() > { > translate([-thickness/2-1,0,0]) > { > translate([-(1+thickness)/2,-thickness*10,-thickness]) cube([1, thickness*11, thickness*3]); > translate([(1+thickness)/2+1,-thickness*8,0]) linear_extrude(height = thickness*3, center = true) polygon(points=[[0,0],[0,9*thickness],[-(thickness-1), 9*thickness]]); > translate([(1+thickness)/2+1-thickness+1,thickness-1,-thickness]) cube([thickness/2, thickness, thickness*3]); > translate([-thickness*3/2,0,-thickness]) cube([thickness, thickness, thickness*3]); > } > } > } > > difference () { > union() { > translate([-10, -40, 0]) cube([20, 40, 3]); > clipTab(0, 0, 0, 3); > } > clipInner(0, 0, 0, 3); > } > ``` > > It doesn't seem like a very general approach. > > As a riff on what I think you're suggesting, I guess that I could > write a pair of modules, one of which defines a bounding box for a > doohickey and one of which defines the doohickey itself. I could > delete the bounding box (basically making a "slot") and then add the > doohickey into the resulting emptiness. > > I feel like this has to be well trod ground and would appreciate > points to how other libraries/designs have approached it. > > **THANKS!**, > > g. > > [lasercut]: https://github.com/rogerclarkmelbourne/lasercut > > > > > > > > > -- > > Sent from: http://forum.openscad.org/ > > > > _______________________________________________ > > OpenSCAD mailing list > > Discuss@lists.openscad.org > > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
GH
George Hartzell
Sat, Feb 3, 2018 3:14 AM

Hans L writes:

Hi George, how about this solution?

[... elegant solution elided ...]

That's quite nice.  I was just playing around with deleting a bounding
cube explicitly then merging and it works.  This is a nice way to do
that programmatically.  I like the use of let and the
apply_features method.

It's too bad that I have to calculate the bounding cube "by hand", but
I've read through a couple of threads that make it sounds as if it's
not reasonably do-able in OpenSCAD at the moment.

I have a vague memory about being careful about butting two objects up
against each other, that OpenSCAD might get confused about their
edges.  I can't find it now that I'm looking at it.  Is that a
concern?

THANKS!

g.

Hans L writes: > Hi George, how about this solution? > > [... elegant solution elided ...] That's quite nice. I was just playing around with deleting a bounding cube explicitly then merging and it works. This is a nice way to do that programmatically. I like the use of `let` and the `apply_features` method. It's too bad that I have to calculate the bounding cube "by hand", but I've read through a couple of threads that make it sounds as if it's not reasonably do-able in OpenSCAD at the moment. I have a vague memory about being careful about butting two objects up against each other, that OpenSCAD might get confused about their edges. I can't find it now that I'm looking at it. Is that a concern? **THANKS!** g.
N
NateTG
Sat, Feb 3, 2018 3:53 AM

It is possible to generate a the bounding box of a geometry, but minkowski
stuff is typically slow.

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Tips_and_Tricks#Computing_a_bounding_box

--
Sent from: http://forum.openscad.org/

It is possible to generate a the bounding box of a geometry, but minkowski stuff is typically slow. https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Tips_and_Tricks#Computing_a_bounding_box -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Sat, Feb 3, 2018 4:28 AM

This bounding box computation is pretty fast because minkowsky is applied
to just three cubes.

2018-02-03 1:53 GMT-02:00 NateTG nate-openscadforum@pedantic.org:

It is possible to generate a the bounding box of a geometry, but minkowski
stuff is typically slow.

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Tips_and_
Tricks#Computing_a_bounding_box

--
Sent from: http://forum.openscad.org/


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

This bounding box computation is pretty fast because minkowsky is applied to just three cubes. 2018-02-03 1:53 GMT-02:00 NateTG <nate-openscadforum@pedantic.org>: > It is possible to generate a the bounding box of a geometry, but minkowski > stuff is typically slow. > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Tips_and_ > Tricks#Computing_a_bounding_box > > > > > -- > Sent from: http://forum.openscad.org/ > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
J
jon
Sat, Feb 3, 2018 12:57 PM

Is this supposed to actually work in OpenSCAD?  I get a compiler error
at $negative but I am not using the latest OpenSCAD.

On 2/2/2018 9:26 PM, Hans L wrote:

Hi George, how about this solution?

// A little C shaped thingy with a dingus hanging off the top.
module doohickey () {
      /*  the C shaped bit */
    if ($negative) {
           translate([-4, -3, 0]) cube([4, 6, 1]);
           translate([-3, -1, 0]) cube([3,2,1]);
    } else {
      /* the dingus */
      translate([0,3,0]) cube([2,1,1]);
   }
}

// applies positive and negative features to the first child from all
subsequent children
module apply_features() {
   union() {
     difference() {
       children(0);
       for (i = [1:$children-1]) let($negative = true) {
         children(i);
       }
     }
     for (i = [1:$children-1]) let($negative = false) {
       children(i);
     }
   }
}

apply_features() {
   cube([10, 20, 1]);
   translate([10,10,0]) doohickey();
}
Is this supposed to actually work in OpenSCAD?  I get a compiler error at $negative but I am not using the latest OpenSCAD. On 2/2/2018 9:26 PM, Hans L wrote: > Hi George, how about this solution? > > ``` > // A little C shaped thingy with a dingus hanging off the top. > module doohickey () { > /* the C shaped bit */ > if ($negative) { > translate([-4, -3, 0]) cube([4, 6, 1]); > translate([-3, -1, 0]) cube([3,2,1]); > } else { > /* the dingus */ > translate([0,3,0]) cube([2,1,1]); > } > } > > // applies positive and negative features to the first child from all > subsequent children > module apply_features() { > union() { > difference() { > children(0); > for (i = [1:$children-1]) let($negative = true) { > children(i); > } > } > for (i = [1:$children-1]) let($negative = false) { > children(i); > } > } > } > > apply_features() { > cube([10, 20, 1]); > translate([10,10,0]) doohickey(); > } > ```
GH
George Hartzell
Sat, Feb 3, 2018 5:52 PM

It does not work in version version 2015.03-3, which is the stable
version installed via Homebrew Cask.

It does work in the dev release that I manually downloaded,
2017.12.23 (git 39823be1).

This usage seems to be a variant of the list comprehension form, it's
documented here without any caveats about what
release it will work in, although the top of that list comprehension
section states that it (list comprehensions in general?) requires
"2015.03".

There's a comment in this thread from 2016 that states
that let is only available in the dev releases.  It also states that
"the wiki" has been fixed.

Is there a doc bug in the User Manual?

g.

It does not work in version `version 2015.03-3`, which is the stable version installed via Homebrew Cask. It does work in the dev release that I manually downloaded, `2017.12.23 (git 39823be1)`. This usage seems to be a variant of the list comprehension form, it's documented [here][list-comp-let] without any caveats about what release it will work in, although the top of that list comprehension section states that it (list comprehensions in general?) requires "2015.03". There's a comment in [this thread][let-thread] from 2016 that states that `let` is only available in the dev releases. It also states that "the wiki" has been fixed. Is there a doc bug in the User Manual? g. [let-thread]: http://forum.openscad.org/quot-Let-quot-deprecated-td17469.html [list-comp-let]: https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#let
GH
George Hartzell
Sat, Feb 3, 2018 6:37 PM

Hans L writes:

Hi George, how about this solution?

// A little C shaped thingy with a dingus hanging off the top.
module doohickey () {
     /*  the C shaped bit */
   if ($negative) {
          translate([-4, -3, 0]) cube([4, 6, 1]);
          translate([-3, -1, 0]) cube([3,2,1]);
   } else {
     /* the dingus */
     translate([0,3,0]) cube([2,1,1]);
  }
}
[...]

One other comment about this solution.

The doohickey that my original code draws in isolation looks something
like this:

             +---+
             |   |
+------------+---+
|            |
|   +--------+
|   |
|   |
|   |
|   +--------+
|            |
+------------+

My intent was that it would be glued into a bigger whole like so:

+--------------+
|              |
|              +---+
|                  |
|              +---+
|              |
|     +--------+
|     |
|     |
|     |
|     +--------+
|              |
|              |
+--------------+

In Hans' solution:

  • when $negative is true it carves out negative space for each of
    the spaces it fills; and
  • when $negative is false it draws all
    of its bits.

I had originally thought of simplifying this so that the negative step
carved out a bounding cube in one simple step and the positive step
filled it as it deemed appropriate.  The advantage of this is that
code for the negative case is simpler.

If I were to take this approach then I would need to modify my
original positive step to fill in the area above the "C" shape,
otherwise it would be open space in the result.

On the other hand, with that simplification there's no way to position
the top of the "C" along the top edge of a base feature and have the
little dingus hang off into space.  Hans' solution allows this, at the
cost of a slightly more complicated "negative" step.

On the gripping hand, there's the approach from the lasercut
library
, where each object has a method that adds it's
positive bits and another method that carves out its negative space
and it's up to the end user to call them appropriately.

Horses for courses, I suppose.  I'll screw around with it and see if I
have a preference.  My end goal is to be able to output a
drawing for a lasercut boxes, e.g. clip-box.

g.

Hans L writes: > Hi George, how about this solution? > > ``` > // A little C shaped thingy with a dingus hanging off the top. > module doohickey () { > /* the C shaped bit */ > if ($negative) { > translate([-4, -3, 0]) cube([4, 6, 1]); > translate([-3, -1, 0]) cube([3,2,1]); > } else { > /* the dingus */ > translate([0,3,0]) cube([2,1,1]); > } > } > [...] One other comment about this solution. The doohickey that my original code draws in isolation looks something like this: ``` +---+ | | +------------+---+ | | | +--------+ | | | | | | | +--------+ | | +------------+ ``` My intent was that it would be glued into a bigger whole like so: ``` +--------------+ | | | +---+ | | | +---+ | | | +--------+ | | | | | | | +--------+ | | | | +--------------+ ``` In Hans' solution: - when `$negative` is `true` it carves out negative space for each of the spaces it fills; and - when `$negative` is `false` it draws all of its bits. I had originally thought of simplifying this so that the negative step carved out a bounding cube in one simple step and the positive step filled it as it deemed appropriate. The advantage of this is that code for the negative case is simpler. If I were to take this approach then I would need to modify my original positive step to fill in the area above the "C" shape, otherwise it would be open space in the result. On the other hand, with that simplification there's no way to position the top of the "C" along the top edge of a base feature and have the little dingus hang off into space. Hans' solution allows this, at the cost of a slightly more complicated "negative" step. On the gripping hand, there's the approach from the [lasercut library][lasercut], where each object has a method that adds it's positive bits and another method that carves out its negative space and it's up to the end user to call them appropriately. Horses for courses, I suppose. I'll screw around with it and see if I have a preference. My end goal is to be able to output a [drawing][clip-box.eps] for a lasercut boxes, e.g. [clip-box]. g. [clip-box]: https://www.thingiverse.com/thing:53032 [clip-box.eps]: https://www.thingiverse.com/download:177605 [lasercut]: https://github.com/bmsleight/lasercut