discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Re: [OpenSCAD] Vertex arrays?

M
MichaelAtOz
Mon, Jan 25, 2016 3:09 AM

Your post is still flagged as "This post has NOT been accepted by the mailing
list yet", so nobody gets it unless they look.
You need to subscribe to the  mailing list
http://forum.openscad.org/mailing_list/MailingListOptions.jtp?forum=1  ,
and respond to the registration email.

I've included your post below for others to see now.

Lord Asriel wrote

Hello. I regularly use the polyhedron function coupled with for-generates
to make complex shapes. When going for high quality, the speed and
resources become a problem.

Since triangles tesellate at such a way that each vertex is used 6 times,
it would be better if I could actually make a large array of vertices, and
the just read the memory instead of calculating each vertex 6 or even 3
times. Many times I've swapped to (manually) porting my openscad code to c
to do exactly that, export an stl, and then load it on openscad to see it.
But it is tiresome, and a pity for such a great program.

Anyone got any ideas that I might have overlooked?

By the way, big thanks for letting variables be set outside of assign()s!


Newly minted Admin - PM me if you need anything, or if I've done something stupid...

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it! http://www.ourfairdeal.org/  time is running out!

View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15881.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Your post is still flagged as "This post has NOT been accepted by the mailing list yet", so nobody gets it unless they look. You need to subscribe to the mailing list <http://forum.openscad.org/mailing_list/MailingListOptions.jtp?forum=1> , and respond to the registration email. I've included your post below for others to see now. Lord Asriel wrote > Hello. I regularly use the polyhedron function coupled with for-generates > to make complex shapes. When going for high quality, the speed and > resources become a problem. > > Since triangles tesellate at such a way that each vertex is used 6 times, > it would be better if I could actually make a large array of vertices, and > the just read the memory instead of calculating each vertex 6 or even 3 > times. Many times I've swapped to (manually) porting my openscad code to c > to do exactly that, export an stl, and then load it on openscad to see it. > But it is tiresome, and a pity for such a great program. > > Anyone got any ideas that I might have overlooked? > > By the way, big thanks for letting variables be set outside of assign()s! ----- Newly minted Admin - PM me if you need anything, or if I've done something stupid... Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above. The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out! -- View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15881.html Sent from the OpenSCAD mailing list archive at Nabble.com.
DM
doug moen
Mon, Jan 25, 2016 5:42 PM

Hi, Lord Asriel. You said "it would be better if I could actually make a
large array of vertices, and the just read the memory instead of
calculating each vertex 6 or even 3 times."

But polyhedron already works the way you want. You can pass your "large
array of vertices" as the "points" argument, separate from the "faces"
argument, which contains indices into the points array. I haven't noticed
any problem caused by having extra points that aren't referenced by "faces".

I find it a bit disturbing that OpenSCAD can successfully load an STL file
containing a polyhedron that is too big to describe directly using the
polyhedron() command. That suggests a problem in the implementation that
maybe could be fixed.

Maybe if you posted your code, we would have a better understanding of what
is going wrong.

Doug Moen.

Hi, Lord Asriel. You said "it would be better if I could actually make a large array of vertices, and the just read the memory instead of calculating each vertex 6 or even 3 times." But polyhedron already works the way you want. You can pass your "large array of vertices" as the "points" argument, separate from the "faces" argument, which contains indices into the points array. I haven't noticed any problem caused by having extra points that aren't referenced by "faces". I find it a bit disturbing that OpenSCAD can successfully load an STL file containing a polyhedron that is too big to describe directly using the polyhedron() command. That suggests a problem in the implementation that maybe could be fixed. Maybe if you posted your code, we would have a better understanding of what is going wrong. Doug Moen.
LA
Lord Asriel
Thu, Jan 28, 2016 11:55 AM

Indeed the polyhedron functionality is satisfying. The point is, how can I
make a large vertex array to pass it. Like, 1000 elements. Or, even
better, of x elements, where x is a variable.

I here provide a code to see a simplified example of what I'm doing.
Severely increasing phi_n means a severe increase in faces:

phi_n=50;
function foobar(phi) = 2+cos(phi);
dphi=360/phi_n;

