Help combining bits into an object

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Help combining bits into an object

George Hartzell

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.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

NateTG
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/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

George Hartzell
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
 > [hidden email]
 > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

thehans
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 <[hidden email]> 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
>  > [hidden email]
>  > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

George Hartzell
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.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

NateTG
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

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

2018-02-03 1:53 GMT-02:00 NateTG <[hidden email]>:
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

jon_bondy
In reply to this post by thehans
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();
> }
> ```


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

George Hartzell

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

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

George Hartzell
In reply to this post by thehans
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

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

thehans
In reply to this post by George Hartzell
Let *can* be used inside a list comprehension, but it can also be its
own statement.  To be clear, in the code I posted above, I am not
using list comprehensions.

Documentation for the let statement exists on the wikibooks

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Let_Statement
"[Note: Requires version 2016.XX] (ie a development version)"

Hans

On Sat, Feb 3, 2018 at 11:52 AM, George Hartzell <[hidden email]> wrote:

>
> 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
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

George Hartzell
Hans L writes:
 > Let *can* be used inside a list comprehension, but it can also be its
 > own statement.  To be clear, in the code I posted above, I am not
 > using list comprehensions.
 >
 > Documentation for the let statement exists on the wikibooks
 >
 > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Let_Statement
 > "[Note: Requires version 2016.XX] (ie a development version)"
 > [...]

What that documents is a form like so:

```scad
for (...) {
  let(...) {
    ...
  }
}
```

What confused me a bit was that in the code you provided for me, the
"for block" was simple enough that it didn't require braces:

```scad
for (i = [1:$children-1]) let($negative = true) {
  children(i);
}
```

This seems to function equivalently:

```scad
for (i = [1:$children-1]) {
  let($negative = true) {
    children(i);
  }
}
```

Is that correct?  If so, then I believe I understand the subtleties.

Thank you again!

g.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: Help combining bits into an object

thehans
Yes, precisely.  Curly braces are only *required* when creating a
"block" around *multiple* statements.

If there is only a single statement under another, then the braces are
optional.
This is similar to the syntax found in most "c-style" languages
(though I don't consider OpenSCAD to be c-style, it does share some
simliarities such as this)

You could even do the whole loop with no braces in this case, if you
wanted.  It is a matter of preference:

for (i = [1:$children-1]) let($negative = true) children(i);

On Sat, Feb 3, 2018 at 1:56 PM, George Hartzell <[hidden email]> wrote:

> Hans L writes:
>  > Let *can* be used inside a list comprehension, but it can also be its
>  > own statement.  To be clear, in the code I posted above, I am not
>  > using list comprehensions.
>  >
>  > Documentation for the let statement exists on the wikibooks
>  >
>  > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Let_Statement
>  > "[Note: Requires version 2016.XX] (ie a development version)"
>  > [...]
>
> What that documents is a form like so:
>
> ```scad
> for (...) {
>   let(...) {
>     ...
>   }
> }
> ```
>
> What confused me a bit was that in the code you provided for me, the
> "for block" was simple enough that it didn't require braces:
>
> ```scad
> for (i = [1:$children-1]) let($negative = true) {
>   children(i);
> }
> ```
>
> This seems to function equivalently:
>
> ```scad
> for (i = [1:$children-1]) {
>   let($negative = true) {
>     children(i);
>   }
> }
> ```
>
> Is that correct?  If so, then I believe I understand the subtleties.
>
> Thank you again!
>
> g.
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org