
1234567
... 9

I did a 3d printing test to assess how much of a difference these roundovers
make in the real world. I printed four 50mm squares and rounded them
using my previous code with a "cut" setting. I made one using circular arcs
with a cut of 5mm (and found a bug in my codecircles are definitely more
trouble) and I did the other three using the settings [5,.7], [5,.5], and
[5*.97,.3] where I reduced the last one so the roundover would fit on the
square.
In comparing the printed objects, I note first of all that the circular
rounded model shows a clear line visible in reflected light as I shift it
around, so the transition between the flat part of the model and the curved
part is visible. No such transition line is visible in any of the
continuous curvature 3 cases. In comparing the 0.3 case to the 0.7 case I
am able to see the flat section light up in reflected light all at once, but
it does so without the sharp edges of the circular case. The 0.3 case has
no flat section so it never has a section that lights up.
If I feel the models the circular model has what feels like a perceptible
lump at the transition. The transition is tactile. The other three cases
are indistinguishable and all feel smooth, with no perceptible transition.
My conclusion is that for models where appearance and/or feel are important,
it's better to choose the continuous curvature roundover. And really,
there's no reason not to use it for 2d scenarios since the code is now
available in cases like this (or, if you prefer to write yourself...it's
easier to write than the circular case).
The other conclusion is that it doesn't seem to matter much if you pick the
curvature parameter anywhere in the range of [0.3,0.7], as they all feel the
same. I think that the 0.3 looks slightly more elegant visuallythe more
gradual curve is visually perceptiblebut it does require a lot more room
to execute the curve. I would suggest that if elegant appearance is
paramount, choose the smallest curvature parameter that fits with your
model.
I would post pictures but I don't think any of this stuff can be conveyed
photographically. I asked a second person to examine the models without
explaining what was different, and presenting the models in a blind fashion,
and my observations were confirmed, so I think I didn't just dream it up.
Of course, I now wonder about the analogous 3d roundover problem. Can we
make a continuous curvature rounded cube in a similar fashion?

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Parkinbot wrote
> adrianv wrote
>> Of course, I now wonder about the analogous 3d roundover problem. Can we
>> make a continuous curvature rounded cube in a similar fashion?
>
> It shouldn't be too difficult to rotate_extrude such an arc rounding a 90°
> corner and to translate/rotate 8 instances to the corners of a cube and to
> hull them. Have a try.
Wouldn't rotate extruding give a shape with discontinuous curvature in the
direction of rotation? It's the equivalent of the circular roundover, so
where it meets the linear section (the rounded edge) the curvature of the
edge will be zero and the curvature of the extruded corner will be nonzero.
It seems like some 3d bezier approach is necessary to construct the shape in
the corner. And curvature on a surface now is a vector of two values, so
maybe matching curvature is more difficult?
If I wanted a cylinder with a rounded end the rotate extrude method should
work.
Perhaps if I did a sweep of the shape I have already constructed along a
path defined by the same shape? Would that work?

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


