discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

OpenSCAD programming question, recursion, functions, and modules

DS
Dan Shriver
Thu, Feb 8, 2018 8:14 PM

I'm going to attach some code (only look at it if you need it to get an
idea of what I am trying to do, I am sure there are bugs plus I didn't copy
any of the helper functions...).

I am having trouble figuring out how to deal with recursion on something I
am drawing.  My problems are:

  1. a Module can't return anything, correct?  At the same time I don't see
    how to (in a Function) do a lot of code setup, call helper functions, etc.
    I guess I could setup a variable in a Function with "let" but how do I do a
    block of code with conditionals etc.  I would either like to return a list
    of points from a Module, or figure out how to do "real work" (helper calls,
    conditionals, etc) from a Function

  2. If I have something that generates a list of points, assuming I
    recursively call that how do I elegantly keep the list one dimensional (not
    nested lists).  Do I just a call to some flatten function at the end?
    Ideally I'd like not to generate nested lists to begin with, but I'm having
    a little trouble seeing how to do that?

Basically, what I am doing below is what I call a "bat curve" because I
imagine it will look slightly like the stylized bats in traditional Chinese
art (somewhat, not exactly, I can go into differences later, I don't need
it to look exactly like that and am just using that as a convenient
description).  The shape is going to be a fractal of arcs of increasingly
smaller circles (generations determines how many levels deep the fractal
goes).  Basically one large arc subdivides on both sides into a spiral of
increasingly smaller radii arcs.  You could think of a letter D where the
straight line is removed and at both ends of the D there is a spiral.


module bCurve2(radius, number, generations, quadrant, pointsPerGeneration,
direction, angle) {
if (direction > 0) {
newQuadrant = (quadrant + 1) % 4;
startAngle = angle;
endAngle = computeAngle(number, newQuadrant);
}
else {
newQuadrant = (quadrant + 3) % 4;
startAngle = computeAngle(number, newQuadrant);
endAngle = angle;
}
}

//quadrant is the graph quadrant for the next circle except it is C indexed
so it is 0 - 3 rather than 1 - 4
module bCurve(radius, number, generations, quadrant, pointsPerGeneration) {

if (generations > -1) {
  angle1 = computeAngle(number, quadrant);
  angle2 = computeAngle(number, nextQuadrant(quadrant));

  span = angle1 - angle2;
  stepSize = span/pointsPerGeneration;
  newRadius = radius * sin(atan(2/(number-1)));

  quadrantA = (quadrant + 3)%4;
  quadrantB = (quadrant + 2) %4;

  points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius,

number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1),
xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)],
bCurve2(newRadius, number, (generations -1), quadrantB,
pointsPerGeneration, 1, angle2) ];

difference() {
  offset(0.01) polygon(points);
  polygon(points);
  }
  }

}

