qhull
Delaunay triangulation, Voronoi diagrams and convex hulls.
Based on the qhull
C library.
Delaunay tesselation
Consider this list of vertices (actually these are the vertices of a
polyhedron):
vertices = [
[ -5, -5, 16 ] -- 0
, [ -5, 8, 3 ] -- 1
, [ 4, -1, 3 ] -- 2
, [ 4, -5, 7 ] -- 3
, [ 4, -1, -10 ] -- 4
, [ 4, -5, -10 ] -- 5
, [ -5, 8, -10 ] -- 6
, [ -5, -5, -10 ] -- 7
]
The delaunay
function splits the polyhedron into simplices, the tiles of the
tesselation:
> import Delaunay
> d <- delaunay vertices False False
> _tiles d
fromList
[ ( 0
, Tile
{ _simplex =
Simplex
{ _points =
fromList
[ ( 2 , [ 4.0 , -1.0 , 3.0 ] )
, ( 4 , [ 4.0 , -1.0 , -10.0 ] )
, ( 5 , [ 4.0 , -5.0 , -10.0 ] )
, ( 7 , [ -5.0 , -5.0 , -10.0 ] )
]
, _circumcenter =
[ -0.5000000000000009 , -3.0 , -3.499999999999999 ]
, _circumradius = 8.154753215150047
, _volume = 78.0
}
, _neighborsIds = fromList [ 1 , 3 ]
, _facetsIds = fromList [ 0 , 1 , 2 , 3 ]
, _family = Nothing
, _toporiented = False
}
)
, ( 1
, Tile
{ _simplex =
......
The field _tiles
is a map of Tile
objects. The keys of the map are
the tiles identifiers. A Tile
object has five fields:
-
_simplex
, a Simplex
object;
-
_neighborsIds
, a set of tiles identifiers, the neighbors of the tile;
-
facetsIds
, a set of facets identifiers, the facets of the tile;
-
family
, two tiles of the same family share the same circumcenter;
-
toporiented
, Boolean, whether the tile is top-oriented.
A Simplex
object has four fields:
-
_points
, the vertices of the simplex, actually a map of the vertices
identifiers to their coordinates
-
_circumcenter
, the coordinates of the circumcenter of the simplex;
-
_circumradius
, the circumradius;
-
_volume
, the volume of the simplex (the area in dimension 2, the
length in dimension 1).
Another field of the output of delaunay
is _tilefacets
:
> _tilefacets d
fromList
[ ( 0
, TileFacet
{ _subsimplex =
Simplex
{ _points =
fromList
[ ( 4 , [ 4.0 , -1.0 , -10.0 ] )
, ( 5 , [ 4.0 , -5.0 , -10.0 ] )
, ( 7 , [ -5.0 , -5.0 , -10.0 ] )
]
, _circumcenter = [ -0.5000000000000009 , -3.0 , -10.0 ]
, _circumradius = 4.924428900898053
, _volume = 36.0
}
, _facetOf = fromList [ 0 ]
, _normal = [ 0.0 , 0.0 , -1.0 ]
, _offset = -10.0
}
)
, ( 1
, TileFacet
{ _subsimplex =
......
This is a map of TileFacet
objects. A tile facet is a subsimplex. The keys of
the map are the identifiers of the facets.
A TileFacet
object has four fields: _subsimplex
, a Simplex
object,
_facetOf
, the identifiers of the tiles this facet belongs to (a set of one
or two integers), _normal
, the normal of the facet, and offset
, the offset
of the facet.
Finally, the output of delaunay
has a _sites
field, the vertices with
additional information:
> _sites d
fromList
[ ( 0
, Site
{ _point = [ -5.0 , -5.0 , 16.0 ]
, _neighsitesIds = fromList [ 1 , 3 , 7 ]
, _neighfacetsIds = fromList [ 15 , 16 , 17 ]
, _neightilesIds = fromList [ 5 ]
}
)
, ( 1
, Site
......
This is a map of Site
objects. The keys of the map are the identifiers of
the vertices. A Site
object has four fields:
-
_point
, the coordinates of the vertex;
-
_neighsitesIds
, the identifiers of the connected vertices;
-
_neighfacetsIds
, a set of integers, the identifiers of the facets the
vertex belongs to;
-
_neightilesIds
, the set of the identifiers of the tiles the vertex belongs
to.
Voronoi diagrams
The library allows to get the Voronoi diagram of a list of sites (vertices)
from the Delaunay tesselation. Here is a 3D example.
centricCuboctahedron :: [[Double]]
centricCuboctahedron = [[i,j,0] | i <- [-1,1], j <- [-1,1]] ++
[[i,0,j] | i <- [-1,1], j <- [-1,1]] ++
[[0,i,j] | i <- [-1,1], j <- [-1,1]] ++
[[0,0,0]]
import Delaunay
import Voronoi3D
d <- delaunay centricCuboctahedron False False
v = voronoi3 d
In some circumstances, one has to run the Delaunay tesselation including the
degenerate tiles in order to get the correct Voronoi diagram, that is to say
delaunay vertices False True
.
The output of voronoi3
is a list of Voronoi cells given as pairs, each pair
consisting of a site and a list of edges.
This is the cell of the center [0, 0, 0]
:
> last v
( [ 0.0 , 0.0 , 0.0 ]
, [ Edge3 ( ( -0.5 , -0.5 , 0.5 ) , ( 0.0 , 0.0 , 1.0 ) )
, Edge3 ( ( -0.5 , -0.5 , 0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , -0.5 , 0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( -0.5 , 0.5 , 0.5 ) , ( 0.0 , 0.0 , 1.0 ) )
, Edge3 ( ( -0.5 , 0.5 , 0.5 ) , ( 0.0 , 1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , 0.5 , 0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( 0.5 , -0.5 , 0.5 ) , ( 0.0 , 0.0 , 1.0 ) )
, Edge3 ( ( 0.5 , -0.5 , 0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( 0.5 , -0.5 , 0.5 ) , ( 1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( 0.5 , 0.5 , 0.5 ) , ( 0.0 , 0.0 , 1.0 ) )
, Edge3 ( ( 0.5 , 0.5 , 0.5 ) , ( 0.0 , 1.0 , 0.0 ) )
, Edge3 ( ( 0.5 , 0.5 , 0.5 ) , ( 1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( -0.5 , -0.5 , -0.5 ) , ( 0.0 , 0.0 , -1.0 ) )
, Edge3 ( ( -0.5 , -0.5 , -0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , -0.5 , -0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( -0.5 , 0.5 , -0.5 ) , ( 0.0 , 0.0 , -1.0 ) )
, Edge3 ( ( -0.5 , 0.5 , -0.5 ) , ( 0.0 , 1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , 0.5 , -0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( 0.5 , -0.5 , -0.5 ) , ( 0.0 , 0.0 , -1.0 ) )
, Edge3 ( ( 0.5 , -0.5 , -0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( 0.5 , -0.5 , -0.5 ) , ( 1.0 , 0.0 , 0.0 ) )
, Edge3 ( ( 0.5 , 0.5 , -0.5 ) , ( 0.0 , 0.0 , -1.0 ) )
, Edge3 ( ( 0.5 , 0.5 , -0.5 ) , ( 0.0 , 1.0 , 0.0 ) )
, Edge3 ( ( 0.5 , 0.5 , -0.5 ) , ( 1.0 , 0.0 , 0.0 ) )
]
)
This is a bounded cell: it has finite edges only. The other ones are not
bounded, they have infinite edges:
> head v
( [ -1.0 , -1.0 , 0.0 ]
, [ Edge3 ( ( -0.5 , -0.5 , 0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , -0.5 , 0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, IEdge3
( ( -0.5 , -0.5 , 0.5 )
, ( -0.5773502691896258 , -0.5773502691896258 , 0.5773502691896258 )
)
, Edge3 ( ( -0.5 , -0.5 , -0.5 ) , ( 0.0 , -1.0 , 0.0 ) )
, Edge3 ( ( -0.5 , -0.5 , -0.5 ) , ( -1.0 , 0.0 , 0.0 ) )
, IEdge3
( ( -0.5 , -0.5 , -0.5 )
, ( -0.5773502691896258 , -0.5773502691896258 , -0.5773502691896258 )
)
, IEdge3 ( ( -1.0 , 0.0 , 0.0 ) , ( 1.0 , 0.0 , 0.0 ) )
, IEdge3 ( ( 0.0 , -1.0 , 0.0 ) , ( 0.0 , -1.0 , 0.0 ) )
]
)
Convex hull
The convexHull
function of the ConvexHull
module generates the convex hull
of a list of points.
import ConvexHull
import ConvexHull.Examples -- for the function randomInCube
points <- randomInCube 100 -- 100 random points in a cube
hull <- convexHull points False False Nothing
The vertices of the convex hull are stored in the field _hvertices
:
> _hvertices hull
fromList
[ ( 3
, Vertex
{ _point =
[ 0.7872072051657094 , 0.450772463858757 , 1.9900427529711773e-2 ]
, _neighfacets = fromList [ 42 , 43 , 47 , 48 ]
, _neighvertices = fromList [ 1 , 11 , 64 , 88 ]
, _neighridges = fromList [ 70 , 71 , 72 , 77 ]
}
)
, ( 6
, Vertex
......
The edges in the field _hedges
:
> _hedges hull
fromList
[ ( Pair 14 70
, ( [ 0.9215432980174852 , 0.8554065771602318 , 0.9842902519648512 ]
, [ 0.9497713758656887 , 0.998006476041318 , 0.7243639875028591 ]
)
)
, ( Pair 84 99
......
The facets in the field _hfacets
:
> _hfacets hull
fromList
[ ( 0
, Facet
{ _fvertices =
fromList
[ ( 4
, [ 1.5757133629105136e-3
, 0.6442797662244039
, 0.7058559215899725
]
)
, ( 67
, [ 2.7500520534961326e-2
, 0.37516259577251554
, 0.7331611715042575
]
)
, ( 77
, [ 3.46399386146774e-2
, 5.575911794526589e-2
, 0.46787034305814157
]
)
]
, _fridges =
fromList
[ ( 0
, Ridge
{ _rvertices =
fromList
[ ( 4
, [ 1.5757133629105136e-3
, 0.6442797662244039
, 0.7058559215899725
]
)
, ( 77
, [ 3.46399386146774e-2
, 5.575911794526589e-2
, 0.46787034305814157
]
)
]
, _ridgeOf = fromList [ 0 , 4 ]
}
)
, ( 1
, Ridge
{ _rvertices =
fromList
[ ( 4
, [ 1.5757133629105136e-3
, 0.6442797662244039
, 0.7058559215899725
]
)
, ( 67
, [ 2.7500520534961326e-2
, 0.37516259577251554
, 0.7331611715042575
]
)
]
, _ridgeOf = fromList [ 0 , 2 ]
}
)
, ( 2
, Ridge
{ _rvertices =
fromList
[ ( 67
, [ 2.7500520534961326e-2
, 0.37516259577251554
, 0.7331611715042575
]
)
, ( 77
, [ 3.46399386146774e-2
, 5.575911794526589e-2
, 0.46787034305814157
]
)
]
, _ridgeOf = fromList [ 0 , 1 ]
}
)
]
, _centroid =
[ 2.1238724170849748e-2 , 0.3584004933140618 , 0.6356291453841239 ]
, _normal =
[ -0.9930268604214181
, -8.766369712550202e-2
, 7.882087723357102e-2
]
, _offset = 2.40848904384814e-3
, _area = 4.0339144929987907e-2
, _neighbors = fromList [ 1 , 2 , 4 ]
, _family = None
, _fedges =
fromList
[ ( Pair 4 67
, ( [ 1.5757133629105136e-3
, 0.6442797662244039
, 0.7058559215899725
]
, [ 2.7500520534961326e-2
, 0.37516259577251554
, 0.7331611715042575
]
)
)
, ( Pair 67 77
, ( [ 2.7500520534961326e-2
, 0.37516259577251554
, 0.7331611715042575
]
, [ 3.46399386146774e-2
, 5.575911794526589e-2
, 0.46787034305814157
]
)
)
, ( Pair 4 77
, ( [ 1.5757133629105136e-3
, 0.6442797662244039
, 0.7058559215899725
]
, [ 3.46399386146774e-2
, 5.575911794526589e-2
, 0.46787034305814157
]
)
)
]
}
)
, ( 1
, Facet
......
Halfspaces intersections
import HalfSpaces
import Data.Ratio ((%))
x = newVar 1
y = newVar 2
z = newVar 3
constraints =
[ x .>= 0 -- shortcut for x .>=. cst 0
, x .<= 3
, y .>= 0
, y .<=. cst 2 ^-^ (2%3)*^x
, z .>= 0
, z .<=. cst 6 ^-^ 2*^x ^-^ 3*^y ]
> hsintersections constraints False
[ [ -1.1102230246251565e-16 , -1.1102230246251565e-16 , 6.0 ]
, [ 0.0 , 2.0 , 0.0 ]
, [ 0.0 , 0.0 , 0.0 ]
, [ 3.0 , 0.0 , 0.0 ] ]
Gallery
The convex hull of a curve on the sphere:
The Voronoi cell of a point inside the Utah teapot:
The Voronoi diagram of a projection of the truncated tesseract:
The Voronoi diagram of a cube surrounded by three perpendicular circles: