discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Voronoi Generator

KS
Kenneth Sloan
Fri, Apr 9, 2021 8:54 PM

Lifting the 2D points to a 3D paraboloid and computing the 3D Convex Hull has been the method of choice since the 1980's.  I have implemented this several times.

Computing the dual is not difficult in an imperative language.  I have no idea what the best method would be in OpenSCAD.

Briefly, every Delaunay Triangle is mapped to a point - that point is the triangle's circumcenter.  Edges of the Delaunay Triangles are mapped to edge in the Voronoi Diagram - a DT edge which is shared by two DTs is mapped to a VD edge connecting the DT circumcenters.

This is easiest if you use data structures capable of representing Edges, Triangles, and Points, with information on which edges belong to which triangles (each edge is shared by 1 or 2 triangles).

If all you have is a collection of triangles, computing the Voronoi Point corresponding to each triangle is easy - but finding the connections between the points (that is, the triangles which share edges with each other) can involve considerable search overhead.

In my opinion, intersecting cones is a very "OpenSCAD-like" method - but, as noted, it's unlikely to be fast.

--
Kenneth Sloan
KennethRSloan@gmail.com
Vision is the art of seeing what is invisible to others.

On Apr 9, 2021, at 10:20, NateTG nate-openscadforum@pedantic.org wrote:

I made another algorithm for a voronoi generator. It works, but don't be in a hurry, because it's slow, very slow (tips for speeding it up appreciated)....
I don't think that using CGAL to do calculations using geometry by intersecting coneis going to be particularly efficient.  The traditional sweep line approach is likely to be much faster, even if it is a chore to implement in OpenSCAD.

I think there's a  geometric way to get a Delaunay triangulation by mapping [x,y] to [x,y,x^2+y^2] and then taking the convex Hull.  That's likely to to be much faster, but I don't think you can extract the dual in any way.
Sent from the OpenSCAD mailing list archive http://forum.openscad.org/ at Nabble.com.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

Lifting the 2D points to a 3D paraboloid and computing the 3D Convex Hull has been the method of choice since the 1980's. I have implemented this several times. Computing the dual is not difficult in an imperative language. I have no idea what the best method would be in OpenSCAD. Briefly, every Delaunay Triangle is mapped to a point - that point is the triangle's circumcenter. Edges of the Delaunay Triangles are mapped to edge in the Voronoi Diagram - a DT edge which is shared by two DTs is mapped to a VD edge connecting the DT circumcenters. This is easiest if you use data structures capable of representing Edges, Triangles, and Points, with information on which edges belong to which triangles (each edge is shared by 1 or 2 triangles). If all you have is a collection of triangles, computing the Voronoi Point corresponding to each triangle is easy - but finding the connections between the points (that is, the triangles which share edges with each other) can involve considerable search overhead. In my opinion, intersecting cones is a very "OpenSCAD-like" method - but, as noted, it's unlikely to be fast. -- Kenneth Sloan KennethRSloan@gmail.com Vision is the art of seeing what is invisible to others. > On Apr 9, 2021, at 10:20, NateTG <nate-openscadforum@pedantic.org> wrote: > > I made another algorithm for a voronoi generator. It works, but don't be in a hurry, because it's slow, very slow (tips for speeding it up appreciated).... > I don't think that using CGAL to do calculations using geometry by intersecting coneis going to be particularly efficient. The traditional sweep line approach is likely to be much faster, even if it is a chore to implement in OpenSCAD. > > I think there's a geometric way to get a Delaunay triangulation by mapping [x,y] to [x,y,x^2+y^2] and then taking the convex Hull. That's likely to to be much faster, but I don't think you can extract the dual in any way. > Sent from the OpenSCAD mailing list archive <http://forum.openscad.org/> at Nabble.com. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
N
NateTG
Sun, Apr 11, 2021 5:48 PM

Troberg wrote

...
I agree, this is not the efficient way, but it's a simple way (especially
in
OpenSCAD). Sometimes, efficiency in terms of developer time takes
precedence
over efficiency in terms of execution time.

...

A big issue with using the geometry engine is that you don't get access to
the result of the computation in a way that lets you do more with it.spe

I did try to make simple stupid Voronoi and  Delaunay using the n^4 approach
of checking every possible circumcircle but even that is much longer than
your example, and involves subtle stuff like dealing with floating point
math and more than 3 points on a circle.

dumb_voronoi2d.scad
http://forum.openscad.org/file/t2140/dumb_voronoi2d.scad

dumb_delaunay2d.scad
http://forum.openscad.org/file/t2140/dumb_delaunay2d.scad

--
Sent from: http://forum.openscad.org/

Troberg wrote > ... > I agree, this is not the efficient way, but it's a simple way (especially > in > OpenSCAD). Sometimes, efficiency in terms of developer time takes > precedence > over efficiency in terms of execution time. > > ... A big issue with using the geometry engine is that you don't get access to the result of the computation in a way that lets you do more with it.spe I did try to make simple stupid Voronoi and Delaunay using the n^4 approach of checking every possible circumcircle but even that is much longer than your example, and involves subtle stuff like dealing with floating point math and more than 3 points on a circle. dumb_voronoi2d.scad <http://forum.openscad.org/file/t2140/dumb_voronoi2d.scad> dumb_delaunay2d.scad <http://forum.openscad.org/file/t2140/dumb_delaunay2d.scad> -- Sent from: http://forum.openscad.org/
KS
Kenneth Sloan
Sun, Apr 11, 2021 6:31 PM

Note that the N^4 method also has a potential bug - 4 co-circular points will generate 4 triangles which overlap.  Perhaps that's what  NateTG is referring to.

Floating point math is always an issue with these  computations.  Use standard precautions.

I  have not-so-fond memories of debugging the "flip-triangles" method, about a year before the "lift to a paraboloid" method was published.  The "sweep-line" method used to be popular, but (in my opinion) was poorly described when first published.  In my opinion, it is valuable for the ability to modify it for variants of the Voronoi Diagram - but is not the method of choice for classic Delaunay Triangulation.

My choice (for the last several decades) has been the "lift to a paraboloid" method.  Once implemented (not trivial, but not difficult) I can't recall any serious issues with precision.  I do  take some care with conditioning input data (mostly merging points that are "too close").

And again - I have no clue what  difficulties might be involved in implementing this in OpenSCAD.
My inclination would be to use "intersecting cones", if forced to implement it in OpenSCAD.
At least, I'd implement that first and wait to see what the performance penalty was.

--
Kenneth Sloan
KennethRSloan@gmail.com
Vision is the art of seeing what is invisible to others.

On Apr 11, 2021, at 12:48, NateTG nate-openscadforum@pedantic.org wrote:
...
I did try to make simple stupid Voronoi and  Delaunay using the n^4 approach of checking every possible circumcircle but even that is much longer than your example, and involves subtle stuff like dealing with floating point math and more than 3 points on a circle.

Note that the N^4 method also has a potential bug - 4 co-circular points will generate 4 triangles which overlap. Perhaps that's what NateTG is referring to. Floating point math is *always* an issue with these computations. Use standard precautions. I have not-so-fond memories of debugging the "flip-triangles" method, about a year *before* the "lift to a paraboloid" method was published. The "sweep-line" method used to be popular, but (in my opinion) was poorly described when first published. In my opinion, it is valuable for the ability to modify it for variants of the Voronoi Diagram - but is not the method of choice for classic Delaunay Triangulation. My choice (for the last several decades) has been the "lift to a paraboloid" method. Once implemented (not trivial, but not difficult) I can't recall any serious issues with precision. I do take some care with conditioning input data (mostly merging points that are "too close"). And again - I have no clue what difficulties might be involved in implementing this in OpenSCAD. My inclination would be to use "intersecting cones", if forced to implement it in OpenSCAD. At least, I'd implement that first and wait to see what the performance penalty was. -- Kenneth Sloan KennethRSloan@gmail.com Vision is the art of seeing what is invisible to others. > On Apr 11, 2021, at 12:48, NateTG <nate-openscadforum@pedantic.org> wrote: > ... > I did try to make simple stupid Voronoi and Delaunay using the n^4 approach of checking every possible circumcircle but even that is much longer than your example, and involves subtle stuff like dealing with floating point math and more than 3 points on a circle.
A
adrianv
Sun, Apr 11, 2021 6:40 PM