I'm going to attach some code (only look at it if you need it to get an idea of what I am trying to do, I am sure there are bugs plus I didn't copy any of the helper functions...). I am having trouble figuring out how to deal with recursion on something I am drawing. My problems are: 1) a Module can't return anything, correct? At the same time I don't see how to (in a Function) do a lot of code setup, call helper functions, etc. I guess I could setup a variable in a Function with "let" but how do I do a block of code with conditionals etc. I would either like to return a list of points from a Module, or figure out how to do "real work" (helper calls, conditionals, etc) from a Function 2) If I have something that generates a list of points, assuming I recursively call that how do I elegantly keep the list one dimensional (not nested lists). Do I just a call to some flatten function at the end? Ideally I'd like not to generate nested lists to begin with, but I'm having a little trouble seeing how to do that? Basically, what I am doing below is what I call a "bat curve" because I imagine it will look slightly like the stylized bats in traditional Chinese art (somewhat, not exactly, I can go into differences later, I don't need it to look exactly like that and am just using that as a convenient description). The shape is going to be a fractal of arcs of increasingly smaller circles (generations determines how many levels deep the fractal goes). Basically one large arc subdivides on both sides into a spiral of increasingly smaller radii arcs. You could think of a letter D where the straight line is removed and at both ends of the D there is a spiral. ------------------------ module bCurve2(radius, number, generations, quadrant, pointsPerGeneration, direction, angle) { if (direction > 0) { newQuadrant = (quadrant + 1) % 4; startAngle = angle; endAngle = computeAngle(number, newQuadrant); } else { newQuadrant = (quadrant + 3) % 4; startAngle = computeAngle(number, newQuadrant); endAngle = angle; } } //quadrant is the graph quadrant for the next circle except it is C indexed so it is 0 - 3 rather than 1 - 4 module bCurve(radius, number, generations, quadrant, pointsPerGeneration) { if (generations > -1) { angle1 = computeAngle(number, quadrant); angle2 = computeAngle(number, nextQuadrant(quadrant)); span = angle1 - angle2; stepSize = span/pointsPerGeneration; newRadius = radius * sin(atan(2/(number-1))); quadrantA = (quadrant + 3)%4; quadrantB = (quadrant + 2) %4; points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius, number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1), xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)], bCurve2(newRadius, number, (generations -1), quadrantB, pointsPerGeneration, 1, angle2) ]; difference() { offset(0.01) polygon(points); polygon(points); } } }
FV
Frank van der Hulst
Thu, Feb 8, 2018 10:17 PM
  1. A module "returns" an object... whatever object  is generated by a
    module is its return "value". So you could return a polygon created from a
    list of points, for example, by having a polygon ([list]) statement at the
    end of the module.

You can use the ternary operator to do if-then-else evaluations in a let()
call in a function. And a function can call other functions.

  1. The concat () function flattens multiple lists into a single list.

On Friday, February 9, 2018, Dan Shriver tabbydan@gmail.com wrote:

I'm going to attach some code (only look at it if you need it to get an
idea of what I am trying to do, I am sure there are bugs plus I didn't copy
any of the helper functions...).

I am having trouble figuring out how to deal with recursion on something I
am drawing.  My problems are:

  1. a Module can't return anything, correct?  At the same time I don't see
    how to (in a Function) do a lot of code setup, call helper functions, etc.
    I guess I could setup a variable in a Function with "let" but how do I do a
    block of code with conditionals etc.  I would either like to return a list
    of points from a Module, or figure out how to do "real work" (helper calls,
    conditionals, etc) from a Function

  2. If I have something that generates a list of points, assuming I
    recursively call that how do I elegantly keep the list one dimensional (not
    nested lists).  Do I just a call to some flatten function at the end?
    Ideally I'd like not to generate nested lists to begin with, but I'm having
    a little trouble seeing how to do that?

Basically, what I am doing below is what I call a "bat curve" because I
imagine it will look slightly like the stylized bats in traditional Chinese
art (somewhat, not exactly, I can go into differences later, I don't need
it to look exactly like that and am just using that as a convenient
description).  The shape is going to be a fractal of arcs of increasingly
smaller circles (generations determines how many levels deep the fractal
goes).  Basically one large arc subdivides on both sides into a spiral of
increasingly smaller radii arcs.  You could think of a letter D where the
straight line is removed and at both ends of the D there is a spiral.


module bCurve2(radius, number, generations, quadrant, pointsPerGeneration,
direction, angle) {
if (direction > 0) {
newQuadrant = (quadrant + 1) % 4;
startAngle = angle;
endAngle = computeAngle(number, newQuadrant);
}
else {
newQuadrant = (quadrant + 3) % 4;
startAngle = computeAngle(number, newQuadrant);
endAngle = angle;
}
}

//quadrant is the graph quadrant for the next circle except it is C
indexed so it is 0 - 3 rather than 1 - 4
module bCurve(radius, number, generations, quadrant, pointsPerGeneration) {

 if (generations > -1) {
   angle1 = computeAngle(number, quadrant);
   angle2 = computeAngle(number, nextQuadrant(quadrant));

   span = angle1 - angle2;
   stepSize = span/pointsPerGeneration;
   newRadius = radius * sin(atan(2/(number-1)));

   quadrantA = (quadrant + 3)%4;
   quadrantB = (quadrant + 2) %4;

   points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius,

number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1),
xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)],
bCurve2(newRadius, number, (generations -1), quadrantB,
pointsPerGeneration, 1, angle2) ];

 difference() {
   offset(0.01) polygon(points);
   polygon(points);
   }
   }

}

