1 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN">
6 <meta http-equiv=
"Content-Type" content=
"text/html; charset=windows-1252"><title>Voronoi Advanced Tutorial
</title></head><body>
7 <h1>Voronoi Advanced Tutorial
<br>
10 This tutorial consists of two parts. The first one provides two
11 examples of a real world problems that default configuration of Voronoi
12 library is capable to solve. By default configuration we mean the one
14 signed
32-bit integer and outputs floating-point (
64-bit
15 double) coordinates. We provide those examples to convince even the
16 most skeptical users that they probably don't need to configure library
17 for higher-precision input or output coordinate types. However if the
18 posed problem really requires those, fully featured configuration of
19 both input and output coordinate types is provided in the second part
24 <h3>Problem Statement
</h3>
26 <img style=
"width: 665px; height: 369px;" alt=
"" src=
"images/rover.jpg"><br>
28 <br>Lets imagine that NASA is
29 planning to send a new robot to Mars. Each day the center situated on Earth
30 will send a destination point coordinates the robot needs to reach by
31 the end of the day. Of course we'd like to save as much energy as
32 possible thus choosing the shortest possible path. This would be a
33 straight line in a perfect world (we don't consider curvature of
34 surface), but situation becomes more complicated as there are some
35 rocks and wells on Mars our robot can't go through. Behind of those our
36 robot has some dimensions that might not allow it to pass narrow places.
<br>
38 <h3>Application of Voronoi diagram
</h3>
40 The problem above could be solved using Voronoi diagram. The first
41 stage would be to discretize obstacles (rocks and wells) with
42 polylines. Afterwards we will compute Voronoi diagram of the input set
43 of segments. As each Voronoi edge is equidistant from the two closest
44 sites we are able to filter edges the robot won't be able to pass due
45 to it's dimensions. The last step would be to run a bit optimized A*
47 the shortest or at least suboptimal path and we are done.
<br>
49 <h3>Discretization of input geometries
</h3>
51 To show how good is the default input coordinate type provided by the
53 we will discretize the whole area of Mars. That will be approximately
54 1.44 *
10^
8 square kilometres that is equal to
1.44 *
55 10^
18 square centimetres, which could be snapped to the integer
56 grid with a side of
1.2 *
10^
9 centimetres.
To make the Voronoi
58 precise on the boundaries of that grid we will replicate input map
9
59 times (
3x3), thus Voronoi diagram within a central piece will
60 provide us with a correct connectivity graph. This step will increase
61 the size of our grid to
3.6 *
10^
9 centimetres that is less than
2^
32.
62 So we are able to discretize the Red Planet's surface within a
1
64 precision using the default input coordinate type (signed
32-bit
65 integer). That would imply maximum absolute error to be
66 equal up to
0.5 centimetres per coordinate. Considering the radius of
68 0.3 metres and for security reasons avoiding any large enough obstacles
69 that are within
1 metre distance from it that error would be irrelevant.
<br>
71 <span style=
"color: rgb(0, 0, 0); font-family: sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 13px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; background-color: rgb(249, 249, 249); display: inline ! important; float: none;"></span>
72 <h3>Output analysis
</h3>
74 Estimates of the resulting Voronoi diagram precision were already
75 explained
<a href=
"voronoi_main.htm">here
</a>.
76 So to avoid those computations again we will simply state that the
77 maximum absolute error of the output geometries will be on the grid
78 boundaries and will be equal to
2^-
16 centimetres, which is
79 approximately equal to
150 nanometres and is
100 times larger than
80 a radius of a complex molecule. We would like to notice that the
81 absolute error of the discretization step is much higher than the one
82 produced by the Voronoi diagram construction algorithm.
85 <h3>Problem Statement
</h3>
87 <img style=
"width: 400px; height: 283px;" alt=
"" src=
"images/vlsi.jpg"><br>
91 Very-large-scale integration (
<a href=
"http://www.rulabinsky.com/cavd/index.html">VLSI
</a>) is the
93 integrated circuits by combining thousands of transistors into a single
94 chip. Considering the fact that it may take weeks or months to get an
95 integrated circuit manufactured, designers often spend large amounts of
96 time analyzing their layouts to avoid costly mistakes. One of the
97 common static analysis checks is minimum distance requirement between
98 the components of an integrated circuit (distance should be greater
100 specified value).
<br>
102 <h3>Application of Voronoi diagram
</h3>
104 It appears that the minimum distance between components of the input
105 set of points and segments corresponds to the one of the Voronoi
106 diagram edges. This means that we can iterate through each edge of
107 the Voronoi graph, extract the pair of input geometries that form it
109 the distance between those. As the total amount of such edges is O(N)
111 (N - is the number of input geometries) the minimum distance could be
112 efficiently find in a linear time once we construct the diagram.
<br>
114 <h3>Discretization of input geometries
</h3>
116 The average size of the modern CPUs is around
2.5 x
2.5 centimetres.
117 Snapping this to the
32-bit integer grid will give discretization
118 precision of
2.5 /
2^
33 centimetres or
3 picometres that is
10 times
119 smaller value than radius of an atom. That would be probably good
120 enough precision even for a few next generations of processors.
<br>
122 <h3>Output analysis
</h3>
124 The maximum absolute error of the output geometries will be
2.5 /
2^
47
125 centimetres or
0.2 femtometres that is
10 times smaller value than
126 the radius of an electron. However in this particular case we are not
127 interested in the precision of the output, rather in its topology. As
129 the
<a href=
"voronoi_main.htm">Voronoi main page
</a> very small edges
130 are removed from the Voronoi diagram. However user should not worry
131 because the edge that correspond to the minimal distance won't be among
132 those. That means that we would be able to
100% correctly identify a
133 pair of closest objects within the discretization precision.
<br>
137 The above two examples show usage of the default Voronoi coordinate
139 in the macro and micro world. The main point of those was to give the user
140 understanding of a scale that the default coordinate types provide. There
142 two main points we didn't mention before, but that would be relevant to
143 the most real world problems:
<br>
147 <li>The absolute error of the coordinates of the output Voronoi
149 inside the
32-bit integer discretization grid is slightly smaller than
150 the absolute error of discretization itself, thus could be neglected at
152 <li>In both problems above we didn't consider error of measurement.
153 For example: is it possible to construct a map of the Mars within the
155 centimetres precision, or to get coordinates of the circuit parts
156 withing the subatomic precision? I guess the answer for both questions
157 would be
"No". And that actually means that the error of the
159 step could be neglected comparing to the error produced by the
164 The second statement means that there is actually no point to provide
165 implementation that operates with floating-point input coordinates,
166 because those always could be snapped to the integer grid. In case the
167 user is not satisfied with the precision that the
32-bit integer grid
168 provides or would like to retrieve coordinates of the output geometries
170 relative error, follow the next paragraph.
<br>
172 <h2>Voronoi Coordinate Types Configuration
</h2>
174 In the following chapter we are going to extend input coordinate type
176 integer and output coordinate type to the
80-bit IEEE floating-point
178 (long double). The code for this chapter is available in
<a href=
"../example/voronoi_advanced_tutorial.cpp">voroni_advanced_tutorial.cpp
</a>.
179 While it won't be possible to compile it using the MSVC compiler (it
181 support
80-bit long double type; ieee754.h header is required), it
182 should give a clear understanding of how the library supports the user
183 provided coordinate types.
<br>
187 So the main step would be to declare the voronoi coordinate type traits
188 that satisfy set of restrictions explained
<a href=
"voronoi_builder.htm">here
</a>:
<br>
192 <span style=
"font-family: Courier New,Courier,monospace;">struct
193 my_voronoi_ctype_traits {
</span><br style=
"font-family: Courier New,Courier,monospace;">
195 <span style=
"font-family: Courier New,Courier,monospace;">
196 typedef boost::int64_t int_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
198 <span style=
"font-family: Courier New,Courier,monospace;">
199 typedef detail::extended_int
<3> int_x2_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
201 <span style=
"font-family: Courier New,Courier,monospace;">
202 typedef detail::extended_int
<3> uint_x2_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
204 <span style=
"font-family: Courier New,Courier,monospace;">
205 typedef detail::extended_int
<128> big_int_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
207 <span style=
"font-family: Courier New,Courier,monospace;">
208 typedef fpt80 fpt_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
210 <span style=
"font-family: Courier New,Courier,monospace;">
211 typedef fpt80 efpt_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
213 <span style=
"font-family: Courier New,Courier,monospace;">
214 typedef my_ulp_comparison ulp_cmp_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
216 <span style=
"font-family: Courier New,Courier,monospace;">
217 typedef my_fpt_converter to_fpt_converter_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
219 <span style=
"font-family: Courier New,Courier,monospace;">
220 typedef my_fpt_converter to_efpt_converter_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
222 <span style=
"font-family: Courier New,Courier,monospace;">};
<br>
224 </span>It is always better to use C++ built-in types wherever it's
225 possible. That's why we use the
64-bit signed integer type to handle
227 input coordinates.
<span style=
"font-family: Courier New,Courier,monospace;">int_x2_type
</span>
228 and
<span style=
"font-family: Courier New,Courier,monospace;">uint_x2_type
</span>
229 is required to handle
96-bit signed/unsigned integers. As there is no
230 such built-in type we use library provided efficient fixed integer
232 The big integer type should be capable to handle
48 *
64 bit integers,
234 less than
32 *
128, and so far we are good with
<span style=
"font-family: Courier New,Courier,monospace;">extended_int
<128></span>
235 type. We use the same floating point type for both
<span style=
"font-family: Courier New,Courier,monospace;">fpt_type
</span>
236 and
<span style=
"font-family: Courier New,Courier,monospace;">efpt_type
</span>
237 as it has enough exponent bits to represent both
48 *
32 bit and
48 *
238 64 bit integers (that is also the reason we don't need two
239 floating-point converter structures). The
<span style=
"font-family: Courier New,Courier,monospace;">ulp_cmp_type
</span>
240 structure checks weather two IEEE floating-point values are within the
241 given signed integer ulp range (we won't analyze corresponding code
242 here as it requires deep understanding of the
<a href=
"http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html">floating-point
243 architecture
</a> and its
<a href=
"../../../boost/polygon/detail/voronoi_ctypes.hpp">usage to compare
244 floating-point values
</a>), but just to mention the declaration is
247 <span style=
"font-family: Courier New,Courier,monospace;"></span><br style=
"font-family: Courier New,Courier,monospace;">
249 <span style=
"font-family: Courier New,Courier,monospace;">struct
250 my_ulp_comparison {
</span><br style=
"font-family: Courier New,Courier,monospace;">
252 <span style=
"font-family: Courier New,Courier,monospace;"> enum
253 Result {
</span><span style=
"font-family: Courier New,Courier,monospace;"><br>
254 LESS = -
1,
</span><br style=
"font-family: Courier New,Courier,monospace;">
256 <span style=
"font-family: Courier New,Courier,monospace;">
257 EQUAL =
0,
</span><br style=
"font-family: Courier New,Courier,monospace;">
259 <span style=
"font-family: Courier New,Courier,monospace;">
260 MORE =
1</span><br style=
"font-family: Courier New,Courier,monospace;">
262 <span style=
"font-family: Courier New,Courier,monospace;"> };
</span><br style=
"font-family: Courier New,Courier,monospace;">
264 <span style=
"font-family: Courier New,Courier,monospace;"> Result
265 operator()(fpt80 a, fpt80 b, unsigned int maxUlps) const;
</span><br style=
"font-family: Courier New,Courier,monospace;">
267 <span style=
"font-family: Courier New,Courier,monospace;">};
<br>
269 </span>The last step would be to declare the
<span style=
"font-family: Courier New,Courier,monospace;">my_fpt_converter
</span>
270 structure (converts the integer types to the floating-point type):
<br>
274 <span style=
"font-family: Courier New,Courier,monospace;">struct
275 my_fpt_converter {
</span><br style=
"font-family: Courier New,Courier,monospace;">
277 <span style=
"font-family: Courier New,Courier,monospace;">
278 template
<typename T
></span><br style=
"font-family: Courier New,Courier,monospace;">
280 <span style=
"font-family: Courier New,Courier,monospace;"> fpt80
281 operator()(const T
& that) const {
</span><br style=
"font-family: Courier New,Courier,monospace;">
283 <span style=
"font-family: Courier New,Courier,monospace;">
284 return static_cast
<fpt80
>(that);
</span><br style=
"font-family: Courier New,Courier,monospace;">
286 <span style=
"font-family: Courier New,Courier,monospace;"> }
</span><br style=
"font-family: Courier New,Courier,monospace;">
288 <br style=
"font-family: Courier New,Courier,monospace;">
290 <span style=
"font-family: Courier New,Courier,monospace;">
291 template
<size_t N
></span><br style=
"font-family: Courier New,Courier,monospace;">
293 <span style=
"font-family: Courier New,Courier,monospace;"> fpt80
294 operator()(const typename detail::extended_int
<N
>& that)
295 const {
</span><br style=
"font-family: Courier New,Courier,monospace;">
297 <span style=
"font-family: Courier New,Courier,monospace;">
298 fpt80 result =
0.0;
</span><br style=
"font-family: Courier New,Courier,monospace;">
300 <span style=
"font-family: Courier New,Courier,monospace;">
301 for (size_t i =
1; i
<= (std::min)((size_t)
3, that.size()); ++i) {
</span><br style=
"font-family: Courier New,Courier,monospace;">
303 <span style=
"font-family: Courier New,Courier,monospace;">
304 if (i !=
1)
</span><br style=
"font-family: Courier New,Courier,monospace;">
306 <span style=
"font-family: Courier New,Courier,monospace;">
307 result *= static_cast
<fpt80
>(
0x100000000ULL);
</span><br style=
"font-family: Courier New,Courier,monospace;">
309 <span style=
"font-family: Courier New,Courier,monospace;">
310 result += that.chunks()[that.size() - i];
</span><br style=
"font-family: Courier New,Courier,monospace;">
312 <span style=
"font-family: Courier New,Courier,monospace;">
313 }
</span><br style=
"font-family: Courier New,Courier,monospace;">
315 <span style=
"font-family: Courier New,Courier,monospace;">
316 return (that.count()
< 0) ? -result : result;
</span><br style=
"font-family: Courier New,Courier,monospace;">
318 <span style=
"font-family: Courier New,Courier,monospace;"> }
</span><br style=
"font-family: Courier New,Courier,monospace;">
320 <span style=
"font-family: Courier New,Courier,monospace;">};
<br>
322 </span>At this point we are done with declaration of the Voronoi
323 coordinate type traits. The next step is to declare the Voronoi diagram
328 <span style=
"font-family: Courier New,Courier,monospace;">struct
329 my_voronoi_diagram_traits {
</span><br style=
"font-family: Courier New,Courier,monospace;">
331 <span style=
"font-family: Courier New,Courier,monospace;">
332 typedef fpt80 coordinate_type;
</span><span style=
"font-family: Courier New,Courier,monospace;"></span><span style=
"font-family: Courier New,Courier,monospace;"></span><br style=
"font-family: Courier New,Courier,monospace;">
334 <span style=
"font-family: Courier New,Courier,monospace;">
335 typedef voronoi_cell
<coordinate_type
> cell_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
337 <span style=
"font-family: Courier New,Courier,monospace;">
338 typedef voronoi_vertex
<coordinate_type
> vertex_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
340 <span style=
"font-family: Courier New,Courier,monospace;">
341 typedef voronoi_edge
<coordinate_type
> edge_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
343 <span style=
"font-family: Courier New,Courier,monospace;">
344 typedef struct {
</span><br style=
"font-family: Courier New,Courier,monospace;">
346 <span style=
"font-family: Courier New,Courier,monospace;"> public:
</span><br style=
"font-family: Courier New,Courier,monospace;">
348 <span style=
"font-family: Courier New,Courier,monospace;">
349 enum { ULPS =
128 };
</span><br style=
"font-family: Courier New,Courier,monospace;">
351 <span style=
"font-family: Courier New,Courier,monospace;">
352 bool operator()(const point_type
&v1, const point_type
&v2)
353 const {
</span><br style=
"font-family: Courier New,Courier,monospace;">
355 <span style=
"font-family: Courier New,Courier,monospace;">
356 return (ulp_cmp(v1.x(), v2.x(), ULPS) == my_ulp_comparison::EQUAL
357 &&</span><br style=
"font-family: Courier New,Courier,monospace;">
359 <span style=
"font-family: Courier New,Courier,monospace;">
360 ulp_cmp(v1.y(), v2.y(), ULPS) == my_ulp_comparison::EQUAL);
</span><br style=
"font-family: Courier New,Courier,monospace;">
362 <span style=
"font-family: Courier New,Courier,monospace;">
363 }
</span><br style=
"font-family: Courier New,Courier,monospace;">
365 <span style=
"font-family: Courier New,Courier,monospace;">
366 private:
</span><br style=
"font-family: Courier New,Courier,monospace;">
368 <span style=
"font-family: Courier New,Courier,monospace;">
369 my_ulp_comparison ulp_cmp;
</span><br style=
"font-family: Courier New,Courier,monospace;">
371 <span style=
"font-family: Courier New,Courier,monospace;"> }
372 vertex_equality_predicate_type;
</span><br style=
"font-family: Courier New,Courier,monospace;">
374 <span style=
"font-family: Courier New,Courier,monospace;">};
</span><br>
376 <span style=
"font-family: Courier New,Courier,monospace;"></span><br>
378 Above we simply declared the Voronoi primitive types
380 equality predicate using the new coordinate type and corresponding ulp
381 comparison structure. As we are done with the declaration of the
383 type specific structures we are ready to proceed to the construction
384 step itself. The first step would be to initialize voronoi_builder
385 structure with a set of random points:
<br>
389 <span style=
"font-family: Courier New,Courier,monospace;">// Random
390 generator and distribution. MAX is equal to
2^
48.
</span><br>
392 <span style=
"font-family: Courier New,Courier,monospace;">boost::mt19937_64
393 gen(std::time(
0));
</span><br style=
"font-family: Courier New,Courier,monospace;">
395 <span style=
"font-family: Courier New,Courier,monospace;">boost::random::uniform_int_distribution
<boost::int64_t
>
396 distr(-MAX, MAX-
1);
<br>
398 </span><span style=
"font-family: Courier New,Courier,monospace;">
399 // Declaring and configuring Voronoi builder with the new coordinate
401 voronoi_builder
<boost::int64_t, my_voronoi_ctype_traits
> vb;
</span><br>
402 <span style=
"font-family: Courier New,Courier,monospace;"></span><br style=
"font-family: Courier New,Courier,monospace;">
404 <span style=
"font-family: Courier New,Courier,monospace;">// Voronoi
405 builder initialization step.
<br>
406 for (size_t i =
0; i
< GENERATED_POINTS; ++i) {
</span><br style=
"font-family: Courier New,Courier,monospace;">
408 <span style=
"font-family: Courier New,Courier,monospace;">
409 boost::int64_t x = distr(gen);
</span><br style=
"font-family: Courier New,Courier,monospace;">
411 <span style=
"font-family: Courier New,Courier,monospace;">
412 boost::int64_t y = distr(gen);
</span><br style=
"font-family: Courier New,Courier,monospace;">
414 <span style=
"font-family: Courier New,Courier,monospace;">
415 vb.insert_point(x, y);
</span><br style=
"font-family: Courier New,Courier,monospace;">
417 <span style=
"font-family: Courier New,Courier,monospace;">}
<br>
419 </span>The second step would be to generate the Voronoi diagram and
420 this is done as before with the two lines of code:
<br>
424 <span style=
"font-family: Courier New,Courier,monospace;">// Declaring
425 and configuring Voronoi diagram structure with the new coordinate type
427 voronoi_diagram
<fpt80, my_voronoi_diagram_traits
> vd;
</span><br>
429 <span style=
"font-family: Courier New,Courier,monospace;">vb.construct(
&vd);
<br>
431 </span>From this point the user can operate with the Voronoi diagram
433 and in our tutorial we output some simple stats of the resulting
434 Voronoi graph. Probably the hardest part of this tutorial is
435 the declaration of the ulp comparison structure. The library provides
436 efficient well-commented cross-platform implementation for
64-bit
437 floating-point type (double). So the best advice would be to follow
438 that implementation, but before doing that really consider thoughtfully if the
440 coordinate types are not capable to deal with your problem.
<br>
444 <table class=
"docinfo" id=
"table1" frame=
"void" rules=
"none">
446 <colgroup> <col class=
"docinfo-name"><col class=
"docinfo-content"> </colgroup>
449 <th class=
"docinfo-name">Copyright:
</th>
450 <td>Copyright © Andrii Sydorchuk
2010-
2012.
</td>
453 <th class=
"docinfo-name">License:
</th>
454 <td class=
"field-body">Distributed under the Boost Software
455 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">
456 http://www.boost.org/LICENSE_1_0.txt
</a>)
</td>