There is a vornoi calculator in the dotSCAD library:

https://github.com/JustinSDK/dotSCAD

I have no idea what algorithm it uses, or its performance, but might be
worth a look.

Kenneth Sloan wrote

Note that the N^4 method also has a potential bug - 4 co-circular points
will generate 4 triangles which overlap.  Perhaps that's what  NateTG is
referring to.

Floating point math is always an issue with these  computations.  Use
standard precautions.

I  have not-so-fond memories of debugging the "flip-triangles" method,
about a year before the "lift to a paraboloid" method was published.
The "sweep-line" method used to be popular, but (in my opinion) was poorly
described when first published.  In my opinion, it is valuable for the
ability to modify it for variants of the Voronoi Diagram - but is not the
method of choice for classic Delaunay Triangulation.

My choice (for the last several decades) has been the "lift to a
paraboloid" method.  Once implemented (not trivial, but not difficult) I
can't recall any serious issues with precision.  I do  take some care with
conditioning input data (mostly merging points that are "too close").

And again - I have no clue what  difficulties might be involved in
implementing this in OpenSCAD.
My inclination would be to use "intersecting cones", if forced to
implement it in OpenSCAD.
At least, I'd implement that first and wait to see what the performance
penalty was.

--
Kenneth Sloan

KennethRSloan@

Vision is the art of seeing what is invisible to others.

On Apr 11, 2021, at 12:48, NateTG <

nate-openscadforum@

> wrote:

...
I did try to make simple stupid Voronoi and  Delaunay using the n^4
approach of checking every possible circumcircle but even that is much
longer than your example, and involves subtle stuff like dealing with
floating point math and more than 3 points on a circle.


OpenSCAD mailing list
To unsubscribe send an email to

discuss-leave@.openscad

There is a vornoi calculator in the dotSCAD library: https://github.com/JustinSDK/dotSCAD I have no idea what algorithm it uses, or its performance, but might be worth a look. Kenneth Sloan wrote > Note that the N^4 method also has a potential bug - 4 co-circular points > will generate 4 triangles which overlap. Perhaps that's what NateTG is > referring to. > > Floating point math is *always* an issue with these computations. Use > standard precautions. > > I have not-so-fond memories of debugging the "flip-triangles" method, > about a year *before* the "lift to a paraboloid" method was published. > The "sweep-line" method used to be popular, but (in my opinion) was poorly > described when first published. In my opinion, it is valuable for the > ability to modify it for variants of the Voronoi Diagram - but is not the > method of choice for classic Delaunay Triangulation. > > My choice (for the last several decades) has been the "lift to a > paraboloid" method. Once implemented (not trivial, but not difficult) I > can't recall any serious issues with precision. I do take some care with > conditioning input data (mostly merging points that are "too close"). > > And again - I have no clue what difficulties might be involved in > implementing this in OpenSCAD. > My inclination would be to use "intersecting cones", if forced to > implement it in OpenSCAD. > At least, I'd implement that first and wait to see what the performance > penalty was. > > -- > Kenneth Sloan > KennethRSloan@ > Vision is the art of seeing what is invisible to others. > > > > > >> On Apr 11, 2021, at 12:48, NateTG &lt; > nate-openscadforum@ > &gt; wrote: >> ... >> I did try to make simple stupid Voronoi and Delaunay using the n^4 >> approach of checking every possible circumcircle but even that is much >> longer than your example, and involves subtle stuff like dealing with >> floating point math and more than 3 points on a circle. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to > discuss-leave@.openscad -- Sent from: http://forum.openscad.org/
T
Troberg
Mon, Apr 12, 2021 7:21 AM

NateTG wrote

A big issue with using the geometry engine is that you don't get access to
the result of the computation in a way that lets you do more with it.

Yep, but I made it just to generate a cool shape for a lamp shade for laser
cutting, so I just wanted a quick and dirty solution for that.

--
Sent from: http://forum.openscad.org/

