

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


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


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 offcenter
translate([thickness/21,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],[(thickness1), 9*thickness]]);
}
translate([thickness,thickness,0]) linear_extrude(height = thickness) polygon(points=[[0,0],[thickness+1,0],[thickness,thickness1],[1,thickness1]]);
}
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/21,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],[(thickness1), 9*thickness]]);
translate([(1+thickness)/2+1thickness+1,thickness1,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


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:$children1]) let($negative = true) {
children(i);
}
}
for (i = [1:$children1]) 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 offcenter
> translate([thickness/21,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],[(thickness1), 9*thickness]]);
> }
> translate([thickness,thickness,0]) linear_extrude(height = thickness) polygon(points=[[0,0],[thickness+1,0],[thickness,thickness1],[1,thickness1]]);
> }
> 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/21,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],[(thickness1), 9*thickness]]);
> translate([(1+thickness)/2+1thickness+1,thickness1,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


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 doable 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


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:$children1]) let($negative = true) {
> children(i);
> }
> }
> for (i = [1:$children1]) 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


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][clipbox.eps] for a lasercut boxes, e.g. [clipbox].
g.
[clipbox]: https://www.thingiverse.com/thing:53032[clipbox.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


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:$children1]) let($negative = true) {
children(i);
}
```
This seems to function equivalently:
```scad
for (i = [1:$children1]) {
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


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 "cstyle" languages
(though I don't consider OpenSCAD to be cstyle, 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:$children1]) 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:$children1]) let($negative = true) {
> children(i);
> }
> ```
>
> This seems to function equivalently:
>
> ```scad
> for (i = [1:$children1]) {
> 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

