I've been playing with children(), and I've run into a couple of cases
that are surprising me. I'm wondering if there are better approaches
Case 1:
// For loop generates 1 union'd child, not 1 per iteration. How can I
use a loop, but not union the
// generated entities?
// Passes along children as a single union entity
distribute_inside_x(case.x)
for (letter = "12")
number(letter);
// Sends multiple child, and works as expected.
distribute_inside_x(case.x) {
number("1");
number("2");
}
Case 2:
// Chaining children() joins them together, when I expected them to be
kept separate. How can I
// pass them along to another operator as independent children?
// Works
module grid_layout(row_offset=20, column_offset=20, row_size=3)
{
for (i = [0:1:$children-1])
{
row = i % row_size;
column = floor(i / row_size);
translate([row * row_offset, column * column_offset, 0])
children(i);
}
}
// Receives N children, but passes union of them to grid_layout.
module distribute_inside_x(width=100)
{
offset = width / ($children + 1);
grid_layout(row_offset=offset)
children();
}
--
Don
The lazy-union stuff might do something - I haven't tried to understand it.
Otherwise... mostly, you can't. A module, which includes not only your
own modules but also for(), if(), children(), and so on, always returns
exactly one object.
On 4/14/2022 8:21 AM, Don Garrett wrote:
Case 1:
// For loop generates 1 union'd child, not 1 per iteration. How can I
use a loop, but not union the
// generated entities?
// Passes along children as a single union entity
distribute_inside_x(case.x)
for (letter = "12")
number(letter);
// Sends multiple child, and works as expected.
distribute_inside_x(case.x) {
number("1");
number("2");
}
This is why the language includes intersection_for().
You may be able to do something similar by passing a range or list to
your module, having it run the loop, and having it pass a $ variable
to the children, something like
module my_for(r) {
for ($i = r) {
children();
}
}
my_for([1:10]) {
echo($i);
}
Case 2:
// Chaining children() joins them together, when I expected them to be
kept separate. How can I
// pass them along to another operator as independent children?
// Works
module grid_layout(row_offset=20, column_offset=20, row_size=3)
{
for (i = [0:1:$children-1])
{
row = i % row_size;
column = floor(i / row_size);
translate([row * row_offset, column * column_offset, 0])
children(i);
}
}
// Receives N children, but passes union of them to grid_layout.
module distribute_inside_x(width=100)
{
offset = width / ($children + 1);
grid_layout(row_offset=offset)
children();
}
You can't.
Note that these restrictions are kind of intrinsic to how $children and
children() work.
Children are not evaluated until the parent calls children() on them.
Thus, for instance:
module null() {
// Does nothing
}
null() {
foo();
}
never runs foo().
Now suppose that for() returned separate children.
module onlysecond() {
children(1);
}
onlysecond() {
for (i = [1:10])
cube();
sphere();
}
What would this emit? Until it runs the for() it doesn't know how many
children the for() would emit... and it doesn't run the for().
Or, to make your head explode, how many cubes should this produce?
module howmany() {
$n = $children;
children();
}
howmany() {
for (i = [1:$n+1]) {
echo($i);
cube();
}
}
In general, you have to be able to determine how many "candidate
children" there are before you start executing the parent, so that you
can have $children and so that children(i) can work, and you can't know
how many actual child nodes there will be until after you've executed
the parent.
Could it in theory be different? Yes. But it isn't.
(In particular something like the experimental render() operator could
return a CSG tree that you could then examine. But we don't have that.)
Thanks! What I've heard is "the language doesn't work that way" which
is really useful, because I don't spend time trying to make it "work
that way". ;>
On Thu, Apr 14, 2022 at 8:12 PM Jordan Brown
openscad@jordan.maileater.net wrote:
The lazy-union stuff might do something - I haven't tried to understand it.
Otherwise... mostly, you can't. A module, which includes not only your own modules but also for(), if(), children(), and so on, always returns exactly one object.
On 4/14/2022 8:21 AM, Don Garrett wrote:
Case 1:
// For loop generates 1 union'd child, not 1 per iteration. How can I
use a loop, but not union the
// generated entities?
// Passes along children as a single union entity
distribute_inside_x(case.x)
for (letter = "12")
number(letter);
// Sends multiple child, and works as expected.
distribute_inside_x(case.x) {
number("1");
number("2");
}
This is why the language includes intersection_for().
You may be able to do something similar by passing a range or list to your module, having it run the loop, and having it pass a $ variable to the children, something like
module my_for(r) {
for ($i = r) {
children();
}
}
my_for([1:10]) {
echo($i);
}
Case 2:
// Chaining children() joins them together, when I expected them to be
kept separate. How can I
// pass them along to another operator as independent children?
// Works
module grid_layout(row_offset=20, column_offset=20, row_size=3)
{
for (i = [0:1:$children-1])
{
row = i % row_size;
column = floor(i / row_size);
translate([row * row_offset, column * column_offset, 0])
children(i);
}
}
// Receives N children, but passes union of them to grid_layout.
module distribute_inside_x(width=100)
{
offset = width / ($children + 1);
grid_layout(row_offset=offset)
children();
}
You can't.
Note that these restrictions are kind of intrinsic to how $children and children() work.
Children are not evaluated until the parent calls children() on them. Thus, for instance:
module null() {
// Does nothing
}
null() {
foo();
}
never runs foo().
Now suppose that for() returned separate children.
module onlysecond() {
children(1);
}
onlysecond() {
for (i = [1:10])
cube();
sphere();
}
What would this emit? Until it runs the for() it doesn't know how many children the for() would emit... and it doesn't run the for().
Or, to make your head explode, how many cubes should this produce?
module howmany() {
$n = $children;
children();
}
howmany() {
for (i = [1:$n+1]) {
echo($i);
cube();
}
}
In general, you have to be able to determine how many "candidate children" there are before you start executing the parent, so that you can have $children and so that children(i) can work, and you can't know how many actual child nodes there will be until after you've executed the parent.
Could it in theory be different? Yes. But it isn't.
(In particular something like the experimental render() operator could return a CSG tree that you could then examine. But we don't have that.)
--
Don