The behaviour if intersection has changed.

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

Re: The behaviour if intersection has changed.

JordanBrown
On 10/4/2020 10:41 AM, adrianv wrote:
Isn't the new lazy union mode already doing the "modules return multiple
objects" behavior?  Or is there some subtle distinction here?

I don't know exactly what lazy-union does, but for programmatic purposes it does not appear to implement "modules return multiple objects".  It produces a different CSG tree, but doesn't seem to affect the number of objects visible to the program.
module howmany() {
    echo($children);
}

howmany() {
    for(i=[1:10])
        translate([i*10,0,0]) cube();
}
echoes "1" whether or not lazy unions are enabled.

Similarly:
module two() {
    cube();
    translate([2,0,0]) cube();
}

howmany() two();
always echoes "1".

[...] I seem to recall there being talk about having for() return its objects separately, and hence not needing intersection_for.

That would be the "modules return multiple objects" behavior - or, as I would say it, the "modules return zero or more objects" behavior.  Eliminating intersection_for would be one of the advantages.  Similarly, if you had a spread() module that spaced its children out, you could say:
spread() {
    for(i=[1:10]) cube();
}
However, it would lead to a need for more explicit unions:
module spherecube() {
    sphere(10);
    cube(15, center=true);
}

spread() spherecube();

would not do what you would expect; you would need

module spherecube() {
    union() {
        sphere(10);
        cube(15, center=true);
    }
}

  


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

Re: The behaviour if intersection has changed.

acwest
As explicit unions can always be added, but unioned objects can't be easily unioned, it is definitely a more flexible solution. Breaking compatibility is the only good reason to ever disable it

On Sun, 4 Oct 2020, 14:19 Jordan Brown, <[hidden email]> wrote:
On 10/4/2020 10:41 AM, adrianv wrote:
Isn't the new lazy union mode already doing the "modules return multiple
objects" behavior?  Or is there some subtle distinction here?

I don't know exactly what lazy-union does, but for programmatic purposes it does not appear to implement "modules return multiple objects".  It produces a different CSG tree, but doesn't seem to affect the number of objects visible to the program.
module howmany() {
    echo($children);
}

howmany() {
    for(i=[1:10])
        translate([i*10,0,0]) cube();
}
echoes "1" whether or not lazy unions are enabled.

Similarly:
module two() {
    cube();
    translate([2,0,0]) cube();
}

howmany() two();
always echoes "1".

[...] I seem to recall there being talk about having for() return its objects separately, and hence not needing intersection_for.

That would be the "modules return multiple objects" behavior - or, as I would say it, the "modules return zero or more objects" behavior.  Eliminating intersection_for would be one of the advantages.  Similarly, if you had a spread() module that spaced its children out, you could say:
spread() {
    for(i=[1:10]) cube();
}
However, it would lead to a need for more explicit unions:
module spherecube() {
    sphere(10);
    cube(15, center=true);
}

spread() spherecube();

would not do what you would expect; you would need

module spherecube() {
    union() {
        sphere(10);
        cube(15, center=true);
    }
}

  
_______________________________________________
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: The behaviour if intersection has changed.

adrianv
In reply to this post by JordanBrown
Here's the forum post about lazy unions:

http://forum.openscad.org/quot-Lazy-union-quot-is-now-experimental-in-snapshots-td27991.html

I have to admit I don't quite understand the workings of the change because
it seems like a half-way change where sometimes objects are passed
separately and sometimes not.  As you note, if you write your own module a
union gets applied.  But if you use difference() or intersection() applied
to a for() you get the behavior of individual objects without a union.   (So
intersection_for is already unnecessary with this change.)  

Try this one with and without lazy union:

difference() {
  for(i=[-1,1], j=[-1,1], k=[-1,1])
    translate([i,j,k])
      sphere(r=.1,$fn=32);
  translate([1,1,1])sphere(r=.15,$fn=32);
}  





--
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: The behaviour if intersection has changed.

cacb
In reply to this post by adrianv
On 04.10.2020 19:41, adrianv wrote:

> Isn't the new lazy union mode already doing the "modules return multiple
> objects" behavior?  Or is there some subtle distinction here?  It at least
> seems like a step in that direction, and I seem to recall there being talk
> about having for() return its objects separately, and hence not needing
> intersection_for.
>
> For anybody who hasn't paid attention, I found that if I make a rounded cube
> as the hull of 8 spheres it takes 9.5 seconds to preview without lazy union
> and 0.2 seconds to preview with lazy union.
>
> hull()
>    for(i=[-1,1], j=[-1,1], k=[-1,1])
>      translate([i,j,k])
>        sphere(r=.1,$fn=32);

