2
0
mirror of https://github.com/boostorg/polygon.git synced 2026-01-27 19:12:14 +00:00
Files
polygon/doc/voronoi_basic_tutorial.htm
2012-05-10 23:20:44 +00:00

361 lines
28 KiB
HTML
Raw Blame History

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><title>Voronoi Basic Tutorial</title><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>
<h1>Voronoi Basic Tutorial<br>
</h1>
<p>In this tutorial we will cover the basic usage of the Boost.Polygon
Voronoi library that should be enough for the 95% of cases. Below we will
discuss the following topics:<br>
</p>
<ul>
<li>preparing input geometries;<br>
</li>
<li>Voronoi diagram construction;</li>
<li>Voronoi graph traversal;<br>
</li>
<li>associating the user data with the Voronoi primitives;</li>
<li>Voronoi diagram discretization and rendering.</li>
</ul>
In the example that goes through this tutorial (<a href="../example/voronoi_basic_tutorial.cpp">voronoi_basic_tutorial.cpp</a>)
we
are going to construct the Voronoi diagram of a few points and
segments.
On the image below one may see the corresponding rendered Voronoi
graph. The primary Voronoi edges
are marked with
the black color, non-primary with green, input geometries have blue
color. In
case you forgot, we split each input segment onto three sites (segment
itself and both endpoints), edges that go between those sites are
considered to be non-primary.<br>
<br>
<img style="border: 2px solid ; width: 300px; height: 300px;" alt="" src="images/voronoi4.png"><br>
<br>
And before you proceed don't forget to:<span style="font-family: Courier New,Courier,monospace;"><br>
<br>
#include "boost/polygon/voronoi.hpp"<br>
using boost::polygon;</span><br>
<h2>Preparing Input Geometries</h2>Below is the example of how the user provided point and segment classes might look like:<br>
<br><span style="font-family: Courier New,Courier,monospace;">struct Point {<br>&nbsp; int a;<br>
&nbsp; int b;<br>
&nbsp; Point (int x, int y) : a(x), b(y) {}<br>
};</span><span style="font-family: Courier New,Courier,monospace;"><br>
<br>struct Segment {</span><span style="font-family: Courier New,Courier,monospace;"></span><br>
<span style="font-family: Courier New,Courier,monospace;">
&nbsp; Point p0;<br>
&nbsp; Point p1;<br>
&nbsp; Segment (int x1, int y1, int x2, int y2) : p0(x1, y1), p1(x2, y2) {}<br>
</span><span style="font-family: Courier New,Courier,monospace;"></span>
<span style="font-family: Courier New,Courier,monospace;">};<br>
<br>
</span>As we are going to use the default routines defined in the
voronoi.hpp header to construct the Voronoi diagram, we are required to map
our point and segment classes to the corresponding Boost.Polygon concepts:<br>
<br>
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">template &lt;&gt;</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"><br>
struct geometry_concept&lt;Point&gt; { typedef point_concept type; };</span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"></span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp;&nbsp; <span class="Apple-converted-space"></span></span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"></span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">template &lt;&gt;</span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">struct point_traits&lt;</span><span style="font-family: Courier New,Courier,monospace;">Point</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&gt; {</span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; typedef int coordinate_type;</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"><br>
&nbsp; &nbsp;<span class="Apple-converted-space"> </span></span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; static inline coordinate_type get(const </span><span style="font-family: Courier New,Courier,monospace;">Point</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&amp; point,<span class="Apple-converted-space"> </span></span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">orientation_2d orient) {<br>
&nbsp;&nbsp;&nbsp; return </span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">(orient == HORIZONTAL) ? point.a : point.b;</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"></span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;"><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; }<br>
};</span><br>
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">
<br>
template &lt;&gt;<br>
</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">struct geometry_concept&lt;Segment&gt; { typedef segment_concept type; };<br>
<br>
</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">template &lt;&gt;</span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">struct point_traits&lt;</span><span style="font-family: Courier New,Courier,monospace;">Segment</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&gt; {</span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; typedef int coordinate_type;<br>
&nbsp; typedef Point point_type;<br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
</span>
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span></span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; static inline coordinate_type get(const </span><span style="font-family: Courier New,Courier,monospace;">Segment</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&amp; segment,<span class="Apple-converted-space"> direction_1d dir</span></span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">) {<br>
&nbsp;&nbsp;&nbsp; return </span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">dir.to_int() ? segment.p1() : segment.p0();</span><span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;"></span><br style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium;">
<span style="color: rgb(0, 0, 0); font-family: 'Courier New'; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; font-size: medium; display: inline ! important; float: none;">&nbsp; }<br>};</span><br>
<br>
It's also possible to use the native Boost.Polygon types as <a href="../../../boost/polygon/point_data.hpp">point_data</a> and <a href="../../../boost/polygon/segment_data.hpp">segment_data</a>, that won't require the above mapping.<br>
<br>
So once we are done we can create the sample input:<br>
<br>
<span style="font-family: Courier New,Courier,monospace;">std::vector&lt;Point&gt;
points;<br>
points.push_back(Point(0, 0));<br>
points.push_back(Point(1, 6));<br>
std::vector&lt;Segment&gt; segments;<br>
segments.push_back(Segment(-4, 5, 5, -1));<br>
segments.push_back(Segment(3, -11, 13, -1));</span><span style="font-family: Courier New,Courier,monospace;"><br>
</span>
<h2>Construction of the Voronoi Diagram<br>
</h2>At this point we are ready to construct the Voronoi diagram:<br>
<span style="font-family: Courier New,Courier,monospace;"><br>
</span><span style="font-family: Courier New,Courier,monospace;">
voronoi_diagram&lt;double&gt; vd;<br>
construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &amp;vd);<br>
</span><br>
So brief, isn't that awesome!<br>
<h2>Traversing Voronoi Graph</h2>
Voronoi graph traversal is the basic
operation one would like to do once the Voronoi diagram is constructed.
There are three ways to do that and we are going to cover all of them:<br>
<ul>
<li>simply iterating over the Voronoi edges (counts each edge twice):<br>
<span style="font-family: Courier New,Courier,monospace;"><br>
int iterate_primary_edges1(const voronoi_diagram&lt;double&gt; &amp;vd)
{<br>
&nbsp; int result = 0;<br>
&nbsp; for (voronoi_diagram&lt;double&gt;::const_edge_iterator it =
vd.edges().begin();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it != vd.edges().end(); ++it) {<br>
&nbsp;&nbsp;&nbsp; if (it-&gt;is_primary())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++result;<br>
&nbsp; }<br>
&nbsp; return result;<br>
}</span><br>
<span style="font-family: Courier New,Courier,monospace;">&nbsp;</span><br>
</li>
<li>iterating over the Voronoi cells and then traversing edges around
each cell (counts each edge twice):<br>
<br>
<span style="font-family: Courier New,Courier,monospace;">int
iterate_primary_edges2(const voronoi_diagram&lt;double&gt; &amp;vd) {<br>
&nbsp; int result = 0;<br>
&nbsp; for (voronoi_diagram&lt;double&gt;::const_cell_iterator it =
vd.cells().begin();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it != vd.cells().end(); ++it) {<br>
&nbsp;&nbsp;&nbsp; const voronoi_diagram&lt;double&gt;::cell_type
&amp;cell = *it;<br>
&nbsp;&nbsp;&nbsp; const voronoi_diagram&lt;double&gt;::edge_type *edge
= cell.incident_edge();<br>
&nbsp;&nbsp;&nbsp; // This is convenient way to iterate edges around
Voronoi cell.<br>
&nbsp;&nbsp;&nbsp; do {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (edge-&gt;is_primary())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++result;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; edge = edge-&gt;next();<br>
&nbsp;&nbsp;&nbsp; } while (edge != cell.incident_edge());<br>
&nbsp; }<br>
&nbsp; return result;<br>
}</span><br>
<br>
</li>
<li>iterating over the Voronoi
vertices and then traversing edges around each vertex (the number of the
iterations through each edge is equal to the number of finite endpoints
of the edge):<span style="font-family: Courier New,Courier,monospace;"></span><br>
<span style="font-family: Courier New,Courier,monospace;">int
iterate_primary_edges3(const voronoi_diagram&lt;double&gt; &amp;vd) {<br>
&nbsp; int result = 0;<br>
&nbsp; for (voronoi_diagram&lt;double&gt;::const_vertex_iterator it =
vd.vertices().begin();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it != vd.vertices().end(); ++it) {<br>
&nbsp;&nbsp;&nbsp; const voronoi_diagram&lt;double&gt;::vertex_type
&amp;vertex = *it;<br>
&nbsp;&nbsp;&nbsp; const voronoi_diagram&lt;double&gt;::edge_type *edge
= vertex.incident_edge();<br>
&nbsp;&nbsp;&nbsp; // This is convenient way to iterate edges around
Voronoi vertex.<br>
&nbsp;&nbsp;&nbsp; do {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (edge-&gt;is_primary())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ++result;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; edge = edge-&gt;rot_next();<br>
&nbsp;&nbsp;&nbsp; } while (edge != vertex.incident_edge());<br>
&nbsp; }<br>
&nbsp; return result;<br>
}</span></li>
</ul>
This should give a very nice idea on how to do the Voronoi
diagram traversal. Notice that while the output from the first two methods should
be the same, it wouldn't for the third one. The reason is that in the
last case we will iterate only once through the edges with a single
finite endpoint and will skip all the edges with no finite endpoints.<br>
<h2>Associating User Data with Voronoi Primitives</h2>
A few simple cases of associating the user data with the Voronoi primitives are
following:<br>
<ul>
<li>associating number of incident edges with each cell, vertex;</li>
<li>associating color information with each edge;</li>
<li>using DFS or BFS on the Voronoi graph requires to mark visited
edges/vertices/cells.</li>
</ul>
We will consider the first example and will associate the total number
of incident edges with each cell.<br>
Note: Each Voronoi primitive contains mutable pointer to the void* type,
that allows to associate any type of data with it.<br>
<br>
<span style="font-family: Courier New,Courier,monospace;">std::vector&lt;int&gt;
counts;</span><br>
<span style="font-family: Courier New,Courier,monospace;">// This is
required as reallocation of underlying vector will invalidate all the
pointers.<br>
counts.reserve(vd.num_cells());<br>
for (voronoi_diagram&lt;double&gt;::const_cell_iterator it =
vd.cells().begin();<br>
&nbsp;&nbsp;&nbsp;&nbsp; it != vd.cells().end(); ++it) {<br>
&nbsp; const voronoi_diagram&lt;double&gt;::cell_type &amp;cell = *it;<br>
&nbsp; const voronoi_diagram&lt;double&gt;::edge_type *edge =
cell.incident_edge();<br>
&nbsp; int count = 0;<br>
&nbsp; do {<br>
&nbsp;&nbsp;&nbsp; ++count;<br>
&nbsp;&nbsp;&nbsp; edge = edge-&gt;next();<br>
&nbsp; } while (edge != cell.incident_edge());<br>
&nbsp; counts.push_back(count);<br>
&nbsp; cell.data(&amp;counts.back());<br>
}</span><span style="font-family: Courier New,Courier,monospace;"><br>
</span><br>
Note: In the example above we could not use count variable
without the vector, because the pointer to it will become invalid as soon as
we leave the scope of the enclosing for-loop.<br>
<h2>Rendering Voronoi Diagram</h2>
There are two main issues that don't allow to strictly render the resulting
Voronoi diagram using such rendering tools as OpenGL or DirectX.
Those are:<br>
<ul>
<li>Some of the Voronoi edges are infinite, so should be clipped;</li>
<li>Some of the Voronoi edge are parabolic arcs, so should be
discretized.</li>
</ul>
Note: This would be the issues not only for rendering tools.
Basically every task that requires diagram to be represented as a set
of finite segments will fall into this category.<br>
<br>
All the above functionality is already implemented in the Voronoi
utils.
Before clipping an edge we are going to define the clipping rectangle.
It is practical to choose it so that it wraps all the input geometries
plus some offset.<br>
<span style="font-family: Courier New,Courier,monospace;"><br>
bounding_rectangle&lt;double&gt; bbox;<br>for (std::vector&lt;Point&gt;::iterator it = points.begin(); it != points.end(); ++it)<br>
&nbsp; bbox.update(it-&gt;a, it-&gt;b);<br>
for (std::vector&lt;Segment&gt;::iterator it = segments.begin(); it != segments.end(); ++it) {<br>
&nbsp; bbox.update(it-&gt;p0.a, it-&gt;p0.b);<br>
&nbsp; bbox.update(it-&gt;p1.a, it-&gt;p1.b);<br>
}<br>
// Add 10% offset to the bounding rectangle.<br>
bbox = voronoi_utils&lt;double&gt;::scale(bbox, 1.1);</span><span style="font-family: Courier New,Courier,monospace;"><br>
</span><br>
Now lets consider that we have the 3rd party library function that
draws segments using the following prototype:<span style="font-family: Courier New,Courier,monospace;"><br>
<br>
void draw_segment(double x1, double y1, double x2, double y2);<br>
<br>
</span>Then the function that renders our diagram edges will have the
following implementation:<br>
<br>
<span style="font-family: Courier New,Courier,monospace;">void
render_diagram(const voronoi_diagram&lt;double&gt; &amp;vd,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
const voronoi_utils&lt;double&gt;::brect_type &amp;bbox) {<br>
&nbsp; int visited = 1;<br>
&nbsp; for (voronoi_diagram&lt;double&gt;::const_edge_iterator it =
vd.edges().begin();<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it != vd.edges().end(); ++it) {<br>
&nbsp;&nbsp;&nbsp; // We use data pointer to mark visited edges.<br>
&nbsp;&nbsp;&nbsp; it-&gt;data(&amp;visited);<br>
&nbsp;&nbsp;&nbsp; // Don't render the same edge twice.<br>
&nbsp;&nbsp;&nbsp; if (it-&gt;twin()-&gt;data()) continue;<br>
&nbsp;&nbsp;&nbsp; voronoi_utils&lt;double&gt;::point_set_type polyline;<br>
&nbsp;&nbsp;&nbsp; if (it-&gt;is_linear())<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; voronoi_utils&lt;double&gt;::clip(*it,
bbox, polyline);<br>
&nbsp;&nbsp;&nbsp; else<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Parabolic edges are always finite.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
voronoi_utils&lt;double&gt;::discretize(*it, 1E-1, polyline);<br>
&nbsp;&nbsp;&nbsp; // Note: discretized edge segments may also lie
outside of the bbox.<br>
&nbsp;&nbsp;&nbsp; for (int i = 1; i &lt; polyline.size(); ++i)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; draw_segment(polyline[i-1].x(),
polyline[i-1].y(),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
polyline[i].x(), polyline[i].y());<br>
&nbsp; }<br>
}<br>
<br>
</span><a href="../example/voronoi_visualizer.cpp">voronoi_visualizer.cpp</a>
contains a simple fully featured implementation of the Voronoi diagram
renderer using the Qt libraries. It was used to generate all the .png
drawings under the ./libs/polygon/example directory.<span style="text-decoration: underline;"><br>
</span><span style="font-family: Courier New,Courier,monospace;">
<br>
</span>I hope the reader managed to get to this point and found the
basic tutorial to be useful (in the end it's not so basic). Worth
to notice that construction of the Voronoi diagram takes only two lines
of code, everything else is about initializing input data structures,
traversing Voronoi graph, associating data with the diagram primitives and
using the <a href="voronoi_utils.htm">Voronoi utilities</a>. In the
default mode the Voronoi diagram operates with the signed int (32-bit) input
coordinate type and double (64-bit) output coordinate type. In the <a href="voronoi_advanced_tutorial.htm">advanced Voronoi tutorial</a> we
explain why this is enough for the 95% of cases and how to expand the
algorithm coordinate types for the other 5%.<br>
<span style="font-family: Courier New,Courier,monospace;"></span><br>
<table class="docinfo" id="table1" frame="void" rules="none">
<colgroup> <col class="docinfo-name"><col class="docinfo-content"> </colgroup>
<tbody valign="top">
<tr>
<th class="docinfo-name">Copyright:</th>
<td>Copyright <20> Andrii Sydorchuk 2010-2012.</td>
</tr>
<tr class="field">
<th class="docinfo-name">License:</th>
<td class="field-body">Distributed under the Boost Software
License, Version 1.0. (See accompanying file <tt class="literal"> <span class="pre">LICENSE_1_0.txt</span></tt> or copy at <a class="reference" target="_top" href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)</td>
</tr>
</tbody>
</table>
</body></html>