NateTG wrote > A big issue with using the geometry engine is that you don't get access to > the result of the computation in a way that lets you do more with it. Yep, but I made it just to generate a cool shape for a lamp shade for laser cutting, so I just wanted a quick and dirty solution for that. -- Sent from: http://forum.openscad.org/
RV
Roel Vanhout
Mon, Apr 12, 2021 8:07 AM

I sort of lost track as to what the original requirement was in this
thread, but since it has been generating so many responses - I had a need
for a Voronoi pattern in a design last week, and I ended up cheating and
using https://voronoi-editor.web.app/ , tweaking it to my liking, exporting
the svg and then import()/linear_extrude()'ing that svg. Was much easier to
use than the various native solutions I found online. The main disadvantage
was that the regular preview was completely screwed up so I had to F6 every
time I wanted a proper idea of what the result would look like. Just
mentioning that maybe an external solution is the more pragmatic approach.

cheers

On Mon, Apr 12, 2021 at 9:21 AM Troberg troberg.anders@gmail.com wrote:

NateTG wrote
A big issue with using the geometry engine is that you don't get access to
the result of the computation in a way that lets you do more with it.

Yep, but I made it just to generate a cool shape for a lamp shade for
laser cutting, so I just wanted a quick and dirty solution for that.

Sent from the OpenSCAD mailing list archive http://forum.openscad.org/
at Nabble.com.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

I sort of lost track as to what the original requirement was in this thread, but since it has been generating so many responses - I had a need for a Voronoi pattern in a design last week, and I ended up cheating and using https://voronoi-editor.web.app/ , tweaking it to my liking, exporting the svg and then import()/linear_extrude()'ing that svg. Was much easier to use than the various native solutions I found online. The main disadvantage was that the regular preview was completely screwed up so I had to F6 every time I wanted a proper idea of what the result would look like. Just mentioning that maybe an external solution is the more pragmatic approach. cheers On Mon, Apr 12, 2021 at 9:21 AM Troberg <troberg.anders@gmail.com> wrote: > NateTG wrote > A big issue with using the geometry engine is that you don't get access to > the result of the computation in a way that lets you do more with it. > > Yep, but I made it just to generate a cool shape for a lamp shade for > laser cutting, so I just wanted a quick and dirty solution for that. > ------------------------------ > Sent from the OpenSCAD mailing list archive <http://forum.openscad.org/> > at Nabble.com. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org >
C
caterpillar
Mon, Apr 12, 2021 10:08 AM

adrianv wrote

There is a vornoi calculator in the dotSCAD library:

https://github.com/JustinSDK/dotSCAD

I have no idea what algorithm it uses, or its performance, but might be
worth a look.

// Half-plane Intersection: it's slow but simple.
voronoi/vrn2_cells_from(points)
voronoi/vrn2_from(points, spacing = 1, ...)

// Half-plane Intersection && Nearest Neighbor (idea from
https://thebookofshaders.com/12/)
voronoi/vrn2_cells_space(size, grid_w, seed = undef)
voronoi/vrn2_space(size, grid_w, seed = undef, spacing = 1, ...)


https://openhome.cc

Sent from: http://forum.openscad.org/

adrianv wrote > There is a vornoi calculator in the dotSCAD library: > > https://github.com/JustinSDK/dotSCAD > > I have no idea what algorithm it uses, or its performance, but might be > worth a look. // Half-plane Intersection: it's slow but simple. voronoi/vrn2_cells_from(points) voronoi/vrn2_from(points, spacing = 1, ...) // Half-plane Intersection && Nearest Neighbor (idea from https://thebookofshaders.com/12/) voronoi/vrn2_cells_space(size, grid_w, seed = undef) voronoi/vrn2_space(size, grid_w, seed = undef, spacing = 1, ...) ----- https://openhome.cc -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Mon, Apr 12, 2021 12:11 PM

And again - I have no clue what  difficulties might be involved in
implementing this in OpenSCAD.
My inclination would be to use "intersecting cones", if forced to
implement it in OpenSCAD.
At least, I'd implement that first and wait to see what the performance
penalty was.