There is really no need for a union in this case, so "lazy union" looks
like a fancy name for no implicit union. The difference between 9.5
seconds and 0.2 seconds is an unnecessary union vs. no union. You are
essentially creating an array of spheres and computing the convex hull
from them directly instead of first unioning them and then computing the
hull, much like

https://gist.github.com/arnholm/eda3f740da4f101421a8141b2446a4df

Carsten Arnholm

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

Re: The behaviour if intersection has changed.

JordanBrown
In reply to this post by adrianv
On 10/4/2020 11:51 AM, adrianv wrote:
I have to admit I don't quite understand the workings of the change because
it seems like a half-way change where sometimes objects are passed
separately and sometimes not.

Ugh.  And a particular module (say, "for") sometimes yields multiple objects and sometimes does not.  It appears to yield multiple objects when its parent is "intersection", but a single object when its parent is a user-defined module.

I like either answer better than an (apparently) inconsistent answer.


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

Re: The behaviour if intersection has changed.

adrianv
Based on the quoted forum post it sounded like this was an initial step with
the intent of eliminating the implicit union everywhere, so an inconsistent
intermediate state with a consistent destination.  


JordanBrown wrote

> On 10/4/2020 11:51 AM, adrianv wrote:
>> I have to admit I don't quite understand the workings of the change
>> because
>> it seems like a half-way change where sometimes objects are passed
>> separately and sometimes not.
>
> Ugh.  And a particular module (say, "for") sometimes yields multiple
> objects and sometimes does not.  It appears to yield multiple objects
> when its parent is "intersection", but a single object when its parent
> is a user-defined module.
>
> I like either answer better than an (apparently) inconsistent answer.
>
>
> _______________________________________________
> OpenSCAD mailing list

> Discuss@.openscad

> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org





--
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: The behaviour if intersection has changed.

nophead
 A place where lazy union breaks my code is with an intersection again. If you have a for loop as the second argument it changes the result because each interaction of the for makes a new argument.

        color(gold)
             linear_extrude(size.z)
                intersection() {
                    square([size.x, size.y], center = true);

                    for(end = [-1, 1])
                        translate([end * size.x / 2, 0])
                            ring(or = r, ir = r / 2);
                }

Easy to fix by adding explicit union() but not easy to spot without regression tests.

On Sun, 4 Oct 2020 at 22:06, adrianv <[hidden email]> wrote:
Based on the quoted forum post it sounded like this was an initial step with
the intent of eliminating the implicit union everywhere, so an inconsistent
intermediate state with a consistent destination. 


JordanBrown wrote
> On 10/4/2020 11:51 AM, adrianv wrote:
>> I have to admit I don't quite understand the workings of the change
>> because
>> it seems like a half-way change where sometimes objects are passed
>> separately and sometimes not.
>
> Ugh.  And a particular module (say, "for") sometimes yields multiple
> objects and sometimes does not.  It appears to yield multiple objects
> when its parent is "intersection", but a single object when its parent
> is a user-defined module.
>
> I like either answer better than an (apparently) inconsistent answer.
>
>
> _______________________________________________
> OpenSCAD mailing list

> Discuss@.openscad

> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org





--
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
tp3
Reply | Threaded
Open this post in threaded view
|

Re: The behaviour if intersection has changed.

tp3
On 05.10.20 11:09, nop head wrote:
>  A place where lazy union breaks my code is with an
> intersection again. If you have a for loop as the second
> argument it changes the result because each interaction
> of the for makes a new argument.

I think that relates to the question how to handle
$children. I would assume this needs to be calculated
in a way so the behavior does not change depending on
the number of child objects returned.

ciao,
  Torsten.


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

Re: The behaviour if intersection has changed.

nophead
Lazy union also breaks difference when the first argument is a for loop. Anything after the first iteration gets subtracted, so another case where explicit union is needed. As far as I can tell only two unions() needed adding to my library to fix it.

Speed doesn't seem much different, two seconds slower for a 20 minute build, which is just noise. Some things get faster and some slower.

On Mon, 5 Oct 2020 at 13:13, Torsten Paul <[hidden email]> wrote:
On 05.10.20 11:09, nop head wrote:
>  A place where lazy union breaks my code is with an
> intersection again. If you have a for loop as the second
> argument it changes the result because each interaction
> of the for makes a new argument.

