Parkinbot wrote
adrianv wrote
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
What is the difference between these two things? Taking the hull() of an
individual cube won't do anything.
I thought the interesting case was wanting to do sequential hulls, like the
hull of every adjacent pair of objects in a list, where the list was
produced by for().
--
Sent from: http://forum.openscad.org/
adrianv wrote
What is the difference between these two things? Taking the hull() of an
individual cube won't do anything.
The code hulls two cubes. They could be translated to create something
meaningful, but this doesn't matter for the argument. The cubes will get
unioned in the first case and then hulled, and in the second case they
only get hulled. (Better think of 8 (translated) corners to be hulled to
gain a BezierCube).
While the result is the same, it is a significant runtime difference,
whether hull() will operate over a set of objects or a unioned object.
hull() is much faster then union().
--
Sent from: http://forum.openscad.org/
Parkinbot rudolf@digitaldocument.de wrote:
While the result is the same, it is a significant runtime difference,
whether hull() will operate over a set of objects or a unioned object.
hull() is much faster then union().
Hum... There is something strange here. The following code generates a
regular cube even with F6:
hull()
for(i=[0,1]){
polyhedron([[0,0,i],[1,0,i],[1,1,i],[0,1,i]],[[0,1,2,3,4]]);
cube(0.5);
}
although the two polyhedron are defective (non-manifold). If we drop the
hull() we get a non-manifold warning with F6. So, I don't think the hull()
for(){ } construct really does any union before the hull().
Parkinbot rudolf@digitaldocument.de 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.
We don't need a hull_for() to have a faster run. hull() disregards any edge
or facets of the objects we collect for it. It operates just on the
vertices. As we don't have a primitive point, we need to resort to
polyhedron to hull() a list of points like I do here:
$fn= 10; // number of points in all roundover
r0 = 0.15; // shape parameter
r = 2; // rounding "radius"
s = [10,15,20]; // cube edge length
roundedCube(s,r,r0);
module roundedCube(s=10, r=1, r0=0.073) {
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=true);
else {
cp = cornerPatchCP(-s/2,r,r0);
cp0 = PatchSample(cp,n); // corner at -s/2
Mx =[[-1,0,0],[0, 1,0],[0,0, 1]];
My =[[ 1,0,0],[0,-1,0],[0,0, 1]];
Mz =[[ 1,0,0],[0, 1,0],[0,0,-1]];
cp2 = concat( cp0, [for(pi=cp0) Mxpi] );
cp4 = concat( cp2, [for(pi=cp2) Mypi] );
cp8 = concat( cp4, [for(pi=cp4) Mz*pi] );
hull() polyhedron(cp8, [[for(i=[0:len(cp8)-1]) i]]);
}
}
function BezierPoint(p, u) =
(len(p) == 2)?
u*p[1] + (1-u)p[0] :
uBezierPoint([for(i=[1:len(p)-1]) p[i] ], u)
+ (1-u)*BezierPoint([for(i=[0:len(p)-2]) p[i] ], u);
function BPatchPoint(p,u,v) =
BezierPoint(BezierPoint(p, u), v);
function PatchSample(cp,n) =
[for(i=[0:n-1], j=[0:i])
BPatchPoint(cp,i/(n-1),i==0? 0 : j/i) ];
function cornerPatchCP(P0,d,r0=0.5) =
let( dx = d*[1,0,0],
dy = d*[0,1,0],
dz = d*[0,0,1] )
[ [for(j=[0:4]) P0+dx+dy],
cCP([P0+dx+(1-r0)dy, P0+(dx+dy)(1-r0), P0+dx*(1-r0)+dy],r0),
cCP([P0+dx, P0, P0+dy], r0),
cCP([P0+dx+(1-r0)*dz, P0+(1-r0)*dz, P0+dy+(1-r0)*dz],r0),
cCP([P0+dx+dz, P0+dz, P0+dy+dz],r0) ];
function cCP(p,r0=0.5) =
[ p[0],
p[0]+r0*(p[1]-p[0]),
p[1],
p[2]+r0*(p[1]-p[2]),
p[2] ];
This is the fastest strategy I can imagine. The points sampled from the
corner patches are collected in a simple list which will be the vertices of
the fake polyhedron to be hulled. That fake polyhedron has just one face
collecting all the vertex indices. This polyhedron is defective and it is
not a manifold at all but that polyhedron is not really built, just hulled.
The second aspect of the code is that it samples the corner patch in an non
uniform distribution in the parameter space. The sample rate is poor near
the collapsed row of the rectangular patch and increases linearly up to the
opposed patch edge. As the patch is really triangular, the sampling is
geometrically more uniform.
[image: cornerSampling.PNG]
I haven't tried your code yet (although I have borrowed some lines of code
from it :) ) but I believe this last code is faster. It renders the cube in
1s with $fn=50 and in 12s with $fn=100.
Anyway, "fast" is of course always relative, because any further Boolean
operation will take its time with these vertex monsters.
It is not a monster. The number of vertices of the rounded cube is about
the same of one sphere with the same $fn. So, I would not expect anything
worst than the boolean operation with a sphere. In fact, it required just
9s to difference a cylinder crossing a rounded edge with $fn=32.
Ronaldo wrote
although the two polyhedron are defective (non-manifold). If we drop the
hull() we get a non-manifold warning with F6. So, I don't think the hull()
for(){ } construct really does any union before the hull().
I think warnings are only tested and emitted on the final object.
--
Sent from: http://forum.openscad.org/
Ronaldo wrote
We don't need a hull_for() to have a faster run. hull() disregards any
edge
or facets of the objects we collect for it. It operates just on the
vertices. As we don't have a primitive point, we need to resort to
polyhedron to hull() a list of points like I do here:
If you create a convex body it is indeed avoidable - even I would say, it is
a work-around if you have to recur to a lazy-union to avoid the "for union
problem".
The following code creates a random convex body and looks a bit dirty. I am
somehow very reluctant to build a serious library module on this technique:
points = [for(i=[0:30]) rands(-10, 10, 3)];
faces = [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces); // tricky convex body
However, there are also non-convex shapes. For them you need to do a proper
sweep, so this strategy is quite limited. In general I prefer to create such
a patch in a way so that it can also be swept.
--
Sent from: http://forum.openscad.org/
Wouldn't Oskar Linde's hull() function solve this problem? I don't know its
runtime performance, but it takes a point list and computes faces of the
convex hull without the uncomfortable scheme of creating a bogus polyhedron.
https://github.com/openscad/scad-utils/blob/master/hull.scad
--
Sent from: http://forum.openscad.org/
adrianv wrote
Wouldn't Oskar Linde's hull() function solve this problem?
It wouldn't solve the problem, because in general we have the case in which
a for-loop will create objects (even fancy polyhedra are objects) that get
hulled, and Oskar Linde's hull() function depends like a lazy union on a
point representation, which OpenSCAD is successfully hiding from user space.
But for fun, I did a quick runtime test and compared Oskar Linde's hull()
function with the fancy hull()polyhedron() approach. It turned out that
Oskar's function is indeed pretty much faster, when it comes to a higher
number of points. Good to know!
points = [for(i=[0:3000]) rands(-10, 10, 3)];
// polyhedron (points, hull(points)); // Oskar's approach: 6s
faces = [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces); // tricky convex body 74s:
--
Sent from: http://forum.openscad.org/
I have never tried Oskar Linde's hull(). I will give it a go.
However, the bogus polyhedron technique seems to be faster and simpler. For
the advocates of more orthodox solutions, it is possible to apply hull to a
set of spherical regular polyhedron built by lazyUnion() the 8 corner
patches glued together. As hull() will consider just the vertices and
disregard the edges and faces, that seems to be a waste of running time and
coding effort.
I have not looked at the sweep technique in detail yet. My concern would
certainly be on the curvature continuity.
It is a great news (and surprise) that Oskar Linde's hull is so fast. I
will study it.
A domingo, 24/03/2019, 11:44, adrianv avm4@cornell.edu escreveu:
Wouldn't Oskar Linde's hull() function solve this problem? I don't know
its
runtime performance, but it takes a point list and computes faces of the
convex hull without the uncomfortable scheme of creating a bogus
polyhedron.
https://github.com/openscad/scad-utils/blob/master/hull.scad
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Parkinbot rudolf@digitaldocument.de wrote:
adrianv wrote
Wouldn't Oskar Linde's hull() function solve this problem?
(...)
But for fun, I did a quick runtime test and compared Oskar Linde's hull()
function with the fancy hull()polyhedron() approach. It turned out that
Oskar's function is indeed pretty much faster, when it comes to a higher
number of points. Good to know!
points = [for(i=[0:3000]) rands(-10, 10, 3)];
// polyhedron (points, hull(points)); // Oskar's approach: 6s
faces = [[for(i=[0:len(points)-1]) i]];
hull() polyhedron(points, faces); // tricky convex body 74s:
I have checked this comparison and concluded that the delay of the second
alternative is due to the big face in the polyhedron call. I guess that the
system does a triangulation of that bogus face. Instead of one big face I
have defined a big list of triangular faces covering all vertices and the
results were very different:
points = [for(i=[0:120000-1]) rands(-10, 10, 3)];
faces = [for(i=[0:3:len(points)-1]) [i,i+1,i+2]];
hull() // hull() spent 0s
polyhedron(points, faces); // tricky polyhedron spent 3s
On the other hand, Oskar Linde's hull() crashed with 6000 or more points.
If that function were used in a roundedCube code, it would crash with
$fn>=38.