1) A module "returns" an object... whatever object is generated by a module is its return "value". So you could return a polygon created from a list of points, for example, by having a polygon ([list]) statement at the end of the module. You can use the ternary operator to do if-then-else evaluations in a let() call in a function. And a function can call other functions. 2) The concat () function flattens multiple lists into a single list. On Friday, February 9, 2018, Dan Shriver <tabbydan@gmail.com> wrote: > I'm going to attach some code (only look at it if you need it to get an > idea of what I am trying to do, I am sure there are bugs plus I didn't copy > any of the helper functions...). > > I am having trouble figuring out how to deal with recursion on something I > am drawing. My problems are: > > 1) a Module can't return anything, correct? At the same time I don't see > how to (in a Function) do a lot of code setup, call helper functions, etc. > I guess I could setup a variable in a Function with "let" but how do I do a > block of code with conditionals etc. I would either like to return a list > of points from a Module, or figure out how to do "real work" (helper calls, > conditionals, etc) from a Function > > 2) If I have something that generates a list of points, assuming I > recursively call that how do I elegantly keep the list one dimensional (not > nested lists). Do I just a call to some flatten function at the end? > Ideally I'd like not to generate nested lists to begin with, but I'm having > a little trouble seeing how to do that? > > Basically, what I am doing below is what I call a "bat curve" because I > imagine it will look slightly like the stylized bats in traditional Chinese > art (somewhat, not exactly, I can go into differences later, I don't need > it to look exactly like that and am just using that as a convenient > description). The shape is going to be a fractal of arcs of increasingly > smaller circles (generations determines how many levels deep the fractal > goes). Basically one large arc subdivides on both sides into a spiral of > increasingly smaller radii arcs. You could think of a letter D where the > straight line is removed and at both ends of the D there is a spiral. > > > > ------------------------ > module bCurve2(radius, number, generations, quadrant, pointsPerGeneration, > direction, angle) { > if (direction > 0) { > newQuadrant = (quadrant + 1) % 4; > startAngle = angle; > endAngle = computeAngle(number, newQuadrant); > } > else { > newQuadrant = (quadrant + 3) % 4; > startAngle = computeAngle(number, newQuadrant); > endAngle = angle; > } > } > > //quadrant is the graph quadrant for the next circle except it is C > indexed so it is 0 - 3 rather than 1 - 4 > module bCurve(radius, number, generations, quadrant, pointsPerGeneration) { > > if (generations > -1) { > angle1 = computeAngle(number, quadrant); > angle2 = computeAngle(number, nextQuadrant(quadrant)); > > span = angle1 - angle2; > stepSize = span/pointsPerGeneration; > newRadius = radius * sin(atan(2/(number-1))); > > quadrantA = (quadrant + 3)%4; > quadrantB = (quadrant + 2) %4; > > points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius, > number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1), > xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)], > bCurve2(newRadius, number, (generations -1), quadrantB, > pointsPerGeneration, 1, angle2) ]; > > difference() { > offset(0.01) polygon(points); > polygon(points); > } > } > } >
DS
Dan Shriver
Fri, Feb 9, 2018 12:23 AM

on 2) the wiki book says that concat() does not change the levels, just
tacks one on to another.  Because of recursion I will have a heterogeneous
list which has points and also members that are lists of points...

like this (ignore the values they are nonsense)

[  [ (4,7), (8,2), (7,8) ] (1,2), (5,10), (3,8) [ (11,21), (15,10), (3,18)
] ]

and I want to flatten it into a one dimensional list (not a list of
lists... which will have nested lists up to how many times I am recursing)

like this

[  (4,7), (8,2), (7,8)  (1,2), (5,10), (3,8)  (11,21), (15,10), (3,18)  ]

On Thu, Feb 8, 2018 at 5:17 PM, Frank van der Hulst <drifter.frank@gmail.com