I think that relates to the question how to handle
$children. I would assume this needs to be calculated
in a way so the behavior does not change depending on
the number of child objects returned.

ciao,
  Torsten.


_______________________________________________
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
tp3
Reply | Threaded
Open this post in threaded view
|

Re: The behaviour if intersection has changed.

tp3
On 05.10.20 15:20, nop head wrote:
> Lazy union also breaks difference when the first argument
> is a for loop. Anything after the first iteration gets
> subtracted, so another case where explicit union is needed.
> As far as I can tell only two unions() needed adding to my
> library to fix it.

My preference would be to have it unchanged in behavior, but
maybe with deprecation warnings where needed.

As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.

> Speed doesn't seem much different, two seconds slower
> for a 20 minute build, which is just noise. Some things
> get faster and some slower.

If I remember correctly, it's not yet available in all places
so it might not reach the full potential. At this point it's
probably affecting mostly cases where the top level union is
the big slow operation.

ciao,
  Torsten.

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

Re: The behaviour if intersection has changed.

nophead
My tests are all preview mode, so there is no top level union. Union is free in OpenCSG anyway. It might speed up STL generation but I don't do that inside the library.

Also a lot of my code is optimised to avoid unions inside hulls, etc. For the cube example above I would make a nested module that placed the sphere at a specified x,y,x and then call it 8 times to avoid a for loop.

On Mon, 5 Oct 2020 at 14:53, Torsten Paul <[hidden email]> wrote:
On 05.10.20 15:20, nop head wrote:
> Lazy union also breaks difference when the first argument
> is a for loop. Anything after the first iteration gets
> subtracted, so another case where explicit union is needed.
> As far as I can tell only two unions() needed adding to my
> library to fix it.

My preference would be to have it unchanged in behavior, but
maybe with deprecation warnings where needed.

As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.

> Speed doesn't seem much different, two seconds slower
> for a 20 minute build, which is just noise. Some things
> get faster and some slower.

If I remember correctly, it's not yet available in all places
so it might not reach the full potential. At this point it's
probably affecting mostly cases where the top level union is
the big slow operation.

ciao,
  Torsten.

_______________________________________________
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
rew
Reply | Threaded
Open this post in threaded view
|

Re: The behaviour if intersection has changed.

rew
In reply to this post by tp3
On Mon, Oct 05, 2020 at 03:53:09PM +0200, Torsten Paul wrote:

> On 05.10.20 15:20, nop head wrote:
> > Lazy union also breaks difference when the first argument
> > is a for loop. Anything after the first iteration gets
> > subtracted, so another case where explicit union is needed.
> > As far as I can tell only two unions() needed adding to my
> > library to fix it.
>
> My preference would be to have it unchanged in behavior, but
> maybe with deprecation warnings where needed.
>
> As already mentioned, I think the only way to handle those
> cases is to keep the implicit union / child() selection based
> on static "slots". So if the first "slot" of the union is
> a for(), it will still do the union, or if that "slot" is
> accessed via child() then that will return the list of objects
> that for() generated.

This IMHO would be complicated: Complicated to do in the code,
complicated to explain to the users.

In Unix the filosophy is that you implement what's an easy-to-use
building block and then allow the users to expand using the building
blocks provided.

So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the right
choice: supplying the \n in the format string is simple and easy, but
the other way around is not: If your printf adds the \n at the end
it is NOT easy to make a printf-without-\n out of that.

So IMHO, a "for" primitive in openscad should NOT do an implicit union
and return one object. It's easy to union the objects with an explicit
union () in front of the for. But not the other way around.


And doing it this way can even be funny to use.

Consider such a puzzle.
https://cdn.shopify.com/s/files/1/0181/8685/products/Crystal_Puzzle.jpg?v=1571438517