adrianv wrote
> Wouldn't rotate extruding give a shape with discontinuous curvature in the
> direction of rotation? It's the equivalent of the circular roundover, so
this is correct. But it is a start.
Looking at a poor man's cube with rounded edges:
r0 = 5;
r = 10;
hull() for(i=[r, r], j=[r, r],k=[r, r]) translate([i,j,k]) sphere(r0,
$fn=40);
< http://forum.openscad.org/file/t887/roundedcube.png>
shows that you have to produce appropriate corner pieces that will have
proper transitions of the three corners. If you know where you have to go,
you can try to define a sweep path for it. For this you need to find a
proper parametrization of your path along the zaxis, that will transit from
a rect to the rounded path.

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Maybe my idea wasn't clear. Suppose I start with square =
[[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so
roundsquare = roundedcorners(square,...). Now roundsquare is a path that
traces out a square with continuously rounded corners. If I use roundsquare
as a shape and sweep it along the path (elevated to 3d) of 5*roundsquare
that should give me a sort of rectangular torus with smooth edges. So I
union in some filler cube in the center and the result should hopefully be a
rounded cube with continuous curvature.
It seems like the alternative approach would be to actually figure out how
bezier curves work in 3d and directly implement the required corner patch

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


adrianv wrote
> Maybe my idea wasn't clear. Suppose I start with square =
> [[0,0],[1,0],[1,1],[0,1]], and then apply my roundcorners function, so
> roundsquare = roundedcorners(square,...). Now roundsquare is a path that
> traces out a square with continuously rounded corners.
I understand this and that you want to go the hard way (for which
rotate_extrude will not do).
In order to do a sweep you need to create a sequence of polygons that can be
coated. Thus you have to define this sequence so that the polygons also will
*grow* in the desired way (as given by roundsquare) and find the
zcoordinate sequence that will also reflect the roundsquare path and the
roundedcorners rules.
With reference to my last image: You will have to define and arrange the
extrusion polygons in the way it is shown there as layers.
As I understand your approach you currently can gradually refine a given
corner in xyspace, but you don't have the means (parameters) to produce a
sequence arranged in the same sense as these layers are: so that the middle
point will follow the roundsquare path in z direction, as well as in any
other direction.

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Here some code for my initial approach using rotate_extrude to make a corner
and hull it. I used Ronaldos Bezier implementation. The horizontal edge
roundings are Bezier roundings, and the vertical ones are quarter circles,
due to the rotate_extrude call.
Now, look at the corner and study how you would sweep the rounding (xy) with
a Bezier instead of a quarter circle.
< http://forum.openscad.org/file/t887/BezierCube.png>
BezierCube(30, 200);
// #cube(200, center = true); // sizetest
module BezierCube(r = 30, s = 100)
{
q = [[0,r], [r,r], [r,0]];
p = concat([[0,0]], BZeroCurvature(q[0],q[1],q[2],n=20,r0=2/3,r1=1/2)); //
the polygon
hull() // construct the cube by hulling the corners
for(i=[0:3], j=[1,1]) scale(j)rotate(i*90) translate([s/2r,s/2r,
s/2r]) corner(p);
}
module corner(p) rotate_extrude(angle = 90, $fa=1) polygon(p);
function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1u)*p[0] :
u*BezierPoint([for(i=[1:len(p)1]) p[i] ], u)
+ (1u)*BezierPoint([for(i=[0:len(p)2]) p[i] ], u);
function BezierCurve(p, n=10) = [for(i=[0:n1]) BezierPoint(p, i/(n1)) ];
function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) =
assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1")
let( p = [ p0,
p0 + r0*(p1p0)*r1,
p0 + r0*(p1p0),
p2 + r0*(p1p2),
p2 + r0*(p1p2)*r1,
p2 ] )
BezierCurve(p,n);

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


OK, and here is some code that sweeps the corners in the desired way. It
scales each polygon in the sequence to get the desired extension for the xy
path before putting it into 3D (by zrotating it (Rz)). By this you get a
bezier in all three directions.
Although it is another piece of work, it shouldn't be too difficult to
transfer this scheme into a single (and fast processing) sweep path to avoid
the unions.
< http://forum.openscad.org/file/t887/BezierCube1.png>
use <Naca_Sweep.scad> // https://www.thingiverse.com/thing:1208001BezierCube(30, 200);
module BezierCube(r = 30, s = 100)
{
q = [[0.001,r], [r,r], [r,0.001]];
b = BZeroCurvature(q[0],q[1],q[2],n=20,r0=4/5,r1=2/3);
hull() // construct the cube by hulling the corners
for(i=[0:3], j=[1,1]) scale(j)rotate(i*90) translate([s/2r,s/2r,
s/2r])
bcorner(b, r);
}
module bcorner(b, r)
{
sweep(gendata(b,r));
function gendata(b,r) =
[
let(step = 90/(len(b)1))
for(x=[0:len(b)1])
let(l = norm(b[x])/r) // scale by bezier
Rz(x*step, Sx(l, Rx(90, vec3(b)))) // rotatex, scalex and rotatez
];
}

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


