Functions that can query a given 3D shape and provide size or location info #301

Open
filipmu opened this Issue Mar 10, 2013 · 64 comments

Comments

Projects
None yet
@filipmu

filipmu commented Mar 10, 2013

All openscad functions take parameters as input and produce shapes. It would be useful to have functions that take shapes as input and produce parameters. This would be useful for aligning shapes. Some examples are max/min dimensions on each axis, center of gravity, etc. There are a number of uses of this feature: 1-since all shapes in openscad are polyhedrons, spheres and cylinders do not render exactly as specified. So there is no way to exactly align shapes based only on input parameters. 2-To align two objects created by separate modules, the user needs to know the inner workings of each module to calculate how to align them. 3- Application of complex transformations like Minkowski and Convex Hull or many CSG combinations create shapes with very complex boundaries that can't be easily calculated.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@ivoknutsel

This comment has been minimized.

Show comment Hide comment
@ivoknutsel

ivoknutsel Apr 29, 2013

Contributor

What would the syntax for these functions and their use look like ?

Contributor

ivoknutsel commented Apr 29, 2013

What would the syntax for these functions and their use look like ?

@GilesBathgate

This comment has been minimized.

Show comment Hide comment
@GilesBathgate

GilesBathgate Apr 29, 2013

Contributor

For now It doesn't really matter how they look like until someone can come up with a sensible way to implement it.

The problem is this:

To find the boundaries of objects you have to first evaluate the script into its CSG result. At this point you then have to feed those boundary values back into the script and evaluate the CSG result again. If the value from the first evaluation effects the result of the boundary in the second evaluation you will have to feed those boundary values back into the script and evaluate the CSG again, and of course this process would go in forever in an infinite loop.

At least that's the fundamental problem with it the way I see it. Perhaps I've misunderstood.

Regards,
Giles

Contributor

GilesBathgate commented Apr 29, 2013

For now It doesn't really matter how they look like until someone can come up with a sensible way to implement it.

The problem is this:

To find the boundaries of objects you have to first evaluate the script into its CSG result. At this point you then have to feed those boundary values back into the script and evaluate the CSG result again. If the value from the first evaluation effects the result of the boundary in the second evaluation you will have to feed those boundary values back into the script and evaluate the CSG again, and of course this process would go in forever in an infinite loop.

At least that's the fundamental problem with it the way I see it. Perhaps I've misunderstood.

Regards,
Giles

@ivoknutsel

This comment has been minimized.

Show comment Hide comment
@ivoknutsel

ivoknutsel Apr 29, 2013

Contributor

I have more or less the same problem, i create geometries in nested modules. In the root i need to position the geometries relative to each other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree and the tree and all variables are calculated compile time. There is no way to assign a geometry or the result of a module to a variable, modules don't return values but can only (with "child()") modify or disable branches in the model tree.

I am an OpenSCAD novice and may be completely wrong.

Contributor

ivoknutsel commented Apr 29, 2013

I have more or less the same problem, i create geometries in nested modules. In the root i need to position the geometries relative to each other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree and the tree and all variables are calculated compile time. There is no way to assign a geometry or the result of a module to a variable, modules don't return values but can only (with "child()") modify or disable branches in the model tree.

I am an OpenSCAD novice and may be completely wrong.

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Apr 29, 2013

Contributor

The shapes I make have required dimensions, so those are parameters and if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have generated
but getting the size of imported STLs would be useful and I don't think has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree and
the tree and all variables are calculated compile time. There is no way to
assign a geometry or the result of a module to a variable, modules don't
return values but can only (with "child()") modify or disable branches in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17169033
.

Contributor

nophead commented Apr 29, 2013

The shapes I make have required dimensions, so those are parameters and if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have generated
but getting the size of imported STLs would be useful and I don't think has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree and
the tree and all variables are calculated compile time. There is no way to
assign a geometry or the result of a module to a variable, modules don't
return values but can only (with "child()") modify or disable branches in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17169033
.

@TakeItAndRun

This comment has been minimized.

Show comment Hide comment
@TakeItAndRun

TakeItAndRun Apr 29, 2013

Use stl-viers (like MiniMagics) to measure the dimensions of an stl. Thats
easy and comfortable.

I see no need to teach OpenSCAD was other programs can do better.

Sincerely,

TakeItAndRun

On 29 April 2013 17:01, Chris notifications@github.com wrote:

The shapes I make have required dimensions, so those are parameters and if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have generated
but getting the size of imported STLs would be useful and I don't think
has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree
and
the tree and all variables are calculated compile time. There is no way
to
assign a geometry or the result of a module to a variable, modules don't
return values but can only (with "child()") modify or disable branches
in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17169033>
.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17171908
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

Use stl-viers (like MiniMagics) to measure the dimensions of an stl. Thats
easy and comfortable.

I see no need to teach OpenSCAD was other programs can do better.

Sincerely,

TakeItAndRun

On 29 April 2013 17:01, Chris notifications@github.com wrote:

The shapes I make have required dimensions, so those are parameters and if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have generated
but getting the size of imported STLs would be useful and I don't think
has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree
and
the tree and all variables are calculated compile time. There is no way
to
assign a geometry or the result of a module to a variable, modules don't
return values but can only (with "child()") modify or disable branches
in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17169033>
.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17171908
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Apr 29, 2013

Contributor

I do if I want to know the size, but if I want to import an STL and
manipulate it in openscad I don't want to measure it in another program and
accompany it with some hard coded numbers.

On 29 April 2013 21:24, TakeItAndRun notifications@github.com wrote:

Use stl-viers (like MiniMagics) to measure the dimensions of an stl. Thats
easy and comfortable.

I see no need to teach OpenSCAD was other programs can do better.

Sincerely,

TakeItAndRun

On 29 April 2013 17:01, Chris notifications@github.com wrote:

The shapes I make have required dimensions, so those are parameters and
if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have
generated
but getting the size of imported STLs would be useful and I don't think
has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to
each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree
and
the tree and all variables are calculated compile time. There is no
way
to
assign a geometry or the result of a module to a variable, modules
don't
return values but can only (with "child()") modify or disable branches
in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17169033>
.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17171908>
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17191803
.

Contributor

nophead commented Apr 29, 2013

I do if I want to know the size, but if I want to import an STL and
manipulate it in openscad I don't want to measure it in another program and
accompany it with some hard coded numbers.

On 29 April 2013 21:24, TakeItAndRun notifications@github.com wrote:

Use stl-viers (like MiniMagics) to measure the dimensions of an stl. Thats
easy and comfortable.

I see no need to teach OpenSCAD was other programs can do better.

Sincerely,

TakeItAndRun

On 29 April 2013 17:01, Chris notifications@github.com wrote:

The shapes I make have required dimensions, so those are parameters and
if
I need them later for positioning, etc, I use variables or functions to
access them. I never need to query the size of something I have
generated
but getting the size of imported STLs would be useful and I don't think
has
the problems Giles alluded to..

On 29 April 2013 15:15, ivoknutsel notifications@github.com wrote:

I have more or less the same problem, i create geometries in nested
modules. In the root i need to position the geometries relative to
each
other based on the length or another function of those geometries.

As i understand OpenSCAD, geometries are always leaves in a model tree
and
the tree and all variables are calculated compile time. There is no
way
to
assign a geometry or the result of a module to a variable, modules
don't
return values but can only (with "child()") modify or disable branches
in
the model tree.

I am an OpenSCAD novice and may be completely wrong.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17169033>
.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-17171908>
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17191803
.

@GilesBathgate

This comment has been minimized.

Show comment Hide comment
@GilesBathgate

GilesBathgate Apr 29, 2013

Contributor

Rapcad implements a bounds module. It just echos the bounds of its children to the console, which you can then copy back into the script. Its still hardcoded numbers but I think its better than nothing. Still can't get my head around how it would feed the value back into the script without re-evaluation.

On the other hand as nophead points out a stl_dim() function (equivalent to dxf_dim()) would be nice.

Regards,
Giles

Contributor

GilesBathgate commented Apr 29, 2013

Rapcad implements a bounds module. It just echos the bounds of its children to the console, which you can then copy back into the script. Its still hardcoded numbers but I think its better than nothing. Still can't get my head around how it would feed the value back into the script without re-evaluation.

On the other hand as nophead points out a stl_dim() function (equivalent to dxf_dim()) would be nice.

Regards,
Giles

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Apr 29, 2013

Contributor

You could have a function that takes the STL filename and returns a vector
of bounds. Behind the scenes openscad could cache the STL so it doesn't
need to be read twice when it gets to the import, or vice versa.

On 29 April 2013 21:36, Giles Bathgate notifications@github.com wrote:

Rapcad implements a bounds module. It just echos the bounds of its
children to the console, which you can then copy back into the script. Its
still hardcoded numbers but I think its better than nothing. Still can't
get my head around how it would feed the value back into the script without
re-evaluation.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17192560
.

Contributor

nophead commented Apr 29, 2013

You could have a function that takes the STL filename and returns a vector
of bounds. Behind the scenes openscad could cache the STL so it doesn't
need to be read twice when it gets to the import, or vice versa.

On 29 April 2013 21:36, Giles Bathgate notifications@github.com wrote:

Rapcad implements a bounds module. It just echos the bounds of its
children to the console, which you can then copy back into the script. Its
still hardcoded numbers but I think its better than nothing. Still can't
get my head around how it would feed the value back into the script without
re-evaluation.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17192560
.

@kintel

This comment has been minimized.

Show comment Hide comment
@kintel

kintel Apr 29, 2013

Member

If we handled imports similar to how we handle use and include, this would work.
Imported objects would then become resources which can be used by the script.
Naturally, the script then cannot be evaluated before files are loaded, but that's decent enough I'd think.

RapCad actually started on doing this by introducing a new import syntax: import <myfile.stl> as myfile.

Ideally, myfile would in this case become a variable which could be queried, e.g. myfile.bounds (not sure what else would be interesting to query for).

Also, there already is a similar hack in OpenSCAD: We have have dxfdim() function, which reads dimensions from a DXF file and makes it available to the script. I really don't like that function, but it's there :/

Member

kintel commented Apr 29, 2013

If we handled imports similar to how we handle use and include, this would work.
Imported objects would then become resources which can be used by the script.
Naturally, the script then cannot be evaluated before files are loaded, but that's decent enough I'd think.

RapCad actually started on doing this by introducing a new import syntax: import <myfile.stl> as myfile.

Ideally, myfile would in this case become a variable which could be queried, e.g. myfile.bounds (not sure what else would be interesting to query for).

Also, there already is a similar hack in OpenSCAD: We have have dxfdim() function, which reads dimensions from a DXF file and makes it available to the script. I really don't like that function, but it's there :/

@kintel

This comment has been minimized.

Show comment Hide comment
@kintel

kintel May 9, 2013

Member

Related to this, the new resize() module might provide a workflow for some of the cases where a query would be the obvious solution.