(now in this specific puzzle, I'm not sure if the actual puzzle is
equivalent to what I'm suggesting).

If I create a module that returns block number i in the position in
the final puzzle, in the order that the puzzle is assembled.....
(but without the cutouts for to-be-assembled blocks).

for (i=[0:1:NBLOCKS])
  difference ()
    for (j=[i:1:NBLOCKS])
      block(j);

This code is simplified when for does not implicitly union the objects
that for returns. In the current situation it has to be something like:

for (i=[0:1:NBLOCKS])
  difference () {
    block (i); // this one is the one we're  building
    for (j=[i+1:1:NBLOCKS]) // but there have to be cutouts for all the future blocks.
      block(j);
  }

with the for-endpoint-smaller-than-start issue we've discussed
before.....  (but for clarity writing it the second way might be a
good idea anyway. I'm torn between the two: I'm a proponent of less
code is good.)

        Roger.

--
** [hidden email] ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a is going up.  -- Chris Hadfield about flying up the space shuttle.

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

Re: The behaviour if intersection has changed.

tp3
On 05.10.20 17:08, Rogier Wolff wrote:
>> As already mentioned, I think the only way to handle those
>> cases is to keep the implicit union / child() selection based
>> on static "slots". So if the first "slot" of the union is
>> a for(), it will still do the union, or if that "slot" is
>> accessed via child() then that will return the list of objects
>> that for() generated.
>
> This IMHO would be complicated: Complicated to do in the code,
> complicated to explain to the users.

So far this is the only solution that actually allows
computation of the needed values. That it's currently
a bit awkward to return data structures is a totally
different topic.

https://github.com/openscad/openscad/issues/3143

I'm open to other suggestions which do solve the issue.

ciao,
  Torsten.

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

Re: The behaviour if intersection has changed.

JordanBrown
In reply to this post by tp3
On 10/5/2020 6:53 AM, Torsten Paul wrote:
As already mentioned, I think the only way to handle those cases is to keep the implicit union / child() selection based on static "slots". So if the first "slot" of the union is a for(), it will still do the union, or if that "slot" is accessed via child() then that will return the list of objects that for() generated.

I *think* what you're describing would make "implicit union" be an implementation detail, something that is invisible to the program.  Right?

Yes - I think there should be two mostly-separate questions:

(1) When does the geometry engine actually do the unions?  I'm not sure because I don't know beans about the internals, but I don't think this needs to interact with the user program *at all*.  I suspect that it could be done while walking the geometry tree to render the final result.
I'm assuming here that the program generates the CSG tree that we see in Design/Display CSG tree, and then one of the two geometry engines walks the tree to build the final result.  Is that a reasonably close model?

Note that this behavior could even extend up through explicit "union" invocations.  If there's some reason why union(A,B,C,D) is better than union(union(A,B),union(C,D)) the geometry engine should be free to rearrange the expression.
(2) When a module - builtin or otherwise - creates multiple objects, does its parent see one object, or several?  (And the degenerate case of zero.)  This is *all* on the front end.


(1) should be totally invisible to the program, totally compatible.
(2) is not at all compatible.


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

Re: The behaviour if intersection has changed.

JordanBrown
In reply to this post by rew
On 10/5/2020 8:08 AM, Rogier Wolff wrote:
So when you get to chose what "printf" does, you can say: most people will want the trailing \n, so we'll tack it on for them. Not the right choice: supplying the \n in the format string is simple and easy, but the other way around is not: If your printf adds the \n at the end it is NOT easy to make a printf-without-\n out of that.

If it wasn't for the huge number of bugs where programs forget to include a \n, or include one where it's not appropriate, I'd agree with you.  But people get this wrong *all* the time.  I think it would have been better to have a function that prints a line (with line termination, whatever that is) and an otherwise similar function that prints a partial line without termination.  That's what Java did with print() and println().  I have to bet that Java programs have many fewer of that class of bugs than C programs, because Java programmers have to make an explicit and obvious choice.  I think Java got it slightly wrong, by having "print" be the less common form; I think BASIC and sh got it right by having the printing statement (print, echo) default to printing a line, and optionally *not* terminate it.

I think the best strategy is to have the usual case be easy and obvious, and the advanced case be possible.


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

Re: The behaviour if intersection has changed.

rew
On Mon, Oct 05, 2020 at 04:48:26PM +0000, Jordan Brown wrote:

> On 10/5/2020 8:08 AM, Rogier Wolff wrote:
> > So when you get to chose what "printf" does, you can say: most people
> > will want the trailing \n, so we'll tack it on for them. Not the right
> > choice: supplying the \n in the format string is simple and easy, but
> > the other way around is not: If your printf adds the \n at the end it
> > is NOT easy to make a printf-without-\n out of that.
>
> If it wasn't for the huge number of bugs where programs forget to
> include a \n, or include one where it's not appropriate, I'd agree with
> you.  But people get this wrong *all* the time.  I think it would have
> been better to have a function that prints a line (with line
> termination, whatever that is) and an otherwise similar function that
> prints a partial line without termination.  That's what Java did with
> print() and println().  I have to bet that Java programs have many fewer
> of that class of bugs than C programs, because Java programmers have to
> make an explicit and obvious choice.  I think Java got it slightly
> wrong, by having "print" be the less common form; I think BASIC and sh
> got it right by having the printing statement (print, echo) default to
> printing a line, and optionally *not* terminate it.
>
> I think the best strategy is to have the usual case be easy and obvious,
> and the advanced case be possible.

In my example of a library function, you can easily provide two variants.

In the case of how to define a language construct you have the restriction
that you have to make ONE choice. That translates back to the library
function example with a restriction: "You are only allowed to provide ONE
function".

In the case of print/println you should then go for "print" as you can
easily define
  println (somestring)
  {
    print (somestring);
    print(NEWLINE);
  }

in almost all languages and you can (must under the restriction that
the library is only allowed one function) leave that to the user.

With this: "what would we want?" discussion I don't think I can
influence openscad to change to do things right: That would lose
compatibility with older programs, and that's not acceptable. But the
realization: "we should've done it differently is" important: it might
help "design" future modules/operations.

        Roger.

--
** [hidden email] ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
f equals m times a. When your f is steady, and your m is going down
your a is going up.  -- Chris Hadfield about flying up the space shuttle.

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

Re: The behaviour if intersection has changed.

adrianv
In reply to this post by tp3
With regards to speed improvements, the one big case I am aware of is calling
hull() on a for loop, the example I posted above.  What are other cases
where unnecessary union gets forced, leading to unnecessarily long run
times?  

I noticed nophead said he avoids the problem of for() loops in hull() by
unwrapping for() loops.  I'll note that this is (1) not always possible and
(2) ugly and annoying to code.  But it seems a necessary workaround (when
possible) in the current stable version because of the performance hit.   I
have a code that generates polyhedra and I'd rather not unroll the loops for
all of the polyhedra: it would make the code huge, incomprehensible and
unmaintainable.   And I'd have to write code to do the unrolling and write
out the unrolled scad code.   Of course, another strategy is to avoid
constructing objects with hull(), which I think is a method nophead also
used: he has described the speed up he achieved by recoding his models to
perform all the difficult operations in 2d and avoid 3d operations.  One
could argue this is sort of like my approach to making rounded solids: avoid
minkowski and compute the rounded solids directly so I can use polyhedron.
It would be nice if we didn't have to work around limitations this way.  

It seems like there are a couple strategies that could be deployed to avoid
breaking compatibility.  One would be to introduce a new for loop, call it
split_for() that performs for() without the implicit union.  If this was
combined with split_children() to pass the children without a union I think
it would provide the full flexibility to pass objects separately or the old
way.   Or I suppose an option flag like for(i=[0:N], union=false) could also
do the job.  

Another strategy (that might be impractical to implement---I don't know)
would be to have a second mechanism to access children that accesses the
children without the union.  This seems harder to understand and use.  




tp3 wrote

> On 05.10.20 15:20, nop head wrote:
>> Lazy union also breaks difference when the first argument
>> is a for loop. Anything after the first iteration gets
>> subtracted, so another case where explicit union is needed.
>> As far as I can tell only two unions() needed adding to my
>> library to fix it.
>
> My preference would be to have it unchanged in behavior, but
> maybe with deprecation warnings where needed.
>
> As already mentioned, I think the only way to handle those
> cases is to keep the implicit union / child() selection based
> on static "slots". So if the first "slot" of the union is
> a for(), it will still do the union, or if that "slot" is
> accessed via child() then that will return the list of objects
> that for() generated.
>
>> Speed doesn't seem much different, two seconds slower
>> for a 20 minute build, which is just noise. Some things
>> get faster and some slower.
>
> If I remember correctly, it's not yet available in all places
> so it might not reach the full potential. At this point it's
> probably affecting mostly cases where the top level union is
> the big slow operation.





--
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: The behaviour if intersection has changed.

nophead
There is a fundamental problem with children and for loops that Torsten linked to above though. If the child is a for loop that isn't unioned then $children can't be evaluated until the loop has run but with dynamic scoped variables the loop count might depend on variables in the parent. So you get a chicken and egg problem.



On Mon, 5 Oct 2020 at 21:36, adrianv <[hidden email]> wrote:
With regards to speed improvements, the one big case I am aware of is calling
hull() on a for loop, the example I posted above.  What are other cases
where unnecessary union gets forced, leading to unnecessarily long run
times? 

I noticed nophead said he avoids the problem of for() loops in hull() by
unwrapping for() loops.  I'll note that this is (1) not always possible and
(2) ugly and annoying to code.  But it seems a necessary workaround (when
possible) in the current stable version because of the performance hit.   I
have a code that generates polyhedra and I'd rather not unroll the loops for
all of the polyhedra: it would make the code huge, incomprehensible and
unmaintainable.   And I'd have to write code to do the unrolling and write
out the unrolled scad code.   Of course, another strategy is to avoid
constructing objects with hull(), which I think is a method nophead also
used: he has described the speed up he achieved by recoding his models to
perform all the difficult operations in 2d and avoid 3d operations.  One
could argue this is sort of like my approach to making rounded solids: avoid
minkowski and compute the rounded solids directly so I can use polyhedron.
It would be nice if we didn't have to work around limitations this way. 

It seems like there are a couple strategies that could be deployed to avoid
breaking compatibility.  One would be to introduce a new for loop, call it
split_for() that performs for() without the implicit union.  If this was
combined with split_children() to pass the children without a union I think
it would provide the full flexibility to pass objects separately or the old
way.   Or I suppose an option flag like for(i=[0:N], union=false) could also
do the job. 

Another strategy (that might be impractical to implement---I don't know)
would be to have a second mechanism to access children that accesses the
children without the union.  This seems harder to understand and use. 




tp3 wrote
> On 05.10.20 15:20, nop head wrote:
>> Lazy union also breaks difference when the first argument
>> is a for loop. Anything after the first iteration gets
>> subtracted, so another case where explicit union is needed.
>> As far as I can tell only two unions() needed adding to my
>> library to fix it.
>
> My preference would be to have it unchanged in behavior, but
> maybe with deprecation warnings where needed.
>
> As already mentioned, I think the only way to handle those
> cases is to keep the implicit union / child() selection based
> on static "slots". So if the first "slot" of the union is
> a for(), it will still do the union, or if that "slot" is
> accessed via child() then that will return the list of objects
> that for() generated.
>
>> Speed doesn't seem much different, two seconds slower
>> for a 20 minute build, which is just noise. Some things
>> get faster and some slower.
>
> If I remember correctly, it's not yet available in all places
> so it might not reach the full potential. At this point it's
> probably affecting mostly cases where the top level union is
> the big slow operation.





--
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: The behaviour if intersection has changed.

JordanBrown
In reply to this post by rew
On 10/5/2020 11:47 AM, Rogier Wolff wrote:
In the case of how to define a language construct you have the restriction that you have to make ONE choice. That translates back to the library function example with a restriction: "You are only allowed to provide ONE function".

You could do as some other languages (BASIC and sh come to mind) and have "don't terminate the line" be an option on the print operation.

That is, it could be
print(..., line={true|false})

where the default is true.  Or something like that.

In BASIC, a PRINT statement normally terminates the line.  When terminated with a semicolon, it ends without terminating the line.  In UNIX shells, "echo" normally terminates the line.  In Berkeley-derived shells, "echo -n" does not terminate the line; in AT&T-derived shells a "\c" at the end prevents it from terminating the line.

With this: "what would we want?" discussion I don't think I can
influence openscad to change to do things right: That would lose
compatibility with older programs, and that's not acceptable. But the
realization: "we should've done it differently is" important: it might
help "design" future modules/operations.

Yes.  And in particular a hypothetical printf-like module.  (Which I will try to throw together, but it'll be stretching my C++ skills.)


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

Re: The behaviour if intersection has changed.

JordanBrown
In reply to this post by nophead
On 10/5/2020 2:04 PM, nop head wrote:
There is a fundamental problem with children and for loops that Torsten linked to above though. If the child is a for loop that isn't unioned then $children can't be evaluated until the loop has run but with dynamic scoped variables the loop count might depend on variables in the parent. So you get a chicken and egg problem.

That's a good point, and a problem with any scheme where a module can return other than one child - that children aren't executed until they are referred to.  The same problem would apply to an "failing if yields nothing" scheme.

I don't think - and as usual I'm speaking as somebody who only has a mental model of how this stuff works, not actual experience with the guts - that this necessarily affects a lazy union mechanism.  A lazy union mechanism could walk the geometry tree accumulating lists of objects that need to eventually be unioned, and do the actual union only when needed for that particular context.


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