It seems like the alternative approach would be to actually figure out how
bezier curves work in 3d and directly implement the required corner patch.
Yes, that is far better and easier than the sweep idea. I am travelling without my notebook and have no way to develop it here in detail. But I will give you some general ideas.
A rectangular Bézier surface patch is a parametric bivariate polynomial. Its control points (CP) are usually represented by a bidimensional matrix of points whose columns represent the control of one of the parameter and the rows the control of the other parameter. For instance, the surface patch of the roundover of a cube edge like you suggested has a CP matrix with two columns with 5 points each. It is a degree 1 by degree 4 Bézier surface.
For the corner, we will need at least a degree 4 by degree 4 Bézier patch which has 25 control points in a matrix 5x5.
A point in a Bézier patch with a matrix of control points P corresponding to a pair of parameters (u, v) can be easily computed by the following simple code:
function BPatchPoint(P, u, v) = transpose(BezierPoint(transpose(BezierPoint(P, u)), v));
where transpose() is the matrix transpose and BezierPoint() is the function I defined before. A polyhedral approximation of the patch can be generated by calling this function for a matrix of parameters (ui, vi). Given two patches joined side by side, to have curvature continuity between them all that is needed is to satisfy the curvature continuity condition by the rows of CPs, row by row, as they were CPs of simple independent curves.
With that in mind, we could devise a patch to roundover a cube corner with curvature continuity.
I will be back home soon and I hope to detail this stuff in two days. I also have some comments about your curvature study and graphs but I have to test my ideas first.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


