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.
View this message in context: http://forum.openscad.org/Vertex-arrays-tp15876p15881.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
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.
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.
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
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
More complex example generating a polyhedron:
https://github.com/openscad/list-comprehension-demos/blob/master/3d-function.scad
ciao,
Torsten.
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 pideg/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
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.
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.
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
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.212pisin(5t))sin(t+shift),
1.212picos(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 = [pp2-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,ptpp)]));
} 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.