for(phi=[0:dphi:360-dphi])
{
curr=[foobar(phi)*cos(phi),foobar(phi)*sin(phi),5]; //current
next=[foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5];
bottom=[0,0,0];
top=[0,0,10];

polyhedron(
points=[bottom,curr,next,top],
faces=[[0,1,2],[3,2,1]]
);
}

--
View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15954.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Indeed the polyhedron functionality is satisfying. The point is, how can I *make* a large vertex array to pass it. Like, 1000 elements. Or, even better, of x elements, where x is a variable. I here provide a code to see a simplified example of what I'm doing. Severely increasing phi_n means a severe increase in faces: phi_n=50; function foobar(phi) = 2+cos(phi); dphi=360/phi_n; for(phi=[0:dphi:360-dphi]) { curr=[foobar(phi)*cos(phi),foobar(phi)*sin(phi),5]; //current next=[foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5]; bottom=[0,0,0]; top=[0,0,10]; polyhedron( points=[bottom,curr,next,top], faces=[[0,1,2],[3,2,1]] ); } -- View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15954.html Sent from the OpenSCAD mailing list archive at Nabble.com.
TP
Torsten Paul
Thu, Jan 28, 2016 12:01 PM

On 01/28/2016 12:55 PM, Lord Asriel wrote:

Indeed the polyhedron functionality is satisfying. The point is, how can I
make a large vertex array to pass it. Like, 1000 elements. Or, even
better, of x elements, where x is a variable.

See the manual for a simple example generating 2D vertices for an ellipse

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Generating_vertices_for_a_polygon

More complex example generating a polyhedron:

https://github.com/openscad/list-comprehension-demos/blob/master/3d-function.scad

ciao,
Torsten.

On 01/28/2016 12:55 PM, Lord Asriel wrote: > Indeed the polyhedron functionality is satisfying. The point is, how can I > *make* a large vertex array to pass it. Like, 1000 elements. Or, even > better, of x elements, where x is a variable. > See the manual for a simple example generating 2D vertices for an ellipse https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Generating_vertices_for_a_polygon More complex example generating a polyhedron: https://github.com/openscad/list-comprehension-demos/blob/master/3d-function.scad ciao, Torsten.
J
jon
Thu, Jan 28, 2016 12:10 PM

I see some kinds of questions come up repeatedly, or rather, some kinds
of answers come up repeatedly.

The documentation (when I last saw it) was oriented around the
facilities available in the language.  cube().  difference().

Do we need a section that says "if you need to do something like this,
here are the techniques to consider"?

Jon

On 1/28/2016 7:01 AM, Torsten Paul wrote:

On 01/28/2016 12:55 PM, Lord Asriel wrote:

Indeed the polyhedron functionality is satisfying. The point is, how can I
make a large vertex array to pass it. Like, 1000 elements. Or, even
better, of x elements, where x is a variable.

See the manual for a simple example generating 2D vertices for an ellipse

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Generating_vertices_for_a_polygon

More complex example generating a polyhedron:

https://github.com/openscad/list-comprehension-demos/blob/master/3d-function.scad

ciao,
Torsten.

I see some kinds of questions come up repeatedly, or rather, some kinds of answers come up repeatedly. The documentation (when I last saw it) was oriented around the facilities available in the language. cube(). difference(). Do we need a section that says "if you need to do something like this, here are the techniques to consider"? Jon On 1/28/2016 7:01 AM, Torsten Paul wrote: > On 01/28/2016 12:55 PM, Lord Asriel wrote: >> Indeed the polyhedron functionality is satisfying. The point is, how can I >> *make* a large vertex array to pass it. Like, 1000 elements. Or, even >> better, of x elements, where x is a variable. >> > See the manual for a simple example generating 2D vertices for an ellipse > > https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#Generating_vertices_for_a_polygon > > More complex example generating a polyhedron: > > https://github.com/openscad/list-comprehension-demos/blob/master/3d-function.scad > > ciao, > Torsten. > >
A
arnholm@arnholm.org
Thu, Jan 28, 2016 12:44 PM

On 2016-01-28 12:55, Lord Asriel wrote:

Indeed the polyhedron functionality is satisfying. The point is, how
can I
make a large vertex array to pass it. Like, 1000 elements. Or, even
better, of x elements, where x is a variable.

