Change tags() to just apply the label and add force_tags to actually

apply tagging to objects.
Simplify diff() by removing pos argument, rework docs and add examples
This commit is contained in:
Adrian Mariano 2022-03-18 23:38:12 -04:00
parent de77bc3b8e
commit fbaff36531
2 changed files with 127 additions and 52 deletions

View file

@ -538,12 +538,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 +583,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 +646,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 +687,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();
} else {
if (keep == undef) {
hide(neg) children();
} else {
hide(str(neg," ",keep)) children();
}
}
show(neg) children();
}
}
if (keep!=undef) {
show(keep) children();
} else if (pos!=undef) {
hide(str(pos," ",neg)) children();
}
}

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);