See https://github.com/openscad/openscad/blob/master/testdata/scad/features/resize-2d-tests.scad and https://github.com/openscad/openscad/blob/master/testdata/scad/features/resize-tests.scad

Member

kintel commented May 9, 2013

Related to this, the new resize() module might provide a workflow for some of the cases where a query would be the obvious solution.

See https://github.com/openscad/openscad/blob/master/testdata/scad/features/resize-2d-tests.scad and https://github.com/openscad/openscad/blob/master/testdata/scad/features/resize-tests.scad

@NateTG

This comment has been minimized.

Show comment Hide comment
@NateTG

NateTG May 12, 2013

Contributor

... At this point you then have to feed those boundary values back into the script and evaluate the CSG result
again.

My understanding is that variables can only have their value set once in OpenSCAD, so if you could assign a mesh to a variable, and then operate on the variable, you should never get in trouble. Since you can't alter the underlying variable after getting its dimensions.

Contributor

NateTG commented May 12, 2013

... At this point you then have to feed those boundary values back into the script and evaluate the CSG result
again.

My understanding is that variables can only have their value set once in OpenSCAD, so if you could assign a mesh to a variable, and then operate on the variable, you should never get in trouble. Since you can't alter the underlying variable after getting its dimensions.

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead May 12, 2013

Contributor

echo(i);

i =1;

ECHO: 1

So it seems you can use variables before they are defined, so that would
cause problems if the mesh depended on that variable.

On 12 May 2013 18:56, NateTG notifications@github.com wrote:

... At this point you then have to feed those boundary values back into
the script and evaluate the CSG result
again.

My understanding is that variables can only have their value set once in
OpenSCAD, so if you could assign a mesh to a variable, and then operate on
the variable, you should never get in trouble. Since you can't alter the
underlying variable after getting its dimensions.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17782075
.

Contributor

nophead commented May 12, 2013

echo(i);

i =1;

ECHO: 1

So it seems you can use variables before they are defined, so that would
cause problems if the mesh depended on that variable.

On 12 May 2013 18:56, NateTG notifications@github.com wrote:

... At this point you then have to feed those boundary values back into
the script and evaluate the CSG result
again.

My understanding is that variables can only have their value set once in
OpenSCAD, so if you could assign a mesh to a variable, and then operate on
the variable, you should never get in trouble. Since you can't alter the
underlying variable after getting its dimensions.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-17782075
.

@kintel

This comment has been minimized.

Show comment Hide comment
@kintel

kintel May 12, 2013

Member

Assignments are collected over the entire scope and evaluated first (but in individual order of each variable's last assignment). I don't see how this would cause problems.
However, to be able to assign meshes to variables, we'd need to be able to evaluate the corresponding geometry inline with the parser, which is a major architecture change.

Member

kintel commented May 12, 2013

Assignments are collected over the entire scope and evaluated first (but in individual order of each variable's last assignment). I don't see how this would cause problems.
However, to be able to assign meshes to variables, we'd need to be able to evaluate the corresponding geometry inline with the parser, which is a major architecture change.

@ablapo

This comment has been minimized.

Show comment Hide comment
@ablapo

ablapo Jun 18, 2013

Here is my idea. Just make a rough estimate, that would be sufficient for most things.
Do you think it is possible to use the hull() function on an imported STL-file and remember that hull-data for later function calls. And is it possible to get some info from that hull data?
hull_import (hulldata, "3D_Object.stl");

length= outbound_length ( angle [x,y,z], hulldata); -> gives the length to boarder from the center (0,0,0)
vertex=outbound_vertex ( angle [x,y,z], hulldata); -> gives the 3d-vertex of the hitting face of the hull

With that tools you could arrange elements around a stl-file. Make Masks from 3D scanned humans. Make cloth around scanned bodies.

Maybe split that into two parts, if its too difficult.

  1. Step: generate a .dat -file with a hull data from a stl.
  2. Step: use that .dat file to get the important values

ablapo commented Jun 18, 2013

Here is my idea. Just make a rough estimate, that would be sufficient for most things.
Do you think it is possible to use the hull() function on an imported STL-file and remember that hull-data for later function calls. And is it possible to get some info from that hull data?
hull_import (hulldata, "3D_Object.stl");

length= outbound_length ( angle [x,y,z], hulldata); -> gives the length to boarder from the center (0,0,0)
vertex=outbound_vertex ( angle [x,y,z], hulldata); -> gives the 3d-vertex of the hitting face of the hull

With that tools you could arrange elements around a stl-file. Make Masks from 3D scanned humans. Make cloth around scanned bodies.

Maybe split that into two parts, if its too difficult.

  1. Step: generate a .dat -file with a hull data from a stl.
  2. Step: use that .dat file to get the important values
@GilesBathgate

This comment has been minimized.

Show comment Hide comment
@GilesBathgate

GilesBathgate Jun 18, 2013

Contributor

Can we add a FAQ to the main OpenSCAD website? this question/idea keeps being asked/suggested.

Contributor

GilesBathgate commented Jun 18, 2013

Can we add a FAQ to the main OpenSCAD website? this question/idea keeps being asked/suggested.

@kintel

This comment has been minimized.

Show comment Hide comment
@kintel

kintel Jun 18, 2013

Member

Yes, we should start a FAQ

Member

kintel commented Jun 18, 2013

Yes, we should start a FAQ

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Dec 27, 2013

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the evaluate the csg tree to obtain the final geometry. Because of that, any measure on the geometry is only available long after the parsing is done.

However, nothing prevents a partial evaluation of the csg tree during parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its childs) immediately during parsing, and it computes the bounding box of the resulting polyset geometry.
To make this information available to the code, it simply defines variables ($xmin, $xmax, ...) in the context of its parsing parent. This means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation" for render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the bounding box:

bbox-a

The code looks like this:

module openbbox(ep=3,sc=0.7) {
    render() child(0); // draw and measure the child
    echo("bbox X is ",$xmin,$xmax);
    echo("bbox Y is ",$ymin,$ymax);
    echo("bbox Z is ",$zmin,$zmax);
    color("blue",0.2) union() {
        translate([$xmin-ep/2,0,0]) scale([1,sc,sc]) cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
        translate([$xmax+ep/2,0,0]) scale([1,sc,sc]) cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
        translate([0,$ymin-ep/2,0]) scale([sc,1,sc]) cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
        translate([0,$ymax+ep/2,0]) scale([sc,1,sc]) cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
        translate([0,0,$zmin-ep/2]) scale([sc,sc,1]) cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
        translate([0,0,$zmax+ep/2]) scale([sc,sc,1]) cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
    }
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);

This means that once an object is created, it is easy to place other objects relative to it. What about measuring geometry before using it, so we can place the object according to its size? What we need is a way to "render but don' t use the resulting geometry" . I ended up using '%', which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured sizes:

bbox-b

The code (a little ugly, sorry) :

module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed)) cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }

// stack the second child so its resting on top of second child
module stack() {
        render() child(0); // the "base"
        // use the zmax of this object as a reference
        assign(alt=$zmax) {
                %render() child(1); // do not keep this geometry
                translate([0,0,-$zmin+alt]) child(1); // show the child at the right place
        }
}

stack() {
        stack() {
                stack() {
                        stack() {
                                stack() {
                                        stack() {
                                                base(h=5);
                                                randcylinder(100);
                                        }
                                        base(h=10);
                                }
                                randcylinder(101);
                        }
                        base(h=2);
                }
                randcylinder(102);
        }
        base(h=4);
}

Before I submit this, I would like to know what people think of this approach to measuring. Also, my changes are too much of a "hack" at this point and need a bit of work to integrate nicely.

blobule commented Dec 27, 2013

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the evaluate the csg tree to obtain the final geometry. Because of that, any measure on the geometry is only available long after the parsing is done.

However, nothing prevents a partial evaluation of the csg tree during parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its childs) immediately during parsing, and it computes the bounding box of the resulting polyset geometry.
To make this information available to the code, it simply defines variables ($xmin, $xmax, ...) in the context of its parsing parent. This means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation" for render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the bounding box:

bbox-a

The code looks like this:

module openbbox(ep=3,sc=0.7) {
    render() child(0); // draw and measure the child
    echo("bbox X is ",$xmin,$xmax);
    echo("bbox Y is ",$ymin,$ymax);
    echo("bbox Z is ",$zmin,$zmax);
    color("blue",0.2) union() {
        translate([$xmin-ep/2,0,0]) scale([1,sc,sc]) cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
        translate([$xmax+ep/2,0,0]) scale([1,sc,sc]) cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
        translate([0,$ymin-ep/2,0]) scale([sc,1,sc]) cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
        translate([0,$ymax+ep/2,0]) scale([sc,1,sc]) cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
        translate([0,0,$zmin-ep/2]) scale([sc,sc,1]) cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
        translate([0,0,$zmax+ep/2]) scale([sc,sc,1]) cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
    }
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);

This means that once an object is created, it is easy to place other objects relative to it. What about measuring geometry before using it, so we can place the object according to its size? What we need is a way to "render but don' t use the resulting geometry" . I ended up using '%', which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured sizes:

bbox-b

The code (a little ugly, sorry) :

module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed)) cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }

// stack the second child so its resting on top of second child
module stack() {
        render() child(0); // the "base"
        // use the zmax of this object as a reference
        assign(alt=$zmax) {
                %render() child(1); // do not keep this geometry
                translate([0,0,-$zmin+alt]) child(1); // show the child at the right place
        }
}

stack() {
        stack() {
                stack() {
                        stack() {
                                stack() {
                                        stack() {
                                                base(h=5);
                                                randcylinder(100);
                                        }
                                        base(h=10);
                                }
                                randcylinder(101);
                        }
                        base(h=2);
                }
                randcylinder(102);
        }
        base(h=4);
}

Before I submit this, I would like to know what people think of this approach to measuring. Also, my changes are too much of a "hack" at this point and need a bit of work to integrate nicely.

@TakeItAndRun

This comment has been minimized.

Show comment Hide comment
@TakeItAndRun

TakeItAndRun Dec 28, 2013

+1

2013/12/27 blobule notifications@github.com

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the
evaluate the csg tree to obtain the final geometry. Because of that, any
measure on the geometry is only available long after the parsing is done.

However, nothing prevents a partial evaluation of the csg tree during
parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its
childs) immediately during parsing, and it computes the bounding box of the
resulting polyset geometry.
To make this information available to the code, it simply defines
variables ($xmin, $xmax, ...) in the context of its parsing parent. This
means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are
only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation" for
render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the
bounding box:

[image: bbox-a]https://f.cloud.github.com/assets/3324317/1816370/35346296-6f3a-11e3-9286-3a9af66d175f.png

The code looks like this:

