Merge pull request #806 from adrianVmariano/master

add force_tags() and streamline diff()
This commit is contained in:
Revar Desmera 2022-03-19 20:53:38 -07:00 committed by GitHub
commit 70ab47012b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 204 additions and 60 deletions

View file

@ -17,6 +17,27 @@
$tags = "";
$overlap = 0;
$color = undef;//"yellow";
$save_color = undef; // Saved color to revert back for children
$color_scheme = "cornfield"; // Default color scheme
_default_colors = [
["cornfield", "#f9d72c"],
["metallic", "#ddddff"],
["sunset", "#ffaaaa"],
["starnight", "#ffffe0"],
["beforedawn", "#cccccc"],
["nature", "#16a085"],
["deepocean", "#eeeeee"],
["solarized", "#b58800"],
["tomorrow", "#4271ae"],
["tomorrow night", "#81a2be"],
["monotone", "#f9d72c"]
];
function _default_color() =
let(ind = search([downcase($color_scheme)], _default_colors, 1, 0))
assert(ind[0]!=[], str("$color_scheme set to unknown value ",$color_scheme))
_default_colors[ind[0]][1];
$attach_to = undef;
$attach_anchor = [CENTER, CENTER, UP, 0];
@ -538,12 +559,44 @@ module attach(from, to, overlap, norot=false)
// Usage:
// tags(tags) {...}
// Topics: Attachments
// See Also: recolor(), hide(), show(), diff(), intersect()
// See Also: force_tags(), recolor(), hide(), show(), diff(), intersect()
// Description:
// Marks all children with the given tags, so that they will `hide()`/`show()`/`diff()` correctly.
// This is especially useful for working with children that are not attachment enhanced, such as:
// Sets the `$tags` variable as specified for all its children. This makes it easy to set the tags
// on multiple items without having to repeat the tag setting for each one. Note that if you want
// to apply tags to non-tag-aware objects you need to use {{force_tags()}} instead.
// .
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// tags = String containing space delimited set of tags to apply.
// Example(3D): Applies the tags to both cuboids instead of having to repeat `$tags="remove"` for each one.
// diff("remove")
// cuboid(10){
// position(TOP) cuboid(3);
// tags("remove")
// {
// position(FRONT) cuboid(3);
// position(RIGHT) cuboid(3);
// }
// }
module tags(tags)
{
$tags = tags;
children();
}
// Module: force_tags()
// Usage:
// force_tags([tags]) {...}
// Topics: Attachments
// See Also: tags(), recolor(), hide(), show(), diff(), intersect()
// Description:
// You use this module when you want to make a non-attachable or non-BOSL2 module respect tags.
// It applies to its children the tags specified (or the tags currently in force if you don't specify any tags),
// making a final determination about whether to show or hide the children. This means that tagging in children's children will be ignored.
// This module is specifically provided for operating on children that are not tag aware such as modules
// that don't use {{attachable()}} or built in modules such as
// - `polygon()`
// - `text()`
// - `projection()`
// - `polyhedron()` (or use [`vnf_polyhedron()`](vnf.scad#vnf_polyhedron))
// - `linear_extrude()` (or use [`linear_sweep()`](regions.scad#linear_sweep))
@ -551,42 +604,60 @@ module attach(from, to, overlap, norot=false)
// - `surface()`
// - `import()`
// .
// When you use tag-based modules like {{diff()}} with a non-attachable module, the result may be puzzling.
// Any time a test occurs for display of child() that test will succeed. This means that when diff() checks
// to see if it should show a module it will show it, and when diff() checks to see if it should subtract the module
// it will subtract it. The result will be a hole, possibly with zero-thickness edges or faces. In order to
// get the correct behavior, every non-attachable module needs an invocation of force_tags, even ones that are not
// .
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// tags = String containing space delimited set of tags to apply.
module tags(tags)
// Example(NoRender): This program produces no output because the objects are created and then differenced away. The specified tag is ignored.
// diff("remove")
// {
// polygon(square(10));
// move(-[.01,.01])polygon(square(5),$tags="remove");
// }
// Example(2D): Adding force_tags() fixed the model. Note you need to add it to *every* non-attachable module, even the untagged ones.
// diff("remove")
// {
// force_tags()
// polygon(square(10));
// force_tags("remove")
// move(-[.01,.01])polygon(square(5));
// }
module force_tags(tags)
{
$tags = tags;
if(_attachment_is_shown(tags)) {
$tags = is_def(tags) ? tags : $tags;
if(_attachment_is_shown($tags)) {
children();
}
}
// Module: diff()
// Usage:
// diff(neg, [keep]) {...}
// diff(neg, pos, [keep]) {...}
// Topics: Attachments
// See Also: tags(), recolor(), show(), hide(), intersect()
// Description:
// If `neg` is given, takes the union of all children with tags that are in `neg`, and differences
// them from the union of all children with tags in `pos`. If `pos` is not given, then all items in
// `neg` are differenced from all items not in `neg`. If `keep` is given, all children with tags in
// `keep` are then unioned with the result. If `keep` is not given, all children without tags in
// `pos` or `neg` are then unioned with the result.
// Perform a differencing operation using tags to control what happens. The children are grouped into
// three categories. The `neg` argument is a space delimited list of tags specifying objects to
// subtract. The `keep` argument, if given, is a similar list of tags giving objects to be kept.
// Objects not matching `neg` or `keep` form the third category of base objects.
// To produce its output, diff() forms the union of all the base objects, which don't match any tags.
// Next it subtracts all the objects with tags in `neg`. Finally it adds in objects listed in `keep`.
// .
// Cannot be used in conjunction with `intersect()` or `hulling()` on the same parent object.
// .
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// neg = String containing space delimited set of tag names of children to difference away.
// pos = String containing space delimited set of tag names of children to be differenced away from.
// keep = String containing space delimited set of tag names of children to keep whole.
// keep = String containing space delimited set of tag names of children to keep, that is, to union into the model after differencing is completed.
// Example:
// diff("neg", "pos", keep="axle")
// sphere(d=100, $tags="pos") {
// diff("neg", keep="axle")
// sphere(d=100) {
// attach(CENTER) xcyl(d=40, l=120, $tags="axle");
// attach(CENTER) cube([40,120,100], anchor=CENTER, $tags="neg");
// }
@ -596,7 +667,40 @@ module tags(tags)
// edge_mask(FWD)
// rounding_edge_mask(l=max($parent_size)*1.01, r=25);
// }
// Example: Working with Non-Attachables Like rotate_extrude()
// Example(3D,VPR=[104,0,200], VPT=[-0.9,3.03, -0.74], VPD=19,NoAxes,NoScales): A pipe module that subtracts its interior when you call it using diff(). Normally if you union two pipes together, you'll get interfering walls at the intersection, but not here:
// $fn=16;
// // This module must be called by subtracting with "diff"
// module pipe(length, od, id) {
// // Strip the tag the user is using to subtract
// cylinder(h=length, d=od, center=true,$tags="");
// // Leave the tag along here, so this one is removed
// cylinder(h=length+.02, d=id, center=true);
// }
// // Draw some intersecting pipes
// diff("rem",keep="keep"){
// pipe(length=5, od=2, id=1.9, $tags="rem");
// zrot(10)xrot(75)
// pipe(length=5, od=2, id=1.9, $tags="rem");
// // The orange bar has its center removed
// color("orange") down(1) xcyl(h=8, d=1);
// // "keep" prevents interior of the blue bar intact
// recolor("blue") up(1) xcyl(h=8, d=1,$tags="keep");
// }
// // Objects outside the diff don't have pipe interiors removed
// color("purple") down(2.2) ycyl(h=8, d=0.3,$tags="keep");
// Example(3D,NoScales,NoAxes): Nested diff() calls work as expected, but be careful of reusing tag names, even hidden in submodules.
// $fn=16;
// diff("rem1")
// cyl(r=10,h=10){
// diff("rem2",$tags="rem1"){
// cyl(r=8,h=11);
// diff("rem3", $tags="rem2"){
// cyl(r=6,h=12);
// cyl(r=4,h=13,$tags="rem3");
// }
// }
// }
// Example(3D,NoAxes,NoScales): Working with Non-Attachables like rotate_extrude() you must apply {{force_tags()}} to every non-attachable object.
// back_half()
// diff("remove")
// cuboid(40) {
@ -604,33 +708,27 @@ module tags(tags)
// recolor("lightgreen")
// cyl(l=10,d=30);
// position(TOP+RIGHT)
// tags("remove")
// force_tags("remove")
// xrot(90)
// rotate_extrude()
// right(20)
// circle(5);
// }
module diff(neg, pos, keep)
module diff(neg, keep)
{
// Don't perform the operation if the current tags are hidden
if (_attachment_is_shown($tags)) {
difference() {
if (pos != undef) {
show(pos) children();
if (keep == undef) {
hide(neg) children();
} else {
if (keep == undef) {
hide(neg) children();
} else {
hide(str(neg," ",keep)) children();
}
hide(str(neg," ",keep)) children();
}
show(neg) children();
}
}
if (keep!=undef) {
show(keep) children();
} else if (pos!=undef) {
hide(str(pos," ",neg)) children();
}
}
@ -733,23 +831,67 @@ module hulling(a)
// Module: recolor()
// Usage:
// recolor(c) {...}
// recolor([c]) {...}
// Topics: Attachments
// See Also: tags(), hide(), show(), diff(), intersect()
// See Also: color_this(), tags(), hide(), show(), diff(), intersect()
// Description:
// Sets the color for children that can use the $color special variable. For a more step-by-step
// explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Sets the color for children that can use the $color special variable. For this to work
// you cannot have any color() modules above it in any parents, only other recolor() or color_this() modules.
// Not ethat recolor() affects its children and all their descendants.
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// c = Color name or RGBA vector.
// c = Color name or RGBA vector. Default: The standard OpenSCAD yellow
// Example:
// recolor("red") cyl(l=20, d=10);
// cuboid([10,10,5])
// recolor("green")attach(TOP,BOT) cuboid([9,9,4.5])
// attach(TOP,BOT) cuboid([8,8,4])
// recolor("purple") attach(TOP,BOT) cuboid([7,7,3.5])
// attach(TOP,BOT) cuboid([6,6,3])
// recolor("cyan")attach(TOP,BOT) cuboid([5,5,2.5])
// attach(TOP,BOT) cuboid([4,4,2]);
module recolor(c)
{
$color = c;
$color = default(c,_default_color());
children();
}
// Module: color_this()
// Usage:
// color_this([c]) {...}
// Topics: Attachments
// See Also: tags(), recolor()
// Description:
// Sets the color for children at one level, reverting to the previous color for further descendants.
// This works only with attachables and you cannot have any color() modules above it in any parents,
// only recolor() or other color_this() modules.
// .
// This module works by saving the current color, which means it needs to know the current color. If you have
// not yet set the color with {{recolor()}} then the current color is the default color.
// OpenSCAD provides no method for learning the value of the default color, so if you don't use the default
// "cornfield" color scheme you should set $color_scheme to the color scheme you are using.
// Alternatively, always use {{recolor()}} on a parent before using color_this().
// .
// For a more step-by-step explanation of attachments, see the [[Attachments Tutorial|Tutorial-Attachments]].
// Arguments:
// c = Color name or RGBA vector. Default: the standard OpenSCAD yellow
// Example:
// $color_scheme = "cornfield"; // Change this if necessary
// cuboid([10,10,5])
// color_this("green")attach(TOP,BOT) cuboid([9,9,4.5])
// attach(TOP,BOT) cuboid([8,8,4])
// color_this("purple") attach(TOP,BOT) cuboid([7,7,3.5])
// attach(TOP,BOT) cuboid([6,6,3])
// color_this("cyan")attach(TOP,BOT) cuboid([5,5,2.5])
// attach(TOP,BOT) cuboid([4,4,2]);
module color_this(c)
{
$save_color=default($color, _default_color());
$color=default(c, _default_color());
children();
}
// Module: hide()
// Usage:
// hide(tags) {...}
@ -1306,11 +1448,15 @@ module attachable(
children(0);
}
}
if (is_def($save_color)) {
$color=$save_color;
$save_color=undef;
children(1);
} else
children(1);
}
}
// Function: reorient()
//
// Usage: Square/Trapezoid Geometry