I may be wrong but I guess the best candidate for an implementation of
Delaunay in OpenSCAD would be the divide and conquer: divide the pointset
in two halves, recursively build the Delaunay triangulation of the right
and left sets and merge them. It is a O(n.log n) method whose hardest (and
runtime expensive) part is to devise and build an appropriate data
structure that keeps the local tasks constant time. In an implementation of
the Catmull-Clark and similar subdivision methods we did, a suitable data
structure played the most demanding effort. With the appropriate data
structure, to find the dual to get the Voronoi is easy.

> > And again - I have no clue what difficulties might be involved in > implementing this in OpenSCAD. > My inclination would be to use "intersecting cones", if forced to > implement it in OpenSCAD. > At least, I'd implement that first and wait to see what the performance > penalty was. > > I may be wrong but I guess the best candidate for an implementation of Delaunay in OpenSCAD would be the divide and conquer: divide the pointset in two halves, recursively build the Delaunay triangulation of the right and left sets and merge them. It is a O(n.log n) method whose hardest (and runtime expensive) part is to devise and build an appropriate data structure that keeps the local tasks constant time. In an implementation of the Catmull-Clark and similar subdivision methods we did, a suitable data structure played the most demanding effort. With the appropriate data structure, to find the dual to get the Voronoi is easy.
N
NateTG
Mon, Apr 12, 2021 1:31 PM

Ronaldo wrote

...
I may be wrong but I guess the best candidate for an implementation of
Delaunay in OpenSCAD would be the divide and conquer: divide the pointset
in two halves, recursively build the Delaunay triangulation of the right
and left sets and merge them. It is a O(n.log n) method whose hardest (and
runtime expensive) part is to devise and build an appropriate data
structure that keeps the local tasks constant time....

Fortune's algorithm (https://en.wikipedia.org/wiki/Fortune%27s_algorithm)
looks pretty doable.  To make that work in n log n time requires data
structures for the event queue and beach line that have log n insertion
time.

That said, I've been thinking about the computational complexity thing, and
there's a tendency to end up with a recursion pattern like:

concat( partial_list, function(index+1) )

If concatenation takes order n time for a length n list, then anything that
uses a pattern like that will have time complexity n^2 in the size of the
output anyway,  so the value of getting from n^2 to n log n for Delaunay
triangulation may be marginal unless that's also changed.

--
Sent from: http://forum.openscad.org/

Ronaldo wrote > ... > I may be wrong but I guess the best candidate for an implementation of > Delaunay in OpenSCAD would be the divide and conquer: divide the pointset > in two halves, recursively build the Delaunay triangulation of the right > and left sets and merge them. It is a O(n.log n) method whose hardest (and > runtime expensive) part is to devise and build an appropriate data > structure that keeps the local tasks constant time.... Fortune's algorithm (https://en.wikipedia.org/wiki/Fortune%27s_algorithm) looks pretty doable. To make that work in n log n time requires data structures for the event queue and beach line that have log n insertion time. That said, I've been thinking about the computational complexity thing, and there's a tendency to end up with a recursion pattern like: concat( partial_list, function(index+1) ) If concatenation takes order n time for a length n list, then anything that uses a pattern like that will have time complexity n^2 in the size of the output anyway, so the value of getting from n^2 to n log n for Delaunay triangulation may be marginal unless that's also changed. -- Sent from: http://forum.openscad.org/
JB
Jordan Brown
Mon, Apr 12, 2021 4:10 PM

On 4/12/2021 1:07 AM, Roel Vanhout wrote:

[...] exporting the svg and then import()/linear_extrude()'ing that
svg. [...] The main disadvantage was that the regular preview was
completely screwed up so I had to F6 every time I wanted a proper idea
of what the result would look like.

Sounds like you need to set convexity on your linear_extrude.  Set it to
10 or so.  People have done performance experiments, and there's almost
no downside to setting a larger convexity.

On 4/12/2021 1:07 AM, Roel Vanhout wrote: > [...] exporting the svg and then import()/linear_extrude()'ing that > svg. [...] The main disadvantage was that the regular preview was > completely screwed up so I had to F6 every time I wanted a proper idea > of what the result would look like. Sounds like you need to set convexity on your linear_extrude.  Set it to 10 or so.  People have done performance experiments, and there's almost no downside to setting a larger convexity.