Welcome! Log In Create A New Profile

Advanced

Accumulating parameters

Posted by dmould 
Accumulating parameters
August 07, 2015 08:57AM
I often have parameter driven designs that have a variable number of objects, the positions of which I define as an array. e.g. (copy to OpenScad between the ** marks if you want to try)

**
MountPositions=[
[0,-3.2],
[8,-3.2],
[0,5.8],
[8,5.8],
[3,2],
[7,3.5]
// Add or remove positions at will
];
//This array can be used in a "for" loop e.g.

for (Mnt=MountPositions)
{
translate([Mnt[0],Mnt[1],0])
cylinder(r=1,h=5,$fn=20);
translate([Mnt[0],Mnt[1],5])
cylinder(r=.5,h=2,$fn=20);
}
**

Which automatically executes the number of times that there are variables in the array. This is really great for designs where different variations will have a different number of objects in different places - maybe box dividers, support fixtures etc.

My problem is that I often need a variable that is the number of objects that there are, or variables containing the max and min extents of the objects, or find the total or average of all the variables. e.g. let's say that I want to make a box or baseplate for all the cylinders in the above example, the size of which depends on the extent of the objects and so will change if I alter, add or remove values in the array. In that case I need to define variables of the min and max X & Y positions. Or maybe I need the average X or Y spacing, in which case I need to add all the parameters and divide by the number of parameters. Is there any way in OpenScad of automatically defining a variable that is the number of parameters, or a variable that is an arithmetic function of the variables?

Because while the "for" loop will automatically go through the array the right number of times to draw things, variables cannot be redefined within a module so I cannot accumulate with a line such as, "Total=Total+Mnt[0];" or "MaxX=max(MaxX,Mnt[0]);" in the "for" loop.

e.g. the following does not work if I need to know the number of variables that have been defined:

NumberOfMounts=0;
for (Mnt=MountPositions)
{
NumberOfMounts=NumberOfMounts+1;
}
echo(NumberOfMounts);

Can anyone figure out a solution?

Dave
Re: Accumulating parameters
August 07, 2015 12:31PM
try
NumberOfMounts= len(MountPositions); // len(??) = size of array
Re: Accumulating parameters
August 07, 2015 04:38PM
The len() function is indeed the simplest solution for getting the length of an array. However, this solves only one special case of dmould's more general problem...

For solving things like sum, minimum or maximum, you could use recursive functions. To illustrate the idea, you could e.g. use something like the following for computing the minimum and maximum [x,y,z] of an array of points:


function minxyz(array,J = 0) = [( J < len(array)?min(array [J] [0],minxyz(array,J +1)[0]):99999999) , ( J < len(array)?min(array [J] [1],minxyz(array, J +1)[1]):99999999),( J < len(array)?min(array [J] [2],minxyz(array,J +1)[2]):99999999)];

function maxxyz(array,J = 0) = [( J < len(array)?max(array [J] [0],maxxyz(array, J +1)[0]):0),( J < len(array)?max(array [J] [1],maxxyz(array, J +1)[1]):0),( J < len(array)?max(array [J] [2],maxxyz(array, J +1)[2]):0)];

pts=[[6,5,7],[8,5,8],[7,1,6],[11,4,7]];  // list of points


echo(minxyz(pts),maxxyz(pts));

for(p = pts) translate(p)cube([1,1,1]); // draw points

color("red",0.5) translate(minxyz(pts))cube(maxxyz(pts)-minxyz(pts)+[1,1,1]);  // draw englobing cube

Edited 6 time(s). Last edit at 08/08/2015 06:38AM by enif.
Re: Accumulating parameters
August 08, 2015 01:56AM
And here a more efficient and cleaner version, which can easily be adapted for any dimension of the array, e.g. just [x,y] as in the original question...
function mina(array,ind,J=0) = ( J < len(array)?min(array [J] [ind],mina(array,ind,J+1)):99999999);
function maxa(array,ind,J=0) = ( J < len(array)?max(array [J] [ind],maxa(array,ind,J+1)):0);

function minxyz(array,i=0) = [mina(array,0),mina(array,1),mina(array,2)];
function maxxyz(array,i=0) = [maxa(array,0),maxa(array,1),maxa(array,2)];

function minxy(array,i=0) = [mina(array,0),mina(array,1)];
function maxxy(array,i=0) = [maxa(array,0),maxa(array,1)];


pts=[[6,5,7],[8,5,8],[7,1,6],[4,8,5],[3,3,3],[11,4,7]];// point list


echo("minxyz=",minxyz(pts));
echo("maxxyz=",maxxyz(pts));

// show points as little cubes
for(p = pts) translate(p)cube([1,1,1]);

// show englobing cube of all points
color("red",0.5)translate(minxyz(pts))cube(maxxyz(pts)-minxyz(pts)+[1,1,1]);

Edited 4 time(s). Last edit at 08/08/2015 06:19AM by enif.
Re: Accumulating parameters
August 10, 2015 08:31AM
Thanks guys, that's brilliant! Exactly what I need, enif. The more I use OpenScad, the more I like it ...

First time I've seen recursive functions - like it!

Dave

Edited 1 time(s). Last edit at 08/10/2015 08:51AM by dmould.
Sorry, only registered users may post in this forum.

Click here to login