View file

@ -404,12 +404,9 @@ cylinder(h=100, d=100, center=true)
BOSL2 introduces the concept of tags. Tags are names that can be given to attachables, so that
you can refer to them when performing `diff()`, `intersect()`, and `hulling()` operations.
### `diff(neg, <pos>, <keep>)`
### `diff(neg, <keep>)`
The `diff()` operator is used to difference away all shapes marked with the tag(s) given to
`neg=`, from shapes marked with the tag(s) given to `pos=`. Anything marked with a tag given
to `keep=` will be unioned onto the result. If no `pos=` argument is given, then everything
marked with a tag given to `neg=` will be differenced from all shapes *not* marked with that
tag.
`neg=`, from the other shapes.
For example, to difference away a child cylinder from the middle of a parent cube, you can
do this:
@ -421,20 +418,6 @@ cube(100, center=true)
cylinder(h=101, d=50, center=true, $tags="hole");
```
If you give both the `neg=` and `pos=` arguments to `diff()`, then the shapes marked by tags
given to `neg=` will be differenced away from the shapes marked with tags given to `pos=`.
Everything else will be unioned to the result.
```openscad-3D
include <BOSL2/std.scad>
diff("hole", "post")
cube(100, center=true)
attach([RIGHT,TOP]) {
cylinder(d=95, h=5, $tags="post");
cylinder(d=50, h=11, anchor=CTR, $tags="hole");
}
```
The `keep=` argument takes tags for shapes that you want to keep in the output.
```openscad-3D
@ -447,6 +430,21 @@ cube(100, center=true)
}
```
Remember that tags are inherited by children. In this case, we need to explicitly
untag the first cylinder (or change its tag to something else), or it
will inherit the "keep" tag and get kept.
```openscad-3D
include <BOSL2/std.scad>
diff("hole", "keep")
cube(100, center=true, $tags="keep")
attach([RIGHT,TOP]) {
cylinder(d=95, h=5, $tags="");
cylinder(d=50, h=11, anchor=CTR, $tags="hole");
}
```
If you need to mark multiple children with a tag, you can use the `tags()` module.
```openscad-3D
@ -477,14 +475,14 @@ Some notable non-attachable modules are `text()`, `linear_extrude()`, `rotate_ex
`intersection()`, `offset()`, `hull()`, and `minkowski()`.
To allow you to use tags-based operations with non-attachable shapes, you can wrap them with the
`tags()` module to specify their tags. For example:
`force_tags()` module to specify their tags. For example:
```openscad-3D
include <BOSL2/std.scad>
diff("hole")
cuboid(50)
attach(TOP)
tags("hole")
force_tags("hole")
rotate_extrude()
right(15)
square(10,center=true);