I here provide a code to see a simplified example of what I'm doing.
Severely increasing phi_n means a severe increase in faces:

phi_n=50;
function foobar(phi) = 2+cos(phi);
dphi=360/phi_n;

for(phi=[0:dphi:360-dphi])
{
curr=[foobar(phi)*cos(phi),foobar(phi)*sin(phi),5]; //current
next=[foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5];
bottom=[0,0,0];
top=[0,0,10];

polyhedron(
points=[bottom,curr,next,top],
faces=[[0,1,2],[3,2,1]]
);
}

That is a relevant practical question and a good example of why language
syntax can be an issue. It may be of interest to you that AngelScript
CSG recently got a dedicated IDE that makes making such models simpler (
http://arnholm.org/angelscript-csg-ide/ ). I just used it to rewrite
your example, using dynamically generated arrays for points, faces and
polyhedra:

// AngelScript CSG code follows

const double pi = 4.0atan(1.0);
double to_rad(double deg) { return pi
deg/180.0; } // from degrees to
radians

double foobar(double phi) { return  2+cos(phi); }

shape@ main_shape()
{
double phi_n=50;
double dphi_deg=360/phi_n;
double dphi=to_rad(dphi_deg);

solid@[] polyhedra;
for(double phi_deg=0; phi_deg<360-dphi_deg; phi_deg+=dphi_deg){
   double phi = to_rad(phi_deg);
   pos3d@[] points;
   

points.push_back(pos3d(foobar(phi)*cos(phi),foobar(phi)*sin(phi),5));
//current

points.push_back(pos3d(foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5));
points.push_back(pos3d(0,0,0));
points.push_back(pos3d(0,0,10));

   pface@[] faces;
   faces.push_back(pface(0,1,2));
   faces.push_back(pface(1,0,3)); // bugfix? was [3,2,1]
   polyhedra.push_back(polyhedron(points,faces));
}
return union3d(polyhedra);

}

void main()
{  // main() receives the finished model and exports it.
shape@ obj = main_shape();
obj.write_csg(GetOutputFullPath('.csg')); // OpenSCAD .csg file, ref.
www.openscad.org
}

If the image attachment gets through, it shows your model in OpenSCAD,
via the generated .csg file. As you can see, I suspect the vertex
indices were wrong in the second face in the loop. The generated code
seems to generate a valid object.

However the code you wrote seems to define invalid polyhedra (not
closed). So a more correct solution is to generate all the vertices and
all the faces in two arrays and create a single polyhedron at the end
(with no union). I just kept the structure as you had it to show the
similarity.

Kind regards
Carsten Arnholm

On 2016-01-28 12:55, Lord Asriel wrote: > Indeed the polyhedron functionality is satisfying. The point is, how > can I > *make* a large vertex array to pass it. Like, 1000 elements. Or, even > better, of x elements, where x is a variable. > > I here provide a code to see a simplified example of what I'm doing. > Severely increasing phi_n means a severe increase in faces: > > phi_n=50; > function foobar(phi) = 2+cos(phi); > dphi=360/phi_n; > > for(phi=[0:dphi:360-dphi]) > { > curr=[foobar(phi)*cos(phi),foobar(phi)*sin(phi),5]; //current > next=[foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5]; > bottom=[0,0,0]; > top=[0,0,10]; > > polyhedron( > points=[bottom,curr,next,top], > faces=[[0,1,2],[3,2,1]] > ); > } That is a relevant practical question and a good example of why language syntax can be an issue. It may be of interest to you that AngelScript CSG recently got a dedicated IDE that makes making such models simpler ( http://arnholm.org/angelscript-csg-ide/ ). I just used it to rewrite your example, using dynamically generated arrays for points, faces and polyhedra: // AngelScript CSG code follows const double pi = 4.0*atan(1.0); double to_rad(double deg) { return pi*deg/180.0; } // from degrees to radians double foobar(double phi) { return 2+cos(phi); } shape@ main_shape() { double phi_n=50; double dphi_deg=360/phi_n; double dphi=to_rad(dphi_deg); solid@[] polyhedra; for(double phi_deg=0; phi_deg<360-dphi_deg; phi_deg+=dphi_deg){ double phi = to_rad(phi_deg); pos3d@[] points; points.push_back(pos3d(foobar(phi)*cos(phi),foobar(phi)*sin(phi),5)); //current points.push_back(pos3d(foobar(phi+dphi)*cos(phi+dphi),foobar(phi+dphi)*sin(phi+dphi),5)); points.push_back(pos3d(0,0,0)); points.push_back(pos3d(0,0,10)); pface@[] faces; faces.push_back(pface(0,1,2)); faces.push_back(pface(1,0,3)); // bugfix? was [3,2,1] polyhedra.push_back(polyhedron(points,faces)); } return union3d(polyhedra); } void main() { // main() receives the finished model and exports it. shape@ obj = main_shape(); obj.write_csg(GetOutputFullPath('.csg')); // OpenSCAD .csg file, ref. www.openscad.org } If the image attachment gets through, it shows your model in OpenSCAD, via the generated .csg file. As you can see, I suspect the vertex indices were wrong in the second face in the loop. The generated code seems to generate a valid object. However the code you wrote seems to define invalid polyhedra (not closed). So a more correct solution is to generate all the vertices and all the faces in two arrays and create a single polyhedron at the end (with no union). I just kept the structure as you had it to show the similarity. Kind regards Carsten Arnholm
LA
Lord Asriel
Thu, Jan 28, 2016 2:41 PM

I checked the 3d example out.
Before discussing if it is an answer or not, let me state that it is
difficult to understand. This list thing feels very simplar to prolog-which
is a serious headache. Making tools user-unfriendly doesn't seem very good
practice. Mildly agreesive answering implying not investing time to read
around seems misplaced to me.

Now that scad file's main idea, if I do get it, is to create point as
list[listx[],listy]?
Why would that produce the needed [[x1,y1,z1],[x2,y2,z2]....] and not
[[x1,x2...],[y1,y2...]0?

And I don't know where to find scad-utils/lists.scad

--
View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15958.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

I checked the 3d example out. Before discussing if it is an answer or not, let me state that it is difficult to understand. This list thing feels very simplar to prolog-which is a serious headache. Making tools user-unfriendly doesn't seem very good practice. Mildly agreesive answering implying not investing time to read around seems misplaced to me. Now that scad file's main idea, if I do get it, is to create point as list[listx[],listy[](,listz[])]? Why would that produce the needed [[x1,y1,z1],[x2,y2,z2]....] and not [[x1,x2...],[y1,y2...]0? And I don't know where to find scad-utils/lists.scad -- View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15958.html Sent from the OpenSCAD mailing list archive at Nabble.com.
TP
Torsten Paul
Thu, Jan 28, 2016 2:49 PM

A more specific example...

This needs the development version which allows multiple list
generators in a single expression.
With the release version, it would need to use concat() to
collect the multiple lists into a single one.

phi_n = 50;

function foobar(phi) = 2 + cos(phi);
function point(phi) = [ foobar(phi) * cos(phi), foobar(phi) * sin(phi), 5 ];

points = [
for (i = [0:phi_n - 1]) point(i * 360 / phi_n),
[0, 0, 0],
[0, 0, 10],
];

faces = [
for (i = [0:phi_n - 1]) [ phi_n, i, (i + 1) % phi_n],
for (i = [0:phi_n - 1]) [ phi_n + 1, (i + 1) % phi_n, i]
];

polyhedron(points, faces);

I don't see a huge syntax issue actually. Generating polyhedrons
directly is not going to be the easiest thing, regardless of the
actual syntax used.
I think the example above is as simple as it gets for this
specific model.

ciao,
Torsten.

A more specific example... This needs the development version which allows multiple list generators in a single expression. With the release version, it would need to use concat() to collect the multiple lists into a single one. phi_n = 50; function foobar(phi) = 2 + cos(phi); function point(phi) = [ foobar(phi) * cos(phi), foobar(phi) * sin(phi), 5 ]; points = [ for (i = [0:phi_n - 1]) point(i * 360 / phi_n), [0, 0, 0], [0, 0, 10], ]; faces = [ for (i = [0:phi_n - 1]) [ phi_n, i, (i + 1) % phi_n], for (i = [0:phi_n - 1]) [ phi_n + 1, (i + 1) % phi_n, i] ]; polyhedron(points, faces); I don't see a huge syntax issue actually. Generating polyhedrons directly is not going to be the easiest thing, regardless of the actual syntax used. I think the example above is as simple as it gets for this specific model. ciao, Torsten.
DM
doug moen
Thu, Jan 28, 2016 8:00 PM

Thanks for the sample code, Torsten. I haven't tried the new list syntax
yet.

I agree, that is really nice and clean looking code. Evidence we are
heading in the right direction.

On Thursday, 28 January 2016, Torsten Paul Torsten.Paul@gmx.de wrote:

A more specific example...

This needs the development version which allows multiple list
generators in a single expression.
With the release version, it would need to use concat() to
collect the multiple lists into a single one.

phi_n = 50;

function foobar(phi) = 2 + cos(phi);
function point(phi) = [ foobar(phi) * cos(phi), foobar(phi) * sin(phi), 5
];

points = [
for (i = [0:phi_n - 1]) point(i * 360 / phi_n),
[0, 0, 0],
[0, 0, 10],
];

faces = [
for (i = [0:phi_n - 1]) [ phi_n, i, (i + 1) % phi_n],
for (i = [0:phi_n - 1]) [ phi_n + 1, (i + 1) % phi_n, i]
];

polyhedron(points, faces);

I don't see a huge syntax issue actually. Generating polyhedrons
directly is not going to be the easiest thing, regardless of the
actual syntax used.
I think the example above is as simple as it gets for this
specific model.

ciao,
Torsten.


OpenSCAD mailing list
Discuss@lists.openscad.org javascript:;
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Thanks for the sample code, Torsten. I haven't tried the new list syntax yet. I agree, that is really nice and clean looking code. Evidence we are heading in the right direction. On Thursday, 28 January 2016, Torsten Paul <Torsten.Paul@gmx.de> wrote: > A more specific example... > > This needs the development version which allows multiple list > generators in a single expression. > With the release version, it would need to use concat() to > collect the multiple lists into a single one. > > phi_n = 50; > > function foobar(phi) = 2 + cos(phi); > function point(phi) = [ foobar(phi) * cos(phi), foobar(phi) * sin(phi), 5 > ]; > > points = [ > for (i = [0:phi_n - 1]) point(i * 360 / phi_n), > [0, 0, 0], > [0, 0, 10], > ]; > > faces = [ > for (i = [0:phi_n - 1]) [ phi_n, i, (i + 1) % phi_n], > for (i = [0:phi_n - 1]) [ phi_n + 1, (i + 1) % phi_n, i] > ]; > > polyhedron(points, faces); > > I don't see a huge syntax issue actually. Generating polyhedrons > directly is not going to be the easiest thing, regardless of the > actual syntax used. > I think the example above is as simple as it gets for this > specific model. > > ciao, > Torsten. > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org <javascript:;> > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > >
DE
David Eccles (gringer)
Fri, Jan 29, 2016 10:06 AM

OpenSCAD, like Prolog, is a declarative language. In Prolog, rules return
true or false, whereas in OpenSCAD, modules return a 3D object. It takes a
bit of mind twisting to get into the swing of declarative programming, but
I've learnt to stop worrying and love the recursion.

As an example, my path extrusion script generates a polyhedron formed by
translating and rotating a polygon along a path in three-dimensional space.
Here's a double helix, created as a polyhedron with about 180 defined
points. Modifying the number of slices of 't' for the point and path
function can result in this quite quickly exceeding 1000 points without any
change in code:

use <path_extrude.scad>;
pi=3.14159;
for(shift = [0, 360/15]){
myPoints = [ for(t = [0:72:359]) [cos(t),sin(t)] ];
myPath = [ for(t = [0:10:359]) [
(10+1.212pisin(5t))cos(t+shift),
(10+1.212
pi
sin(5t))sin(t+shift),
1.212
pi
cos(5*t)
] ];
path_extrude(points=myPoints, path=myPath, merge=true);
}

I've included an image with an 18-point circle and 180-point path for
demonstration.

http://forum.openscad.org/file/n15969/pathextrude_double_helix_3240.png

The backend of the path_extrude function is 4kb of code, which is fairly
lightweight when compared to things that it can replace. It uses list
comprehensions to simplify the code, but I can achieve the same thing by
defining a function to generate recursive vectors (see my EllerSCAD maze
generator for an example of that). I use a recursive function to first
generate the point array:

module path_extrude(points, path, pos=0, merge=false, trimEnds=false,
extruded=[]){
if((len(points) > 0) && (len(path) > 0)){
if(len(extruded) >= (len(path))){
// extrusion is finished, so construct the object
//echo(extruded);
makeExtrudedPoly(extruded, merge=merge, trimEnds=trimEnds);
} else {
// generate points from rotating polygon
if(merge || (pos < (len(path) - 1))){
if((pos == 0) && (!merge)) {
newPts = myRotate(rToS(path[1] - path[0]),
points);
path_extrude(points=points, path=path, pos=pos+1,
merge=merge, trimEnds=trimEnds,
extruded=concat(extruded, [add(newPts,path[pos])]));
} else {
newPts = myRotate(rToS(path[(pos+1) % len(path)]
- path[(pos+len(path)-1) % len(path)]),
points);
path_extrude(points=points, path=path, pos=pos+1,
merge=merge, trimEnds=trimEnds,
extruded=concat(extruded, [add(newPts,path[pos])]));
}
} else {
newPts = myRotate(rToS(path[pos] - path[pos-1]),
points);
path_extrude(points=points, path=path, pos=pos+1,
merge=merge, trimEnds=trimEnds,
extruded=concat(extruded, [add(newPts,path[pos])]));
}
}
}
}

And then another recursive function to generate the polyhedron definition
using the point array. Because each polygon unit has the same number of
points at each position in the 3D path, I can define the joining
quadrilaterals (not necessarily planar) without too much effort:

module makeExtrudedPoly(ex, merge=false, trimEnds=false){
ps = flatten(ex);
pp = len(ex[1]); // points in one polygon
tp = len(ex[1]) * len(ex); // total number of points
if(!merge && !trimEnds){
polyhedron(points=ps, faces=concat(
[[for (i = [pp-1  : -1 :    0]) i]],
[[for (i = [tp-pp :  1 : tp-1]) i]],
[for (pt=[0:(len(ex)-2)])
for(i = [0:pp-1]) phFace(pp,tp,i,ptpp)],
[])
);
} else if(trimEnds) {
polyhedron(points=ps, faces=concat(
[[for (i = [pp
2-1  : -1 :    pp]) i]],
[[for (i = [tp-pp2 :  1 : tp-pp-1]) i]],
[for (pt=[1:(len(ex)-3)])
for(i = [0:pp-1]) phFace(pp,tp,i,pt
pp)]));
} else {
polyhedron(points=ps, faces=
[for (pt=[0:(len(ex)-1)])
for(i = [0:pp-1]) phFace(pp,tp,i,pt*pp)]);
}
}

Hopefully you can see that the majority of the code is spent dealing with
corner cases (i.e. what to do at the ends of the path), rather than the
bread and butter of the algorithm. The remainder of the code is made up from
helper functions to make the code a bit more succinct. OpenSCAD can do a lot
of this stuff natively, but only on actual objects (as far as I can tell)
and not on numerical matrices:

// rotation matrix implementation
// OpenSCAD seems to do this slightly different from Wikipedia
// c.f. https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
function rot2Mat(rotVec, axis) =
(len(rotVec) == 2) ?
rot2Mat([rotVec[0], rotVec[1], 0], axis) :
(axis == "x") ?
[[1,              0,              0],
[0, cos(rotVec[0]),  sin(rotVec[0])],
[0, sin(rotVec[0]), -cos(rotVec[0])]] :
(axis == "y") ?
[[ cos(rotVec[1]), 0, sin(rotVec[1])],
[              0, 1,              0],
[-sin(rotVec[1]), 0, cos(rotVec[1])]] :
(axis == "z") ?
[[ cos(rotVec[2]), sin(rotVec[2]), 0],
[-sin(rotVec[2]), cos(rotVec[2]), 0],
[0,              0,              1]] : undef;

// convert point to 3D by setting Z to zero (if not present)
function c3D(tPoints) =
(len(tPoints[0]) < 3) ?
tPoints * [[1,0,0],[0,1,0]] :
tPoints;

// rotate [2D] points using a specificed XYZ rotation vector
function myRotate(rotation, points) =
c3D(points) * rot2Mat(rotation, "x")
* rot2Mat(rotation, "y")
* rot2Mat(rotation, "z");

// Determine spherical rotation for cartesian coordinates
function rToS(pt) =
[-acos((pt[2]) / norm(pt)),
0,
-atan2(pt[0],pt[1])];

// Generate a line between two points in 3D space [only used for debugging
this code]
module line3D(p1,p2){
translate((p1+p2)/2)
rotate(rToS(p1-p2))
cylinder(r=1, h=norm(p1-p2), center = true, $fn = 3);
}

// Flattens an array down one level (removing the enclosing array)
function flatten(pointArray, done=0, res=[]) =
(done == len(pointArray)) ?
res :
flatten(pointArray=pointArray, done=done+1,
res=concat(res,pointArray[done]));

// Creates a polyhedron face
function phFace(pp, tp, base, add=0) =
[base + add, (base+1) % pp + add,
(((base+1) % pp) + pp + add) % tp, (base + pp + add) % tp];

function add(vecArg, scArg, res=[]) =
(len(res) >= len(vecArg)) ?
res :
add(vecArg, scArg, res=concat(res,[vecArg[len(res)]+scArg]));

The code is a little slow, but I don't yet have any need to optimise it
further because it is sufficiently fast for the things I have been using it
for. See it in action here:

http://www.thingiverse.com/thing:186660

--
View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15969.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

OpenSCAD, like Prolog, is a declarative language. In Prolog, rules return true or false, whereas in OpenSCAD, modules return a 3D object. It takes a bit of mind twisting to get into the swing of declarative programming, but I've learnt to stop worrying and love the recursion. As an example, my path extrusion script generates a polyhedron formed by translating and rotating a polygon along a path in three-dimensional space. Here's a double helix, created as a polyhedron with about 180 defined points. Modifying the number of slices of 't' for the point and path function can result in this quite quickly exceeding 1000 points without any change in code: use <path_extrude.scad>; pi=3.14159; for(shift = [0, 360/15]){ myPoints = [ for(t = [0:72:359]) [cos(t),sin(t)] ]; myPath = [ for(t = [0:10:359]) [ (10+1.212*pi*sin(5*t))*cos(t+shift), (10+1.212*pi*sin(5*t))*sin(t+shift), 1.212*pi*cos(5*t) ] ]; path_extrude(points=myPoints, path=myPath, merge=true); } I've included an image with an 18-point circle and 180-point path for demonstration. <http://forum.openscad.org/file/n15969/pathextrude_double_helix_3240.png> The backend of the path_extrude function is 4kb of code, which is fairly lightweight when compared to things that it can replace. It uses list comprehensions to simplify the code, but I can achieve the same thing by defining a function to generate recursive vectors (see my EllerSCAD maze generator for an example of that). I use a recursive function to first generate the point array: module path_extrude(points, path, pos=0, merge=false, trimEnds=false, extruded=[]){ if((len(points) > 0) && (len(path) > 0)){ if(len(extruded) >= (len(path))){ // extrusion is finished, so construct the object //echo(extruded); makeExtrudedPoly(extruded, merge=merge, trimEnds=trimEnds); } else { // generate points from rotating polygon if(merge || (pos < (len(path) - 1))){ if((pos == 0) && (!merge)) { newPts = myRotate(rToS(path[1] - path[0]), points); path_extrude(points=points, path=path, pos=pos+1, merge=merge, trimEnds=trimEnds, extruded=concat(extruded, [add(newPts,path[pos])])); } else { newPts = myRotate(rToS(path[(pos+1) % len(path)] - path[(pos+len(path)-1) % len(path)]), points); path_extrude(points=points, path=path, pos=pos+1, merge=merge, trimEnds=trimEnds, extruded=concat(extruded, [add(newPts,path[pos])])); } } else { newPts = myRotate(rToS(path[pos] - path[pos-1]), points); path_extrude(points=points, path=path, pos=pos+1, merge=merge, trimEnds=trimEnds, extruded=concat(extruded, [add(newPts,path[pos])])); } } } } And then another recursive function to generate the polyhedron definition using the point array. Because each polygon unit has the same number of points at each position in the 3D path, I can define the joining quadrilaterals (not necessarily planar) without too much effort: module makeExtrudedPoly(ex, merge=false, trimEnds=false){ ps = flatten(ex); pp = len(ex[1]); // points in one polygon tp = len(ex[1]) * len(ex); // total number of points if(!merge && !trimEnds){ polyhedron(points=ps, faces=concat( [[for (i = [pp-1 : -1 : 0]) i]], [[for (i = [tp-pp : 1 : tp-1]) i]], [for (pt=[0:(len(ex)-2)]) for(i = [0:pp-1]) phFace(pp,tp,i,pt*pp)], []) ); } else if(trimEnds) { polyhedron(points=ps, faces=concat( [[for (i = [pp*2-1 : -1 : pp]) i]], [[for (i = [tp-pp*2 : 1 : tp-pp-1]) i]], [for (pt=[1:(len(ex)-3)]) for(i = [0:pp-1]) phFace(pp,tp,i,pt*pp)])); } else { polyhedron(points=ps, faces= [for (pt=[0:(len(ex)-1)]) for(i = [0:pp-1]) phFace(pp,tp,i,pt*pp)]); } } Hopefully you can see that the majority of the code is spent dealing with corner cases (i.e. what to do at the ends of the path), rather than the bread and butter of the algorithm. The remainder of the code is made up from helper functions to make the code a bit more succinct. OpenSCAD can do a lot of this stuff *natively*, but only on actual objects (as far as I can tell) and not on numerical matrices: // rotation matrix implementation // OpenSCAD seems to do this slightly different from Wikipedia // c.f. https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations function rot2Mat(rotVec, axis) = (len(rotVec) == 2) ? rot2Mat([rotVec[0], rotVec[1], 0], axis) : (axis == "x") ? [[1, 0, 0], [0, cos(rotVec[0]), sin(rotVec[0])], [0, sin(rotVec[0]), -cos(rotVec[0])]] : (axis == "y") ? [[ cos(rotVec[1]), 0, sin(rotVec[1])], [ 0, 1, 0], [-sin(rotVec[1]), 0, cos(rotVec[1])]] : (axis == "z") ? [[ cos(rotVec[2]), sin(rotVec[2]), 0], [-sin(rotVec[2]), cos(rotVec[2]), 0], [0, 0, 1]] : undef; // convert point to 3D by setting Z to zero (if not present) function c3D(tPoints) = (len(tPoints[0]) < 3) ? tPoints * [[1,0,0],[0,1,0]] : tPoints; // rotate [2D] points using a specificed XYZ rotation vector function myRotate(rotation, points) = c3D(points) * rot2Mat(rotation, "x") * rot2Mat(rotation, "y") * rot2Mat(rotation, "z"); // Determine spherical rotation for cartesian coordinates function rToS(pt) = [-acos((pt[2]) / norm(pt)), 0, -atan2(pt[0],pt[1])]; // Generate a line between two points in 3D space [only used for debugging this code] module line3D(p1,p2){ translate((p1+p2)/2) rotate(rToS(p1-p2)) cylinder(r=1, h=norm(p1-p2), center = true, $fn = 3); } // Flattens an array down one level (removing the enclosing array) function flatten(pointArray, done=0, res=[]) = (done == len(pointArray)) ? res : flatten(pointArray=pointArray, done=done+1, res=concat(res,pointArray[done])); // Creates a polyhedron face function phFace(pp, tp, base, add=0) = [base + add, (base+1) % pp + add, (((base+1) % pp) + pp + add) % tp, (base + pp + add) % tp]; function add(vecArg, scArg, res=[]) = (len(res) >= len(vecArg)) ? res : add(vecArg, scArg, res=concat(res,[vecArg[len(res)]+scArg])); The code is a little slow, but I don't yet have any need to optimise it further because it is sufficiently fast for the things I have been using it for. See it in action here: http://www.thingiverse.com/thing:186660 -- View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15969.html Sent from the OpenSCAD mailing list archive at Nabble.com.