A point in a Bézier patch with a matrix of control points P corresponding to a pair of parameters (u, v) can be easily computed by the following simple code:
function BPatchPoint(P, u, v) = transpose(BezierPoint(transpose(BezierPoint(P, u)), v));
where transpose() is the matrix transpose and BezierPoint() is the function I defined before.
There is an error in that code: transposition is not needed. The correct code is even simpler:
function BPatchPoint(P, u, v) = BezierPoint(BezierPoint(P, u), v);
As the shape of the corner roundover patch is triangular I am considering to model it with triangular Bezier patches of degree 6.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Ronaldo wrote
> As the shape of the corner roundover patch is triangular I am considering
> to model it with triangular Bezier patches of degree 6.
No doubt that this can be easily done. I remember an older thread, where you
showed it. But how would you automatically weave in such a patch into a
sweep or polyhedron that coats a larger structure like a roundedCube? Wasn't
that one the problems?
I didn't show it in my code, but it is straightforward if you have a quad
patch (which is squashed at one end).

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Given two patches joined side by side, to have curvature continuity between them all that is needed is to satisfy the curvature continuity condition by the rows of CPs, row by row, as they were CPs of simple independent curves. With that in mind, we could devise a patch to roundover a cube corner with curvature continuity.
Following that line of thought, here is a rectangular patch to provide a curvature continuity in rounding a corner of a cube.
The following image shows the mesh of control points (CPs) compared with with the patch itself.
As can be seen, all CPs rest on the faces of the cube in an array where one full row of the mesh is collapsed to a point. Some intermediate rows and columns of the mesh are movable by changing a shape parameter, others CPs have immutable positions. The mesh of CPs of a corner were computed by the following code:
function cornerPatchCP(P0,d,r0=0.5) = [ [for(j=[0:4]) P1+P2], // i=0 let(p0=P1+(1r0)*P2,p1=(P1+P2)*(1r0),p2=P1*(1r0)+P2) // i=1 [p0,p0+r0*(p1p0),p1,p2+r0*(p1p2),p2], let(p0=P1,p1=P0,p2=P2) // i=2 [p0,p0+r0*(p1p0),p1,p2+r0*(p1p2),p2], let(p0=P1+(1r0)*P3,p1=(1r0)*P3,p2=P2+(1r0)*P3) // i=3 [p0,p0+r0*(p1p0),p1,p2+r0*(p1p2),p2], let(p0=P1+P3,p1=P3,p2=P2+P3) // i=4 [p0,p0+r0*(p1p0),p1,p2+r0*(p1p2),p2] ];
Although it is an awkward code, it was easier to be written following the continuity conditions. The arguments of this function are:
P0  the coordinates of the corner d  the extent of cube corner that will be rounded r0  a shape parameter equivalent to the shape parameter of the degree 4 curves with curvature continuity
From the CP matrix, we can sample points on the corner surface by evaluating BPatchPoint(CPs,u,v) for various values of u and v in the interval [0,1] and draw isoparametric lines or build a mesh for a polyhedron call.
I don't like this solution. The collapse of one CP matrix row creates an inconvenient asymmetry that can be observed by comparing the corner rounding surface for r0 = 0.073 with the surface of a sphere:
The image suggests that we have just one symmetry axis instead of 3 as would be desirable.
Besides, a regular sample of parameters to compute points on the surface are very irregular with a high concentration of points in the neighborhood of the point the row was collapsed. That is a reason to pursuit a solution based on Bezier triangular patches.
The corner surface described above has 25 CPs and a total degree of 8. My first glance on that indicates that a degree 4 and degree 5 Bezier triangular patch have not enough degree of freedom to accommodate the curvature continuity conditions. Possibly a degree 6 triangular patch, with 28 CPs, will have room to satisfy all needed conditions. That will be my next investigation. But how would you automatically weave in such a patch into a
sweep or polyhedron that coats a larger structure like a roundedCube? Wasn't
that one the problems?
I have solved this problem before and reported here. My lazyUnion function is able to not only union closed manifold but stitch patches. It is irrelevant for that module whether the patches are manifold or not. The only condition is that each element of the incoming list is in a polyhedron data format. And to generate a polyhedron data format for a matrix of points (a regular mesh) or even a triangular patch is an easy task. To have a manifold at the end is user responsability. To get it we need that the points on the border of a patch match the points on border of a patch it should join to and that the whole model is watertight.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Ronaldo,
well, the outcome of your solution doesn't look very different to mine. I
had to debug the corner() code a bit to use the correct rotation sequence.
The code for the Bezier triangle is rather simple and moved into the
function corner(). I think it shows a triple symmetrie. I transposed the
vertex matrix which is NxN to get a polygon sequence ordered by z. Therefore
the polygons can easily be extended to prepare a more complex sweep, like a
Bezier cube.
A BezierCube module implementing such a sweep on the basis of your Bezier
functions is shown by the following code. It renders in 0.5s on my system.
However, the union test with a cube lasts 15s.
< http://forum.openscad.org/file/t887/BezierCube2.png>
use <Naca_sweep.scad> // https://www.thingiverse.com/thing:1208001BezierCube([200, 100, 50], 30, $fn=30, center =true);
module BezierCube(s = 100, r = 30, r0 = 3/4, r1=2/3, center = false)
{
n=$fn?$fn:360/$fa; // resolution
s=s[0]==undef?[s,s,s]:s; // allow for vector and number
r = abs(r);
if(r==0)
cube(s, center=center);
else
translate(center?[0, 0, 0]:s/2+[r, r, r])
{
q = [[0.001,r], [r,r], [r,0.001]];
b = BZeroCurvature(q[0],q[1],q[2],n=n,r0=r0,r1=r1);
gd = corner(b,r); // just a corner
sweep(composeCube(s/2, r, data=gd));
}
function composeCube(s, r, data) =
let(upper = [for(j=[0:len(data)1])
let(S=[[s[0],s[1],0],[s[0],s[1],0],[s[0],s[1],0],[s[0],s[1], 0]])
[each for(i=[0:3]) Tz(s[2],T(S[i], Rz(90*i, data[j])))]])
let(lower = [for(j=[len(data)1:1:0])
let(S=[[s[0],s[1],0],[s[0],s[1],0],[s[0],s[1],0],[s[0],s[1], 0]])
[each for(i=[0:3]) Tz(s[2],T(S[i], Rz(90*i, Sz(1, data[j]))))]])
concat(upper, lower) ;
function corner(b,r) = //
let(step = 90/(len(b)1))
let (m=[for(x=[0: len(b)1])
let(l = norm(b[x])/r) // scale by bezier
let(a=atan(b[x][0]/b[x][1])) // get angle
Rz(a, Sx((l), Rx(90, vec3(b))))]) // rotatex, scalex and
rotatez
[for(i=[0:len(m)1]) [for( j=[0:len(m[0])1]) m[j][i]]]; // transpose
}
function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1u)*p[0] :
u*BezierPoint([for(i=[1:len(p)1]) p[i] ], u)
+ (1u)*BezierPoint([for(i=[0:len(p)2]) p[i] ], u);
function BezierCurve(p, n=10) = [for(i=[0:n1]) BezierPoint(p, i/(n1)) ];
function BZeroCurvature(p0,p1,p2,n=20,r0=2/3,r1=1/2) =
assert(r0>0 && r0<1 && r1>0 && r1<1, "improper value of r0 or r1")
let( p = [ p0,
p0 + r0*(p1p0)*r1,
p0 + r0*(p1p0),
p2 + r0*(p1p2),
p2 + r0*(p1p2)*r1,
p2 ] )
BezierCurve(p,n);

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