wrote:

  1. A module "returns" an object... whatever object  is generated by a
    module is its return "value". So you could return a polygon created from a
    list of points, for example, by having a polygon ([list]) statement at the
    end of the module.

You can use the ternary operator to do if-then-else evaluations in a let()
call in a function. And a function can call other functions.

  1. The concat () function flattens multiple lists into a single list.

On Friday, February 9, 2018, Dan Shriver tabbydan@gmail.com wrote:

I'm going to attach some code (only look at it if you need it to get an
idea of what I am trying to do, I am sure there are bugs plus I didn't copy
any of the helper functions...).

I am having trouble figuring out how to deal with recursion on something
I am drawing.  My problems are:

  1. a Module can't return anything, correct?  At the same time I don't see
    how to (in a Function) do a lot of code setup, call helper functions, etc.
    I guess I could setup a variable in a Function with "let" but how do I do a
    block of code with conditionals etc.  I would either like to return a list
    of points from a Module, or figure out how to do "real work" (helper calls,
    conditionals, etc) from a Function

  2. If I have something that generates a list of points, assuming I
    recursively call that how do I elegantly keep the list one dimensional (not
    nested lists).  Do I just a call to some flatten function at the end?
    Ideally I'd like not to generate nested lists to begin with, but I'm having
    a little trouble seeing how to do that?

Basically, what I am doing below is what I call a "bat curve" because I
imagine it will look slightly like the stylized bats in traditional Chinese
art (somewhat, not exactly, I can go into differences later, I don't need
it to look exactly like that and am just using that as a convenient
description).  The shape is going to be a fractal of arcs of increasingly
smaller circles (generations determines how many levels deep the fractal
goes).  Basically one large arc subdivides on both sides into a spiral of
increasingly smaller radii arcs.  You could think of a letter D where the
straight line is removed and at both ends of the D there is a spiral.


module bCurve2(radius, number, generations, quadrant,
pointsPerGeneration, direction, angle) {
if (direction > 0) {
newQuadrant = (quadrant + 1) % 4;
startAngle = angle;
endAngle = computeAngle(number, newQuadrant);
}
else {
newQuadrant = (quadrant + 3) % 4;
startAngle = computeAngle(number, newQuadrant);
endAngle = angle;
}
}

//quadrant is the graph quadrant for the next circle except it is C
indexed so it is 0 - 3 rather than 1 - 4
module bCurve(radius, number, generations, quadrant, pointsPerGeneration)
{

 if (generations > -1) {
   angle1 = computeAngle(number, quadrant);
   angle2 = computeAngle(number, nextQuadrant(quadrant));

   span = angle1 - angle2;
   stepSize = span/pointsPerGeneration;
   newRadius = radius * sin(atan(2/(number-1)));

   quadrantA = (quadrant + 3)%4;
   quadrantB = (quadrant + 2) %4;

   points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius,

number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1),
xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)],
bCurve2(newRadius, number, (generations -1), quadrantB,
pointsPerGeneration, 1, angle2) ];

 difference() {
   offset(0.01) polygon(points);
   polygon(points);
   }
   }

}

