]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/polygon/doc/voronoi_advanced_tutorial.htm
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / polygon / doc / voronoi_advanced_tutorial.htm
CommitLineData
7c673cae
FG
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html><head>
3
4
5
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>
8</h1>
9
10This tutorial consists of two parts. The first one provides two
11examples of a real world problems that default configuration of Voronoi
12library is capable to solve. By default configuration we mean the one
13that accepts
14signed 32-bit integer and outputs floating-point (64-bit
15double) coordinates. We provide those examples to convince even the
16most skeptical users that they probably don't need to configure library
17for higher-precision input or output coordinate types. However if the
18posed problem really requires those, fully featured configuration of
19both input and output coordinate types is provided in the second part
20of this tutorial.<br>
21
22<h2>Red Planet</h2>
23
24<h3>Problem Statement</h3>
25
26<img style="width: 665px; height: 369px;" alt="" src="images/rover.jpg"><br>
27
28<br>Lets imagine that NASA is
29planning to send a new robot to Mars. Each day the center situated on Earth
30will send a destination point coordinates the robot needs to reach by
31the end of the day. Of course we'd like to save as much energy as
32possible thus choosing the shortest possible path. This would be a
33straight line in a perfect world (we don't consider curvature of
34surface), but situation becomes more complicated as there are some
35rocks and wells on Mars our robot can't go through. Behind of those our
36robot has some dimensions that might not allow it to pass narrow places.<br>
37
38<h3>Application of Voronoi diagram</h3>
39
40The problem above could be solved using Voronoi diagram. The first
41stage would be to discretize obstacles (rocks and wells) with
42polylines. Afterwards we will compute Voronoi diagram of the input set
43of segments. As each Voronoi edge is equidistant from the two closest
44sites we are able to filter edges the robot won't be able to pass due
45to it's dimensions. The last step would be to run a bit optimized A*
46algorithm to find
47the shortest or at least suboptimal path and we are done.<br>
48
49<h3>Discretization of input geometries</h3>
50
51To show how good is the default input coordinate type provided by the
52Voronoi library
53we will discretize the whole area of Mars. That will be approximately
541.44 *&nbsp; 10^8&nbsp; square kilometres that is equal to 1.44 *&nbsp;
5510^18&nbsp; square centimetres, which could be snapped to the integer
56grid with a side of 1.2 * 10^9 centimetres.&nbsp; To make the Voronoi
57graph
58precise on the boundaries of that grid we will replicate input map 9
59times (3x3), thus Voronoi diagram within a central piece will
60provide us with a correct connectivity graph. This step will increase
61the size of our grid to 3.6 * 10^9 centimetres that is less than 2^32.
62So we are able to discretize the Red Planet's surface within a 1
63centimetre
64precision using the default input coordinate type (signed 32-bit
65integer). That would imply maximum absolute error to be
66equal up to 0.5 centimetres per coordinate. Considering the radius of
67our robot to be
680.3 metres and for security reasons avoiding any large enough obstacles
69that are within 1 metre distance from it that error would be irrelevant.<br>
70
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>
73
74Estimates of the resulting Voronoi diagram precision were already
75explained <a href="voronoi_main.htm">here</a>.
76So to avoid those computations again we will simply state that the
77maximum absolute error of the output geometries will be on the grid
78boundaries and will be equal to 2^-16 centimetres, which is
79approximately equal to 150 nanometres and is 100 times larger than
80a radius of a complex molecule. We would like to notice that the
81absolute error of the discretization step is much higher than the one
82produced by the Voronoi diagram construction algorithm.
83<h2>VLSI Design</h2>
84
85<h3>Problem Statement</h3>
86
87<img style="width: 400px; height: 283px;" alt="" src="images/vlsi.jpg"><br>
88
89<br>
90
91Very-large-scale integration (<a href="http://www.rulabinsky.com/cavd/index.html">VLSI</a>) is the
92process of creating
93integrated circuits by combining thousands of transistors into a single
94chip. Considering the fact that it may take weeks or months to get an
95integrated circuit manufactured, designers often spend large amounts of
96time analyzing their layouts to avoid costly mistakes. One of the
97common static analysis checks is minimum distance requirement between
98the components of an integrated circuit (distance should be greater
99than
100specified value).<br>
101
102<h3>Application of Voronoi diagram</h3>
103
104It appears that the minimum distance between components of the input
105set of points and segments corresponds to the one of the Voronoi
106diagram edges. This means that we can iterate through each edge of
107the Voronoi graph, extract the pair of input geometries that form it
108and find
109the distance between those. As the total amount of such edges is O(N)
110value
111(N - is the number of input geometries) the minimum distance could be
112efficiently find in a linear time once we construct the diagram.<br>
113
114<h3>Discretization of input geometries</h3>
115
116The average size of the modern CPUs is around 2.5 x 2.5 centimetres.
117Snapping this to the 32-bit integer grid will give discretization
118precision of 2.5 / 2^33 centimetres or 3 picometres that is 10 times
119smaller value than radius of an atom. That would be probably good
120enough precision even for a few next generations of processors.<br>
121
122<h3>Output analysis</h3>
123
124The maximum absolute error of the output geometries will be 2.5 / 2^47
125centimetres or 0.2 femtometres that is 10 times smaller value than
126the radius of an electron. However in this particular case we are not
127interested in the precision of the output, rather in its topology. As
128it was noticed on
129the <a href="voronoi_main.htm">Voronoi main page</a> very small edges
130are removed from the Voronoi diagram. However user should not worry
131because the edge that correspond to the minimal distance won't be among
132those. That means that we would be able to 100% correctly identify a
133pair of closest objects within the discretization precision.<br>
134
135<h2>Conclusions</h2>
136
137The above two examples show usage of the default Voronoi coordinate
138types
139in the macro and micro world. The main point of those was to give the user
140understanding of a scale that the default coordinate types provide. There
141are
142two main points we didn't mention before, but that would be relevant to
143the most real world problems:<br>
144
145<ul>
146
147 <li>The absolute error of the coordinates of the output Voronoi
148diagram
149inside the 32-bit integer discretization grid is slightly smaller than
150the absolute error of discretization itself, thus could be neglected at
151all.</li>
152 <li>In both problems above we didn't consider error of measurement.
153For example: is it possible to construct a map of the Mars within the
1540.5
155centimetres precision, or to get coordinates of the circuit parts
156withing the subatomic precision? I guess the answer for both questions
157would be "No". And that actually means that the error of the
158discretization
159step could be neglected comparing to the error produced by the
160measuring
161devices.<br>
162 </li>
163</ul>
164The second statement means that there is actually no point to provide
165implementation that operates with floating-point input coordinates,
166because those always could be snapped to the integer grid. In case the
167user is not satisfied with the precision that the 32-bit integer grid
168provides or would like to retrieve coordinates of the output geometries
169within a smaller
170relative error, follow the next paragraph.<br>
171
172<h2>Voronoi Coordinate Types Configuration</h2>
173
174In the following chapter we are going to extend input coordinate type
175to the 48-bit signed
176integer and output coordinate type to the 80-bit IEEE floating-point
177type
178(long double). The code for this chapter is available in <a href="../example/voronoi_advanced_tutorial.cpp">voroni_advanced_tutorial.cpp</a>.
179While it won't be possible to compile it using the MSVC compiler (it
180doesn't
181support 80-bit long double type; ieee754.h header is required), it
182should give a clear understanding of how the library supports the user
183provided coordinate types.<br>
184
185<br>
186
187So the main step would be to declare the voronoi coordinate type traits
188that satisfy set of restrictions explained <a href="voronoi_builder.htm">here</a>:<br>
189
190<br>
191
192<span style="font-family: Courier New,Courier,monospace;">struct
193my_voronoi_ctype_traits {</span><br style="font-family: Courier New,Courier,monospace;">
194
195<span style="font-family: Courier New,Courier,monospace;">&nbsp;
196typedef boost::int64_t int_type;</span><br style="font-family: Courier New,Courier,monospace;">
197
198<span style="font-family: Courier New,Courier,monospace;">&nbsp;
199typedef detail::extended_int&lt;3&gt; int_x2_type;</span><br style="font-family: Courier New,Courier,monospace;">
200
201<span style="font-family: Courier New,Courier,monospace;">&nbsp;
202typedef detail::extended_int&lt;3&gt; uint_x2_type;</span><br style="font-family: Courier New,Courier,monospace;">
203
204<span style="font-family: Courier New,Courier,monospace;">&nbsp;
205typedef detail::extended_int&lt;128&gt; big_int_type;</span><br style="font-family: Courier New,Courier,monospace;">
206
207<span style="font-family: Courier New,Courier,monospace;">&nbsp;
208typedef fpt80 fpt_type;</span><br style="font-family: Courier New,Courier,monospace;">
209
210<span style="font-family: Courier New,Courier,monospace;">&nbsp;
211typedef fpt80 efpt_type;</span><br style="font-family: Courier New,Courier,monospace;">
212
213<span style="font-family: Courier New,Courier,monospace;">&nbsp;
214typedef my_ulp_comparison ulp_cmp_type;</span><br style="font-family: Courier New,Courier,monospace;">
215
216<span style="font-family: Courier New,Courier,monospace;">&nbsp;
217typedef my_fpt_converter to_fpt_converter_type;</span><br style="font-family: Courier New,Courier,monospace;">
218
219<span style="font-family: Courier New,Courier,monospace;">&nbsp;
220typedef my_fpt_converter to_efpt_converter_type;</span><br style="font-family: Courier New,Courier,monospace;">
221
222<span style="font-family: Courier New,Courier,monospace;">};<br>
223<br>
224</span>It is always better to use C++ built-in types wherever it's
225possible. That's why we use the 64-bit signed integer type to handle
226our
227input coordinates. <span style="font-family: Courier New,Courier,monospace;">int_x2_type</span>
228and <span style="font-family: Courier New,Courier,monospace;">uint_x2_type</span>
229is required to handle 96-bit signed/unsigned integers. As there is no
230such built-in type we use library provided efficient fixed integer
231type.
232The big integer type should be capable to handle 48 * 64 bit integers,
233that is
234less than 32 * 128, and so far we are good with <span style="font-family: Courier New,Courier,monospace;">extended_int&lt;128&gt;</span>
235type. We use the same floating point type for both <span style="font-family: Courier New,Courier,monospace;">fpt_type</span>
236and <span style="font-family: Courier New,Courier,monospace;">efpt_type</span>
237as it has enough exponent bits to represent both 48 * 32 bit and 48 *
23864 bit integers (that is also the reason we don't need two
239floating-point converter structures). The <span style="font-family: Courier New,Courier,monospace;">ulp_cmp_type</span>
240structure checks weather two IEEE floating-point values are within the
241given signed integer ulp range (we won't analyze corresponding code
242here as it requires deep understanding of the <a href="http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html">floating-point
243architecture</a> and its <a href="../../../boost/polygon/detail/voronoi_ctypes.hpp">usage to compare
244floating-point values</a>), but just to mention the declaration is
245following:<br>
246
247<span style="font-family: Courier New,Courier,monospace;"></span><br style="font-family: Courier New,Courier,monospace;">
248
249<span style="font-family: Courier New,Courier,monospace;">struct
250my_ulp_comparison {</span><br style="font-family: Courier New,Courier,monospace;">
251
252<span style="font-family: Courier New,Courier,monospace;">&nbsp; enum
253Result {</span><span style="font-family: Courier New,Courier,monospace;"><br>
254&nbsp;&nbsp;&nbsp; LESS = -1,</span><br style="font-family: Courier New,Courier,monospace;">
255
256<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
257EQUAL = 0,</span><br style="font-family: Courier New,Courier,monospace;">
258
259<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
260MORE = 1</span><br style="font-family: Courier New,Courier,monospace;">
261
262<span style="font-family: Courier New,Courier,monospace;">&nbsp; };</span><br style="font-family: Courier New,Courier,monospace;">
263
264<span style="font-family: Courier New,Courier,monospace;">&nbsp; Result
265operator()(fpt80 a, fpt80 b, unsigned int maxUlps) const;</span><br style="font-family: Courier New,Courier,monospace;">
266
267<span style="font-family: Courier New,Courier,monospace;">};<br>
268<br>
269</span>The last step would be to declare the <span style="font-family: Courier New,Courier,monospace;">my_fpt_converter</span>
270structure (converts the integer types to the floating-point type):<br>
271
272<br>
273
274<span style="font-family: Courier New,Courier,monospace;">struct
275my_fpt_converter {</span><br style="font-family: Courier New,Courier,monospace;">
276
277<span style="font-family: Courier New,Courier,monospace;">&nbsp;
278template &lt;typename T&gt;</span><br style="font-family: Courier New,Courier,monospace;">
279
280<span style="font-family: Courier New,Courier,monospace;">&nbsp; fpt80
281operator()(const T&amp; that) const {</span><br style="font-family: Courier New,Courier,monospace;">
282
283<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
284return static_cast&lt;fpt80&gt;(that);</span><br style="font-family: Courier New,Courier,monospace;">
285
286<span style="font-family: Courier New,Courier,monospace;">&nbsp; }</span><br style="font-family: Courier New,Courier,monospace;">
287
288<br style="font-family: Courier New,Courier,monospace;">
289
290<span style="font-family: Courier New,Courier,monospace;">&nbsp;
291template &lt;size_t N&gt;</span><br style="font-family: Courier New,Courier,monospace;">
292
293<span style="font-family: Courier New,Courier,monospace;">&nbsp; fpt80
294operator()(const typename detail::extended_int&lt;N&gt;&amp; that)
295const {</span><br style="font-family: Courier New,Courier,monospace;">
296
297<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
298fpt80 result = 0.0;</span><br style="font-family: Courier New,Courier,monospace;">
299
300<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
301for (size_t i = 1; i &lt;= (std::min)((size_t)3, that.size()); ++i) {</span><br style="font-family: Courier New,Courier,monospace;">
302
303<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
304if (i != 1)</span><br style="font-family: Courier New,Courier,monospace;">
305
306<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
307result *= static_cast&lt;fpt80&gt;(0x100000000ULL);</span><br style="font-family: Courier New,Courier,monospace;">
308
309<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
310result += that.chunks()[that.size() - i];</span><br style="font-family: Courier New,Courier,monospace;">
311
312<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
313}</span><br style="font-family: Courier New,Courier,monospace;">
314
315<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
316return (that.count() &lt; 0) ? -result : result;</span><br style="font-family: Courier New,Courier,monospace;">
317
318<span style="font-family: Courier New,Courier,monospace;">&nbsp; }</span><br style="font-family: Courier New,Courier,monospace;">
319
320<span style="font-family: Courier New,Courier,monospace;">};<br>
321<br>
322</span>At this point we are done with declaration of the Voronoi
323coordinate type traits. The next step is to declare the Voronoi diagram
324traits:<br>
325
326<br>
327
328<span style="font-family: Courier New,Courier,monospace;">struct
329my_voronoi_diagram_traits {</span><br style="font-family: Courier New,Courier,monospace;">
330
331<span style="font-family: Courier New,Courier,monospace;">&nbsp;
332typedef 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;">
333
334<span style="font-family: Courier New,Courier,monospace;">&nbsp;
335typedef voronoi_cell&lt;coordinate_type&gt; cell_type;</span><br style="font-family: Courier New,Courier,monospace;">
336
337<span style="font-family: Courier New,Courier,monospace;">&nbsp;
338typedef voronoi_vertex&lt;coordinate_type&gt; vertex_type;</span><br style="font-family: Courier New,Courier,monospace;">
339
340<span style="font-family: Courier New,Courier,monospace;">&nbsp;
341typedef voronoi_edge&lt;coordinate_type&gt; edge_type;</span><br style="font-family: Courier New,Courier,monospace;">
342
343<span style="font-family: Courier New,Courier,monospace;">&nbsp;
344typedef struct {</span><br style="font-family: Courier New,Courier,monospace;">
345
346<span style="font-family: Courier New,Courier,monospace;">&nbsp; public:</span><br style="font-family: Courier New,Courier,monospace;">
347
348<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
349enum { ULPS = 128 };</span><br style="font-family: Courier New,Courier,monospace;">
350
351<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
352bool operator()(const point_type &amp;v1, const point_type &amp;v2)
353const {</span><br style="font-family: Courier New,Courier,monospace;">
354
355<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
356return (ulp_cmp(v1.x(), v2.x(), ULPS) == my_ulp_comparison::EQUAL
357&amp;&amp;</span><br style="font-family: Courier New,Courier,monospace;">
358
359<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
360ulp_cmp(v1.y(), v2.y(), ULPS) == my_ulp_comparison::EQUAL);</span><br style="font-family: Courier New,Courier,monospace;">
361
362<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
363}</span><br style="font-family: Courier New,Courier,monospace;">
364
365<span style="font-family: Courier New,Courier,monospace;">&nbsp;
366private:</span><br style="font-family: Courier New,Courier,monospace;">
367
368<span style="font-family: Courier New,Courier,monospace;">&nbsp;&nbsp;&nbsp;
369my_ulp_comparison ulp_cmp;</span><br style="font-family: Courier New,Courier,monospace;">
370
371<span style="font-family: Courier New,Courier,monospace;">&nbsp; }
372vertex_equality_predicate_type;</span><br style="font-family: Courier New,Courier,monospace;">
373
374<span style="font-family: Courier New,Courier,monospace;">};</span><br>
375
376<span style="font-family: Courier New,Courier,monospace;"></span><br>
377
378Above we simply declared the Voronoi primitive types
379and vertex
380equality predicate using the new coordinate type and corresponding ulp
381comparison structure. As we are done with the declaration of the
382coordinate
383type specific structures we are ready to proceed to the construction
384step itself. The first step would be to initialize voronoi_builder
385structure with a set of random points:<br>
386
387<br>
388
389<span style="font-family: Courier New,Courier,monospace;">// Random
390generator and distribution. MAX is equal to 2^48.</span><br>
391
392<span style="font-family: Courier New,Courier,monospace;">boost::mt19937_64
393gen(std::time(0));</span><br style="font-family: Courier New,Courier,monospace;">
394
395<span style="font-family: Courier New,Courier,monospace;">boost::random::uniform_int_distribution&lt;boost::int64_t&gt;
396distr(-MAX, MAX-1);<br>
397<br>
398</span><span style="font-family: Courier New,Courier,monospace;">
399// Declaring and configuring Voronoi builder with the new coordinate
400type traits.<br>
401voronoi_builder&lt;boost::int64_t, my_voronoi_ctype_traits&gt; vb;</span><br>
402<span style="font-family: Courier New,Courier,monospace;"></span><br style="font-family: Courier New,Courier,monospace;">
403
404<span style="font-family: Courier New,Courier,monospace;">// Voronoi
405builder initialization step.<br>
406for (size_t i = 0; i &lt; GENERATED_POINTS; ++i) {</span><br style="font-family: Courier New,Courier,monospace;">
407
408<span style="font-family: Courier New,Courier,monospace;">&nbsp;
409boost::int64_t x = distr(gen);</span><br style="font-family: Courier New,Courier,monospace;">
410
411<span style="font-family: Courier New,Courier,monospace;">&nbsp;
412boost::int64_t y = distr(gen);</span><br style="font-family: Courier New,Courier,monospace;">
413
414<span style="font-family: Courier New,Courier,monospace;">&nbsp;
415vb.insert_point(x, y);</span><br style="font-family: Courier New,Courier,monospace;">
416
417<span style="font-family: Courier New,Courier,monospace;">}<br>
418<br>
419</span>The second step would be to generate the Voronoi diagram and
420this is done as before with the two lines of code:<br>
421
422<br>
423
424<span style="font-family: Courier New,Courier,monospace;">// Declaring
425and configuring Voronoi diagram structure with the new coordinate type
426traits.<br>
427voronoi_diagram&lt;fpt80, my_voronoi_diagram_traits&gt; vd;</span><br>
428
429<span style="font-family: Courier New,Courier,monospace;">vb.construct(&amp;vd);<br>
430<br>
431</span>From this point the user can operate with the Voronoi diagram
432data structure
433and in our tutorial we output some simple stats of the resulting
434Voronoi graph. Probably the hardest part of this tutorial is
435the declaration of the ulp comparison structure. The library provides
436efficient well-commented cross-platform implementation for 64-bit
437floating-point type (double). So the best advice would be to follow
438that implementation, but before doing that really consider thoughtfully if the
439default
440coordinate types are not capable to deal with your problem.<br>
441
442<br>
443
444<table class="docinfo" id="table1" frame="void" rules="none">
445
446 <colgroup> <col class="docinfo-name"><col class="docinfo-content"> </colgroup>
447 <tbody valign="top">
448 <tr>
449 <th class="docinfo-name">Copyright:</th>
450