That seems to be nice (I have not tried yet). However, I have devised what seems to be a solution simplest than the patchwork I suggested before.
Compute one Bezier corner, lazyUnion() it with its rotation and mirror to cover all cube vertices roundover and hull() it. As lazyUnion() and hull() are fast, that may be faster than any other solution.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Ronaldo wrote
> Compute one Bezier corner, lazyUnion() it with its rotation and mirror to
> cover all cube vertices roundover and hull() it. As lazyUnion() and hull()
> are fast, that may be faster than any other solution.
Good point and strategy.
That was actually the solution I showed in
http://forum.openscad.org/RoundedPolygontp21897p25905.html where I did a
sweep to create a corner and hulled over 8 instances of this corner.
And it wasn't as fast as the full sweep() (30s vs. 5s), but that was (as I
started to remember), because I had used a forloop. And a for loop always
implies a union.
I just tried a run for which I put each corner as an explicite instance into
the hull body. It looks like the compile time is indeed even faster than a
full sweep (1s only). This seems to shout for a hull_for() operator that
behaves similar like the intersection_for.
Anyway, "fast" is of course always relative, because any further Boolean
operation will take its time with these vertex monsters.

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


Parkinbot wrote
> I just tried a run for which I put each corner as an explicite instance
> into
> the hull body. It looks like the compile time is indeed even faster than a
> full sweep (1s only). This seems to shout for a hull_for() operator that
> behaves similar like the intersection_for.
I have not yet had the time to go over what you guys have done, but I will
get to it in a few days.
What would hull_for() do? And is the real answer not another special
command but rather a way of passing the output of a for command as a set of
children to a calling module? Because it seems like there are multiple
occasions where you'd like to be able to generate a set of objects with
for() and then pass them to another module that operates on them
individually. Iff a nonunioning for() command existed then it could
replace intersection_for and would have applications in a variety of places,
I think. Is this a simpler concept than the idea of generically being able
to return multiple children from a module?

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


There is already a PR for a nonunion option for for() as part of a built in sweep recently. It would make intersection_for() redundant as well I think. Parkinbot wrote
> I just tried a run for which I put each corner as an explicite instance
> into
> the hull body. It looks like the compile time is indeed even faster than a
> full sweep (1s only). This seems to shout for a hull_for() operator that
> behaves similar like the intersection_for.
I have not yet had the time to go over what you guys have done, but I will
get to it in a few days.
What would hull_for() do? And is the real answer not another special
command but rather a way of passing the output of a for command as a set of
children to a calling module? Because it seems like there are multiple
occasions where you'd like to be able to generate a set of objects with
for() and then pass them to another module that operates on them
individually. Iff a nonunioning for() command existed then it could
replace intersection_for and would have applications in a variety of places,
I think. Is this a simpler concept than the idea of generically being able
to return multiple children from a module?

Sent from: http://forum.openscad.org/
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


adrianv wrote
> Iff a nonunioning for() command existed then it could
> replace intersection_for and would have applications in a variety of
> places,
> I think.
This is correct. And it has been discussed several times before. I think a
practical solution would be to introduce an ungroup() operator that cancels
out a following group(){} clause in the csg file, which implicitly forces a
union.
hull() for(i=[10,20]) cube(i);
translates into the CSG tree:
hull() {
group() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
}
If you edit the CSG file to
hull() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
you obviously get the desired result. Therefore
hull() ungroup() for(i=[10,20]) cube(i);
would translate into
hull() {
ungroup{
group() {
cube(size = [10, 10, 10], center = false);
cube(size = [20, 20, 20], center = false);
}
}
}
and ungroup() would inhibit the immediately following group() clause. If no
immediate group() follows, ungroup() will be ignored or cancelled out. But,
I guess there might be also semantical implications.
@thehans, what do you think?

Sent from: http://forum.openscad.org/_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org


It's not a problem of the language description, it's the internal
processing logic that currently forces each node to return a single
geometry object.
Changing that should open up further options. So basically right
now, every node has to do the implicit union regardless of the
actual need for that. Pushing the responsibility of the to the
level above should help improving a couple of cases, like hull()
with children generated with for(), translate() just translating
the list of children separately or doing an intersection() on
multiple volumes imported from a single 3MF file.
ciao,
Torsten.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
 Torsten


It's not a problem of the language description, it's the internal
processing logic that currently forces each node to return a single
geometry object.
Changing that should open up further options. So basically right
now, every node has to do the implicit union regardless of the
actual need for that. Pushing the responsibility of the to the
level above should help improving a couple of cases, like hull()
with children generated with for(), translate() just translating
the list of children separately or doing an intersection() on
multiple volumes imported from a single 3MF file.
ciao,
Torsten.
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

1234567
... 9