on 2) the wiki book says that concat() does not change the levels, just tacks one on to another. Because of recursion I will have a heterogeneous list which has points and also members that are lists of points... like this (ignore the values they are nonsense) [ [ (4,7), (8,2), (7,8) ] (1,2), (5,10), (3,8) [ (11,21), (15,10), (3,18) ] ] and I want to flatten it into a one dimensional list (not a list of lists... which will have nested lists up to how many times I am recursing) like this [ (4,7), (8,2), (7,8) (1,2), (5,10), (3,8) (11,21), (15,10), (3,18) ] On Thu, Feb 8, 2018 at 5:17 PM, Frank van der Hulst <drifter.frank@gmail.com > wrote: > 1) A module "returns" an object... whatever object is generated by a > module is its return "value". So you could return a polygon created from a > list of points, for example, by having a polygon ([list]) statement at the > end of the module. > > You can use the ternary operator to do if-then-else evaluations in a let() > call in a function. And a function can call other functions. > > 2) The concat () function flattens multiple lists into a single list. > > On Friday, February 9, 2018, Dan Shriver <tabbydan@gmail.com> wrote: > >> I'm going to attach some code (only look at it if you need it to get an >> idea of what I am trying to do, I am sure there are bugs plus I didn't copy >> any of the helper functions...). >> >> I am having trouble figuring out how to deal with recursion on something >> I am drawing. My problems are: >> >> 1) a Module can't return anything, correct? At the same time I don't see >> how to (in a Function) do a lot of code setup, call helper functions, etc. >> I guess I could setup a variable in a Function with "let" but how do I do a >> block of code with conditionals etc. I would either like to return a list >> of points from a Module, or figure out how to do "real work" (helper calls, >> conditionals, etc) from a Function >> >> 2) If I have something that generates a list of points, assuming I >> recursively call that how do I elegantly keep the list one dimensional (not >> nested lists). Do I just a call to some flatten function at the end? >> Ideally I'd like not to generate nested lists to begin with, but I'm having >> a little trouble seeing how to do that? >> >> Basically, what I am doing below is what I call a "bat curve" because I >> imagine it will look slightly like the stylized bats in traditional Chinese >> art (somewhat, not exactly, I can go into differences later, I don't need >> it to look exactly like that and am just using that as a convenient >> description). The shape is going to be a fractal of arcs of increasingly >> smaller circles (generations determines how many levels deep the fractal >> goes). Basically one large arc subdivides on both sides into a spiral of >> increasingly smaller radii arcs. You could think of a letter D where the >> straight line is removed and at both ends of the D there is a spiral. >> >> >> >> ------------------------ >> module bCurve2(radius, number, generations, quadrant, >> pointsPerGeneration, direction, angle) { >> if (direction > 0) { >> newQuadrant = (quadrant + 1) % 4; >> startAngle = angle; >> endAngle = computeAngle(number, newQuadrant); >> } >> else { >> newQuadrant = (quadrant + 3) % 4; >> startAngle = computeAngle(number, newQuadrant); >> endAngle = angle; >> } >> } >> >> //quadrant is the graph quadrant for the next circle except it is C >> indexed so it is 0 - 3 rather than 1 - 4 >> module bCurve(radius, number, generations, quadrant, pointsPerGeneration) >> { >> >> if (generations > -1) { >> angle1 = computeAngle(number, quadrant); >> angle2 = computeAngle(number, nextQuadrant(quadrant)); >> >> span = angle1 - angle2; >> stepSize = span/pointsPerGeneration; >> newRadius = radius * sin(atan(2/(number-1))); >> >> quadrantA = (quadrant + 3)%4; >> quadrantB = (quadrant + 2) %4; >> >> points = [ for (i = [0:pointsPerGeneration]) [ bCurve2(newRadius, >> number, (generations -1), quadrantA, pointsPerGeneration, -1, angle1), >> xArc(radius, angle1, stepSize, i), yArc(radius, angle1, stepSize, i)], >> bCurve2(newRadius, number, (generations -1), quadrantB, >> pointsPerGeneration, 1, angle2) ]; >> >> difference() { >> offset(0.01) polygon(points); >> polygon(points); >> } >> } >> } >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
TP
Torsten Paul
Fri, Feb 9, 2018 12:29 AM

The simplest way to do single level flatten is shown in
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Flattening_a_nested_vector

ciao,
Torsten.

The simplest way to do single level flatten is shown in https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Flattening_a_nested_vector ciao, Torsten.
RP
Ronaldo Persiano
Fri, Feb 9, 2018 1:40 AM

If you want to collect all 2D points in a list, whatever depth it has in
it, this may help you:

function get_2D_points(L,n=0,res=[]) =
n>=len(L) ?
res
: L[n]*0==[0,0] ?
get_2D_points(L,n+1, concat(res,[L[n]]))
: get_2D_points(L,n+1, get_2D_points(L[n],0,res));

l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]];

echo( get_2D_points(l));
// ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]

​However, this function crashes if the list is not a nested list of 2D
points like  [[1,2], 3] or [1,2,3].or ["a"], etc.

2018-02-08 22:23 GMT-02:00 Dan Shriver tabbydan@gmail.com:

on 2) the wiki book says that concat() does not change the levels, just
tacks one on to another.  Because of recursion I will have a heterogeneous
list which has points and also members that are lists of points...

like this (ignore the values they are nonsense)

[  [ (4,7), (8,2), (7,8) ] (1,2), (5,10), (3,8) [ (11,21), (15,10), (3,18)
] ]

and I want to flatten it into a one dimensional list (not a list of
lists... which will have nested lists up to how many times I am recursing)

like this

[  (4,7), (8,2), (7,8)  (1,2), (5,10), (3,8)  (11,21), (15,10), (3,18)  ]

If you want to collect all 2D points in a list, whatever depth it has in it, this may help you: function get_2D_points(L,n=0,res=[]) = n>=len(L) ? res : L[n]*0==[0,0] ? get_2D_points(L,n+1, concat(res,[L[n]])) : get_2D_points(L,n+1, get_2D_points(L[n],0,res)); l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]]; echo( get_2D_points(l)); // ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] ​However, this function crashes if the list is not a nested list of 2D points like [[1,2], 3] or [1,2,3].or ["a"], etc. 2018-02-08 22:23 GMT-02:00 Dan Shriver <tabbydan@gmail.com>: > on 2) the wiki book says that concat() does not change the levels, just > tacks one on to another. Because of recursion I will have a heterogeneous > list which has points and also members that are lists of points... > > like this (ignore the values they are nonsense) > > [ [ (4,7), (8,2), (7,8) ] (1,2), (5,10), (3,8) [ (11,21), (15,10), (3,18) > ] ] > > and I want to flatten it into a one dimensional list (not a list of > lists... which will have nested lists up to how many times I am recursing) > > like this > > [ (4,7), (8,2), (7,8) (1,2), (5,10), (3,8) (11,21), (15,10), (3,18) ] > > >
RP
Ronaldo Persiano
Fri, Feb 9, 2018 1:59 AM

If your lists contain either 2D points or simple lists of 2D points, a
simpler non-recursive solution (by Parkinbot) is:

l = [[1,2],[[3,4]],[[5,6],[7,8]],[[9,10],[11,12],[13,14] ]];

function get_2D_points(L) = [for(a=L, v = (a[0][0]!=undef ? a: [a]) ) v ];

echo( get_2D_points(l));
// ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14]]

2018-02-08 23:40 GMT-02:00 Ronaldo Persiano rcmpersiano@gmail.com:

If you want to collect all 2D points in a list, whatever depth it has in
it, this may help you:

function get_2D_points(L,n=0,res=[]) =
n>=len(L) ?
res
: L[n]*0==[0,0] ?
get_2D_points(L,n+1, concat(res,[L[n]]))
: get_2D_points(L,n+1, get_2D_points(L[n],0,res));

l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]];

echo( get_2D_points(l));
// ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]

​However, this function crashes if the list is not a nested list of 2D
points like  [[1,2], 3] or [1,2,3].or ["a"], etc.

If your lists contain either 2D points or simple lists of 2D points, a simpler non-recursive solution (by Parkinbot) is: l = [[1,2],[[3,4]],[[5,6],[7,8]],[[9,10],[11,12],[13,14] ]]; function get_2D_points(L) = [for(a=L, v = (a[0][0]!=undef ? a: [a]) ) v ]; echo( get_2D_points(l)); // ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14]] 2018-02-08 23:40 GMT-02:00 Ronaldo Persiano <rcmpersiano@gmail.com>: > If you want to collect all 2D points in a list, whatever depth it has in > it, this may help you: > > function get_2D_points(L,n=0,res=[]) = > n>=len(L) ? > res > : L[n]*0==[0,0] ? > get_2D_points(L,n+1, concat(res,[L[n]])) > : get_2D_points(L,n+1, get_2D_points(L[n],0,res)); > > l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]]; > > echo( get_2D_points(l)); > // ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] > > > ​However, this function crashes if the list is not a nested list of 2D > points like [[1,2], 3] or [1,2,3].or ["a"], etc. > >> >>
NH
nop head
Fri, Feb 9, 2018 9:37 AM

