|
|
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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|
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 < [hidden email]> 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
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|
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) ]
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|
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: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|
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: [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14]]
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|
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] ];
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
|
|