On 10. okt. 2016 19:13, otto wrote:
On Mon, 10 Oct 2016 10:44:13 +0100
nop head nop.head@gmail.com wrote:
So @xsq becomes both a name mangled function and a variable holding
its name? That seems like a bit of a kludge to me.
Well its like this, you can pass a function with the name of the
function in quotes.
function div3(x)=x/3;
vec = [1,2,3];
function map(func,vec) = [for (i=vec) @func(i)];
echo(map("div3",vec));
And it works:
Compiling design (CSG Tree generation)...
ECHO: [0.333333, 0.666667, 1]
Sometimes I wonder why OpenSCAD reinvents standard language features of
existing languages... below are some thoughts intended as inspiration.
Your example code is applied to AngelScript, a language I use for 3d
modelling:
funcdef double FUNC(double x);
double div3(double x) { return x/3; }
void map(FUNC @func, double[] @vec)
{ for(uint i=0; i<vec.size(); i++) { vec[i]=func(vec[i]); } }
void main()
{
double[] vec = { 1,2,3 };
map(div3,vec);
for(uint i=0; i<vec.size(); i++) print(vec[i]+' ');
}
output is the expected:
0.333333 0.666667 1
First, a function signature 'FUNC' is defined, i.e. one taking and
returning a double. Second, an actual function 'div3' with a signature
compatible with FUNC is defined. Third, the 'map' function where the
'func' parameter is passed 'by handle' using @ resembles your code
(alternate syntax "FUNC@ func" also ok). The array 'vec' also passed 'by
handle' so the caller sees the modified 'vec' after calling 'map'
If I had tried to call map using another function, e.g.
double divn(double x, int n) { return x/n; }
it would generate an error because 'divn' is incompatible with the FUNC
signature. It is not clear from your example what happens if you did a
similar mistake.
Just take this comment as food for thought & inspiration.
Regards
Carsten Arnholm
Thanks for reference. I am new here, found openscad as an ideal
platform for what I wanted to do. Found some limits and decided to
hack the code. I am concerned that I may be duplicating others work.
I will read these documents.
I am trying to make the code more powerful and maintain compatibility.
This was intended to meet my own personal needs but I see it as a
possibility for the whole community.
Best Regards
Otto
On Mon, 10 Oct 2016 23:23:28 +0200
Torsten Paul Torsten.Paul@gmx.de wrote:
On 10/10/2016 11:15 PM, otto wrote:
Either implementation is possible and if enough people
request one over the other, I am willing to implement
either. The first is much simpler to add for me with
my current shallow knowledge of how the code works and
really requires very small changes.
Did you see the work Doug did?
https://github.com/doug-moen/openscad2
It's proposing a way to a more powerful language while still
trying to be as compatible as possible.
It would be ideal if we could get the feature aligned with
those efforts. I think it would be a nice thing to get for
current OpenSCAD already.
ciao,
Torsten.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
That is very similar to what I have implemented and what I am
proposing. I am not familiar with AngelScript. It looks like in
AngelScript you declare that the argument "func" takes a function. The
C/C++ like syntax of AngelScript doesn't really (IMHO) fit well with the
untyped and functional nature of OpenScad, but it is interesting to see
another language using @ as an indirection indicator, although it
appears (in AngelScript) in the argument list as a declaration of type
instead of in the body as a declaration of indirection at call time.
Is it possible for AngelScript to implement a function anonymously?
It doesn't look like it from the posted code.
Regards
Otto
On Mon, 10 Oct 2016 23:23:53 +0200
Carsten Arnholm arnholm@arnholm.org wrote:
On 10. okt. 2016 19:13, otto wrote:
On Mon, 10 Oct 2016 10:44:13 +0100
nop head nop.head@gmail.com wrote:
So @xsq becomes both a name mangled function and a variable holding
its name? That seems like a bit of a kludge to me.
Well its like this, you can pass a function with the name of the
function in quotes.
function div3(x)=x/3;
vec = [1,2,3];
function map(func,vec) = [for (i=vec) @func(i)];
echo(map("div3",vec));
And it works:
Compiling design (CSG Tree generation)...
ECHO: [0.333333, 0.666667, 1]
Sometimes I wonder why OpenSCAD reinvents standard language features
of existing languages... below are some thoughts intended as
inspiration. Your example code is applied to AngelScript, a language
I use for 3d modelling:
funcdef double FUNC(double x);
double div3(double x) { return x/3; }
void map(FUNC @func, double[] @vec)
{ for(uint i=0; i<vec.size(); i++) { vec[i]=func(vec[i]); } }
void main()
{
double[] vec = { 1,2,3 };
map(div3,vec);
for(uint i=0; i<vec.size(); i++) print(vec[i]+' ');
}
output is the expected:
0.333333 0.666667 1
First, a function signature 'FUNC' is defined, i.e. one taking and
returning a double. Second, an actual function 'div3' with a
signature compatible with FUNC is defined. Third, the 'map' function
where the 'func' parameter is passed 'by handle' using @ resembles
your code (alternate syntax "FUNC@ func" also ok). The array 'vec'
also passed 'by handle' so the caller sees the modified 'vec' after
calling 'map'
If I had tried to call map using another function, e.g.
double divn(double x, int n) { return x/n; }
it would generate an error because 'divn' is incompatible with the
FUNC signature. It is not clear from your example what happens if you
did a similar mistake.
Just take this comment as food for thought & inspiration.
Regards
Carsten Arnholm
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
On 10/10/2016 11:46 PM, otto wrote:
Thanks for reference. I am new here, found openscad
as an ideal platform for what I wanted to do. Found
some limits and decided to hack the code. I am concerned
that I may be duplicating others work. I will read
these documents.
Awesome, that's exactly how I got involved, I really
missed an easy way to add text to a model :-).
I am trying to make the code more powerful and maintain
compatibility. This was intended to meet my own personal
needs but I see it as a possibility for the whole community.
There are very likely a number of things from the OpenSCAD2
proposal (and also other ideas) that could be added to the
current state without too much issues. But please don't be
discouraged if it takes some time as language changes are
always a bit tricky. Once something is out, it's very hard
to change.
ciao,
Torsten.
On 2016-10-10 23:57, otto wrote:
That is very similar to what I have implemented and what I am
proposing. I am not familiar with AngelScript. It looks like in
AngelScript you declare that the argument "func" takes a function.
Yes, funcdef declares a pointer to function type. If FUNC is defined by
'funcdef', you can declare a variable of type FUNC as a pointer to
function, and assign it: FUNC@ some_func = div3;
The
C/C++ like syntax of AngelScript doesn't really (IMHO) fit well with
the
untyped and functional nature of OpenScad,
That may be true, but as you say these things are a matter of opinion.
The strong typing in AngelScript is in my opinion an advantage (there
are other advantages as well).
but it is interesting to see
another language using @ as an indirection indicator, although it
appears (in AngelScript) in the argument list as a declaration of type
instead of in the body as a declaration of indirection at call time.
True. I guess in untyped languages that's the only option you have.
Is it possible for AngelScript to implement a function anonymously?
It doesn't look like it from the posted code.
Yes, indeed it is possible. See quick example at
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_script_anonfunc.html
Regards
Carsten Arnholm
I've been doing some prototyping work, and after some experiments, my
favourite syntax for anonymous functions is
(x, y) -> x + y
This syntax is naturally nestable, so it's easy to write a "curried"
function like this:
x -> y -> x + y
[In my prototype, the parentheses around a parameter list are optional if
the entire parameter list consists of just a single identifier.]
Otto's "map" example would be written
map(x->x/3, [1,2,3])
On 10 October 2016 at 13:13, otto otto@123phase.com wrote:
On Mon, 10 Oct 2016 10:44:13 +0100
nop head nop.head@gmail.com wrote:
So @xsq becomes both a name mangled function and a variable holding
its name? That seems like a bit of a kludge to me.
Well its like this, you can pass a function with the name of the
function in quotes.
function div3(x)=x/3;
vec = [1,2,3];
function map(func,vec) = [for (i=vec) @func(i)];
echo(map("div3",vec));
And it works:
Compiling design (CSG Tree generation)...
ECHO: [0.333333, 0.666667, 1]
Using the construct funcion @xyz .., gives you a way to create a
function and have the compiler generate a name for the function and put
it in a variable for you. "@" used in other contexts is simply a
dereferencing operator. It does require that the name following the
"@" is a variable name known by the compiler and not an expression
returning a string. "@concat("d","iv3")" will not work.
A syntax that would work nicely (but requires more hacking on my part)
would be to create true anonymous functions with syntax such as follows.
Abandon the "function @...",
shorten it to "@(<argument list>,<function,def>)"
Which returns the created name of the function. This would allow for
a more anonymous lambda like usage.
Map could then be invoked, map(@(x,x/3),[1,2,3]), which is more compact
and would get the right behavior.
Thanks for the questions and idea. You are helping me think it
through. Please try current code. I think I will try to program
this capability next week. I am going on a trip this week.
BTW what is best way to pass on this code in github.
Regards
Otto
Defining functions normally and passing them with @name would allow
the compiler to check it was a valid function name without having to
have specially decorated functions. They could be passed as string
equal to their name and then calling @func() could work with any
string that equals a function name. Seems less kludgey to me. You
only have one type of function rather than ones that have to be
called normally and ones that need to be called with @.
On 10 October 2016 at 10:19, otto otto@123phase.com wrote:
On Mon, 10 Oct 2016 10:06:50 +0100
nop head nop.head@gmail.com wrote:
The goal was to get what I wanted easily. The changes are small and
the code seems quite stable.
In declaring a function with the @ decoration.
As in function @xsq(x) = x*x
xsq is an ID token and the variable xsq is given a unique function
name as its contents. The name is a digit followed by a period.
You can see it by echoing xsq.
You can then pass xsq around and then dereference it with @.
Because we use openscads well designed and consistent
parsing/compiling environment to do all the work, this is fast. As
designed I hadn't really anticipated the side effect that any
function can be passed as its token name, and dereferenced later.
The great thing about this is that the compiler resolves functions
by there string name and all I needed to do was detect the
decorator in the parser and then do one level of indirection. The
nice thing is it is safe, it doesn't break other code and it
requires only small changes to the source code and it works now.
Please test the code in the repository if you are inclined or have
the time.
Regards
Otto
You don't seem to use the @ sign in the places I would expect. I
don't see a need for them in the function definition as any
function should be passable as an argument. I would expect them
to be needed where a function is called from a string, so:
function xsq(x) = x*x;
function recip(x)=1/x;
vec1=[1,2,3];
vec2=[.1,.7];
function map(func,vec) = [for (i=vec) @func(i)];
echo(map("xsq",vec1));
echo(map"("xsq",vec2));
echo(map("recip",vec1));
echo(map("recip",vec2));
The @ sign could also be used to make a function literal instead
of passing string but that is a bigger change to the language.
Simply adding @ to take a string and look up function seems like
a simple mod. Creating a new variable type that is a function
would have much bigger implications because it could be used in
any expression. Keeping the name as a string allows all sorts of
tricks by concatenating suffixes, etc.
On 10 October 2016 at 09:53, otto otto@123phase.com wrote:
I have hacked the openscad source code to support function
indirection.
Here is a sample of how it works. Function is decorated with
the "@" character when it is created and when it is used, but
not when it is passed to another function.
//Preferred usage//
function @xsq(x) = x*x;
function @recip(x)=1/x;
vec1=[1,2,3];
vec2=[.1,.7];
function map(func,vec) = [for (i=vec) @func(i)];
echo(map(xsq,vec1));
echo(map(xsq,vec2));
echo(map(recip,vec1));
echo(map(recip,vec2));
//Other crazy usage//
function div3(x)=x/3;
indirect = "div3";
echo(map(indirect,vec2));
Output is:
ECHO: [1, 4, 9]
ECHO: [0.01, 0.49]
ECHO: [1, 0.5, 0.333333]
ECHO: [10, 1.42857]
ECHO: [0.0333333, 0.233333]
Everything is contained in the github repositor:
https://github.com/ottojas/openscad-affine
There is a pdf file there with some sample 3D and 2D output. In
order to get this capability you need to add about 30 lines of
code in changes to five files in the source directory. These
are relatively stable files and you may get away with simply
copying them from the ojasSources directory.
This is very much a work in progress. Comments, questions,
flames, laughter, mockery etc. all welcome. If anyone tests
this please let me know what your experience is. Everything is
gnu public license as is the source code for openscad.
Regards
Otto
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_
lists.openscad.org
Bananapeel wrote:
IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.
I agree with this.
If we implement function values without uniting the namespaces, we have to
use ugly, nonstandard syntax for things like: calling a function stored in
a variable, or passing a named function as an argument. This leads to
complicated rules and ugly syntax, worse than function calls in any modern
programming language. And that's not in the spirit of OpenSCAD, which aims
to be simpler than a general purpose programming language.
Thought experiment: what happens if we change OpenSCAD to use 1 namespace
in the next release? Answer: we'd break some existing code, and that
happens in two ways:
So maybe we should make this change in two phases, first deprecating the 3
namespaces, then uniting them in a subsequent release?
Even with the deprecation release, this is a disruptive change that breaks
existing code. It's more work, but we could mitigate the problem by
providing an upgrade tool that automatically renames objects to avoid
conflicts. (For example, the tool could append a V, F or M to the names of
variables, functions and modules that conflict with one another.) If the
upgrade tool is painless enough to use, maybe we don't need the deprecation
phase?
This is the simplest path I can think of that leads to function values with
a unified namespace. The backwards compatibility scheme I described in the
OpenSCAD2 proposal is much harder to implement.
Doug Moen.
On 10 October 2016 at 15:15, Bananapeel lunatica.xiaoyu@gmail.com wrote:
I don't know why this thread is inside the thread "Convert from object to
polygon/polyhedron." Anyways, regarding passing functions as arguments:
IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.
Using () on a variable that isn't of type function or module would give a
runtime error.
Example:
//Preferred usage//
function xsq(x) = x*x;
function recip(x)=1/x;
vec1=[1, 2, 3];
vec2=[0.1, 0.7];
function map(func,vec) = [for (i=vec) func(i)];
echo(map(xsq,vec1));
echo(map(xsq,vec2));
echo(map(recip,vec1));
echo(map(recip,vec2));
//Other crazy usage//
function div3(x)=x/3;
indirect = div3;
echo(map(indirect,vec2));
--
View this message in context: http://forum.openscad.org/
Convert-from-object-to-polygon-polyhedron-tp18522p18659.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Does this mean we will have to use unique names for everything ?
On 10/15/2016 2:46 AM, doug moen wrote:
Bananapeel wrote:
IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.I agree with this.
If we implement function values without uniting the namespaces, we have to use ugly, nonstandard syntax for things like: calling a function stored in a variable, or passing a named function as an argument. This leads to complicated rules and ugly syntax, worse than function calls in any modern programming language. And that's not in the spirit of OpenSCAD, which aims to be simpler than a general purpose programming language.
Thought experiment: what happens if we change OpenSCAD to use 1 namespace in the next release? Answer: we'd break some existing code, and that happens in two ways:
- If you define a function and a variable with the same name X, in the same scope, then the code no longer works. We should report an error (duplicate definition of X).
- Currently, a variable defined in an inner scope cannot shadow a variable defined in an outer scope, and vice versa. Once we unify the namespaces, the scoping rules change, and this sort of shadowing will occur. And this could be a silent error?
So maybe we should make this change in two phases, first deprecating the 3 namespaces, then uniting them in a subsequent release?
- In release N, we'll deprecate the 3 namespaces. You'll get a warning for duplicate definitions in the same scope, and a warning for objects with different kinds but the same name shadowing each other in nested scopes.
- In release N+1, these warnings turn into errors. We won't silently change the meaning of old code: instead, we'll detect the old incompatible code, report an error and force you to fix it. In this release, we can also make functions into first class values, and introduce a syntax for anonymous functions. Although the namespaces are now unified, modules won't necessarily be first class values (that's harder to do, and I won't discuss the details here).
Even with the deprecation release, this is a disruptive change that breaks existing code. It's more work, but we could mitigate the problem by providing an upgrade tool that automatically renames objects to avoid conflicts. (For example, the tool could append a V, F or M to the names of variables, functions and modules that conflict with one another.) If the upgrade tool is painless enough to use, maybe we don't need the deprecation phase?
This is the simplest path I can think of that leads to function values with a unified namespace. The backwards compatibility scheme I described in the OpenSCAD2 proposal is much harder to implement.
Doug Moen.
On 10 October 2016 at 15:15, Bananapeel <lunatica.xiaoyu@gmail.com> wrote:
I don't know why this thread is inside the thread "Convert from object to
polygon/polyhedron." Anyways, regarding passing functions as arguments:IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.Using () on a variable that isn't of type function or module would give a
runtime error.Example:
//Preferred usage//
function xsq(x) = x*x;
function recip(x)=1/x;
vec1=[1, 2, 3];
vec2=[0.1, 0.7];function map(func,vec) = [for (i=vec) func(i)];
echo(map(xsq,vec1));
echo(map(xsq,vec2));
echo(map(recip,vec1));
echo(map(recip,vec2));//Other crazy usage//
function div3(x)=x/3;
indirect = div3;
echo(map(indirect,vec2));--
View this message in context: http://forum.openscad.org/Convert-from-object-to-polygon-polyhedron-tp18522p18659.html
Sent from the OpenSCAD mailing list archive at Nabble.com._______________________________________________
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org<pre wrap="">_______________________________________________ OpenSCAD mailing list <a class="moz-txt-link-abbreviated" href="mailto:Discuss@lists.openscad.org">Discuss@lists.openscad.org</a> <a class="moz-txt-link-freetext" href="http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org">http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org</a>No virus found in this message.
Checked by AVG - www.avg.com
Version: 2016.0.7797 / Virus Database: 4664/13206 - Release Date: 10/13/16
Breaks all my code as I use lots of single names for both a variable, a
function that exports it and module that it relates to. I find it handy not
to make up three names for one subject. It is obvious which one is
referenced from the context.
If there is a breaking change to OpenScad I will stick with the version I
have now forever as it does everything I need. Same as Python 2, never used
3 as I need to change all my print statements to functions. Please make
such big changes in OpenScad2.
On 14 October 2016 at 23:07, Mark Schafer mschafer@wireframe.biz wrote:
Does this mean we will have to use unique names for everything ?
On 10/15/2016 2:46 AM, doug moen wrote:
Bananapeel wrote:
IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes
just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.
I agree with this.
If we implement function values without uniting the namespaces, we have to
use ugly, nonstandard syntax for things like: calling a function stored in
a variable, or passing a named function as an argument. This leads to
complicated rules and ugly syntax, worse than function calls in any modern
programming language. And that's not in the spirit of OpenSCAD, which aims
to be simpler than a general purpose programming language.
Thought experiment: what happens if we change OpenSCAD to use 1 namespace
in the next release? Answer: we'd break some existing code, and that
happens in two ways:
1. If you define a function and a variable with the same name X, in
the same scope, then the code no longer works. We should report an error
(duplicate definition of X).
2. Currently, a variable defined in an inner scope cannot shadow a
variable defined in an outer scope, and vice versa. Once we unify the
namespaces, the scoping rules change, and this sort of shadowing will
occur. And this could be a silent error?
So maybe we should make this change in two phases, first deprecating the 3
namespaces, then uniting them in a subsequent release?
1. In release N, we'll deprecate the 3 namespaces. You'll get a
warning for duplicate definitions in the same scope, and a warning for
objects with different kinds but the same name shadowing each other in
nested scopes.
2. In release N+1, these warnings turn into errors. We won't silently
change the meaning of old code: instead, we'll detect the old incompatible
code, report an error and force you to fix it. In this release, we can also
make functions into first class values, and introduce a syntax for
anonymous functions. Although the namespaces are now unified, modules won't
necessarily be first class values (that's harder to do, and I won't discuss
the details here).
Even with the deprecation release, this is a disruptive change that breaks
existing code. It's more work, but we could mitigate the problem by
providing an upgrade tool that automatically renames objects to avoid
conflicts. (For example, the tool could append a V, F or M to the names of
variables, functions and modules that conflict with one another.) If the
upgrade tool is painless enough to use, maybe we don't need the deprecation
phase?
This is the simplest path I can think of that leads to function values
with a unified namespace. The backwards compatibility scheme I described in
the OpenSCAD2 proposal is much harder to implement.
Doug Moen.
On 10 October 2016 at 15:15, Bananapeel lunatica.xiaoyu@gmail.com wrote:
I don't know why this thread is inside the thread "Convert from object to
polygon/polyhedron." Anyways, regarding passing functions as arguments:
IMO, there's just one "proper" syntax for this. And that is, that the name
without () acts as a variable, and () means call. And function becomes
just
another type, like string and int. This means functions and variables must
occupy the same namespace. This syntax can also work for modules, however,
this means variables, functions and modules all share the same namespace,
which currently isn't the case.
Using () on a variable that isn't of type function or module would give a
runtime error.
Example:
//Preferred usage//
function xsq(x) = x*x;
function recip(x)=1/x;
vec1=[1, 2, 3];
vec2=[0.1, 0.7];
function map(func,vec) = [for (i=vec) func(i)];
echo(map(xsq,vec1));
echo(map(xsq,vec2));
echo(map(recip,vec1));
echo(map(recip,vec2));
//Other crazy usage//
function div3(x)=x/3;
indirect = div3;
echo(map(indirect,vec2));
--
View this message in context: http://forum.openscad.org/Conv
ert-from-object-to-polygon-polyhedron-tp18522p18659.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OpenSCAD mailing listDiscuss@lists.openscad.orghttp://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
No virus found in this message.
Checked by AVG - www.avg.com
Version: 2016.0.7797 / Virus Database: 4664/13206 - Release Date: 10/13/16
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
nophead wrote
Breaks all my code as I use lots of single names for both a variable, a
function that exports it and module that it relates to. I find it handy
not
to make up three names for one subject. It is obvious which one is
referenced from the context.
nice: :
a = 10;
a();
module a(){
a = a;
echo(a);
echo(a());
a();
function a() = 20;
module a(){
a = a;
echo(a);
echo(a());
function a() = 20;
}
}
--
View this message in context: http://forum.openscad.org/Convert-from-object-to-polygon-polyhedron-tp18522p18714.html
Sent from the OpenSCAD mailing list archive at Nabble.com.