/////////////////////////////////////////////////////////
module openbbox(ep=3,sc=0.7) {
render() child(0); // draw and measure the child
echo("bbox X is ",$xmin,$xmax);
echo("bbox Y is ",$ymin,$ymax);
echo("bbox Z is ",$zmin,$zmax);
color("blue",0.2) union() {
translate([$xmin-ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([$xmax+ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([0,$ymin-ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,$ymax+ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,0,$zmin-ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
translate([0,0,$zmax+ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
}
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);
////////////////////////////////////////////////////////////

This means that once an object is created, it is easy to place other
objects relative to it. What about measuring geometry before using it,
so we can place the object according to its size? What we need is a way to
"render but don' t use the resulting geometry" . I ended up using '%',
which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured sizes:

[image: bbox-b]https://f.cloud.github.com/assets/3324317/1816371/3abe7012-6f3a-11e3-997a-e8bea63c8922.png

The code (a little ugly, sorry) :

//////////////////////////////////////////////////////////////////
module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed))
cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }
// stack the second child so its resting on top of second child
module stack() {
render() child(0); // the "base"
// use the zmax of this object as a reference
assign(alt=$zmax) {
%render() child(1); // do not keep this geometry
translate([0,0,-$zmin+alt]) child(1); // show the child at the right place
}
}

stack() {
stack() {
stack() {
stack() {
stack() {
stack() {
base(h=5);
randcylinder(100);
}
base(h=10);
}
randcylinder(101);
}
base(h=2);
}
randcylinder(102);
}
base(h=4);
}
//////////////////////////////////////////////////

Before I submit this, I would like to know what people think of this
approach to measuring. Also, my changes are too much of a "hack" and need a
bit of work to integrate nicely.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31281107
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

+1

2013/12/27 blobule notifications@github.com

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the
evaluate the csg tree to obtain the final geometry. Because of that, any
measure on the geometry is only available long after the parsing is done.

However, nothing prevents a partial evaluation of the csg tree during
parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its
childs) immediately during parsing, and it computes the bounding box of the
resulting polyset geometry.
To make this information available to the code, it simply defines
variables ($xmin, $xmax, ...) in the context of its parsing parent. This
means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are
only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation" for
render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the
bounding box:

[image: bbox-a]https://f.cloud.github.com/assets/3324317/1816370/35346296-6f3a-11e3-9286-3a9af66d175f.png

The code looks like this:

/////////////////////////////////////////////////////////
module openbbox(ep=3,sc=0.7) {
render() child(0); // draw and measure the child
echo("bbox X is ",$xmin,$xmax);
echo("bbox Y is ",$ymin,$ymax);
echo("bbox Z is ",$zmin,$zmax);
color("blue",0.2) union() {
translate([$xmin-ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([$xmax+ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([0,$ymin-ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,$ymax+ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,0,$zmin-ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
translate([0,0,$zmax+ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
}
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);
////////////////////////////////////////////////////////////

This means that once an object is created, it is easy to place other
objects relative to it. What about measuring geometry before using it,
so we can place the object according to its size? What we need is a way to
"render but don' t use the resulting geometry" . I ended up using '%',
which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured sizes:

[image: bbox-b]https://f.cloud.github.com/assets/3324317/1816371/3abe7012-6f3a-11e3-997a-e8bea63c8922.png

The code (a little ugly, sorry) :

//////////////////////////////////////////////////////////////////
module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed))
cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }
// stack the second child so its resting on top of second child
module stack() {
render() child(0); // the "base"
// use the zmax of this object as a reference
assign(alt=$zmax) {
%render() child(1); // do not keep this geometry
translate([0,0,-$zmin+alt]) child(1); // show the child at the right place
}
}

stack() {
stack() {
stack() {
stack() {
stack() {
stack() {
base(h=5);
randcylinder(100);
}
base(h=10);
}
randcylinder(101);
}
base(h=2);
}
randcylinder(102);
}
base(h=4);
}
//////////////////////////////////////////////////

Before I submit this, I would like to know what people think of this
approach to measuring. Also, my changes are too much of a "hack" and need a
bit of work to integrate nicely.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31281107
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Dec 28, 2013

Contributor

It breaks OpenScad's assignment rules.

x = 1;
render() sphere(r=x);
x = $xmax;

On 28 December 2013 00:07, TakeItAndRun notifications@github.com wrote:

+1

2013/12/27 blobule notifications@github.com

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the
evaluate the csg tree to obtain the final geometry. Because of that, any
measure on the geometry is only available long after the parsing is
done.

However, nothing prevents a partial evaluation of the csg tree during
parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its
childs) immediately during parsing, and it computes the bounding box of
the
resulting polyset geometry.
To make this information available to the code, it simply defines
variables ($xmin, $xmax, ...) in the context of its parsing parent. This
means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are
only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation"
for
render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the
bounding box:

[image: bbox-a]<
https://f.cloud.github.com/assets/3324317/1816370/35346296-6f3a-11e3-9286-3a9af66d175f.png>

The code looks like this:

/////////////////////////////////////////////////////////
module openbbox(ep=3,sc=0.7) {
render() child(0); // draw and measure the child
echo("bbox X is ",$xmin,$xmax);
echo("bbox Y is ",$ymin,$ymax);
echo("bbox Z is ",$zmin,$zmax);
color("blue",0.2) union() {
translate([$xmin-ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([$xmax+ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([0,$ymin-ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,$ymax+ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,0,$zmin-ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
translate([0,0,$zmax+ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
}
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);
////////////////////////////////////////////////////////////

This means that once an object is created, it is easy to place other
objects relative to it. What about measuring geometry before using it,
so we can place the object according to its size? What we need is a way
to
"render but don' t use the resulting geometry" . I ended up using '%',
which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured
sizes:

[image: bbox-b]<
https://f.cloud.github.com/assets/3324317/1816371/3abe7012-6f3a-11e3-997a-e8bea63c8922.png>

The code (a little ugly, sorry) :

//////////////////////////////////////////////////////////////////
module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed))
cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }
// stack the second child so its resting on top of second child
module stack() {
render() child(0); // the "base"
// use the zmax of this object as a reference
assign(alt=$zmax) {
%render() child(1); // do not keep this geometry
translate([0,0,-$zmin+alt]) child(1); // show the child at the right
place
}
}

stack() {
stack() {
stack() {
stack() {
stack() {
stack() {
base(h=5);
randcylinder(100);
}
base(h=10);
}
randcylinder(101);
}
base(h=2);
}
randcylinder(102);
}
base(h=4);
}
//////////////////////////////////////////////////

Before I submit this, I would like to know what people think of this
approach to measuring. Also, my changes are too much of a "hack" and
need a
bit of work to integrate nicely.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-31281107>
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31285935
.

Contributor

nophead commented Dec 28, 2013

It breaks OpenScad's assignment rules.

x = 1;
render() sphere(r=x);
x = $xmax;

On 28 December 2013 00:07, TakeItAndRun notifications@github.com wrote:

+1

2013/12/27 blobule notifications@github.com

I just did an interesting experiment on the issue of "measuring"...

We all known that openscad parse the code first, builds a csg tree, the
evaluate the csg tree to obtain the final geometry. Because of that, any
measure on the geometry is only available long after the parsing is
done.

However, nothing prevents a partial evaluation of the csg tree during
parsing... Here what I did to achieve this:

The command "render()" now does the csg rendering of its subtree (its
childs) immediately during parsing, and it computes the bounding box of
the
resulting polyset geometry.
To make this information available to the code, it simply defines
variables ($xmin, $xmax, ...) in the context of its parsing parent. This
means that this will work:

render() sphere(r=10);
echo("bbox is ",$xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

Of course, since this is done during parsing, those information are
only available to what follows render() in the code.
Because there is a cache system for geometry, this "early evaluation"
for
render does not seem to impact performance.

Here is an example adding walls around an object to illustrate the
bounding box:

[image: bbox-a]<
https://f.cloud.github.com/assets/3324317/1816370/35346296-6f3a-11e3-9286-3a9af66d175f.png>

The code looks like this:

/////////////////////////////////////////////////////////
module openbbox(ep=3,sc=0.7) {
render() child(0); // draw and measure the child
echo("bbox X is ",$xmin,$xmax);
echo("bbox Y is ",$ymin,$ymax);
echo("bbox Z is ",$zmin,$zmax);
color("blue",0.2) union() {
translate([$xmin-ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([$xmax+ep/2,0,0]) scale([1,sc,sc])
cube([ep,$ymax-$ymin,$zmax-$zmin],center=true);
translate([0,$ymin-ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,$ymax+ep/2,0]) scale([sc,1,sc])
cube([$xmax-$xmin,ep,$zmax-$zmin],center=true);
translate([0,0,$zmin-ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
translate([0,0,$zmax+ep/2]) scale([sc,sc,1])
cube([$xmax-$xmin,$ymax-$ymin,ep],center=true);
}
}
openbbox() rotate(rands(-90,90,3,1234)) cylinder(r=10,h=30,center=true);
////////////////////////////////////////////////////////////

This means that once an object is created, it is easy to place other
objects relative to it. What about measuring geometry before using it,
so we can place the object according to its size? What we need is a way
to
"render but don' t use the resulting geometry" . I ended up using '%',
which seems to do exactly that:

%render() sphere(r=10);

Here is an example where I stack objects according to their measured
sizes:

[image: bbox-b]<
https://f.cloud.github.com/assets/3324317/1816371/3abe7012-6f3a-11e3-997a-e8bea63c8922.png>

The code (a little ugly, sorry) :

//////////////////////////////////////////////////////////////////
module randcylinder(seed=1234) { rotate(rands(-90,90,3,seed))
cylinder(r=10,h=30,center=true); }
module base(h=5) { cube([30,30,h],center=true); }
// stack the second child so its resting on top of second child
module stack() {
render() child(0); // the "base"
// use the zmax of this object as a reference
assign(alt=$zmax) {
%render() child(1); // do not keep this geometry
translate([0,0,-$zmin+alt]) child(1); // show the child at the right
place
}
}

stack() {
stack() {
stack() {
stack() {
stack() {
stack() {
base(h=5);
randcylinder(100);
}
base(h=10);
}
randcylinder(101);
}
base(h=2);
}
randcylinder(102);
}
base(h=4);
}
//////////////////////////////////////////////////

Before I submit this, I would like to know what people think of this
approach to measuring. Also, my changes are too much of a "hack" and
need a
bit of work to integrate nicely.


Reply to this email directly or view it on GitHub<
https://github.com/openscad/openscad/issues/301#issuecomment-31281107>
.

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31285935
.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Dec 28, 2013

Indeed, it does break the assignment rule.

How about, instead of changing render(), we define a function similar to assign(), say assignbbox(), which will define in a local context the bounding box variables (xmin,xmax,...) according to the immediate rendering of its first child?

assignbbox() {
     sphere(r=5); // first child, used to compute bbox
     // from here, any geometry can use xmin,xmax,...
     // The bounding box info is only valid inside the assignbbox
}

Would this work?

In general, maybe we could have a "probe()" command which would create a local context just like assign, but were all defined variables would come from analyzing the immediate rendering of the first child. The parameters of probe() would determine what we wish to compute:

probe(boundingbox=true) {
    geometryToProbe();
    geometryUsingTheComputedBoundingBox();
}

As mentioned in previous posts, we could think of other options, like finding the intersection of the geometry with one axis, or an extreme point in some direction, well, any computation on the first child would be assigned as local variables for the following childs.

blobule commented Dec 28, 2013

Indeed, it does break the assignment rule.

How about, instead of changing render(), we define a function similar to assign(), say assignbbox(), which will define in a local context the bounding box variables (xmin,xmax,...) according to the immediate rendering of its first child?

assignbbox() {
     sphere(r=5); // first child, used to compute bbox
     // from here, any geometry can use xmin,xmax,...
     // The bounding box info is only valid inside the assignbbox
}

Would this work?

In general, maybe we could have a "probe()" command which would create a local context just like assign, but were all defined variables would come from analyzing the immediate rendering of the first child. The parameters of probe() would determine what we wish to compute:

probe(boundingbox=true) {
    geometryToProbe();
    geometryUsingTheComputedBoundingBox();
}

As mentioned in previous posts, we could think of other options, like finding the intersection of the geometry with one axis, or an extreme point in some direction, well, any computation on the first child would be assigned as local variables for the following childs.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Dec 28, 2013

Member

While I like the possibilities, calling render() defeats the concept of OpenSCAD.
It uses OpenCSG (F5) for fast preview & CGAL (F6) for proper geometry.
Using render() defeats F5's benefits. (but does allow additional functions)
... two minds...
I assume OpenCSG can't do a bounding box??

Member

MichaelAtOz commented Dec 28, 2013

While I like the possibilities, calling render() defeats the concept of OpenSCAD.
It uses OpenCSG (F5) for fast preview & CGAL (F6) for proper geometry.
Using render() defeats F5's benefits. (but does allow additional functions)
... two minds...
I assume OpenCSG can't do a bounding box??

@kintel

This comment has been minimized.

Show comment Hide comment
@kintel

kintel Dec 28, 2013

Member

The OpenSCAD architecture is based around evaluating the source code into a concrete CSG tree before attempting to render. The render() module is really a workaround for rendering artifacts and performance issues and will hopefully eventually become less and less needed.

This suggestion attempts to bring compiling and rendering closer together in order to create some feedback loop opportunities. It's worth a discussion, but I feel that if we were to go in this direction we should take a more careful look at why/if we should continue to keep compiling and rendering as separate as we do today, rather than patching it up to fix symptoms.

Member

kintel commented Dec 28, 2013

The OpenSCAD architecture is based around evaluating the source code into a concrete CSG tree before attempting to render. The render() module is really a workaround for rendering artifacts and performance issues and will hopefully eventually become less and less needed.

This suggestion attempts to bring compiling and rendering closer together in order to create some feedback loop opportunities. It's worth a discussion, but I feel that if we were to go in this direction we should take a more careful look at why/if we should continue to keep compiling and rendering as separate as we do today, rather than patching it up to fix symptoms.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Dec 29, 2013

I like the simplicity we get by separating compiling and rendering. This approach puts an emphasis on building an object using known components, which is a great way to approach CSG modelling, in my opinion.

However, occasionally, a design will require feedback information about one of its components. Right now, such design can' t be done on openscad. The workaround is to render the component and externally analyze it, then re-compile the design, which is tedious.

By adding a command such as "probe_bounding_box() { <child 0 is probed> <all other child are rendered with the information available about child 0> }", you force the designer to explicitly ask for this information, and thus clearly state that this should be used only when really needed. This is ideal in my opinion since automatically computing the bounding box of all components (i.e. rendering while compiling) would hurt performance and change the approach of openscad to CSG modelling.

So basically I consider the "separate compile/render" model very good, but an occasional "on-demand component information" when the design needs it would add a lot of power.

blobule commented Dec 29, 2013

I like the simplicity we get by separating compiling and rendering. This approach puts an emphasis on building an object using known components, which is a great way to approach CSG modelling, in my opinion.

However, occasionally, a design will require feedback information about one of its components. Right now, such design can' t be done on openscad. The workaround is to render the component and externally analyze it, then re-compile the design, which is tedious.

By adding a command such as "probe_bounding_box() { <child 0 is probed> <all other child are rendered with the information available about child 0> }", you force the designer to explicitly ask for this information, and thus clearly state that this should be used only when really needed. This is ideal in my opinion since automatically computing the bounding box of all components (i.e. rendering while compiling) would hurt performance and change the approach of openscad to CSG modelling.

So basically I consider the "separate compile/render" model very good, but an occasional "on-demand component information" when the design needs it would add a lot of power.

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Dec 29, 2013

Contributor

However, occasionally, a design will require feedback information about
one of its components.

Theoretically this is not true with a declarative language. You always
dictate the size and position of things so you already have all that
information available. You might need to do a bit of trig if you start
rotating things but you never need to query the geometry unless it is
imported as an STL or DXF.

On 29 December 2013 17:13, blobule notifications@github.com wrote:

I like the simplicity we get by separating compiling and rendering. This
approach puts an emphasis on building an object using known components,
which is a great way to approach CSG modelling, in my opinion.

However, occasionally, a design will require feedback information about
one of its components. Right now, such design can' t be done on openscad.
The workaround is to render the component and externally analyze it, then
re-compile the design, which is tedious.

By adding a command such as "probe_bounding_box() { }", you force the
designer to explicitly ask for this information, and thus clearly state
that this should be used only when really needed. This is ideal in my
opinion since automatically computing the bounding box of all components
(i.e. rendering while compiling) would hurt performance and change the
approach of openscad to CSG modelling.

So basically I consider the "separate compile/render" model very good, but
an occasional "on-demand component information" when the design needs it
would add a lot of power.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31320765
.

Contributor

nophead commented Dec 29, 2013

However, occasionally, a design will require feedback information about
one of its components.

Theoretically this is not true with a declarative language. You always
dictate the size and position of things so you already have all that
information available. You might need to do a bit of trig if you start
rotating things but you never need to query the geometry unless it is
imported as an STL or DXF.

On 29 December 2013 17:13, blobule notifications@github.com wrote:

I like the simplicity we get by separating compiling and rendering. This
approach puts an emphasis on building an object using known components,
which is a great way to approach CSG modelling, in my opinion.

However, occasionally, a design will require feedback information about
one of its components. Right now, such design can' t be done on openscad.
The workaround is to render the component and externally analyze it, then
re-compile the design, which is tedious.

By adding a command such as "probe_bounding_box() { }", you force the
designer to explicitly ask for this information, and thus clearly state
that this should be used only when really needed. This is ideal in my
opinion since automatically computing the bounding box of all components
(i.e. rendering while compiling) would hurt performance and change the
approach of openscad to CSG modelling.

So basically I consider the "separate compile/render" model very good, but
an occasional "on-demand component information" when the design needs it
would add a lot of power.


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31320765
.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Dec 29, 2013

Member

you never need to query the geometry unless it is imported as an STL or DXF

I found resize() handy in those situations, make the STL fit to your spec. Won't help for all.

Member

MichaelAtOz commented Dec 29, 2013

you never need to query the geometry unless it is imported as an STL or DXF

I found resize() handy in those situations, make the STL fit to your spec. Won't help for all.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Dec 30, 2013

Member

Bigger picture.
I had though that a capability to produce multiple parts (exports e.g. STLs) from one scad program would be handy, something akin to Thingiverse Customizer 'Part' (which I believe just runs the .scad multiple times in batch mode).
So if there was something like

export(file=str("myfile",part,".stl")
    render() // maybe this should just be implicitly done as part of export
        my_object(part);

Program logic (for/if etc) can then handle an assembly, and if combined with Marius idea from above

import <myfile.stl> as myfile
myfile would in this case become a variable which could be queried, e.g. myfile.bounds

Could then be used to iteratively build upon previous 'part's, automate a build layout based on size etc.

Member

MichaelAtOz commented Dec 30, 2013

Bigger picture.
I had though that a capability to produce multiple parts (exports e.g. STLs) from one scad program would be handy, something akin to Thingiverse Customizer 'Part' (which I believe just runs the .scad multiple times in batch mode).
So if there was something like

export(file=str("myfile",part,".stl")
    render() // maybe this should just be implicitly done as part of export
        my_object(part);

Program logic (for/if etc) can then handle an assembly, and if combined with Marius idea from above

import <myfile.stl> as myfile
myfile would in this case become a variable which could be queried, e.g. myfile.bounds

Could then be used to iteratively build upon previous 'part's, automate a build layout based on size etc.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Jan 2, 2014

It is true that, in theory, the declarative approach of openscad implies that everything can be computed "in advance", before the shape is actually rendered. This is what makes the "fast preview" (F5) possible and useful.

If we had to render() everything with CGAL before getting a preview, that would defeat the original idea of a "fast preview" using openCSG.

However, even simple shapes can be very hard to compute "by hand" just to get a boundary point. As an example, consider this model I just made:

probe6b

The "pistons" use the bounding box of the green shape to select their position. The shape is the projection of a cone, and even if it is simple, there is no obvious (i.e. easy to derive) equation to get the boundary points.
In this case, rendering the shape while parsing is quite cheap, so there is no problem with the fast preview.
In my opinion, the code is much simpler to write and more "natural" than with lots of equations.

Here is the code:

module forme(c=true) {
    projection(cut=c) {
        rotate([45,0,0]) cylinder(r1=20,r2=0,h=40,center=true,$fn=64);
    }
}

module cam(t=0) {
    rotate([t*360,0,0]) translate([-10,0,0]) rotate([0,90,0]) linear_extrude(height=20) forme(false);
}

module piston(t=0.5) {
    probe() {
                // check along the z-axis by intersecting with a cube
        % render() intersection() {
            child(0);
            translate([0,0,0]) cube([0.001,0.001,80],center=true);
        }
                // variables xmin,ymin,zmin,xmax,ymax,zmax are available for the following nodes
        echo(zmin);
        translate([0,0,-40+zmin]) {
            cylinder(r1=5,r2=0,h=40);   
            translate([0,0,-10]) cylinder(r=30,h=10);
        }
    }
    %color("red",0.2) translate([0,0,-32-48]) cylinder(r=31,h=32);
}

color("limegreen") cam($t);
color("limegreen") rotate([$t*360,0,0]) rotate([0,90,0]) cylinder(r=3,h=100,center=true,$fn=6);
rotate([-120,0,0]) piston($t,120)  rotate([120,0,0])  cam($t);
rotate([0,0,0])       piston($t,0)       rotate([0,0,0])       cam($t);
rotate([120,0,0])  piston($t,-120) rotate([-120,0,0]) cam($t);

The probe() function I coded is similar to assign(), but simply performs a CGAL evaluation of its first child, then defines variables related to the geometry (like xmin,xmax,...) which are only available to the following children inside probe() (in the local context). This way, there is no violation of assignment rules.

So this is my latest attempt at tackling the querying of shapes.

blobule commented Jan 2, 2014

It is true that, in theory, the declarative approach of openscad implies that everything can be computed "in advance", before the shape is actually rendered. This is what makes the "fast preview" (F5) possible and useful.

If we had to render() everything with CGAL before getting a preview, that would defeat the original idea of a "fast preview" using openCSG.

However, even simple shapes can be very hard to compute "by hand" just to get a boundary point. As an example, consider this model I just made:

probe6b

The "pistons" use the bounding box of the green shape to select their position. The shape is the projection of a cone, and even if it is simple, there is no obvious (i.e. easy to derive) equation to get the boundary points.
In this case, rendering the shape while parsing is quite cheap, so there is no problem with the fast preview.
In my opinion, the code is much simpler to write and more "natural" than with lots of equations.

Here is the code:

module forme(c=true) {
    projection(cut=c) {
        rotate([45,0,0]) cylinder(r1=20,r2=0,h=40,center=true,$fn=64);
    }
}

module cam(t=0) {
    rotate([t*360,0,0]) translate([-10,0,0]) rotate([0,90,0]) linear_extrude(height=20) forme(false);
}

module piston(t=0.5) {
    probe() {
                // check along the z-axis by intersecting with a cube
        % render() intersection() {
            child(0);
            translate([0,0,0]) cube([0.001,0.001,80],center=true);
        }
                // variables xmin,ymin,zmin,xmax,ymax,zmax are available for the following nodes
        echo(zmin);
        translate([0,0,-40+zmin]) {
            cylinder(r1=5,r2=0,h=40);   
            translate([0,0,-10]) cylinder(r=30,h=10);
        }
    }
    %color("red",0.2) translate([0,0,-32-48]) cylinder(r=31,h=32);
}

color("limegreen") cam($t);
color("limegreen") rotate([$t*360,0,0]) rotate([0,90,0]) cylinder(r=3,h=100,center=true,$fn=6);
rotate([-120,0,0]) piston($t,120)  rotate([120,0,0])  cam($t);
rotate([0,0,0])       piston($t,0)       rotate([0,0,0])       cam($t);
rotate([120,0,0])  piston($t,-120) rotate([-120,0,0]) cam($t);

The probe() function I coded is similar to assign(), but simply performs a CGAL evaluation of its first child, then defines variables related to the geometry (like xmin,xmax,...) which are only available to the following children inside probe() (in the local context). This way, there is no violation of assignment rules.

So this is my latest attempt at tackling the querying of shapes.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Jan 2, 2014

Member

Nice model!

Member

MichaelAtOz commented Jan 2, 2014

Nice model!

@GilesBathgate

This comment has been minimized.

Show comment Hide comment
@GilesBathgate

GilesBathgate Jan 2, 2014

Contributor

@MichaelAtOz Sure its a nice model, the fact that he has implemented a probe() module is much more impressive. I like the idea, it solves a lot of problems (relating to recursion) that I couldn't get my head around when considering this before.

Contributor

GilesBathgate commented Jan 2, 2014

@MichaelAtOz Sure its a nice model, the fact that he has implemented a probe() module is much more impressive. I like the idea, it solves a lot of problems (relating to recursion) that I couldn't get my head around when considering this before.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Jan 3, 2014

(following a comment in issue #586 ) The code for probe() is on github, in the branch "probe" of my fork of openscad ( https://github.com/blobule/openscad ). Feel free to check it out. It is not fully tested (not ready for a pull request I assume), but it already works well.

Quick documentation of the module:

probe() {
      some_geometry; // this is the reference geometry
      some_other_geometry; // this and following can use information about reference geometry
}

probe() will render the first child with CGAL, gather some information about the geometry, define in a local context some variables holding this information, and then evaluate the remaining children with this context.
The variables defined are related to the bounding box of the first child:
xmin, xmax, ymin, ymax, zmin, zmax, and also center=[(xmax+xmin)/2,...] and boxsize=[xmax-xmin,...]

Note that the first child of probe() is discarded after it is computed, to make it easy to use objects for the only purpose of aligning things.

Examples:

probe() {
    cylinder(r=10,h=40);
    echo(center,boxsize);
    #translate(center) cube(boxsize,center=true);
}
////////////////////////////////
// place child(0) on top of child(1)
module stack() {
    probe() {
        children(1);
        translate([0,0,zmax]) probe() {
            children(0);
            translate([0,0,-zmin]) children(0);
        }
    }
    children(1);
}
stack() {
    rotate([10,20,30]) cylinder(r=10,h=40,center=true);
    cube([30,30,5],center=true);
}
///////////////////////////////
// simple resize module
module setsize(sz=[10,10,10]) {
    probe() {
        children(0);
        echo(center,boxsize);
        translate(center)
        multmatrix(m = [ 
            [1/boxsize[0], 0, 0, 0],
            [0, 1/boxsize[1], 0,0],
            [0, 0, 1/boxsize[2], 0],
            [0, 0, 0,  1]
            ])
        scale(sz)
        translate(-center)
        children(0);
    }
}
setsize([5,10,15]) sphere(r=4);
setsize([5,10,25]) translate([10,20,30]) sphere(r=4);
//////////////////////////
// to move an object's center at the origine
module centerize() {
    probe() {
        children(0);
        echo(center,boxsize);
        translate(-center) children(0);
    }
}
centerize() translate([10,20,30]) sphere(r=10);

blobule commented Jan 3, 2014

(following a comment in issue #586 ) The code for probe() is on github, in the branch "probe" of my fork of openscad ( https://github.com/blobule/openscad ). Feel free to check it out. It is not fully tested (not ready for a pull request I assume), but it already works well.

Quick documentation of the module:

probe() {
      some_geometry; // this is the reference geometry
      some_other_geometry; // this and following can use information about reference geometry
}

probe() will render the first child with CGAL, gather some information about the geometry, define in a local context some variables holding this information, and then evaluate the remaining children with this context.
The variables defined are related to the bounding box of the first child:
xmin, xmax, ymin, ymax, zmin, zmax, and also center=[(xmax+xmin)/2,...] and boxsize=[xmax-xmin,...]

Note that the first child of probe() is discarded after it is computed, to make it easy to use objects for the only purpose of aligning things.

Examples:

probe() {
    cylinder(r=10,h=40);
    echo(center,boxsize);
    #translate(center) cube(boxsize,center=true);
}
////////////////////////////////
// place child(0) on top of child(1)
module stack() {
    probe() {
        children(1);
        translate([0,0,zmax]) probe() {
            children(0);
            translate([0,0,-zmin]) children(0);
        }
    }
    children(1);
}
stack() {
    rotate([10,20,30]) cylinder(r=10,h=40,center=true);
    cube([30,30,5],center=true);
}
///////////////////////////////
// simple resize module
module setsize(sz=[10,10,10]) {
    probe() {
        children(0);
        echo(center,boxsize);
        translate(center)
        multmatrix(m = [ 
            [1/boxsize[0], 0, 0, 0],
            [0, 1/boxsize[1], 0,0],
            [0, 0, 1/boxsize[2], 0],
            [0, 0, 0,  1]
            ])
        scale(sz)
        translate(-center)
        children(0);
    }
}
setsize([5,10,15]) sphere(r=4);
setsize([5,10,25]) translate([10,20,30]) sphere(r=4);
//////////////////////////
// to move an object's center at the origine
module centerize() {
    probe() {
        children(0);
        echo(center,boxsize);
        translate(-center) children(0);
    }
}
centerize() translate([10,20,30]) sphere(r=10);
@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Jan 3, 2014

Contributor

Does the discarded object get cached as it will very likely be needed?

On 3 January 2014 20:46, blobule notifications@github.com wrote:

(following a comment in issue #586#586) The code for probe() is on github, in the branch "probe" of my fork of
openscad ( https://github.com/blobule/openscad ). Feel free to check it
out. It is not fully tested (not ready for a pull request I assume), but it
already works well.

Quick documentation of the module:
probe() {
some_geometry; // this is the reference geometry
some_other_geometry; // this and following can use information about
reference geometry
}
probe() will render the first child with CGAL, gather some information
about the geometry, define in a local context some variables holding this
information, and then evaluate the remaining children with this context.
The variables defined are related to the bounding box of the first child:
xmin, xmax, ymin, ymax, zmin, zmax, and also center=[(xmax+xmin)/2,...]
and boxsize=[xmax-xmin,...]

Note that the first child of probe() is discarded after it is computed,
to make it easy to create object for the only purpose of aligning things.

Examples:
probe() {
cylinder(r=10,h=40);
echo(center,boxsize);
#translate(center) cube(boxsize,center=true);
}
////////////////////////////////
// place child(0) on top of child(1)
module stack() {
probe() {
children(1);
translate([0,0,zmax]) probe() {
children(0);
translate([0,0,-zmin]) children(0);
}
}
children(1);
}

stack() {
rotate([10,20,30]) cylinder(r=10,h=40,center=true);
cube([30,30,5],center=true);
}
///////////////////////////////
// simple resize module
module setsize(sz=[10,10,10]) {
probe() {
children(0);
echo(center,boxsize);
translate(center)
multmatrix(m = [
[1/boxsize[0], 0, 0, 0],
[0, 1/boxsize[1], 0,0],
[0, 0, 1/boxsize[2], 0],
[0, 0, 0, 1]
])
scale(sz)
translate(-center)
children(0);
}
}

setsize([5,10,15]) sphere(r=4);
setsize([5,10,25]) translate([10,20,30]) sphere(r=4);


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31552218
.

Contributor

nophead commented Jan 3, 2014

Does the discarded object get cached as it will very likely be needed?

On 3 January 2014 20:46, blobule notifications@github.com wrote:

(following a comment in issue #586#586) The code for probe() is on github, in the branch "probe" of my fork of
openscad ( https://github.com/blobule/openscad ). Feel free to check it
out. It is not fully tested (not ready for a pull request I assume), but it
already works well.

Quick documentation of the module:
probe() {
some_geometry; // this is the reference geometry
some_other_geometry; // this and following can use information about
reference geometry
}
probe() will render the first child with CGAL, gather some information
about the geometry, define in a local context some variables holding this
information, and then evaluate the remaining children with this context.
The variables defined are related to the bounding box of the first child:
xmin, xmax, ymin, ymax, zmin, zmax, and also center=[(xmax+xmin)/2,...]
and boxsize=[xmax-xmin,...]

Note that the first child of probe() is discarded after it is computed,
to make it easy to create object for the only purpose of aligning things.

Examples:
probe() {
cylinder(r=10,h=40);
echo(center,boxsize);
#translate(center) cube(boxsize,center=true);
}
////////////////////////////////
// place child(0) on top of child(1)
module stack() {
probe() {
children(1);
translate([0,0,zmax]) probe() {
children(0);
translate([0,0,-zmin]) children(0);
}
}
children(1);
}

stack() {
rotate([10,20,30]) cylinder(r=10,h=40,center=true);
cube([30,30,5],center=true);
}
///////////////////////////////
// simple resize module
module setsize(sz=[10,10,10]) {
probe() {
children(0);
echo(center,boxsize);
translate(center)
multmatrix(m = [
[1/boxsize[0], 0, 0, 0],
[0, 1/boxsize[1], 0,0],
[0, 0, 1/boxsize[2], 0],
[0, 0, 0, 1]
])
scale(sz)
translate(-center)
children(0);
}
}

setsize([5,10,15]) sphere(r=4);
setsize([5,10,25]) translate([10,20,30]) sphere(r=4);


Reply to this email directly or view it on GitHubhttps://github.com/openscad/openscad/issues/301#issuecomment-31552218
.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Jan 3, 2014

yes, the cache is on the "rendering" side of things, so the cache is working in this case.

blobule commented Jan 3, 2014

yes, the cache is on the "rendering" side of things, so the cache is working in this case.

@obobo2

This comment has been minimized.

Show comment Hide comment
@obobo2

obobo2 Jan 4, 2014

Nice work!

How to account for the difference between an ideal solid and a faceted solid?

On Friday, January 3, 2014 5:57:19 PM, blobule notifications@github.com wrote:

yes, the cache is on the "rendering" side of things, so the cache is working in this case.

Reply to this email directly or view it on GitHub.

obobo2 commented Jan 4, 2014

Nice work!

How to account for the difference between an ideal solid and a faceted solid?

On Friday, January 3, 2014 5:57:19 PM, blobule notifications@github.com wrote:

yes, the cache is on the "rendering" side of things, so the cache is working in this case.

Reply to this email directly or view it on GitHub.

@blobule

This comment has been minimized.

Show comment Hide comment
@blobule

blobule Jan 4, 2014

As I understand, the internal representation is always polygonal.

This is why the bounding box of a sphere(r=2,$fn=16) is +- 3.696 while for the sphere(r=2,$fn=128) it is +-3.999.

blobule commented Jan 4, 2014

As I understand, the internal representation is always polygonal.

This is why the bounding box of a sphere(r=2,$fn=16) is +- 3.696 while for the sphere(r=2,$fn=128) it is +-3.999.

@lordofhyphens

This comment has been minimized.

Show comment Hide comment
@lordofhyphens

lordofhyphens Jan 13, 2015

#1155 might be a useful step towards a solution, especially if you allow for iterative compilation.

#1155 might be a useful step towards a solution, especially if you allow for iterative compilation.

@blobule blobule referenced this issue Jul 14, 2015

Closed

Probe #1388

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 23, 2015

RFC: The probe() solution seems to have too many side effects and non-obvious variable names. I would like to suggest the following interface:

The union()/etc. functions could have optional arguments that work in a "call by reference" way, for example:

module someGeometry() { ... }

// render the bounding box of two random geometries
my_bbox = [ [0,0,0], [0,0,0]];
// store the bounding box data in my_bbox as an array of two vectors
union(query_boundingbox=my_bbox) {
  someGeometry();
  someOtherGeometry()
}
%translate (my_bbox[0]) cube(my_bbox[1]);

Positives:

  • no change in syntax
  • caching works
  • union() call can provide many more attributes
  • query many bounding boxes without collision of variable names

Negatives:

  • query_boundingbox=my_bbox my be surprising; users may expect the left side to be the one that receives a value; we could reverse the order (not logical) or add a syntax, i.e. boundingbox->my_bbox
  • union() returns a geometry that will be rendered; we need an additional method 'query()' that performs a 'union()' call without returning any geometry

RFC: The probe() solution seems to have too many side effects and non-obvious variable names. I would like to suggest the following interface:

The union()/etc. functions could have optional arguments that work in a "call by reference" way, for example:

module someGeometry() { ... }

// render the bounding box of two random geometries
my_bbox = [ [0,0,0], [0,0,0]];
// store the bounding box data in my_bbox as an array of two vectors
union(query_boundingbox=my_bbox) {
  someGeometry();
  someOtherGeometry()
}
%translate (my_bbox[0]) cube(my_bbox[1]);

Positives:

  • no change in syntax
  • caching works
  • union() call can provide many more attributes
  • query many bounding boxes without collision of variable names

Negatives:

  • query_boundingbox=my_bbox my be surprising; users may expect the left side to be the one that receives a value; we could reverse the order (not logical) or add a syntax, i.e. boundingbox->my_bbox
  • union() returns a geometry that will be rendered; we need an additional method 'query()' that performs a 'union()' call without returning any geometry
@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 23, 2015

Indeed query_boundingbox=my_bbox is surprising and not quite so obvious.
I have no idea about the internals but I assume something like this is not an option?

bbox = union() {
  ..
}

tcurdt commented Aug 23, 2015

Indeed query_boundingbox=my_bbox is surprising and not quite so obvious.
I have no idea about the internals but I assume something like this is not an option?

bbox = union() {
  ..
}
@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 23, 2015

I have tried myBBox = bbox() { cube(1) }, but it would require a change in syntax, possibly failing existing scripts. Also, you would have to introduce new calls for bounding boxes, position, orientation, scale, and what ever other queries we will eventually com up with.

A few alternatives that are syntax compatible, or at least not entirely disruptive:

myBBox = [ [0, 0, 0], [0, 0, 0] ]; // not needed, just illustrating the returned format
union(return_bbox=myBBox) { ... } // hint by parameter name, 100% compatible
union(myBBox=query_bbox) { ... } // more obvious data flow direction, but contrary to syntax conv.
union(bbox=>myBBox) { ... } // additional syntax needed, obvious, not breaking things
union() (bbox=*myBBox) { ... } // C++ call by reference syntax 
union() (bbox=&myBBox) { ... } // PHP call by reference syntax 
union() (out myBBox=bbox) { ... } // C# call by reference syntax 

In a perfect world, there would be no differentiation between variables/values and geometry. A geometry would just be another value type. It is possible to get a somewhat compatible syntax, but I am unsure if this would work for all existing scripts. Example:

x = [90, 0, 0]; // x is a vector
y = rotate(x) cube([10]); // y is a geometry
z = bbox(y); // z is an array of vectors
z = y.bbox(); // alternative syntax
render() {
  y; // draw the cube
  translate(z[0]) sphere(); // draw a sphere at the lowest corner of the bounding box
  translate(z[1]) sphere(); // and at the highest corner
}
myBBox = bbox( scale([1, 3, 4]) sphere(r=2) ); // another sample

I have tried myBBox = bbox() { cube(1) }, but it would require a change in syntax, possibly failing existing scripts. Also, you would have to introduce new calls for bounding boxes, position, orientation, scale, and what ever other queries we will eventually com up with.

A few alternatives that are syntax compatible, or at least not entirely disruptive:

myBBox = [ [0, 0, 0], [0, 0, 0] ]; // not needed, just illustrating the returned format
union(return_bbox=myBBox) { ... } // hint by parameter name, 100% compatible
union(myBBox=query_bbox) { ... } // more obvious data flow direction, but contrary to syntax conv.
union(bbox=>myBBox) { ... } // additional syntax needed, obvious, not breaking things
union() (bbox=*myBBox) { ... } // C++ call by reference syntax 
union() (bbox=&myBBox) { ... } // PHP call by reference syntax 
union() (out myBBox=bbox) { ... } // C# call by reference syntax 

In a perfect world, there would be no differentiation between variables/values and geometry. A geometry would just be another value type. It is possible to get a somewhat compatible syntax, but I am unsure if this would work for all existing scripts. Example:

x = [90, 0, 0]; // x is a vector
y = rotate(x) cube([10]); // y is a geometry
z = bbox(y); // z is an array of vectors
z = y.bbox(); // alternative syntax
render() {
  y; // draw the cube
  translate(z[0]) sphere(); // draw a sphere at the lowest corner of the bounding box
  translate(z[1]) sphere(); // and at the highest corner
}
myBBox = bbox( scale([1, 3, 4]) sphere(r=2) ); // another sample
@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 23, 2015

I am not sure I get why "it would require a change in syntax, possibly failing existing scripts" as it should be forward (just not backwards) compatible - or can you assign subtrees like a = union() already?

If you want to avoid all kinds of new calls why not just

props = properties( union(...) );
props.bounds
props.position
etc.

tcurdt commented Aug 23, 2015

I am not sure I get why "it would require a change in syntax, possibly failing existing scripts" as it should be forward (just not backwards) compatible - or can you assign subtrees like a = union() already?

If you want to avoid all kinds of new calls why not just

props = properties( union(...) );
props.bounds
props.position
etc.
@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 23, 2015

In OpenSCAD, if I understand the lex syntax right, values and geometries are syntactically different things (and so are functions and modules). You can't write a function that takes a geometry/module as an argument. Functions can not have children either. So a = func( cube() ); is not possible. union() etc. are different in that they can take geometry as children, but again not as arguments, and they can only return a geometry, not a value.

In OpenSCAD, if I understand the lex syntax right, values and geometries are syntactically different things (and so are functions and modules). You can't write a function that takes a geometry/module as an argument. Functions can not have children either. So a = func( cube() ); is not possible. union() etc. are different in that they can take geometry as children, but again not as arguments, and they can only return a geometry, not a value.

@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 23, 2015

The first thing should not be a problem as this looks OK, too

props = properties(){
  union(...) 
}

props.bounds
props.position

but if they can only return geometries - that's a bummer.
Question is how easy that would be to change.

tcurdt commented Aug 23, 2015

The first thing should not be a problem as this looks OK, too

props = properties(){
  union(...) 
}

props.bounds
props.position

but if they can only return geometries - that's a bummer.
Question is how easy that would be to change.

@TakeItAndRun

This comment has been minimized.

Show comment Hide comment
@TakeItAndRun

TakeItAndRun Aug 23, 2015

You can not assign a value to a variable at runtime in OpenSCAD.
It is a describtive language: you describe a geometry, than this geometry
gets passed in its entirety to a (very slow and comlicated) 3d-program
(CSG).
Then a 3d-model is returened.

So no luck on any boundingbox.

2015-08-23 18:24 GMT+02:00 Torsten Curdt notifications@github.com:

The first thing should not be a problem as this looks OK, too

props = properties(){
union(...)
}

props.bounds
props.position

but if they can only return geometries - that's a bummer.
Question is how easy that would be to change.


Reply to this email directly or view it on GitHub
#301 (comment).

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

You can not assign a value to a variable at runtime in OpenSCAD.
It is a describtive language: you describe a geometry, than this geometry
gets passed in its entirety to a (very slow and comlicated) 3d-program
(CSG).
Then a 3d-model is returened.

So no luck on any boundingbox.

2015-08-23 18:24 GMT+02:00 Torsten Curdt notifications@github.com:

The first thing should not be a problem as this looks OK, too

props = properties(){
union(...)
}

props.bounds
props.position

but if they can only return geometries - that's a bummer.
Question is how easy that would be to change.


Reply to this email directly or view it on GitHub
#301 (comment).

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

@FluxIX

This comment has been minimized.

Show comment Hide comment
@FluxIX

FluxIX Aug 23, 2015

I'm not convinced you couldn't return a value and use it. The compilation process is still hierarchical and thus the compilation order could be arranged so as to process the dependent items first, then use the computed values in the depending items.

An obvious limitation of this approach is you cannot dynamic alter the values, and you have to check for dependency cycles.

FluxIX commented Aug 23, 2015

I'm not convinced you couldn't return a value and use it. The compilation process is still hierarchical and thus the compilation order could be arranged so as to process the dependent items first, then use the computed values in the depending items.

An obvious limitation of this approach is you cannot dynamic alter the values, and you have to check for dependency cycles.

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 23, 2015

FluxIX is right, and it has been done in this thread and also here:
#1388

The CSG is created during compilation. By running branches of the already existing (though incomplete) CSG, the values are calculated and assigned to the variable. This is completely transparent to the compiler and the user. Even the caches are used as expected.

The limitation that you can't change variables still applies. So this code:

a = 0;
union (bbox=>a) { cube(1); }
echo(a);
union (bbox=>a) { cube(2); }

would print [[0,0,0],[2,2,2]] because echo prints the last assigned value of a.

FluxIX is right, and it has been done in this thread and also here:
#1388

The CSG is created during compilation. By running branches of the already existing (though incomplete) CSG, the values are calculated and assigned to the variable. This is completely transparent to the compiler and the user. Even the caches are used as expected.

The limitation that you can't change variables still applies. So this code:

a = 0;
union (bbox=>a) { cube(1); }
echo(a);
union (bbox=>a) { cube(2); }

would print [[0,0,0],[2,2,2]] because echo prints the last assigned value of a.

@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 23, 2015

...which is another reason why I'd prefer a syntax like

props = properties(){
  ...
}
props.bounds

For one it would make the (one-off) assignment clearer - plus it clarifies the scope of where the information is available.

tcurdt commented Aug 23, 2015

...which is another reason why I'd prefer a syntax like

props = properties(){
  ...
}
props.bounds

For one it would make the (one-off) assignment clearer - plus it clarifies the scope of where the information is available.

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 24, 2015

@tcurdt, yes, that would be nicer. Problem here is that you need to calculate all possible properties and put them inside the props variable. Potentially, some properties may take quite a while to calculate.

I will look into modifying the syntax to allow for modules to return values, and maybe even a few steps beyond. If that works, all suggested syntaxes would be possible!

@tcurdt, yes, that would be nicer. Problem here is that you need to calculate all possible properties and put them inside the props variable. Potentially, some properties may take quite a while to calculate.

I will look into modifying the syntax to allow for modules to return values, and maybe even a few steps beyond. If that works, all suggested syntaxes would be possible!

@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 24, 2015

@MatthiasWM nice!

Modifying the syntax to allow return values sounds great. Not sure how easy it is one impl side - but wrapping those properties so they get calculated on first use should possible (in theory).

tcurdt commented Aug 24, 2015

@MatthiasWM nice!

Modifying the syntax to allow return values sounds great. Not sure how easy it is one impl side - but wrapping those properties so they get calculated on first use should possible (in theory).

@TakeItAndRun

This comment has been minimized.

Show comment Hide comment
@TakeItAndRun

TakeItAndRun Aug 24, 2015

Now there had been a discussion for the export of stl-files.
These get read at the very beginning.
Here it would be possible to calculate e.g. the boundingbox and assign a
variable with a value.
The import doesnt need any CSG- calculations.
Same might be possible for 2d-file-import.
But nobody has really pushed this so far.

2015-08-24 10:09 GMT+02:00 Torsten Curdt notifications@github.com:

@MatthiasWM https://github.com/MatthiasWM nice!

Modifying the syntax to allow return values sounds great. Not sure how
easy it is one impl side - but wrapping those properties so they get
calculated on first use should possible (in theory).


Reply to this email directly or view it on GitHub
#301 (comment).

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

Now there had been a discussion for the export of stl-files.
These get read at the very beginning.
Here it would be possible to calculate e.g. the boundingbox and assign a
variable with a value.
The import doesnt need any CSG- calculations.
Same might be possible for 2d-file-import.
But nobody has really pushed this so far.

2015-08-24 10:09 GMT+02:00 Torsten Curdt notifications@github.com:

@MatthiasWM https://github.com/MatthiasWM nice!

Modifying the syntax to allow return values sounds great. Not sure how
easy it is one impl side - but wrapping those properties so they get
calculated on first use should possible (in theory).


Reply to this email directly or view it on GitHub
#301 (comment).

stempeldergeschichte@googlemail.com karsten@rohrbach.de

P.S. Falls meine E-Mail kürzer ausfällt als Dir angenehm ist:
Ich probiere gerade aus kurze Antworten statt gar keine Antworten zu
schreiben.
Wenn Du gerne mehr lesen möchtest, dann lass es mich bitte wissen.

P.S. In case my e-mail is shorter than you enjoy:
I am currently trying short replies instead of no replies at all.
Please let me know, if you like to read more.

Enjoy!

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 25, 2015

RFC: so I think I have solved it.

openscad_query

Short version: I added a new kind of function named "Query". Queries are different from functions by allowing geometry children. Any kind of query can be implemented. Queries have easy access to all children's geometry if needed.

Long version:
This implementation closes the bridge from geometry back to numeric values. The code is based partially on blobule's contribution to "Probe #1388". The syntax has been expanded carefully to allow for logical and obvious code. All the buffering should work transparently to the user. There are no hidden variable names. New Queries can be added easily at "C" source code level.

Here are some syntax examples:

echo( boundingbox() cube() );
myBoundingBox = boundingbox() {
    translate([10, 10, 5]) sphere();
    cube([5, 6, 7]);
} ;
translate(myBoundingBox[0]) cube(myBoundingBox[1]);

module something() {
    import("something.stl");
}
// return two vectors, center and size, instead of minimum and maximium
echo( boundingbox(format="center,size") something() );

Any suggestions?

EDIT: removed boundingbox(render=...) as it made no obvious sense

RFC: so I think I have solved it.

openscad_query

Short version: I added a new kind of function named "Query". Queries are different from functions by allowing geometry children. Any kind of query can be implemented. Queries have easy access to all children's geometry if needed.

Long version:
This implementation closes the bridge from geometry back to numeric values. The code is based partially on blobule's contribution to "Probe #1388". The syntax has been expanded carefully to allow for logical and obvious code. All the buffering should work transparently to the user. There are no hidden variable names. New Queries can be added easily at "C" source code level.

Here are some syntax examples:

echo( boundingbox() cube() );
myBoundingBox = boundingbox() {
    translate([10, 10, 5]) sphere();
    cube([5, 6, 7]);
} ;
translate(myBoundingBox[0]) cube(myBoundingBox[1]);

module something() {
    import("something.stl");
}
// return two vectors, center and size, instead of minimum and maximium
echo( boundingbox(format="center,size") something() );

Any suggestions?

EDIT: removed boundingbox(render=...) as it made no obvious sense

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 25, 2015

PS: git source in MatthiasWM/matt_converge

PS: git source in MatthiasWM/matt_converge

@nophead

This comment has been minimized.

Show comment Hide comment
@nophead

nophead Aug 25, 2015

Contributor

myBoundingBox = boundingbox() {
cube([myBoundingBox[0] * 2, myBoundingBox[1] * 2, myBoundingBox[0] * 2]);
}

On 25 August 2015 at 20:19, MatthiasWM notifications@github.com wrote:

PS: git source in MatthiasWM/matt_converge


Reply to this email directly or view it on GitHub
#301 (comment).

Contributor

nophead commented Aug 25, 2015

myBoundingBox = boundingbox() {
cube([myBoundingBox[0] * 2, myBoundingBox[1] * 2, myBoundingBox[0] * 2]);
}

On 25 August 2015 at 20:19, MatthiasWM notifications@github.com wrote:

PS: git source in MatthiasWM/matt_converge


Reply to this email directly or view it on GitHub
#301 (comment).

@tcurdt

This comment has been minimized.

Show comment Hide comment
@tcurdt

tcurdt Aug 25, 2015

Nice! That looks pretty good!

But didn't you say "[we] would have to introduce new calls for bounding boxes, position, orientation, scale, and what ever other queries we will eventually com up with"?

So shouldn't that better be a properties query?

tcurdt commented Aug 25, 2015

Nice! That looks pretty good!

But didn't you say "[we] would have to introduce new calls for bounding boxes, position, orientation, scale, and what ever other queries we will eventually com up with"?

So shouldn't that better be a properties query?

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 25, 2015

@nophead: WARNING: Ignoring unknown variable 'myBoundingBox'. :boundingbox() is evaluated before myBoundingBox is set.

But:

myBoundingBox = [[-2, -2, -2], [5, 6, 7]];
yourBoundingBox = boundingbox() {
    cube([myBoundingBox[1][0] * 2, myBoundingBox[1][1] * 2, myBoundingBox[1][2] * 2]);
};
echo( myBoundingBox );
echo( yourBoundingBox );
----
ECHO: [[-2, -2, -2], [5, 6, 7]]
ECHO: [[0, 0, 0], [10, 12, 14]]

@nophead: WARNING: Ignoring unknown variable 'myBoundingBox'. :boundingbox() is evaluated before myBoundingBox is set.

But:

myBoundingBox = [[-2, -2, -2], [5, 6, 7]];
yourBoundingBox = boundingbox() {
    cube([myBoundingBox[1][0] * 2, myBoundingBox[1][1] * 2, myBoundingBox[1][2] * 2]);
};
echo( myBoundingBox );
echo( yourBoundingBox );
----
ECHO: [[-2, -2, -2], [5, 6, 7]]
ECHO: [[0, 0, 0], [10, 12, 14]]
@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 25, 2015

@tcurdt: Yep, that's what I said. It's not consistent though, and we would still require different implementations for properties(boundingbox), properties(center), etc. , so nothing gained. You were right. Only slight disadvantage is some namespace pollution.

@tcurdt: Yep, that's what I said. It's not consistent though, and we would still require different implementations for properties(boundingbox), properties(center), etc. , so nothing gained. You were right. Only slight disadvantage is some namespace pollution.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Aug 25, 2015

Member

What's the difference boundingbox() v's boundingbox(render=true) ?

Member

MichaelAtOz commented Aug 25, 2015

What's the difference boundingbox() v's boundingbox(render=true) ?

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 26, 2015

@MichaelAtOz it's from the original boundingbox code, something about a preferred renderer, and only here to illustrate that boundingbox() can take parameters. I will throw that out of the example.

@MichaelAtOz it's from the original boundingbox code, something about a preferred renderer, and only here to illustrate that boundingbox() can take parameters. I will throw that out of the example.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Aug 26, 2015

Member

So just to confirm. boundingcox() et al. effectively do a render() to generate the full geometry with CGAL, hence do not have the fast preview that F5 gives (for that child/ren). Given that CGAL caching applies.

Member

MichaelAtOz commented Aug 26, 2015

So just to confirm. boundingcox() et al. effectively do a render() to generate the full geometry with CGAL, hence do not have the fast preview that F5 gives (for that child/ren). Given that CGAL caching applies.

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Aug 26, 2015

@MichaelAtOz queries will usually need to know the geometry in detail. So, yes, they need to calculate the geometry for the given branch. Additional caching is probably needed to avoid recalculating bounding boxes and possibly other, much more complex calculations. F5-rendering is pixel-based and not sufficient.

I have just started to understand the OpenSCAD source code and I am not involved enough to understand caching at this point. Help would be greatly appreciated.

@MichaelAtOz queries will usually need to know the geometry in detail. So, yes, they need to calculate the geometry for the given branch. Additional caching is probably needed to avoid recalculating bounding boxes and possibly other, much more complex calculations. F5-rendering is pixel-based and not sufficient.

I have just started to understand the OpenSCAD source code and I am not involved enough to understand caching at this point. Help would be greatly appreciated.

@MichaelAtOz

This comment has been minimized.

Show comment Hide comment
@MichaelAtOz

MichaelAtOz Aug 26, 2015

Member

I was just clarifying, and stating it for the wider audience. One of the great benefits of OpenSCAD is the fast preview, and the not so good is the (while accurate) lengthy render.

While obviously, needing access to geometry data will require rendering, bringing this into the main stream will detract from the fast preview, particularly for complex objects. It is of course up to the coder.

Member

MichaelAtOz commented Aug 26, 2015

I was just clarifying, and stating it for the wider audience. One of the great benefits of OpenSCAD is the fast preview, and the not so good is the (while accurate) lengthy render.

While obviously, needing access to geometry data will require rendering, bringing this into the main stream will detract from the fast preview, particularly for complex objects. It is of course up to the coder.

@Yona-Appletree

This comment has been minimized.

Show comment Hide comment
@Yona-Appletree

Yona-Appletree Sep 21, 2015

I've been looking forward to this feature for a while, and would like to chime in with some real-world use-cases and ideas on keeping the implementation simple.

First, I agree with the concern about having many specialized function for properties for geometry. It seems to me that the main goal here is to bridge the geometry space of OpenSCAD with the function/value space.

Why not keep the language changes to a minimum by using render() function to allow obtaining the geometry for a tree, using MatthiasWM's extension to allow geometry with function syntax.

For instance:
geo = render() cube([20,10,20); // geo now contains an array with each separate polyhedron (or polygon, for 2d geometry), each compatible with the polyhedron/polygon call: [[points, faces]]

Now we can compute the bounding box, center of mass, etc. in user-space easily enough with recursive functions.

This would also allow some very neat hybrid functionality where one could iterate the points or faces and then constructively add geometry to them, or use them with any of the existing polyhedron libraries. In particular, this would be very useful for implementing functions like fillet() and chamfer(), both in 2d and 3d space. Other uses include more complex variants on the above piston / cam exmaple, rendering text along a path (or face), all in native OpenSCAD-code.

Currently, we have polyhedron() which takes function/variable data and moves it into the geometry space. Using render() to go the other way is simple, elegant and provides symmetry with minimum complexity. What do you guys think?

I've been looking forward to this feature for a while, and would like to chime in with some real-world use-cases and ideas on keeping the implementation simple.

First, I agree with the concern about having many specialized function for properties for geometry. It seems to me that the main goal here is to bridge the geometry space of OpenSCAD with the function/value space.

Why not keep the language changes to a minimum by using render() function to allow obtaining the geometry for a tree, using MatthiasWM's extension to allow geometry with function syntax.

For instance:
geo = render() cube([20,10,20); // geo now contains an array with each separate polyhedron (or polygon, for 2d geometry), each compatible with the polyhedron/polygon call: [[points, faces]]

Now we can compute the bounding box, center of mass, etc. in user-space easily enough with recursive functions.

This would also allow some very neat hybrid functionality where one could iterate the points or faces and then constructively add geometry to them, or use them with any of the existing polyhedron libraries. In particular, this would be very useful for implementing functions like fillet() and chamfer(), both in 2d and 3d space. Other uses include more complex variants on the above piston / cam exmaple, rendering text along a path (or face), all in native OpenSCAD-code.

Currently, we have polyhedron() which takes function/variable data and moves it into the geometry space. Using render() to go the other way is simple, elegant and provides symmetry with minimum complexity. What do you guys think?

@Neon22

This comment has been minimized.

Show comment Hide comment
@Neon22

Neon22 Sep 21, 2015

Sounds even simpler than my suggestions

On 9/21/2015 1:22 PM, Yona-Appletree
  wrote:


  I've been looking forward to this feature for a while, and
    would like to chime in with some real-world use-cases and ideas
    on keeping the implementation simple. 
  First, I agree with the concern about having many specialized
    function for properties for geometry. It seems to me that the
    main goal here is to bridge the geometry space of OpenSCAD with
    the function/value space. 
  Why not keep the language changes to a minimum by using
    render() function to allow obtaining the geometry for a tree,
    using MatthiasWM's extension to allow geometry with function
    syntax.
  For instance:
    geo = render() cube([20,10,20); // geo now contains an array
    with each separate polyhedron (or polygon, for 2d geometry),
    each compatible with the polyhedron/polygon call: [[points,
    faces]]
  Now we can compute the bounding box, center of mass, etc. in
    user-space easily enough with recursive functions.
  This would also allow some very neat hybrid functionality where
    one could iterate the points or faces and then constructively
    add geometry to them, or use them with any of the existing
    polyhedron libraries. In particular, this would be very useful
    for implementing functions like fillet() and chamfer(), both in
    2d and 3d space. Other uses include more complex variants on the
    above piston / cam exmaple, rendering text along a path (or
    face), all in native OpenSCAD-code.
  Currently, we have polyhedron() which takes function/variable
    data and moves it into the geometry space. Using render() to go
    the other way is simple, elegant and provides symmetry with
    minimum complexity. What do you guys think?
  —
    Reply to this email directly or view
      it on GitHub.







  No virus
    found in this message.
    Checked by AVG - www.avg.com
    Version: 2015.0.6140 / Virus Database: 4419/10672 - Release
    Date: 09/20/15

Neon22 commented Sep 21, 2015

Sounds even simpler than my suggestions

On 9/21/2015 1:22 PM, Yona-Appletree
  wrote:


  I've been looking forward to this feature for a while, and
    would like to chime in with some real-world use-cases and ideas
    on keeping the implementation simple. 
  First, I agree with the concern about having many specialized
    function for properties for geometry. It seems to me that the
    main goal here is to bridge the geometry space of OpenSCAD with
    the function/value space. 
  Why not keep the language changes to a minimum by using
    render() function to allow obtaining the geometry for a tree,
    using MatthiasWM's extension to allow geometry with function
    syntax.
  For instance:
    geo = render() cube([20,10,20); // geo now contains an array
    with each separate polyhedron (or polygon, for 2d geometry),
    each compatible with the polyhedron/polygon call: [[points,
    faces]]
  Now we can compute the bounding box, center of mass, etc. in
    user-space easily enough with recursive functions.
  This would also allow some very neat hybrid functionality where
    one could iterate the points or faces and then constructively
    add geometry to them, or use them with any of the existing
    polyhedron libraries. In particular, this would be very useful
    for implementing functions like fillet() and chamfer(), both in
    2d and 3d space. Other uses include more complex variants on the
    above piston / cam exmaple, rendering text along a path (or
    face), all in native OpenSCAD-code.
  Currently, we have polyhedron() which takes function/variable
    data and moves it into the geometry space. Using render() to go
    the other way is simple, elegant and provides symmetry with
    minimum complexity. What do you guys think?
  —
    Reply to this email directly or view
      it on GitHub.







  No virus
    found in this message.
    Checked by AVG - www.avg.com
    Version: 2015.0.6140 / Virus Database: 4419/10672 - Release
    Date: 09/20/15
@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Sep 24, 2015

Sounds good for most cases IMHO. For large geometries, I can see compile time and memory use exploding. I would love to have a binary plugin interface... .

Sounds good for most cases IMHO. For large geometries, I can see compile time and memory use exploding. I would love to have a binary plugin interface... .

@Yona-Appletree

This comment has been minimized.

Show comment Hide comment
@Yona-Appletree

Yona-Appletree Sep 24, 2015

It's certainly not the best solution, but it's simple and hopefully
fairly easy to implement (if I can ever get OpenSCAD to compile on my
Mac, I'll try.).

The issue is that any better solution I can think of would require
significant changes to OpenSCAD. It would be awesome if OpenSCAD
provided more built-in tools for doing user-space polyhedron work, and
if that ever happens, unifying it with geometry-space would certainly
make sense.

MatthiasWM mailto:notifications@github.com
September 24, 2015 at 10:42

Sounds good for most cases IMHO. For large geometries, I can see
compile time and memory use exploding. I would love to have a binary
plugin interface... .


Reply to this email directly or view it on GitHub
#301 (comment).

Yona Appletree
Senior Developer
Concentric Sky, inc
yona@concentricsky.com

It's certainly not the best solution, but it's simple and hopefully
fairly easy to implement (if I can ever get OpenSCAD to compile on my
Mac, I'll try.).

The issue is that any better solution I can think of would require
significant changes to OpenSCAD. It would be awesome if OpenSCAD
provided more built-in tools for doing user-space polyhedron work, and
if that ever happens, unifying it with geometry-space would certainly
make sense.

MatthiasWM mailto:notifications@github.com
September 24, 2015 at 10:42

Sounds good for most cases IMHO. For large geometries, I can see
compile time and memory use exploding. I would love to have a binary
plugin interface... .


Reply to this email directly or view it on GitHub
#301 (comment).

Yona Appletree
Senior Developer
Concentric Sky, inc
yona@concentricsky.com

@MatthiasWM

This comment has been minimized.

Show comment Hide comment
@MatthiasWM

MatthiasWM Sep 24, 2015

Ah, but it is all in the patch and it is working. The calculations for the bounding box need fixing (use the provided boundingbox() function?), but the logic for returning geometry is there. And it's the same an=mount of change that the "render() call would need.

Ah, but it is all in the patch and it is working. The calculations for the bounding box need fixing (use the provided boundingbox() function?), but the logic for returning geometry is there. And it's the same an=mount of change that the "render() call would need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment