I'm trying to create a knot ( a rolling trefoil  http://makerhome.blogspot.co.uk/2013/12/day110rockingknot.html ) with this code using version 2013.06 . (It constructs a tube as a sequence of cylinders oriented along the parametric path)
pi = 3.14159; function length(p) = sqrt(pow(p[0],2) + pow(p[1],2) + pow(p[1],3)); module cylinder_p2p(p1, p2, r) { assign(p = p2  p1) assign(distance = length(p)) translate(p1 + p/2) rotate([0, 0, atan2(p[1], p[0])]) rotate([0, atan2(sqrt(pow(p[0], 2)+pow(p[1], 2)),p[2]), 0]) cylinder(h = distance, r = r,center=true); }; function f(a,b,t) = // rolling knot [ a * cos (3 * t) / (1  b* sin (2 *t)), a * sin( 3 * t) / (1  b* sin (2 *t)), 1.8 * b * cos (2 * t) /(1  b* sin (2 *t)) ]; module tube(a, b, r, step) { for (t=[0: step: 361]) { assign (p0 = f(a,b,t)) assign (p1 = f(a,b,t +2* step )) cylinder_p2p (p0,p1,r); } }; $fn=20; a = 0.8; scale(15) tube (a, sqrt (1  a * a), 0.3, 1); F5 generates a view instantly, but F6 is very slow : based on timings for N (cylinders) = 2,4.. 20, I get N^2 *0.8 which for 360 would be 25 hours Any suggestions ? 
Administrator

On Jan 20, 2014, at 10:02 AM, kitwallace <[hidden email]> wrote: > I'm trying to create a knot ( a rolling trefoil  > http://makerhome.blogspot.co.uk/2013/12/day110rockingknot.html ) with > this code using version 2013.06 . (It constructs a tube as a sequence of > cylinders oriented along the parametric path) This is close to worstcase scenario for OpenSCAD. See here for an early discussion on more flexible extrusion in OpenSCAD which would help in your case: https://github.com/openscad/openscad/wiki#moregeneralextrusionmodule Marius _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
In reply to this post by kitwallace
Do what I do  use a preprocessing Java program to generate the knot.
I am primarily interested in the behavior of local reference frames that are close to, but not quite exactly the same, as Frenet frames. It never occurred to me that OpenSCAD was the correct tool for this (largely because I started on this project in the mid1980’s). My crosssections are not limited to cylinders, because I want to SEE the rotation of the frame of reference. Warning  I don’t generally feed the resulting STL into OpenSCAD. While *generating* the STL is nearly instantaneous, importing the STL may still involve considerable time.  Kenneth Sloan [hidden email] On Jan 20, 2014, at 09:02 , kitwallace <[hidden email]> wrote: > I'm trying to create a knot ( a rolling trefoil  > http://makerhome.blogspot.co.uk/2013/12/day110rockingknot.html ) with > this code using version 2013.06 . (It constructs a tube as a sequence of > cylinders oriented along the parametric path) > > pi = 3.14159; > > function length(p) = sqrt(pow(p[0],2) + pow(p[1],2) + pow(p[1],3)); > > module cylinder_p2p(p1, p2, r) { > assign(p = p2  p1) > assign(distance = length(p)) > translate(p1 + p/2) > rotate([0, 0, atan2(p[1], p[0])]) > rotate([0, atan2(sqrt(pow(p[0], 2)+pow(p[1], 2)),p[2]), 0]) > cylinder(h = distance, r = r,center=true); > }; > > function f(a,b,t) = // rolling knot > [ a * cos (3 * t) / (1  b* sin (2 *t)), > a * sin( 3 * t) / (1  b* sin (2 *t)), > 1.8 * b * cos (2 * t) /(1  b* sin (2 *t)) > ]; > > module tube(a, b, r, step) { > for (t=[0: step: 361]) { > assign (p0 = f(a,b,t)) > assign (p1 = f(a,b,t +2* step )) > cylinder_p2p (p0,p1,r); > } > }; > > $fn=20; > a = 0.8; > scale(15) tube (a, sqrt (1  a * a), 0.3, 1); > > F5 generates a view instantly, but F6 is very slow : based on timings for N > (cylinders) = 2,4.. 20, I get N^2 *0.8 which for 360 would be 25 hours > > Any suggestions ? > > > >  > View this message in context: http://forum.openscad.org/slowrendertp6556.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > _______________________________________________ > OpenSCAD mailing list > [hidden email] > http://rocklinux.net/mailman/listinfo/openscad > http://openscad.org  https://flattr.com/thing/121566 _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
Interesting shape! Rotating it in OpenScad looks like it actually changes shape. I think there is a typo in the length function. I changed it to: function length(p) = sqrt(pow(p[0],2) + pow(p[1],2) + pow(p[2],2)); That makes it work better with less segments. I think I would make it produce disjoint discs and then hull pairs of them to make the tube. That might allow even less segments. Not sure what the speed would be .
On 20 January 2014 16:49, Kenneth Sloan <[hidden email]> wrote: Do what I do  use a preprocessing Java program to generate the knot. _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
In reply to this post by kintel
I'm very impressed by your elegant knot code. I've really struggled with slow render times too, even for trivial problems like generating tapered pipe threads (or any proper threads at all, in fact). I followed suggestions from one of these discussions and use hulls of pairs of thin thread forms.
The F5 Compile time is reasonable (about 60 seconds for this example), but the results have artifacts that disappear with F6. Unfortunately, F6 takes an hour or two, which really limits the uses to which I can put this thread generator. I have two versions, one for male and one for female threads. They do print wellI didn't expect standard 60 degree threads to work, so allowed for shallower ones like 45 degrees, but in fact on my printer (FlashForge Creator) standard 60 degree threads work great, and the resulting pieces interoperate well with standard pipe fittings. I'd sure love a more powerful and efficient extrude for generating threads. I've thought about generating the whole shape as a polyhedron in external software, and just using OpenSCAD for rendering it. But maybe it makes more sense to just deal with it in Blender. You wouldn't believe how many tries it took to get the polyhedron triangles oriented correctly in the thin tooth formI finally had to make a folded paper model and label the points to get it right. OpenSCAD isn't very helpful in telling you what you've got oriented wrong! I'd love to be able to manipulate threaded parts, so as to use multiple instances in a larger object design, but so far I have the impression it's hopeless in OpenSCAD. I may be wrongI'm a rank beginner. I didn't even realize OpenSCAD could import STLs until reading these posts today, for example. Anyway, here's my female thread example, and I'd appreciate suggestions for making it more usable. It's very noisy with comments, and it may be more complex than necessary due to historical evolution of its design. There are some subtle features, like the sharp ridges of threads are removed to provide somewhere for dirt to go; and the entry is beveled to make it friendlier for inserting mating fittings. It's easy to change the outer forms to longer cylinders, which generates half of a threaded container, or a pipe cap in this case. // This module, TapCutter, generates female threads. It does this by forming a "tap" blank with the // desired threads outside. // To thread an object, create this Tap and difference it from your base object. // Written by David Gustavson, December 20, 2013; Free for anyone to use. // The number of slices per revolution determines the smoothness of the screw. // For printing, 60 works well. For debugging, 12 is pretty fast but very crude. // But the more slices, the slowerit can take many minutes to render one of these, depending on your computer. // The tap is built so that the threads start at z=0 at the surface of the material which is to // have a hole that is threaded, and shrink (if tapered) in the increasing z direction. // The threads that project into the final female part // have a fraction removed from the outside edge for clearance. // Typically one would use 1/8 or 0.125 for this, standard for US threads. // In the case of tapered threads, this also removes a small ridge that follows this peak. // A tapered thread can be generated, by providing the TaperTangent. 0 means not tapered. // Standard taper for US pipe is 3/4 inch (diameter, not radius) per foot, which is 1/16. // There is an additional bevel made on part of the end thread, for easier insertion // (particularly useful for nontapered threads). //The thread proile is determined by the relation between Pitch and ThreadDepth. //ThreadDepth=Pitch/2; for 45 90 45 triangle, 45 degree slopes for better build quality. //ThreadDepth=sqrt(3)*Pitch/2; for 60 60 60 triangle, standard for US metal // but not as good for printing. thin=0.01; // Some small nonzero thickness for the slices of thread forms module Tooth(Radius,Pitch,ThreadDepth) // Makes a tooth pointing to x, pitch along z, thin in y { polyhedron( points=[ [0,0,0],[0,0,Pitch],[Radius,0,Pitch],[Radius+ThreadDepth,0,Pitch/2],[Radius,0,0], // the five points at base face [0,thin,Pitch],[0,thin,0],[Radius,thin,0],[Radius+ThreadDepth,thin,Pitch/2],[Radius,thin,Pitch] ], // the top face // Note that the shoulders have the same heights regardless of taper, which follows the standards: thread angle is // measured from the axis, not from the tapered surface. In this implementation, which draws the peak in the middle of the Tooth, // this causes a small stepped ridge to form, which is cleaned off by Trimmer, eliminating that error. // Alternatively, one could adjust these points out on one side in on the other, moving the peak to preserve the angle symmetry, // but that would shift the thread location slightly, which might be inconvenient for some applications. triangles=[ [0,1,2],[0,2,3],[0,3,4], // base, cw from outside [5,6,7],[5,7,8],[5,8,9], // top, cw from outside [0,4,6],[0,6,5], // two triangles for each rectangle on each side [4,3,7],[4,7,6], [3,2,8],[3,8,7], [2,1,9],[2,9,8], [1,0,5],[1,5,9] ] ); } module Trimmer(Radius,Pitch,ThreadDepth,TaperTangent,ThreadTrimFract) // Makes a trimmer form for a tooth pointing to x, pitch along z, thin in y { polyhedron( points=[[0,0,0],[0,0,Pitch],[Radius+ThreadTrimFract*ThreadDepthPitch*TaperTangent/2,0,Pitch],[Radius+ThreadTrimFract*ThreadDepth+Pitch*TaperTangent/2,0,0], [Radius+ThreadTrimFract*ThreadDepth+Pitch*TaperTangent/2,thin,0],[Radius+ThreadTrimFract*ThreadDepthPitch*TaperTangent/2,thin,Pitch],[0,thin,Pitch],[0,thin,0]], triangles=[[1,2,3],[1,3,0], [7,4,5],[7,5,6], [0,3,4], [0,4,7], [3,2,5], [3,5,4], [2,1,6], [2,6,5], [1,0,7], [1,7,6]] ); } // Make a tap. Make a female threaded object by subtracting this tap from that object. module TapCutter(ScrewDiam,ThreadCount,TaperTangentD,Pitch,ThreadDep,ThreadTrimFrac,SlicesPerTurn){ DPS=360/SlicesPerTurn; // Degrees per slice TaperTangent=TaperTangentD/2; // Convert to radial from diametral translate([0,0,Pitch]) intersection() // Trim top and bottom of threads { union(){ for (i=[0:1:(ThreadCount+1)*SlicesPerTurn1]) // increment by slice { hull() { translate([0,0,i*Pitch/SlicesPerTurn]) rotate(DPS*i) Tooth(ScrewDiam/2ThreadDep(iSlicesPerTurn/2)*Pitch/SlicesPerTurn*TaperTangent,Pitch,ThreadDep,ThreadTrimFrac); translate([0,0,(i+1)*(Pitch/SlicesPerTurn)]) rotate(DPS*(i+1)) Tooth(ScrewDiam/2ThreadDep(i+1SlicesPerTurn/2)*(Pitch/SlicesPerTurn*TaperTangent),Pitch,ThreadDep,ThreadTrimFrac); } // end hull }; // end for // Form the clearance for (i=[0:1:(ThreadCount+1)*SlicesPerTurn1]) // increment by slice { hull() { translate([0,0,i*Pitch/SlicesPerTurn]) rotate(DPS*i) Trimmer(ScrewDiam/2ThreadDep(iSlicesPerTurn/2)*Pitch/SlicesPerTurn*TaperTangent,Pitch,ThreadDep,TaperTangent,ThreadTrimFrac); translate([0,0,(i+1)*(Pitch/SlicesPerTurn)]) rotate(DPS*(i+1)) Trimmer(ScrewDiam/2ThreadDep(i+1SlicesPerTurn/2)*(Pitch/SlicesPerTurn*TaperTangent),Pitch,ThreadDep,TaperTangent,ThreadTrimFrac); } // end hull }; // end for } // end union // shape for trimming clearance and ends off threads translate([0,0,Pitch]) cylinder(r1=ScrewDiam/2+TaperTangent*Pitch*ThreadCount,r2=ScrewDiam/2,h=Pitch*ThreadCount,$fa=3); } // end intersection, threads are now trimmed cylinder(r1=ScrewDiam/2,r2=ScrewDiam/2ThreadDep,h=Pitch/2,$fa=3); // Bevel the last half a pitch } // end module TapCutter // Example, tap a fitting for 3/4" US pipe. TapCutter assumes metric, mm. Cl=0; // Clearance for easy fit, may not need this for tapered thread situations myPitch=25.4/14; // 3/4" US pipe myDepth=myPitch/2*sqrt(3); // Standard 60 degree angle. Omit the sqrt(3) for 45 degrees. myTaper=1/16; // diametral taper for standard pipe rodDiam=1.050*25.4; // standard 3/4" pipe O.D. dieDiam=1.5*25.4; // Outside diameter of object threads=4; difference(){ cylinder(r=dieDiam/2,h=(threads.21)*myPitch);translate([0,0,.01]) TapCutter(ScrewDiam=rodDiam+Cl+4*myPitch*myTaper, // pipe threads don't usually reach full depth for about 4 turns ThreadCount=threads,TaperTangentD=myTaper,Pitch=myPitch,ThreadDep=myDepth,ThreadTrimFrac=0.125, SlicesPerTurn=60); // This determines how round the object ends up. At 60, 10 turns takes my computer about 2 hrs to render. // cube([30,30,30]); // include this to show a cross section of the threads. }; // subtract (difference) this tap from a solid in order to leave a hole threaded with nice clearance and beveled edge. //Settings for various US pipe sizes: //depth=pitch*sqrt(3)/2; (60 degree thread angle, standard) //taper=1/16; (diametral taper) // // Nominal Pipe Size Outside Dia. of Pipe ID for sched 40 Threads per Inch // 1⁄8 0.405 0.269 27 // 1⁄4 0.540 0.364 18 // 3⁄8 0.675 0.493 18 // 1⁄2 0.840 0.622 14 // 3⁄4 1.050 0.824 14 // 1 1.315 1.049 11.5 // 1 1⁄4 1.660 1.380 11.5 // 1 1⁄2 1.900 1.610 11.5 // 2 2.375 2.067 11.5 // 2 1⁄2 2.875 2.469 8 // 3 3.500 3.068 8 // 3 1⁄2 4.000 4.026 8 _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
Den 20012014 20:00, David B. Gustavson skrev:
> I'm very impressed by your elegant knot code. I am too impressed by the brevity of kitwallace's code. When slowly increasing the number of cylinders (by changing the step variable  I even tried with animation) it shows that the endpoints are not calculated quite right. Its only when they have to be very short it seems to fit. > I'd love to be able to manipulate threaded parts, so as to use multiple instances in a larger object design, but so far I have the impression it's hopeless in OpenSCAD. Here is thought from the CG / animations in movies. They do rendering in several resolutions/accuarcies, using very coarse stick models in the early stages when getting the story line/timing right is more important (and the artist haven't quite finished either). Then flat models (ie without shadow/lighting). This way rendering times are bearable, whilst tweaking the geometric factors, and last the heavy rendering with the whole lot. The principle is the same in OpenSCAD. With conditional models (using the if() ) you could have coarse nuts/bolts which in effect are just cylinders (or some slightly more advanced model with several stacked cylinderslices to show there is structure where the thread is) That way you can assemble bigger models for CAD viewing. You only need the threads if/when you print them, and you are likely to print them separate. The conditional variable could be a line at the top of the program or in a renderconfiguration include file. Msquare _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
In reply to this post by nophead
Thanks nophead yes to my chagrin I spotted that silly typo as I experimented with different ways of joining the segments. I overlap the cylinders by a factor of 2 in an attempt to avoid gaps and also reduce the step size  but that merely makes the full render performance worse of course.
I tried hulling pairs of adjacent cylinders (disks) : F5 performance is much slower but F6 is much better  seems almost NlogN . I tried spheres (which don't need orienting of course). This give the best performance and a simpler script. 2 degree resolution still took 28 minutes on my laptop but acceptable. The work is now published http://www.thingiverse.com/thing:230557 Perhaps what would be nice would be if linear_extrude had a function parameter so the crosssection could be computed at each step in the extrusion. 
Somehow this thread seems to have split into 2. In the other one I posted a version that did a hull of disks.
It takes 8 minutes with a step size of 3, 16 minutes for a step size of 2 and an hour for a step size of 1. That is on a not particularly fast desktop. I still find it hard to understand how CGAL takes so long to do it. Surely the hull operation of two discs of 20 vertices is trivial computationally. It does 360 of those in a reasonable time (although very slow considering how fast PCs are) it then takes forever to union them together. But the ends share common vertices, so the union should also be very simple computationally. There are no new vertices to compute, just 720 end walls to remove. How can that take an hour on a machine executing billions of instructions per second? I could do it faster myself on paper! On 21 January 2014 01:04, kitwallace <[hidden email]> wrote: Thanks nophead yes to my chagrin I spotted that silly typo as I _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
When doing sequential hull() operations, I find that sometimes it helps to "flatten" them by way of prefixing them with explicit render() calls.
Andrew. On 20140120, at 8:31 PM, nop head <[hidden email]> wrote:
 "The future is already here. It's just not very evenly distributed"  William Gibson Me: http://clothbot.com/wiki/ _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 signature.asc (506 bytes) Download Attachment 
It seems that the implicit union that joins all the cylinders take a time proportional to the square of the number of objects. I made a version that does an explicit union, one cylinder added onto the knot at a time using a recursive module. That seems to be slower but linear in time. Unfortunately it seems to run out of stack and crash with a step size less than 3.
On 21 January 2014 03:46, Andrew Plumb <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
These performance numbers (nlogn, n^2) for respective operations really should be documented somewhere, even if they are based on experience, and not actual code review. It would be really helpful in choosing modelling strategy when performance is an issue! Szelp, André Szabolcs
+43 (650) 79 22 400 On Tue, Jan 21, 2014 at 2:56 PM, nop head <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
I managed to get it to render with a step size of 2 without crashing but 1 gives a repeatable crash in the June release.
The time is 17 minutes so I don't think sequential explicit unions are any faster than the implicit one. You do see progress on the bar though, rather than it sticking at 998 or similar for a long time.
module disc_p2p(p1, p2, r) { p = p2  p1; translate(p1 + p/2) rotate([0, 0, atan2(p[1], p[0])])
rotate([0, atan2(sqrt(pow(p[0], 2) + pow(p[1], 2)), p[2]), 0]) render() cylinder(h = 0.1, r1 = r, r2 = 0);
} function f(a,b,t) = // rolling knot [ a * cos (3 * t) / (1  b* sin (2 *t)), a * sin( 3 * t) / (1  b* sin (2 *t)), 1.8 * b * cos (2 * t) /(1  b* sin (2 *t))
]; module tube(a, b, r, step, t = 0) { p0 = f(a,b,t); p1 = f(a,b,t + step); p2 = f(a,b,t + 2 * step); if(t < 360) union() {
hull() { disc_p2p (p0,p1,r); disc_p2p (p1,p2,r);
} tube(a, b, r, step, t + step); } }
$fn=20; a = 0.8; scale(15) tube (a, sqrt (1  a * a), 0.3, 2); On 21 January 2014 14:45, Szelp, A. Sz. <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
Administrator

In reply to this post by szabi
You probably need to log your system config too, particularly OpenSCAD cache sizes/render limit. Has anyone with longer running models made sure their cache size is large enough? Just a thought...
Admin  email* me if you need anything, or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me. 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. 
tl;dr, but wouldn't it be fast if you generated spheres at regular points on the path and render the hull between every pair of spheres?
On Tue, Jan 21, 2014 at 9:13 PM, MichaelAtOz <[hidden email]> wrote: szabi wrote _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
I think nop head's idea of a cone creates the minimal number of faces for a given resolution and much fewer than a sphere. My own timings support that view but I will redo them carefully to check that both are still O(N^2) as would be expected.

>tl;dr, but wouldn't it be fast if you generated spheres at regular points on the path and render the hull between every pair of spheres? No because most of the time is not spent making the hulls. It is joining them together to form the knot. That can be done with an explicit union, as in my recursive version. If that is left out then OpenScad does an implicit union. Both seem to take a time proportional to the square of the number of hulls. It probably depends on the number of points, or facets in each hull as well, so probably the square of vertices or square of facets. Either way it seems that union is very inefficient in CGAL as I intuitively I would expect the complexity to be proportional to the number of intersecting facets. All the facets that belong to one half of the union, that are completely outside the other half do not change. So when adding tubes end to end the time should be linear as all the action happens at the junction.
On 22 January 2014 11:28, kitwallace <[hidden email]> wrote: I think nop head's idea of a cone creates the minimal number of faces for a _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
Well I'm really puzzled : I thought I'd minimise the facets on the hulled cylinder by reversing the direction of the second cone so both point inwards which should reduce the cylinder faces from 2N + 2 to N + 2 (modulo the proportion of faces split due to twist) Instead the time inceases by a factor of 3! and (the number of vertices has gone up by 3 . This seems to be because the cylinder ends dont quite match. I assume this is rounding error because the face has been reversed?

In reply to this post by nophead
> So when adding tubes end to end the time should be linear as all the action happens at the junction.
Not so in general  for example tubes like the ones here in a torus knot http://www.thingiverse.com/thing:231727 
In reply to this post by kitwallace
Yes I am currently investigating the effect of reversing the cones. Flat ended cylinders appear to take a lot longer than ones that have a point on one end that penetrates the next one. On 22 January 2014 14:39, kitwallace <[hidden email]> wrote: Well I'm really puzzled : I thought I'd minimise the facets on the hulled _______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
With one conical end and one flat end I get 7 minutes when rendering step size 4 in a newly opened instance of OpenScad. Two flat ends gives 15 minutes. Two conical ends gives 34 minutes.
I did these by changing the order of p0,p1,p2 parameters in the two calls of disc_p2p. On 22 January 2014 14:46, nop head <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://rocklinux.net/mailman/listinfo/openscad http://openscad.org  https://flattr.com/thing/121566 
Free forum by Nabble  Edit this page 