One can also avoid extra nesting with the new keyword each. Here is an
example (a shortened version of Ronaldo's Bezier subdivision avoiding
concat)

function subdivBezier3(p, n=4) =
n<=0 ?
p
:
subdivBezier3( [p[0], for(i=[0:3:len(p)-4]) each _subdivB(p,i) ], n-1);

function _subdivB(p, from=0) =
[ //[1,0,0,0], // to avoid repetitions
[1/2, 1/2, 0,  0],
[1/4, 1/2, 1/4, 0],
[1/8, 3/8, 3/8, 1/8],
[0,  1/4, 1/2, 1/4],
[0,  0,  1/2, 1/2] ,
[0,  0,  0,  1]  ]
* [p[from], p[from+1], p[from+2], p[from+3] ];

On 9 February 2018 at 01:59, Ronaldo Persiano rcmpersiano@gmail.com wrote:

If your lists contain either 2D points or simple lists of 2D points, a
simpler non-recursive solution (by Parkinbot) is:

l = [[1,2],[[3,4]],[[5,6],[7,8]],[[9,10],[11,12],[13,14] ]];

function get_2D_points(L) = [for(a=L, v = (a[0][0]!=undef ? a: [a]) ) v ];

echo( get_2D_points(l));
// ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14]]

2018-02-08 23:40 GMT-02:00 Ronaldo Persiano rcmpersiano@gmail.com:

If you want to collect all 2D points in a list, whatever depth it has in
it, this may help you:

function get_2D_points(L,n=0,res=[]) =
n>=len(L) ?
res
: L[n]*0==[0,0] ?
get_2D_points(L,n+1, concat(res,[L[n]]))
: get_2D_points(L,n+1, get_2D_points(L[n],0,res));

l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]];

echo( get_2D_points(l));
// ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]

​However, this function crashes if the list is not a nested list of 2D
points like  [[1,2], 3] or [1,2,3].or ["a"], etc.

One can also avoid extra nesting with the new keyword each. Here is an example (a shortened version of Ronaldo's Bezier subdivision avoiding concat) function subdivBezier3(p, n=4) = n<=0 ? p : subdivBezier3( [p[0], for(i=[0:3:len(p)-4]) each _subdivB(p,i) ], n-1); function _subdivB(p, from=0) = [ //[1,0,0,0], // to avoid repetitions [1/2, 1/2, 0, 0], [1/4, 1/2, 1/4, 0], [1/8, 3/8, 3/8, 1/8], [0, 1/4, 1/2, 1/4], [0, 0, 1/2, 1/2] , [0, 0, 0, 1] ] * [p[from], p[from+1], p[from+2], p[from+3] ]; On 9 February 2018 at 01:59, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > If your lists contain either 2D points or simple lists of 2D points, a > simpler non-recursive solution (by Parkinbot) is: > > > l = [[1,2],[[3,4]],[[5,6],[7,8]],[[9,10],[11,12],[13,14] ]]; > > function get_2D_points(L) = [for(a=L, v = (a[0][0]!=undef ? a: [a]) ) v ]; > > echo( get_2D_points(l)); > // ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14]] > > > 2018-02-08 23:40 GMT-02:00 Ronaldo Persiano <rcmpersiano@gmail.com>: > >> If you want to collect all 2D points in a list, whatever depth it has in >> it, this may help you: >> >> function get_2D_points(L,n=0,res=[]) = >> n>=len(L) ? >> res >> : L[n]*0==[0,0] ? >> get_2D_points(L,n+1, concat(res,[L[n]])) >> : get_2D_points(L,n+1, get_2D_points(L[n],0,res)); >> >> l = [[1,2],[[3,4],[[5,6]]],[[[[7,8]],[9,10]]],[11,12]]; >> >> echo( get_2D_points(l)); >> // ECHO: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] >> >> >> ​However, this function crashes if the list is not a nested list of 2D >> points like [[1,2], 3] or [1,2,3].or ["a"], etc. >> >>> >>> > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >