From fe99aee370d02c129e8b0c76a8e202d0b1dedc8d Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Mon, 21 Jun 2010 16:16:33 +0000 Subject: [PATCH 01/32] initial checkin to release branch for polygon [SVN r63192] --- .gitattributes | 96 + Jamfile.v2 | 19 + doc/GTL_boostcon2009.pdf | Bin 0 -> 188721 bytes doc/GTL_boostcon_draft03.htm | 79 + doc/GTL_boostcon_draft03.pdf | Bin 0 -> 2079100 bytes doc/analysis.htm | 167 + doc/gtl_connectivity_extraction.htm | 142 + doc/gtl_connectivity_extraction_45.htm | 142 + doc/gtl_connectivity_extraction_90.htm | 142 + doc/gtl_connectivity_extraction_usage.htm | 93 + doc/gtl_coordinate_concept.htm | 144 + doc/gtl_custom_point.htm | 161 + doc/gtl_custom_polygon.htm | 179 + doc/gtl_custom_polygon_set.htm | 249 ++ doc/gtl_design_overview.htm | 176 + doc/gtl_interval_concept.htm | 524 +++ doc/gtl_isotropy.htm | 521 +++ doc/gtl_minkowski_tutorial.htm | 229 ++ doc/gtl_point_concept.htm | 400 ++ doc/gtl_point_usage.htm | 90 + doc/gtl_polygon_45_concept.htm | 360 ++ doc/gtl_polygon_45_set_concept.htm | 739 ++++ doc/gtl_polygon_45_with_holes_concept.htm | 399 ++ doc/gtl_polygon_90_concept.htm | 395 ++ doc/gtl_polygon_90_set_concept.htm | 901 +++++ doc/gtl_polygon_90_with_holes_concept.htm | 448 +++ doc/gtl_polygon_concept.htm | 362 ++ doc/gtl_polygon_set_concept.htm | 653 ++++ doc/gtl_polygon_set_usage.htm | 85 + doc/gtl_polygon_usage.htm | 76 + doc/gtl_polygon_with_holes_concept.htm | 395 ++ doc/gtl_property_merge.htm | 146 + doc/gtl_property_merge_45.htm | 145 + doc/gtl_property_merge_90.htm | 145 + doc/gtl_property_merge_usage.htm | 127 + doc/gtl_rectangle_concept.htm | 752 ++++ doc/gtl_tutorial.htm | 658 ++++ doc/images/NAND.PNG | Bin 0 -> 10878 bytes doc/images/boost.png | Bin 0 -> 6308 bytes doc/images/concept_table.png | Bin 0 -> 21276 bytes doc/images/foo.PNG | Bin 0 -> 20017 bytes doc/images/hand.png | Bin 0 -> 19048 bytes doc/images/intlogo.gif | Bin 0 -> 2378 bytes doc/images/nands.PNG | Bin 0 -> 9605 bytes doc/images/perf_graph.PNG | Bin 0 -> 21294 bytes doc/images/refinements.png | Bin 0 -> 29725 bytes doc/index.htm | 236 ++ doc/tutorial/compare_schematics.hpp | 96 + doc/tutorial/connectivity_database.hpp | 149 + doc/tutorial/device.hpp | 38 + doc/tutorial/extract.cpp | 63 + doc/tutorial/extract_devices.hpp | 99 + doc/tutorial/layout_database.hpp | 41 + doc/tutorial/layout_pin.hpp | 33 + doc/tutorial/layout_rectangle.hpp | 32 + doc/tutorial/nand.layout | 29 + doc/tutorial/nand.schematic | 9 + doc/tutorial/nand_short.layout | 29 + doc/tutorial/nor.layout | 29 + doc/tutorial/nor.schematic | 9 + doc/tutorial/parse_layout.hpp | 39 + doc/tutorial/schematic_database.hpp | 58 + include/boost/polygon/detail/boolean_op.hpp | 448 +++ .../boost/polygon/detail/boolean_op_45.hpp | 1394 +++++++ .../detail/iterator_compact_to_points.hpp | 69 + .../detail/iterator_geometry_to_set.hpp | 309 ++ .../detail/iterator_points_to_compact.hpp | 60 + include/boost/polygon/detail/max_cover.hpp | 278 ++ .../polygon/detail/polygon_45_formation.hpp | 2251 +++++++++++ .../polygon/detail/polygon_45_set_view.hpp | 378 ++ .../boost/polygon/detail/polygon_45_touch.hpp | 236 ++ .../polygon/detail/polygon_90_set_view.hpp | 445 +++ .../boost/polygon/detail/polygon_90_touch.hpp | 418 ++ .../detail/polygon_arbitrary_formation.hpp | 2916 ++++++++++++++ .../polygon/detail/polygon_formation.hpp | 1807 +++++++++ .../boost/polygon/detail/polygon_set_view.hpp | 207 + .../boost/polygon/detail/property_merge.hpp | 588 +++ .../polygon/detail/property_merge_45.hpp | 160 + .../polygon/detail/rectangle_formation.hpp | 267 ++ .../boost/polygon/detail/scan_arbitrary.hpp | 2852 ++++++++++++++ .../boost/polygon/detail/transform_detail.hpp | 553 +++ include/boost/polygon/gmp_override.hpp | 129 + include/boost/polygon/gtl.hpp | 27 + include/boost/polygon/interval_concept.hpp | 592 +++ include/boost/polygon/interval_data.hpp | 67 + include/boost/polygon/interval_traits.hpp | 33 + include/boost/polygon/isotropy.hpp | 542 +++ include/boost/polygon/point_3d_concept.hpp | 270 ++ include/boost/polygon/point_3d_data.hpp | 51 + include/boost/polygon/point_3d_traits.hpp | 35 + include/boost/polygon/point_concept.hpp | 298 ++ include/boost/polygon/point_data.hpp | 105 + include/boost/polygon/point_traits.hpp | 35 + include/boost/polygon/polygon.hpp | 90 + include/boost/polygon/polygon_45_data.hpp | 73 + .../boost/polygon/polygon_45_set_concept.hpp | 441 +++ include/boost/polygon/polygon_45_set_data.hpp | 1877 +++++++++ .../boost/polygon/polygon_45_set_traits.hpp | 146 + .../polygon/polygon_45_with_holes_data.hpp | 108 + include/boost/polygon/polygon_90_data.hpp | 80 + .../boost/polygon/polygon_90_set_concept.hpp | 548 +++ include/boost/polygon/polygon_90_set_data.hpp | 949 +++++ .../boost/polygon/polygon_90_set_traits.hpp | 362 ++ .../polygon/polygon_90_with_holes_data.hpp | 116 + include/boost/polygon/polygon_data.hpp | 70 + include/boost/polygon/polygon_set_concept.hpp | 557 +++ include/boost/polygon/polygon_set_data.hpp | 1000 +++++ include/boost/polygon/polygon_set_traits.hpp | 130 + include/boost/polygon/polygon_traits.hpp | 1848 +++++++++ .../boost/polygon/polygon_with_holes_data.hpp | 108 + include/boost/polygon/rectangle_concept.hpp | 1080 ++++++ include/boost/polygon/rectangle_data.hpp | 64 + include/boost/polygon/rectangle_traits.hpp | 38 + include/boost/polygon/transform.hpp | 501 +++ index.html | 24 + test/Jamfile.v2 | 22 + test/gtl_boost_unit_test.cpp | 3452 +++++++++++++++++ 117 files changed, 42832 insertions(+) create mode 100644 .gitattributes create mode 100644 Jamfile.v2 create mode 100644 doc/GTL_boostcon2009.pdf create mode 100644 doc/GTL_boostcon_draft03.htm create mode 100644 doc/GTL_boostcon_draft03.pdf create mode 100644 doc/analysis.htm create mode 100644 doc/gtl_connectivity_extraction.htm create mode 100644 doc/gtl_connectivity_extraction_45.htm create mode 100644 doc/gtl_connectivity_extraction_90.htm create mode 100644 doc/gtl_connectivity_extraction_usage.htm create mode 100644 doc/gtl_coordinate_concept.htm create mode 100644 doc/gtl_custom_point.htm create mode 100644 doc/gtl_custom_polygon.htm create mode 100644 doc/gtl_custom_polygon_set.htm create mode 100644 doc/gtl_design_overview.htm create mode 100644 doc/gtl_interval_concept.htm create mode 100755 doc/gtl_isotropy.htm create mode 100644 doc/gtl_minkowski_tutorial.htm create mode 100644 doc/gtl_point_concept.htm create mode 100644 doc/gtl_point_usage.htm create mode 100644 doc/gtl_polygon_45_concept.htm create mode 100644 doc/gtl_polygon_45_set_concept.htm create mode 100644 doc/gtl_polygon_45_with_holes_concept.htm create mode 100644 doc/gtl_polygon_90_concept.htm create mode 100644 doc/gtl_polygon_90_set_concept.htm create mode 100644 doc/gtl_polygon_90_with_holes_concept.htm create mode 100644 doc/gtl_polygon_concept.htm create mode 100644 doc/gtl_polygon_set_concept.htm create mode 100644 doc/gtl_polygon_set_usage.htm create mode 100644 doc/gtl_polygon_usage.htm create mode 100644 doc/gtl_polygon_with_holes_concept.htm create mode 100644 doc/gtl_property_merge.htm create mode 100644 doc/gtl_property_merge_45.htm create mode 100644 doc/gtl_property_merge_90.htm create mode 100644 doc/gtl_property_merge_usage.htm create mode 100644 doc/gtl_rectangle_concept.htm create mode 100644 doc/gtl_tutorial.htm create mode 100644 doc/images/NAND.PNG create mode 100644 doc/images/boost.png create mode 100644 doc/images/concept_table.png create mode 100644 doc/images/foo.PNG create mode 100644 doc/images/hand.png create mode 100644 doc/images/intlogo.gif create mode 100644 doc/images/nands.PNG create mode 100644 doc/images/perf_graph.PNG create mode 100644 doc/images/refinements.png create mode 100644 doc/index.htm create mode 100644 doc/tutorial/compare_schematics.hpp create mode 100644 doc/tutorial/connectivity_database.hpp create mode 100644 doc/tutorial/device.hpp create mode 100644 doc/tutorial/extract.cpp create mode 100644 doc/tutorial/extract_devices.hpp create mode 100644 doc/tutorial/layout_database.hpp create mode 100644 doc/tutorial/layout_pin.hpp create mode 100644 doc/tutorial/layout_rectangle.hpp create mode 100644 doc/tutorial/nand.layout create mode 100644 doc/tutorial/nand.schematic create mode 100644 doc/tutorial/nand_short.layout create mode 100644 doc/tutorial/nor.layout create mode 100644 doc/tutorial/nor.schematic create mode 100644 doc/tutorial/parse_layout.hpp create mode 100644 doc/tutorial/schematic_database.hpp create mode 100644 include/boost/polygon/detail/boolean_op.hpp create mode 100644 include/boost/polygon/detail/boolean_op_45.hpp create mode 100644 include/boost/polygon/detail/iterator_compact_to_points.hpp create mode 100644 include/boost/polygon/detail/iterator_geometry_to_set.hpp create mode 100644 include/boost/polygon/detail/iterator_points_to_compact.hpp create mode 100644 include/boost/polygon/detail/max_cover.hpp create mode 100644 include/boost/polygon/detail/polygon_45_formation.hpp create mode 100644 include/boost/polygon/detail/polygon_45_set_view.hpp create mode 100644 include/boost/polygon/detail/polygon_45_touch.hpp create mode 100644 include/boost/polygon/detail/polygon_90_set_view.hpp create mode 100644 include/boost/polygon/detail/polygon_90_touch.hpp create mode 100644 include/boost/polygon/detail/polygon_arbitrary_formation.hpp create mode 100644 include/boost/polygon/detail/polygon_formation.hpp create mode 100644 include/boost/polygon/detail/polygon_set_view.hpp create mode 100644 include/boost/polygon/detail/property_merge.hpp create mode 100644 include/boost/polygon/detail/property_merge_45.hpp create mode 100644 include/boost/polygon/detail/rectangle_formation.hpp create mode 100644 include/boost/polygon/detail/scan_arbitrary.hpp create mode 100644 include/boost/polygon/detail/transform_detail.hpp create mode 100755 include/boost/polygon/gmp_override.hpp create mode 100755 include/boost/polygon/gtl.hpp create mode 100755 include/boost/polygon/interval_concept.hpp create mode 100755 include/boost/polygon/interval_data.hpp create mode 100755 include/boost/polygon/interval_traits.hpp create mode 100755 include/boost/polygon/isotropy.hpp create mode 100755 include/boost/polygon/point_3d_concept.hpp create mode 100755 include/boost/polygon/point_3d_data.hpp create mode 100755 include/boost/polygon/point_3d_traits.hpp create mode 100755 include/boost/polygon/point_concept.hpp create mode 100755 include/boost/polygon/point_data.hpp create mode 100755 include/boost/polygon/point_traits.hpp create mode 100755 include/boost/polygon/polygon.hpp create mode 100755 include/boost/polygon/polygon_45_data.hpp create mode 100755 include/boost/polygon/polygon_45_set_concept.hpp create mode 100755 include/boost/polygon/polygon_45_set_data.hpp create mode 100755 include/boost/polygon/polygon_45_set_traits.hpp create mode 100755 include/boost/polygon/polygon_45_with_holes_data.hpp create mode 100755 include/boost/polygon/polygon_90_data.hpp create mode 100755 include/boost/polygon/polygon_90_set_concept.hpp create mode 100755 include/boost/polygon/polygon_90_set_data.hpp create mode 100755 include/boost/polygon/polygon_90_set_traits.hpp create mode 100755 include/boost/polygon/polygon_90_with_holes_data.hpp create mode 100755 include/boost/polygon/polygon_data.hpp create mode 100755 include/boost/polygon/polygon_set_concept.hpp create mode 100755 include/boost/polygon/polygon_set_data.hpp create mode 100755 include/boost/polygon/polygon_set_traits.hpp create mode 100755 include/boost/polygon/polygon_traits.hpp create mode 100755 include/boost/polygon/polygon_with_holes_data.hpp create mode 100755 include/boost/polygon/rectangle_concept.hpp create mode 100755 include/boost/polygon/rectangle_data.hpp create mode 100755 include/boost/polygon/rectangle_traits.hpp create mode 100755 include/boost/polygon/transform.hpp create mode 100644 index.html create mode 100644 test/Jamfile.v2 create mode 100644 test/gtl_boost_unit_test.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/Jamfile.v2 b/Jamfile.v2 new file mode 100644 index 0000000..ebb4e41 --- /dev/null +++ b/Jamfile.v2 @@ -0,0 +1,19 @@ +# Boost Build v2 Jamroot for Polygon unit +# +# Copyright 2010 Intel Corporation +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project + : requirements + all + intel:on + gcc:"-pedantic -Wall -Wstrict-aliasing -fstrict-aliasing -Wno-long-long" + msvc:/W4 + ../.. + . + ; + + diff --git a/doc/GTL_boostcon2009.pdf b/doc/GTL_boostcon2009.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ea518a65d015bca568634024b3c50ea682f2ed43 GIT binary patch literal 188721 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

>?&JdA+f6<1C#bN#a=Kx@ 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 literal 0 HcmV?d00001 diff --git a/doc/GTL_boostcon_draft03.htm b/doc/GTL_boostcon_draft03.htm new file mode 100644 index 0000000..784ba92 --- /dev/null +++ b/doc/GTL_boostcon_draft03.htm @@ -0,0 +1,79 @@ + + + + + + + + + +GTL Geometry Template Library + + + + + + + + + + +

This presentation contains content that your browser may not be able to show +properly. This presentation was optimized for more recent versions of Microsoft +Internet Explorer.

+ +

If you would like to proceed anyway, click here.

+ +
+ + + diff --git a/doc/GTL_boostcon_draft03.pdf b/doc/GTL_boostcon_draft03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f780f24738fd4ada73534773f5de67ea04799da8 GIT binary patch literal 2079100 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

8^&& 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%0A5g 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∈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�QcdMwV)n#^2mIvF%MW?>}d3g^!NYZdX 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 UBB14)`;LI}7{`XQ|7RWD{s` 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�Y;k4GCwZ;~`W!c)A8X{LWCqpAc;T1Zi^ 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 z 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�+n7X2%= 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%0DeLxR-*m#qTACkB;rUEw=ddqLK%C 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

%2bC5%Z(3K<7?A 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�fCK;j8@Nj%nr)h8yY0Y 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 z

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%0D`%<3*Z(mQrtQXH0c|UP!(e1R6 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 + +Boost Polygon Library: Performance Analysis + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon Set Algorithms Analysis

+

Most non-trivial algorithms in the Boost.Polygon library are +instantiations of generic sweep-line algorithms that provide the capability to +perform Manhattan and 45-degree line segment intersection, n-layer map overlay, +connectivity graph extraction and clipping/Booleans.  These algorithms have O(n log n) +runtime complexity for n equal to input vertices plus intersection vertices.  The +arbitrary angle line segment intersection algorithm is not implemented as a +sweep-line due to complications related to achieving numerical robustness.  +The general line segment intersection algorithm is implemented as an recursive +adaptive heuristic divide and conquer in the y dimension followed by sorting +line segments in each subdivision by x coordinates and scanning left to right.  +By one-dimensional decomposition of the problem space in both x and y the +algorithm approximates the optimal O(n log n) Bentley-Ottmann line segment intersection +runtime complexity in the common case.  Specific examples of inputs that +defeat one dimensional decomposition of the problem space can result in +pathological quadratic runtime complexity to which the Bentley-Ottmann algorithm +is immune.

+

Below is shown a log-log plot of runtime versus input size for inputs that +increase quadratically in size.  The inputs were generated by +pseudo-randomly distributing small axis-parallel rectangles within a square area +proportional the the number of rectangles specified for each trial.  In +this way the probability of intersections being produced remains constant as the +input size grows.  Because intersection vertices are expected to be a +constant factor of input vertices we can examine runtime complexity in terms of +input vertices.  The operation performed was a union (Boolean OR) of the +input rectangles by each of the Manhattan, 45-degree and arbitrary angle +Booleans algorithms, which are labeled "boolean 90", "boolean 45" and "boolean".  +Also shown in the plot is the performance of the arbitrary angle Booleans +algorithm as prior to the addition of divide and conquer recursive subdivision, +which was described in the paper +presented at +boostcon 2009.  Finally, the +time required to sort the input points is shown as a common reference for O(n log n) +runtime to put the data into context.

+We can see in the log-log plot that sorting and the three Booleans algorithms +provided by the Boost.Polygon library have nearly 45 degree "linear" +scaling with empirical exponents just slightly larger than 1.0 and can be +observed to scale proportional to O(n log n) for +these inputs.  The "old boolean" algorithm presented at boostcon 2009 +exhibits scaling close to the expected O(n1.5) +scaling.  Because the speedup provided by the divide and conquer approach +is algorithmic, the 10X potential performance improvement alluded to in the paper is +realized at inputs of 200,000 rectangles and larger.  Even for small inputs +of 2K rectangles the algorithm is 2X faster and now can be expected to be +roughly as fast as GPC at small scales, +while algorithmically faster at large scales.

+

+ + +From the plot we can compare the constant factor performance of the various +Booleans algorithms with the runtime of std::sort as a baseline for O(n log n) +algorithms.  If you consider sort to be one unit of O(n log n) algorithmic +work we can see that Manhattan Booleans cost roughly five units of O(n log n) +work, 45-degree  Booleans cost roughly + + +ten units of O(n log n) work and arbitrary angle Booleans cost roughly +seventy units of O(n log n) work.  Sorting the input vertices is the first +step in a Booleans algorithm and therefore provides a hard lower bound for the +runtime of an optimal Booleans algorithm.

+ + +One final thing to note about performance of the arbitrary angle Booleans +algorithm is that the use of GMP + infinite precision rational data type for numerically robust +computations can be employed by including boost/polygon/gmp_override.hpp and linking +to lgmpxx and lgmp.  This provides +100% assurance that the algorithm will succeed and produce an output snapped to +the integer grid with a minimum of one integer grid of error on polygon +boundaries upon which intersection points are introduced.  However, the +infinite precision data type is never used for predicates (see the boostcon +presentation or paper for description of robust predicates) and is only used for +constructions of intersection coordinate values in the very rare case that long +double computation of the intersection of two line segments fails to produce an +intersection point within one integer unit of both line segments.  This +means that there is effectively no runtime penalty for the use of infinite +precision to ensure 100% robustness.  Most inputs will process through the +algorithm without ever resorting to GMP.

+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction.htm b/doc/gtl_connectivity_extraction.htm new file mode 100644 index 0000000..bd2ae18 --- /dev/null +++ b/doc/gtl_connectivity_extraction.htm @@ -0,0 +1,142 @@ + + +Boost Polygon Library: Connectivity Extraction 45 + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Connectivity Extraction

+ +

+

The connectivity extraction algorithm constructs the connectivity graph where +input polygon sets are modeled as graph nodes and assigned node ids and +overlap/touching between input polygon sets is modeled as graph edges.  One +supported graph formats is std::vector<std::set<int> > where node ids index into +the vector and the sets of integers at each index are the ids of nodes for which +an edge exists in the graph.  It is required that such vector pre-allocate +sufficient elements to store the graph generated by the algorithm, because only +the operator[] is used internally to access the graph   The other +supported graph format is std::map<int, std::set<int> > which is slightly easier to +work with, but potentially more expensive.  Improving the interface to +support more generic graph concepts is deferred to future work.

The following +is the declaration of the connectivity extraction algorithm.

+template <typename coordinate_type>
+class connectivity_extraction;

+Example code connectivity_extraction_usage.cpp + demonstrates using the connectivity extraction algorithm to build a +connectivity graph on geometry.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
connectivity_extraction()Default constructor.
connectivity_extraction(
     const + connectivity_extraction& that)
Copy construct.
+unsigned int
insert(const polygon_set_data<coordinate_type>& ps)
Insert a polygon set graph node, the + value returned is the id of the graph node.
+ +template <class GeoObjT>
+unsigned int insert(const GeoObjT& geoObj)
Insert a geometry object that is a refinement of polygon set as a + graph node, the return value is the id of the graph node.
+ +template <class GraphT>
+void extract(GraphT& graph)
Accepts a graph object that conforms to the expectations defined + above.  Performs connectivity extraction and populates the graph + object.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction_45.htm b/doc/gtl_connectivity_extraction_45.htm new file mode 100644 index 0000000..9abe542 --- /dev/null +++ b/doc/gtl_connectivity_extraction_45.htm @@ -0,0 +1,142 @@ + + +Boost Polygon Library: Connectivity Extraction 45 + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Connectivity Extraction 45

+ +

+

The connectivity extraction algorithm constructs the connectivity graph where +input polygon sets are modeled as graph nodes and assigned node ids and +overlap/touching between input polygon sets is modeled as graph edges.  One +supported graph formats is std::vector<std::set<int> > where node ids index into +the vector and the sets of integers at each index are the ids of nodes for which +an edge exists in the graph.  It is required that such vector pre-allocate +sufficient elements to store the graph generated by the algorithm, because only +the operator[] is used internally to access the graph   The other +supported graph format is std::map<int, std::set<int> > which is slightly easier to +work with, but potentially more expensive.  Improving the interface to +support more generic graph concepts is deferred to future work.

The following +is the declaration of the connectivity extraction algorithm.

+template <typename coordinate_type>
+class connectivity_extraction_45;

+Example code connectivity_extraction_usage.cpp + demonstrates using the connectivity extraction algorithm to build a +connectivity graph on geometry.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
connectivity_extraction_45()Default constructor.
connectivity_extraction_45(
     const + connectivity_extraction_45& that)
Copy construct.
+unsigned int
insert(const polygon_45_set_data<coordinate_type>& ps)
Insert a polygon set graph node, the + value returned is the id of the graph node.
+ +template <class GeoObjT>
+unsigned int insert(const GeoObjT& geoObj)
Insert a geometry object that is a refinement of polygon 45 set as a + graph node, the return value is the id of the graph node.
+ +template <class GraphT>
+void extract(GraphT& graph)
Accepts a graph object that conforms to the expectations defined + above.  Performs connectivity extraction and populates the graph + object.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction_90.htm b/doc/gtl_connectivity_extraction_90.htm new file mode 100644 index 0000000..64a4b12 --- /dev/null +++ b/doc/gtl_connectivity_extraction_90.htm @@ -0,0 +1,142 @@ + + +Boost Polygon Library: Connectivity Extraction 90 + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Connectivity Extraction 90

+ +

+

The connectivity extraction algorithm constructs the connectivity graph where +input polygon sets are modeled as graph nodes and assigned node ids and +overlap/touching between input polygon sets is modeled as graph edges.  One +supported graph formats is std::vector<std::set<int> > where node ids index into +the vector and the sets of integers at each index are the ids of nodes for which +an edge exists in the graph.  It is required that such vector pre-allocate +sufficient elements to store the graph generated by the algorithm, because only +the operator[] is used internally to access the graph   The other +supported graph format is std::map<int, std::set<int> > which is slightly easier to +work with, but potentially more expensive.  Improving the interface to +support more generic graph concepts is deferred to future work.

The following +is the declaration of the connectivity extraction algorithm.

+template <typename coordinate_type>
+class connectivity_extraction_90;

+Example code connectivity_extraction_usage.cpp + demonstrates using the connectivity extraction algorithm to build a +connectivity graph on geometry.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
connectivity_extraction_90()Default constructor.
connectivity_extraction_90(
     const + connectivity_extraction_90& that)
Copy construct.
+unsigned int
insert(const polygon_90_set_data<coordinate_type>& ps)
Insert a polygon set graph node, the + value returned is the id of the graph node.
+ +template <class GeoObjT>
+unsigned int insert(const GeoObjT& geoObj)
Insert a geometry object that is a refinement of polygon 90 set as a + graph node, the return value is the id of the graph node.
+ +template <class GraphT>
+void extract(GraphT& graph)
Accepts a graph object that conforms to the expectations defined + above.  Performs connectivity extraction and populates the graph + object.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction_usage.htm b/doc/gtl_connectivity_extraction_usage.htm new file mode 100644 index 0000000..9f599f3 --- /dev/null +++ b/doc/gtl_connectivity_extraction_usage.htm @@ -0,0 +1,93 @@ + + + + +Connectivity Extraction Usage + + + + +

#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+
+//This function works with both the 90 and 45 versions
+//of connectivity extraction algroithm
+template <typename ce_type>
+void test_ce() {
+  //first we create an object to do the connectivity extraction
+  ce_type ce;
+
+  //create some test data
+  std::vector<gtl::rectangle_data<int> > test_data;
+  test_data.push_back(gtl::rectangle_data<int>(10, 10, 90, 90));
+  test_data.push_back(gtl::rectangle_data<int>(0, 0, 20, 20));
+  test_data.push_back(gtl::rectangle_data<int>(80, 0, 100, 20));
+  test_data.push_back(gtl::rectangle_data<int>(0, 80, 20, 100));
+  test_data.push_back(gtl::rectangle_data<int>(80, 80, 100, 100));
+  //There is one big square and four little squares covering each
+  //of its corners.
+
+  for(unsigned int i = 0; i < test_data.size(); ++i) {
+    //insert returns an id starting at zero and incrementing
+    //with each call
+    assert(ce.insert(test_data[i]) == i);
+  }
+  //notice that ids returned by ce.insert happen to match
+  //index into vector of inputs in this case
+
+  //make sure the vector graph has elements for our nodes
+  std::vector<std::set<int> > graph(test_data.size());
+
+  //populate the graph with edge data
+  ce.extract(graph);
+
+  //make a map type graph to compare results
+  std::map<int, std::set<int> > map_graph;
+  ce.extract(map_graph);
+
+  assert(map_graph.size() && map_graph.size() == graph.size());
+  for(unsigned int i = 0; i < graph.size(); ++i) {
+    assert(graph[i] == map_graph[i]);
+    if(i == 0)
+      assert(graph[i].size() == 4); //four little +squares
+    else
+      assert(graph[i].size() == 1); //each little +toches the big square
+  }
+}
+
+int main() {
+  test_ce<gtl::connectivity_extraction_90<int> >();
+  test_ce<gtl::connectivity_extraction_45<int> >();
+  return 0;
+}
+
+//Now you know how to use the connectivity extraction algorithm
+//to extract the connectivity graph for overlapping geometry

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_coordinate_concept.htm b/doc/gtl_coordinate_concept.htm new file mode 100644 index 0000000..b106a94 --- /dev/null +++ b/doc/gtl_coordinate_concept.htm @@ -0,0 +1,144 @@ + + +Boost Polygon Library: Coordinate Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Coordinate Concept

+ +

+The coordinate concept tag is +coordinate_concept

+To register a user defined type as a model of coordinate concept, specialize the +geometry concept meta-function for that type.  In the example below +CCoordinate is registered as a model of coordinate concept.

+template <>
+struct geometry_concept<CCoordinate> { typedef coordinate_concept type; };

+The coordinate type is expected to be integral and built-in numerical data types +such as float and int already have concept type traits specializations in the +library.  In the coordinate traits are type definitions for related types +are provided to allow the library to choose the best type to cast to under +various circumstances.  The definition of coordinate_traits and its +specialization for int are shown below.

+template <typename T>
+struct coordinate_traits {};
+
+template <>
+struct coordinate_traits<int> {
+     typedef int coordinate_type;
+     typedef long double area_type;
+     typedef long long manhattan_area_type;
+     typedef unsigned long long unsigned_area_type;
+     typedef long long coordinate_difference;
+     typedef long double coordinate_distance;
+};

+By making use of the coordinate traits of int the library is able to avoid +overflow and handle the normal issues encountered when programming integer +geometry.  For the out of the ordinary issues there is a special +meta-function that provides the library with a numerical type suitable for exact +numerical calculations.  It defaults to the highest precision data type +available in most compilers, long double, but can be overridden by specializing +for a particular coordinate type.  Use of gmp multi-precision rational or +similar data type is recommended for numerically robust calculations in the +general polygon algorithms.

+template <typename T>
+struct high_precision_type {
+     typedef long double type;
+};

+There is only one generic function on coordinate concepts, Euclidean distance.

+template <typename coordinate_type_1, typename +coordinate_type_2>
+coordinate_difference euclidean_distance(coordinate_type_1, coordinate_type_2)

+This function returns the absolution value of the difference between the two +coordinates.

+Note: older versions of the stl define a fully generic distance(T, T) function +for computing the difference between two iterators.  We were forced to name +our distance function euclidean_distance to avoid name collision.

+The + +Algorithmic C ac_int<128> is an example of a user defined coordinate data +type that satisfies the coordinate concept.  In general a data type should +define std::numeric_limits and be integer-like.  Floating point coordinate +types are not supported by all the algorithms and generally not suitable for use +with the library at present.

+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_custom_point.htm b/doc/gtl_custom_point.htm new file mode 100644 index 0000000..f05f302 --- /dev/null +++ b/doc/gtl_custom_point.htm @@ -0,0 +1,161 @@ + + + + +Custom Point + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+//lets make the body of main from point_usage.cpp
//a generic function parameterized by point type
template <typename Point>
void test_point() {
  +  //constructing a gtl point
    +int x = 10;
    +int y = 20;
    +//Point pt(x, y);
    +Point pt = gtl::construct<Point>(x, y);
    +assert(gtl::x(pt) == 10);
    +assert(gtl::y(pt) == 20);
    +
    +//a quick primer in isotropic point access
    +typedef gtl::orientation_2d O;
    +using gtl::HORIZONTAL;
    +using gtl::VERTICAL;
    +O o = HORIZONTAL;
    +assert(gtl::x(pt) == gtl::get(pt, o));
    +
    +o = o.get_perpendicular();
    +assert(o == VERTICAL);
    +assert(gtl::y(pt) == gtl::get(pt, o));
    +
    +gtl::set(pt, o, 30);
    +assert(gtl::y(pt) == 30);
    +
    +//using some of the library functions
    +//Point pt2(10, 30);
    +Point pt2 = gtl::construct<Point>(10, 30);
    +assert(gtl::equivalence(pt, pt2));
    +
    +gtl::transformation<int> tr(gtl::axis_transformation::SWAP_XY);
    +gtl::transform(pt, tr);
    +assert(gtl::equivalence(pt, gtl::construct<Point>(30, 10)));
    +
    +gtl::transformation<int> tr2 = tr.inverse();
    +assert(tr == tr2); //SWAP_XY is its own inverse transform
    +
    +gtl::transform(pt, tr2);
    +assert(gtl::equivalence(pt, pt2)); //the two points are equal again
    +
    +gtl::move(pt, o, 10); //move pt 10 units in y
    +assert(gtl::euclidean_distance(pt, pt2) == 10.0f);
    +
    +gtl::move(pt, o.get_perpendicular(), 10); //move pt 10 units in x
    +assert(gtl::manhattan_distance(pt, pt2) == 20);
}
    +
//Now lets declare our own point type
//Bjarne says that if a class doesn't maintain an
//invariant just use a struct.
struct CPoint {
    +int x;
    +int y;
};
    +
//There, nice a simple...but wait, it doesn't do anything
//how do we use it to do all the things a point needs to do?
    +
    +
//First we register it as a point with boost polygon
namespace boost { +namespace polygon {
    +template <>
    +struct geometry_concept<CPoint> { typedef point_concept type; };
 
    +
    //Then we specialize the gtl point traits for our point type
    +template <>
    +struct point_traits<CPoint> {
    +    +typedef int coordinate_type;
    +
    +    +static inline coordinate_type get(const CPoint& point,
    +    +orientation_2d orient) {
    +    +    +if(orient == HORIZONTAL)
    +    +    +    +return point.x;
    +    +    +return point.y;
    +    +}
    +};
    +
    +template <>
    +struct point_mutable_traits<CPoint> {
    +    +static inline void set(CPoint& point, orientation_2d orient, int value) {
    +    +    +if(orient == HORIZONTAL)
    +    +    +    +point.x = value;
    +    +    +else
    +    +    +point.y = value;
    +    +}
    +    +static inline CPoint construct(int x_value, int y_value) {
    +    +    +CPoint retval;
    +    +    +retval.x = x_value;
    +    +    +retval.y = y_value;
    +    +    +return retval;
    +    +}
    +};
} }
    +
//Now lets see if the CPoint works with the library functions
int main() {
    +test_point<CPoint>(); //yay! All your testing is done for you.
    +return 0;
}
    +
//Now you know how to map a user type to the library point concept
//and how to write a generic function parameterized by point type
//using the library interfaces to access it.
    + 

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_custom_polygon.htm b/doc/gtl_custom_polygon.htm new file mode 100644 index 0000000..699078e --- /dev/null +++ b/doc/gtl_custom_polygon.htm @@ -0,0 +1,179 @@ + + + + +Custom Polygon + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+#include <list>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+//first lets turn our polygon usage code into a generic
+//function parameterized by polygon type
+template <typename Polygon>
+void test_polygon() {
+  //lets construct a 10x10 rectangle shaped polygon
+  typedef typename gtl::polygon_traits<Polygon>::point_type Point;
+  Point pts[] = {gtl::construct<Point>(0, 0),
+  gtl::construct<Point>(10, 0),
+  gtl::construct<Point>(10, 10),
+  gtl::construct<Point>(0, 10) };
+  Polygon poly;
+  gtl::set_points(poly, pts, pts+4);
+
+  //now lets see what we can do with this polygon
+  assert(gtl::area(poly) == 100.0f);
+  assert(gtl::contains(poly, gtl::construct<Point>(5, 5)));
+  assert(!gtl::contains(poly, gtl::construct<Point>(15, 5)));
+  gtl::rectangle_data<int> rect;
+  assert(gtl::extents(rect, poly)); //get bounding box of poly
+  assert(gtl::equivalence(rect, poly)); //hey, that's slick
+  assert(gtl::winding(poly) == gtl::COUNTERCLOCKWISE);
+  assert(gtl::perimeter(poly) == 40.0f);
+
+  //add 5 to all coords of poly
+  gtl::convolve(poly, gtl::construct<Point>(5, 5));
+  //multiply all coords of poly by 2
+  gtl::scale_up(poly, 2);
+  gtl::set_points(rect, gtl::point_data<int>(10, 10),
+  gtl::point_data<int>(30, 30));
+  assert(gtl::equivalence(poly, rect));
+}
+
+//Now lets declare our own polygon class
+//Oops, we need a point class to support our polygon, lets borrow
+//the CPoint example
+struct CPoint {
+  int x;
+  int y;
+};
+
+//we have to get CPoint working with boost polygon to make our polygon
+//that uses CPoint working with boost polygon
+namespace boost { namespace polygon {
+  template <>
+  struct geometry_concept<CPoint> { typedef point_concept type; };
+  template <>
+  struct point_traits<CPoint> {
+    typedef int coordinate_type;
+
+    static inline coordinate_type get(const CPoint& point,
+    orientation_2d orient) {
+      if(orient == HORIZONTAL)
+        return point.x;
+      return point.y;
+    }
+  };
+
+  template <>
+  struct point_mutable_traits<CPoint> {
+    static inline void set(CPoint& point, orientation_2d orient, +int value) {
+      if(orient == HORIZONTAL)
+        point.x = value;
+      else
+        point.y = value;
+    }
+    static inline CPoint construct(int x_value, int y_value) {
+      CPoint retval;
+      retval.x = x_value;
+      retval.y = y_value;
+      return retval;
+    }
+  };
+} }
+
+//I'm lazy and use the stl everywhere to avoid writing my own classes
+//my toy polygon is a std::list<CPoint>
+typedef std::list<CPoint> CPolygon;
+
+//we need to specialize our polygon concept mapping in boost polygon
+namespace boost { namespace polygon {
+  //first register CPolygon as a polygon_concept type
+  template <>
+  struct geometry_concept<CPolygon>{ typedef polygon_concept type; };
+
+  template <>
+  struct polygon_traits<CPolygon> {
+    typedef int coordinate_type;
+    typedef CPolygon::const_iterator iterator_type;
+    typedef CPoint point_type;
+
+    // Get the begin iterator
+    static inline iterator_type begin_points(const CPolygon& t) {
+      return t.begin();
+    }
+
+    // Get the end iterator
+    static inline iterator_type end_points(const CPolygon& t) {
+      return t.end();
+    }
+
+    // Get the number of sides of the polygon
+    static inline std::size_t size(const CPolygon& t) {
+      return t.size();
+    }
+
+    // Get the winding direction of the polygon
+    static inline winding_direction winding(const CPolygon& t) {
+      return unknown_winding;
+    }
+  };
+
+  template <>
+  struct polygon_mutable_traits<CPolygon> {
+    //expects stl style iterators
+    template <typename iT>
+    static inline CPolygon& set_points(CPolygon& t,
+                                       +iT input_begin, iT input_end) {
+      t.clear();
+      t.insert(t.end(), input_begin, input_end);
+      return t;
+    }
+
+  };
+} }
+
+//now there's nothing left to do but test that our polygon
+//works with library interfaces
+int main() {
+  test_polygon<CPolygon>(); //woot!
+  return 0;
+}

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_custom_polygon_set.htm b/doc/gtl_custom_polygon_set.htm new file mode 100644 index 0000000..13d80af --- /dev/null +++ b/doc/gtl_custom_polygon_set.htm @@ -0,0 +1,249 @@ + + + + +Custom Polygon Set + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <list>
+#include <time.h>
+#include <cassert>
+#include <deque>
+#include <iostream>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+//once again we make our usage of the library generic
+//and parameterize it on the polygon set type
+template <typename PolygonSet>
+void test_polygon_set() {
+  using namespace gtl;
+  PolygonSet ps;
+  ps += rectangle_data<int>(0, 0, 10, 10);
+  PolygonSet ps2;
+  ps2 += rectangle_data<int>(5, 5, 15, 15);
+  PolygonSet ps3;
+  assign(ps3, ps * ps2);
+  PolygonSet ps4;
+  ps4 += ps + ps2;
+  assert(area(ps4) == area(ps) + area(ps2) - area(ps3));
+  assert(equivalence((ps + ps2) - (ps * ps2), ps ^ ps2));
+  rectangle_data<int> rect;
+  assert(extents(rect, ps ^ ps2));
+  assert(area(rect) == 225);
+  assert(area(rect ^ (ps ^ ps2)) == area(rect) - area(ps ^ ps2));
+}
+
+//first thing is first, lets include all the code from previous examples
+
+//the CPoint example
+struct CPoint {
+  int x;
+  int y;
+};
+
+namespace boost { namespace polygon {
+  template <>
+  struct geometry_concept<CPoint> { typedef point_concept type; };
+  template <>
+  struct point_traits<CPoint> {
+    typedef int coordinate_type;
+
+    static inline coordinate_type get(const CPoint& point,
+                                      +orientation_2d orient) {
+      if(orient == HORIZONTAL)
+      return point.x;
+      return point.y;
+    }
+  };
+
+  template <>
+  struct point_mutable_traits<CPoint> {
+    static inline void set(CPoint& point, orientation_2d orient, +int value) {
+      if(orient == HORIZONTAL)
+        point.x = value;
+      else
+        point.y = value;
+    }
+    static inline CPoint construct(int x_value, int y_value) {
+      CPoint retval;
+      retval.x = x_value;
+      retval.y = y_value;
+      return retval;
+    }
+  };
+} }
+
+//the CPolygon example
+typedef std::list<CPoint> CPolygon;
+
+//we need to specialize our polygon concept mapping in boost polygon
+namespace boost { namespace polygon {
+  //first register CPolygon as a polygon_concept type
+  template <>
+  struct geometry_concept<CPolygon>{ typedef polygon_concept type; };
+
+  template <>
+  struct polygon_traits<CPolygon> {
+    typedef int coordinate_type;
+    typedef CPolygon::const_iterator iterator_type;
+    typedef CPoint point_type;
+
+    // Get the begin iterator
+    static inline iterator_type begin_points(const CPolygon& t) {
+      return t.begin();
+    }
+
+    // Get the end iterator
+    static inline iterator_type end_points(const CPolygon& t) {
+      return t.end();
+    }
+
+    // Get the number of sides of the polygon
+    static inline std::size_t size(const CPolygon& t) {
+      return t.size();
+    }
+
+    // Get the winding direction of the polygon
+    static inline winding_direction winding(const CPolygon& t) {
+      return unknown_winding;
+    }
+  };
+
+  template <>
+  struct polygon_mutable_traits<CPolygon> {
+    //expects stl style iterators
+    template <typename iT>
+    static inline CPolygon& set_points(CPolygon& t,
+                      +iT input_begin, iT input_end) {
+      t.clear();
+      while(input_begin != input_end) {
+        t.push_back(CPoint());
+        gtl::assign(t.back(), *input_begin);
+        ++input_begin;
+      }
+      return t;
+    }
+
+  };
+} }
+
+//OK, finally we get to declare our own polygon set type
+typedef std::deque<CPolygon> CPolygonSet;
+
+//deque isn't automatically a polygon set in the library
+//because it is a standard container there is a shortcut
+//for mapping it to polygon set concept, but I'll do it
+//the long way that you would use in the general case.
+namespace boost { namespace polygon {
+  //first we register CPolygonSet as a polygon set
+  template <>
+  struct geometry_concept<CPolygonSet> { typedef polygon_set_concept type; +};
+
+  //next we map to the concept through traits
+  template <>
+  struct polygon_set_traits<CPolygonSet> {
+    typedef int coordinate_type;
+    typedef CPolygonSet::const_iterator iterator_type;
+    typedef CPolygonSet operator_arg_type;
+
+    static inline iterator_type begin(const CPolygonSet& +polygon_set) {
+      return polygon_set.begin();
+    }
+
+    static inline iterator_type end(const CPolygonSet& +polygon_set) {
+      return polygon_set.end();
+    }
+
+    //don't worry about these, just return false from them
+    static inline bool clean(const CPolygonSet& polygon_set) { +return false; }
+    static inline bool sorted(const CPolygonSet& polygon_set) { +return false; }
+  };
+
+  template <>
+  struct polygon_set_mutable_traits<CPolygonSet> {
+    template <typename input_iterator_type>
+    static inline void set(CPolygonSet& polygon_set, +input_iterator_type input_begin, input_iterator_type input_end) {
+      polygon_set.clear();
+      //this is kind of cheesy. I am copying the +unknown input geometry
+      //into my own polygon set and then calling get to +populate the
+      //deque
+      polygon_set_data<int> ps;
+      ps.insert(input_begin, input_end);
+      ps.get(polygon_set);
+      //if you had your own odd-ball polygon set you +would probably have
+      //to iterate through each polygon at this point +and do something
+      //extra
+    }
+  };
+} }
+
+int main() {
+  long long c1 = clock();
+  for(int i = 0; i < 1000; ++i)
+    test_polygon_set<CPolygonSet>();
+  long long c2 = clock();
+  for(int i = 0; i < 1000; ++i)
+    test_polygon_set<gtl::polygon_set_data<int> >();
+  long long c3 = clock();
+  long long diff1 = c2 - c1;
+  long long diff2 = c3 - c2;
+  if(diff1 > 0 && diff2)
+    std::cout << "library polygon_set_data is " << +float(diff1)/float(diff2) << "X faster than custom polygon set deque of CPolygon" +<< std::endl;
+  else
+    std::cout << "operation was too fast" << std::endl;
+  return 0;
+}

+

//Now you know how to map your own data type to +polygon set concept
+//Now you also know how to make your application code that operates on geometry
+//data type agnostic from point through polygon set + 

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_design_overview.htm b/doc/gtl_design_overview.htm new file mode 100644 index 0000000..60cf0a7 --- /dev/null +++ b/doc/gtl_design_overview.htm @@ -0,0 +1,176 @@ + + +Boost Polygon Library: Overview + + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon Library Design Overview

+ +

+

The Polygon library uses C++-Concepts inspired template programming to +provide generic library functions overloaded on concept type.  There are +currently thirteen concepts in the Polygon library type system.  A concept +object in the Polygon library is just an empty struct similar to a tag that +would be used for tag dispatching.   These concepts are shown in the +refinement diagram below.

+ + +

+The arrows between diagram bubbles show concept refinement relationships.  This is +similar, but not identical to, inheritance relationships between normal classes.  +A refinement of a concept narrows down the definition of a more general concept.  +For example, the rectangle concept is a refinement of a polygon concept because +it restricts the polygon to a four sided, axis-parallel, rectilinear figure.  A refinement +of a concept is always acceptable to an API that expects read only access to a +given concept, but never acceptable to an API that expects to write to that +concept.  There are three types of geometry in the polygon library, the +general case, the case restricted to angles that are multiples of 45 degrees, +and the Manhattan/rectilinear case where angles are restricted to multiples of +90 degrees.   The refinement diagram shows that 90 degree concepts are +refinements of 45 degree concepts, which are themselves refinements of the +general case.  This allows the compiler to choose between the three +implementations of algorithms to select the best algorithm for the conceptual +data types passed to an overload of a function including heterogeneous +combinations of 90, 45 and general case geometry.  To provide the +operator& that performs the intersection on any +pair of objects from the ten conceptual types related to each other through +refinement in the diagraph above fully one hundred distinct combinations of +conceptual types are supported by the library, but only three overloads are +required to implement the operator (one for 90, one for 45 and one for arbitrary +angle version of the intersection operation) because refinement generalizes the +implementation of the interface.  In this way a fully symmetric, complete +and internally consistent API is implemented to provide meaningful and correct +behaviors for all combinations of argument types in all APIs where those types +make sense.  For example, it doesn't make sense to copy data from a polygon +into a rectangle, so attempting to do so yields a syntax error, while copying a +rectangle into a polygon does make sense.  The +assign() function that is used to copy geometry data between concepts +instantiates for the 49 combinations of concepts that make sense, but not for +the 51 combinations that are illegal.  The syntax error you will see when +attempting an illegal assign operation is simple and clear because use of SFINAE +by the library to overload generic functions means no matching function is found +by the compiler in cases where no overload is provided.

+

+error: no matching function for call to 'assign(rectangle_data<int>&, +polygon_data<int>&)'

+

Associated with each concept is a traits struct that generally must be +specialized for a given data type to provide the concept mapping between the +interfaces of the data type and the expected behaviors of an object of that type +required by the library.  The library also provides its own data types for +each concept that conform to the default traits definition.  These library +provided data types are no more than dumb containers that provide access to +their data and rely on the generic library functions to enforce invariants and +provide useful behaviors specific to their type of geometry that would normally +be member functions of the data type in an OO design.  The library data +types conform to the default traits associated with their related geometry +concept and are registered as models of that concept.  When a data +type has been mapped to a concept through traits it needs to be registered +as that conceptual type with the library by +specializing the geometry_concept meta-function.  Once mapped and +registered, a user data type can be used interchangeably with library data types +in the generic free functions that are overloaded on concept.

Traits for +mapping a data type to a concept are broken down into mutable and read only +traits.  Read only traits are specialized internally to work with any types +that are refinements of a concept.  The mutable traits are defined only for +objects that exactly model the concept.  Both read only traits and mutable +traits need to be defined for a type to model a concept, but a type can be used +without defining the mutable traits as long as no API that needs to modify the +object is used with that type.  For example, a triangle type could be +registered as a polygon_concept and the read only traits but not the mutable +traits defined for that triangle type.  This would allow the triangle type +to be passed into any API that expects a const reference to an object that models +polygon.  +

An object that is a model of a given concept can usually be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restrictions of +those concepts.  This concept casting is accomplished through the +view_as<>() function.  For example if +an object of conceptual type polygon 90 has four sides it must be a rectangle, +and can be viewed as a rectangle with the following syntax:

+

view_as<rectangle_concept>(polygon_90_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.  The exception to this ability to +concept cast geometric objects is that polygon set objects cannot be viewed as +individual polygons or rectangles.

+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_interval_concept.htm b/doc/gtl_interval_concept.htm new file mode 100644 index 0000000..e06bbdd --- /dev/null +++ b/doc/gtl_interval_concept.htm @@ -0,0 +1,524 @@ + + +Boost Polygon Library: Interval Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Interval Concept

+ +

+

The interval concept tag is +interval_concept

+

+To register a user defined type as a model of interval concept, specialize the +geometry concept meta-function for that type.  In the example below +CInterval is registered as a model of interval  concept.

+template <>
+struct geometry_concept<CInterval> { typedef interval_concept type; };

+The semantic of an interval is that it has a low +and high coordinate and there is an invariant that low is less than or equal to +high.  This invariant is enforced by the generic library functions that +operate on intervals, and is not expected of the data type itself or the concept +mapping of that data type to the interval concept through its traits.  In +this way a std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> +could all be made models of interval by simply providing indirect access to their +elements through traits.

+Below is shown the default interval traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.

+template <typename T>
+struct interval_traits {
+  typedef typename T::coordinate_type coordinate_type;
+
+  static inline coordinate_type get(const T& interval, direction_1d dir) {
+    return interval.get(dir);
+  }
+};
+
+template <typename T>
+struct interval_mutable_traits {
+  static inline void set(T& interval, direction_1d dir,
+
+                         typename interval_traits<T>::coordinate_type value) {
+    +interval.set(dir, value);
+  +}
+  +static inline T construct(typename interval_traits<T>::coordinate_type low_value, +
+                            +typename interval_traits<T>::coordinate_type high_value) {
+    +return T(low_value, high_value);
+  +}
+};

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ coordinate_type get(const T& interval, direction_1d)
Expects a model of interval.  + Returns the low or high coordinate of the interval, depending on the + direction_1d value.
template <typename T, typename + coordinate_type>
+ void set(T& interval, direction_1d, coordinate_type)
Expects a model of interval.   + Sets the low or high coordinate of the interval to the coordinate, + depending on the direction_1d value.  If low would be greater than + high after this change then both are set to the input coordinate value.
template <typename T>
+ T construct(coordinate_type low, coordinate_type high)
Construct an object that is a model of interval given low and high + coordinate values.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models interval into left object + that models interval.
template <typename T, typename + T2>
+ bool equivalence(const T& interval1, const T2& interval2)
Given two objects that model interval, compares and returns true if + their low and high values are respectively equal to each other.
template <typename T>
+ bool contains(const T&, coordinate_type,
+              + bool consider_touch=true)
Given an object that models interval and a coordinate, returns true + if the interval contains the coordinate.  If the consider_touch + flag is true will return true if the coordinate is equal to one of the + interval ends.
template <typename T1, typename + T2>
+ bool contains(const T1& a, const T2& b,
+              + bool consider_touch = true)
Returns true if model of interval a contains both ends of model of + interval b.  If the consider_touch flag is true will consider the + end of b contained within a even if it is equal to an end of a.
template <typename + interval_type>
+ coordinate_type low(const interval_type& interval)
Returns the low end of an object that models interval.
template <typename + interval_type>
+ coordinate_type high(const interval_type& interval)
Returns the high end of an object that models interval.
// get the center coordinate
+ template <typename interval_type>
+ coordinate_type center(const interval_type& interval)
Returns the center coordinate of an object that models interval.
template <typename + interval_type>
+ void low(interval_type& interval, coordinate_type )
Sets the low end of the object that models interval to the + coordinate value.  If the low end would be set to larger than high + end then both are set to the coordinate value.
template <typename + interval_type>
+ void high(interval_type& interval, coordinate_type )
Sets the high end of the object that models interval to the + coordinate value.  If the high end would be set to less than low + end then both are set to the coordinate value.
template <typename + interval_type>
+ coordinate_difference delta(const interval_type& interval)
Returns the distance from low to high end of an object that models + interval.
template <typename + interval_type>
+ interval_type& flip(interval_type& interval,
+                    + coordinate_type axis = 0)
Flips an object that models interval about the axis coordinate.  + If no axis is provided the interval is flipped across the the origin.
template <typename + interval_type>
+ interval_type& scale_up(interval_type& interval,
+                        + unsigned_area_type factor)
Multiplies low and high ends of an object that models interval by + unsigned factor.
template <typename + interval_type>
+ interval_type& scale_down(interval_type& interval,
+                          + unsigned_area_type factor)
Divides low and high ends of an object that models interval by + unsigned factor.
template <typename + interval_type>
+ interval_type& scale(interval_type& interval,
+                     + double factor)
Multiplies low and high ends of an object that models interval by + floating point value.
template <typename + interval_type>
+ interval_type& move(interval_type& interval,
+                    + coordinate_difference displacement)
Adds displacement value to low and high ends of an object that + models interval.
template <typename + interval_type>
+ interval_type& convolve(interval_type& interval,
+                        + coordinate_type b)
Adds coordinate value to low and high ends of an object that models + interval.
template <typename + interval_type>
+ interval_type& deconvolve(interval_type& interval,
+                          + coordinate_type b)
Subtracts coordinate value from low and high ends of an object that + models interval.
template <typename T1, typename + T2>
+ T1& convolve(T1& a, const T2& b)
Adds low end of b to low end of a and adds high end of b to high end + of a.
template <typename T1, typename + T2>
+ T1& deconvolve(T1& a, const T2& b)
Subtracts low end of b from low end of a and subtracts high end of b + from high end of a.
template <typename T1, typename + T2>
+ T1& reflected_convolve(T1& a, const T2& b)
Adds high end of b to low end of a and adds low end of b to high end + of a.
template <typename T1, typename + T2>
+ T1& reflected_deconvolve(T1& a, const T2& b)
Subtracts high end of b from low end of a and subtracts low end of b + from high end of a.
template <typename T>
+ coordinate_difference euclidean_distance(const T&,
+                      + coordinate_type)
Returns the distance from an object that models interval to a + coordinate.  Returns zero if the coordinate is equal to an end of + the interval or contained within the interval.
template <typename T1, typename + T2>
+ bool intersects(const T1& interval, const T2& b,
+                + bool consider_touch = true)
Returns true if two objects that model interval overlap.  If + the consider_touch flag is true touching at the endpoints is considered + overlap.
template <typename T1, typename + T2>
+ bool boundaries_intersect(const T1& interval, const T2& b,
+                          + bool consider_touch = true)
Returns true is two objects that model interval partially overlap + such that one end point of each is contained within the other.  If + the consider_touch flag is true a coordinate is considered contained + even if it is equal to an end.
template <typename T1, typename + T2>
+ bool abuts(const T1& a, const T2& b,
+           direction_1d dir) +
Returns true if interval b abuts but down not overlap interval a on + the end of interval a specified by dir.
template <typename T1, typename + T2>
+ bool abuts(const T1& a, const T2& b)
Returns true if interval b abuts but down not overlap interval a.
template <typename T1, typename + T2>
+ bool intersect(T1& a, const T2& b,
+               + bool consider_touch = true)
Sets interval a to the intersection of interval a and interval b and + return true.  If the two intervals do not intersect interval a is + unchanged and the function returns false.  If the flag + consider_touch is true intervals that abut are considered to intersect.
template <typename T1, typename + T2>
+ T& generalized_intersect(T1& a, const T2& b)
Same as intersect, but if they do not intersect set a to the + interval between a and b.
template <typename T>
+ T& bloat(T& interval, coordinate_type)
Adds the coordinate value to high end of interval and subtracts it + from low end of interval.
template <typename T>
+ T& bloat(T& interval, direction_1d, coordinate_type)
Adds the coordinate value to high end of interval or subtracts it + from low end of interval depending on the direction_1d.
template <typename T>
+ T& shrink(T& interval, coordinate_type)
Subtracts the coordinate value from high end of interval and adds it + to low end of interval.
template <typename T>
+ T& shrink(T& interval, direction_1d, coordinate_type)
Subtracts the coordinate value from high end of interval or adds it + to low end of interval depending on the direction_1d.
template <typename T1, typename + T2>
+ bool encompass(T1& a, const T2& b)
Sets low of a to min of low of a and low of b and sets high of a to + max of high of a and high of b.  Returns true if b was not + contained within a to begin with.
template <typename T>
+ bool encompass(T& a, coordinate_type)
Sets low of a to min of low of a and coordinate value and sets high + of a to max of high of a and coordinate value.  Returns true if + coordinate value was not contained within a to begin with.
+

Interval Data

+ +

+

The library provides a model of interval concept declared + +template<typename T> interval_data where T is the coordinate type.

+

This data type is used internally when an interval is needed and is available +to the library user who finds it convenient to use a library interval data type +instead of providing their own.  The data type is implemented to be +convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typeinterval_concept
coordinate_typeT
interval_data()Default constructs the two coordinate + values of the interval.
interval_data(T low, T + high)Constructs an interval with two + coordinates.
interval_data(const + interval_data& that)Copy construct
interval_data& operator=(const + interval_data& that)Assignment operator.
template <typename T2>  +
interval_data& operator=(const T2& that) const
Assign from an object that is a model of interval.
template <typename T2> +
bool + operator==(const T2& that) const
Compare equality to an object that is a model of interval.
template <typename T2> +
bool + operator!=(const T2& that) const
Compare inequality to an object that is a model of interval.
template <typename T2> +
bool + operator<(const T2& that) const
Compares low coordinates then high coordinates to break ties.
template <typename T2> +
bool + operator<=(const T2& that) const
Compares low coordinates then high coordinates to break ties.
template <typename T2> +
bool + operator>(const T2& that) const
Compares low coordinates then high coordinates to break ties.
template <typename T2> +
bool + operator>=(const T2& that) const
Compares low coordinates then high coordinates to break ties.
T get(direction_1d dir) + constGet the coordinate in the given direction.
void set(direction_1d + dir, T value)Sets the coordinate in the given direction to the value.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_isotropy.htm b/doc/gtl_isotropy.htm new file mode 100755 index 0000000..f97b3a0 --- /dev/null +++ b/doc/gtl_isotropy.htm @@ -0,0 +1,521 @@ + + +Boost Polygon Library: Isotropy + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Isotropy

+ +

+

What is isotropy?

+ +
+

+ Isotropy - Function: adjective Etymology: International + Scientific Vocabulary
+ : exhibiting properties (as velocity of light transmission) with the + same values when measured along axes in all directions <an isotropic + crystal>

+

In computational geometry things are often symmetric and +invariant to direction and orientation.  This invariance to direction is +called isotropy.  In such situations it is convenient to parameterize +direction or orientation and write code that is invariant to the direction or +orientation in which it is applied.  To do this effectively we provide an +internally consistent set of isotropic data types to represent program +data that describes orientations and directions.  These data types are:

+
    +
  • direction_1d - has one of the following 2 states: LOW, HIGH
  • +
  • orientation_2d - has one of the following 2 states: HORIZONTAL, + VERTICAL
  • +
  • direction_2d - has one of the following 4 states: WEST, EAST, SOUTH, + NORTH
  • +
  • orientation_3d - has one of the following 3 states: HORIZONTAL, + VERTICAL, PROXIMAL
  • +
  • direction_3d - has one of the following 6 states: WEST, EAST, SOUTH, + NORTH, DOWN, UP
  • +
+ +

The isotropic types create a system and interact with each other +in various ways, such as casting.  Together they create a language for +describing isotropic situations programmatically.  For instance, to get the +positive direction_2d from an orientation_2d you would call a member function of +orientation_2d and pass a direction_1d:

+

orientation_2d orient = HORIZONTAL;
+direction_2d dir = orient.get_direction(direction_1d(HIGH));
+assert(dir == EAST);

+

The motivation for providing isotropic data types is to +encourage programming at a higher level of abstraction where program behavior is +controlled by program data passed into function calls rather than flow control +syntax.  Isotropic programming style is particularly applicable to working +with points, intervals and rectangles.  Often times the implementation of +such logic is identical when implemented for the x or y coordinates, except that +the names of functions and data members are changed in a mechanical way leading +to code duplication and bloat that results in copy-paste programming errors and +maintenance problems where changes made to a given code block relating to x +coordiantes are not duplicated to the code block that refers to y.  +Isotropy therefore represents an opportunity to refactor and improve the quality +of low level geometry code especially in regard to inter-relating coordinates, +points, intervals and rectangles.

+

direction_1d

+ +

+

The direction_1d data type has two possible states.  These +are the positive and negative directions on a continuum such as the number line.   +These states can be described by one of several direction_1d_enum values:  +We make clockwise and counterclockwise winding orientation of polygons a +direction 1d value instead of providing a separate winding_orientation data +type.  This is because winding orientation can be thought of as positive +and negative directions in a 1d (although cyclic) space.  We assign +counterclockwise to be the positive direction of travel in the 1d cyclic space +to conform with the mathematical convention frequently described as the "right +hand rule" which assigns positive normal value to counterclockwise and negative +normal value to clockwise as well as the common convention that counterclockwise +polygon winding corresponds to positive polygonal regions where as clockwise +polygon winding corresponds to hole (negative) polygonal regions.

+

enum direction_1d_enum {LOW = 0, HIGH = +1,
+                        +LEFT = 0, RIGHT = 1,
+                        +CLOCKWISE = 0, COUNTERCLOCKWISE = 1,
+                        +REVERSE = 0, FORWARD = 1,
+                        +NEGATIVE = 0, POSITIVE = 1 };

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
direction_1d(direction_1d_enum + val = LOW)Constructor defaults to LOW.
direction_1d(const + direction_1d& that)Copy construct.
direction_1d(const + direction_2d& that)Down cast direction_2d, extracting out whether positive or negative
direction_1d(const + direction_3d& that)Down cast direction_3d, extracting out whether positive or negative
+direction_1d& operator=(const direction_1d dir)Assignment
+direction_1d& operator==(const direction_1d dir) +constEquivalence
+direction_1d& operator!=(const direction_1d dir) +constInequivalence
+unsigned int to_int() constConvert to the integer enum value of current state to use as index.  + Auto-cast to int is disallowed for type safety reasons.
+direction_1d& backward()Inverts direction.
+int get_sign() constReturns positive 1 if positive direction and negative one if + negative direction.
+

orientation_2d

+ +

+

The orientation_2d data type has two possible states.  +These are the horizontal and vertical axis of a 2d Cartesian coordinate system.   +These states can be described by one of the two orientation_2d_enum values:

+

enum orientation_2d_enum { HORIZONTAL = +0, VERTICAL = 1 };

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
orientation_2d(orientation_2d_enum + val = HORIZONTAL)Constructor defaults to HORIZONTAL.
orientation_2d(const + orientation_2d& that)Copy construct.
explicit + orientation_2d(const + direction_2d& that)Down cast direction_2d, extracting out whether horizontal or + vertical direction type
+orientation_2d& operator=(const orientation_2d +o)Assignment
+orientation_2d& operator==(const orientation_2d +o) constEquivalence
+orientation_2d& operator!=(const orientation_2d +o) constInequivalence
+unsigned int to_int() constConvert to the integer enum value of current state to use as index.  + Auto-cast to int is disallowed for type safety reasons
+orientation_2d& turn_90()Change to orthogonal orientation
+int get_perpendicular() constReturns orthogonal orientation
+int get_direction(direction_1d dir) constReturns the positive or negative direction_2d depending on the value + of dir
+

direction_2d

+ +

+

The direction_2d data type has four possible states.  These +are the cardinal directions of the 2D Cartesian coordinate system.   +These states can be described by one of several direction_2d_enum values:

+

enum direction_2d_enum { WEST = 0, EAST += 1, SOUTH = 2, NORTH = 3 };

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
direction_2d(direction_2d_enum + val = WEST)Constructor defaults to WEST.
direction_2d(const + direction_2d& that)Copy construct.
+direction_1d& operator=(const direction_2d dir)Assignment
+direction_1d& operator==(const direction_2d dir) +constEquivalence
+direction_1d& operator!=(const direction_2d dir) +constInequivalence
+unsigned int to_int() constConvert to the integer enum value of current state to use as index.  + Auto-cast to int is disallowed for type safety reasons.
+direction_2d& backward()Inverts direction.
+direction_2d& turn(direction_1d dir)Changes to direction_2d to the left if dir is LOW, to the right if + dir is HIGH
+direction_2d& left()Changes to the direction_2d to the left
+direction_2d& right()Changes to the direction_2d to the right
+int is_positive() constReturns true if EAST or NORTH
+int is_negative() constReturns true if WEST or SOUTH
+int get_sign() constReturns positive 1 if positive direction and negative one if + negative direction.
+

orientation_3d

+ +

+

The orientation_3d data type has three possible states.  +These are the horizontal, vertical and proximal (x, y, z) axis of a 3d Cartesian +coordinate system.   These states can be described by one of the +orientation_2d_enum values or by the orientation_3d_enum value:

+

enum orientation_3d_enum { PROXIMAL = 2 +};

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
orientation_3d(orientation_2d_enum + val = HORIZONTAL)Constructor defaults to HORIZONTAL.
orientation_3d(const + orientation_3d& that)Copy construct.
explicit + orientation_3d(const + direction_2d& that)Extract out the orientation of the direction
explicit + orientation_3d(const + direction_3d& that)Extract out the orientation of the direction
orientation_3d(const + orientation_2d& that)Up cast orientation_2d to orientation_3d.
orientation_3d(const + orientation_3d_enum& that)Construct from constant value
+orientation_3d& operator=(const orientation_3d +o)Assignment
+orientation_3d& operator==(const orientation_3d +o) constEquivalence
+orientation_3d& operator!=(const orientation_3d +o) constInequivalence
+unsigned int to_int() constConvert to the integer enum value of current state to use as index.  + Auto-cast to int is disallowed for type safety reasons
+int get_direction(direction_1d dir) constReturns the positive or negative direction_2d depending on the value + of dir
+

direction_3d

+ +

+

The direction_3d data type has six possible states.  These +are the cardinal directions of the 3D Cartesian coordinate system.   +These states can be described by one of the direction_2d_enum values or the +direction_3d_enum values:

+

enum direction_3d_enum { DOWN = 4, UP = +5 };

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
direction_3d(direction_2d_enum + val = WEST)Constructor defaults to LOW.
direction_3d(direction_3d_enum that)Construct from constant value
direction_3d(const + direction_3d& that)Copy construct
direction_3d(direction_2d that)Up cast direction_2d to direction_3d
+direction_3d& operator=(const direction_3d dir)Assignment
+direction_3d& operator==(const direction_3d dir) +constEquivalence
+direction_2d& operator!=(const direction_3d dir) +constInequivalence
+unsigned int to_int() constConvert to the integer enum value of current state to use as index.  + Auto-cast to int is disallowed for type safety reasons.
+direction_1d& backward()Inverts direction.
+int is_positive() constReturns true if direction is EAST, NORTH or UP.
+int is_negative() constReturns true if direction is WEST, SOUTH or DOWN
+int get_sign() constReturns positive 1 if positive direction and negative one if + negative direction.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_minkowski_tutorial.htm b/doc/gtl_minkowski_tutorial.htm new file mode 100644 index 0000000..0607a76 --- /dev/null +++ b/doc/gtl_minkowski_tutorial.htm @@ -0,0 +1,229 @@ + + + + +Polygon Usage + + + + +

Minkowski Sum Tutorial

+

In this tutorial we will implement an algorithm to compute the Minkowski sum +of two polygon sets.  The Minkowski sum of two polygon sets is the +convolution of the two polygon sets and is defined as the set of points which is +produced if you sum all pairs of points in the two polygon sets.  The sum +of two points is implemented in Boost.Polygon by the +convolve function for point_concept.  +Similarly there is a +convolve function for rectangle_concept.  +The convolution of two polygon sets produces a polygon set as its output.  +An example of the convolution of two polygons is shown below.  The center +point of the green +star can be imagined to slide around freely inside the blue picture frame shape +painting the area the star touches to produce the red bloated picture frame.

+

 

+

The above image was produced using the code presented in this tutorial.  +We can see that the algorithm for Minkowski sum should support non-convex +polygons that may potentially have holes.  It should also support disjoint +polygons in both input polygon sets.  Shown below is what happens when +multiple polygons are present in each input polygon set.

+

+

In each of these examples the origin of the coordinate system is in the lower +left corner of the image and the sum of the x and y locations of the input +polygons places the result in the upper right hand corner of the images.  +In the example above the lower left red triangle is the convolution of the small +blue triangle with the small green triangle.  The upper right red triangle +is the convolution of the large blue and large green triangle.  The two +medium sized red polygons are the result of the convolution of the small with +large and large with small blue and green triangles.  The test case was +carefully contrived to prevent the result from merging together, though that +could certainly happen.

+

The algorithm implemented for Minkowski sum in this tutorial is very simple.  +It is based on the convolution of polygon edges.  The convolution of two +edges is very easy to compute and is in general a parallelogram.  An +example of two edges being convolved to produce a parallelogram is shown below.

+

+

Now that we know what we need from a function to convolve two edges, let's +implement one now.  Below we show the code for convolving two edges along +with some type definitions we will be using throughout the tutorial.  The +code for this tutorial is available in +minkowski.cpp.

+

typedef boost::polygon::point_data<int> +point;
+typedef boost::polygon::polygon_set_data<int> polygon_set;
+typedef boost::polygon::polygon_with_holes_data<int> polygon;
+typedef std::pair<point, point> edge;
+using namespace boost::polygon::operators;
+
+void convolve_two_segments(std::vector<point>& figure, const edge& a, const +edge& b) {
+  using namespace boost::polygon;
+  figure.clear();
+  figure.push_back(point(a.first));
+  figure.push_back(point(a.first));
+  figure.push_back(point(a.second));
+  figure.push_back(point(a.second));
+  convolve(figure[0], b.second);
+  convolve(figure[1], b.first);
+  convolve(figure[2], b.first);
+  convolve(figure[3], b.second);
+}

+

This function for convolving two line segments just convolves the end points +of the two line segments in all combinations to produce the four points of a +parallelogram and populates a vector of points with them in the correct order.  +We are using the Boost.Polygon library function for convolving two points and +the library point data structure.

+

To compute the convolution of two polygon sets we start by taking the union +of the convolution of all pairs of edges between the two polygon sets.  +Given an operation for convolving two edges it is pretty easy to convolve all +pairs of edges of two polygon sets.  The result is the convolution the +perimeters of the polygon sets, but doesn't handle the convolution of their +interiors.  To illustrate this we show what happens when one of the above +examples is computed using just the all pairs of edges convolution.

+

 

+

As we can see, the result is as if the small triangles were slid around the +perimeter of the large triangles leaving a hole in the center that should be +filled in if the small triangle were allowed to slide freely within the large +triangle.  Also available in Boost.Polygon is the +convolve function for polygon_concept +that convolves a polygon over a point.  All this does is translate the +polygon by the x and y value of the point.  To fill in the interior regions +of the result of the convolution of two polygon sets we perform an all pairs of +polygon convolution to the first vertex of the other polygon and merge that into +the union of edge convolutions.

+

Let's implement the rest of Minkowski sum of two polygon sets as the union of +all pairs edges convolutions and the all pairs of polygons to point +convolutions.  First we implement a function that convolves all pairs of +edges represented by iterator pairs over points.  We assume that the first +point is equal to the last point in each sequence because we know the polygons +that gave rise to the iterators were produced by the Boost.Polygon algorithm for +general polygon formation.

+

template <typename itrT1, typename itrT2>
+void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 +bb, itrT2 be) {
+  using namespace boost::polygon;
+  if(ab == ae || bb == be)
+    return;
+  point prev_a = *ab;
+  std::vector<point> vec;
+  polygon poly;
+  ++ab;
+  for( ; ab != ae; ++ab) {
+    point prev_b = *bb;
+    itrT2 tmpb = bb;
+    ++tmpb;
+    for( ; tmpb != be; ++tmpb) {
+      convolve_two_segments(vec, std::make_pair(prev_b, +*tmpb), std::make_pair(prev_a, *ab));
+      set_points(poly, vec.begin(), vec.end());
+      result.insert(poly);
+      prev_b = *tmpb;
+    }
+    prev_a = *ab;
+  }
+}

+

Using the function defined above we can implement a function for computing +the convolution of all pairs of edges represented by an iterator pair over +points and edges in a collection of polygons.  We just call the +convolve_two_point_sequences for the input point sequence and all outer shell +and hole point sequences from the container of polygons.

+

template <typename itrT>
+void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, +const std::vector<polygon>& polygons) {
+  using namespace boost::polygon;
+  for(std::size_t i = 0; i < polygons.size(); ++i) {
+    convolve_two_point_sequences(result, b, e, +begin_points(polygons[i]), end_points(polygons[i]));
+    for(polygon_with_holes_traits<polygon>::iterator_holes_type +itrh = begin_holes(polygons[i]);
+        itrh != end_holes(polygons[i]); ++itrh) +{
+      convolve_two_point_sequences(result, b, e, +begin_points(*itrh), end_points(*itrh));
+    }
+  }
+}

+

Using the function defined above we can implement a function for computing +the convolution of all pairs of edges from polygons contained within two polygon +sets.  We also convolve each polygon with the first vertex of every polygon +from the other set to fill in the interiors of the result.

+

void convolve_two_polygon_sets(polygon_set& +result, const polygon_set& a, const polygon_set& b) {
+  using namespace boost::polygon;
+  result.clear();
+  std::vector<polygon> a_polygons;
+  std::vector<polygon> b_polygons;
+  a.get(a_polygons);
+  b.get(b_polygons);
+  for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) {
+    convolve_point_sequence_with_polygons(result, +begin_points(a_polygons[ai]),
+                                          +end_points(a_polygons[ai]), b_polygons);
+    for(polygon_with_holes_traits<polygon>::iterator_holes_type +itrh = begin_holes(a_polygons[ai]);
+        itrh != end_holes(a_polygons[ai]); ++itrh) +{
+      convolve_point_sequence_with_polygons(result, +begin_points(*itrh),
+                                            +end_points(*itrh), b_polygons);
+    }
+    for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) {
+      polygon tmp_poly = a_polygons[ai];
+      result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi]))));
+      tmp_poly = b_polygons[bi];
+      result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai]))));
+    }
+  }
+}

+

We test the convolution of two polygon sets with the code shown below that +produces the first example shown in this tutorial. +

+

polygon_set a, b, c;
+a += boost::polygon::rectangle_data<int>(0+300, 0, 200+300, 200);
+a -= boost::polygon::rectangle_data<int>(50+300, 50, 150+300, 150);
+std::vector<polygon> polys;
+std::vector<point> pts;
+pts.push_back(point(-40, 0+300));
+pts.push_back(point(-10, 10+300));
+pts.push_back(point(0, 40+300));
+pts.push_back(point(10, 10+300));
+pts.push_back(point(40, 0+300));
+pts.push_back(point(10, -10+300));
+pts.push_back(point(0, -40+300));
+pts.push_back(point(-10, -10+300));
+pts.push_back(point(-40, 0+300));
+polygon poly;
+boost::polygon::set_points(poly, pts.begin(), pts.end());
+b+=poly;
+convolve_two_polygon_sets(c, a, b);

+

Output (a is blue, b is green and c is red):

+

+

This concludes our tutorial on how to implement Minkowski sum of polygons as +the convolution of polygon sets based on the Boolean OR operation of geometry +produced by simpler convolution features provided by the Boost.Polygon library.

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + \ No newline at end of file diff --git a/doc/gtl_point_concept.htm b/doc/gtl_point_concept.htm new file mode 100644 index 0000000..4283c2b --- /dev/null +++ b/doc/gtl_point_concept.htm @@ -0,0 +1,400 @@ + + +Boost Polygon Library: Point Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Point Concept

+ +

+

+The point concept tag is +point_concept

+To register a user defined type as a model of point concept, specialize the +geometry concept meta-function for that type.  In the example below CPoint is registered as a model of +point  concept.

+template <>
+struct geometry_concept<CPoint> { typedef point_concept type; };

+The semantic of a point is that it has an x and y +coordinate.  A std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> +could all be made models of point by simply providing indirect access to their +elements through traits, however, these objects cannot be made a model of both +point and interval in the same compilation unit, for obvious reason that +duplicate specialization of the geometry_concept struct is illegal, but also +because it would make overloading generic function by concept ambiguous if a +type modeled more than one concept.

+Below is shown the default point traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.

+template <typename T>
+struct point_traits {
+     typedef typename T::coordinate_type coordinate_type;
+
+     static inline coordinate_type get(const T& point, +orientation_2d orient) {
+          return point.get(orient); +
+     }
+};
+
+template <typename T>
+struct point_mutable_traits {
+     static inline void set(T& point, orientation_2d orient, +typename point_traits<T>::coordinate_type value) {
+          point.set(orient, value); +
+     }
+     static inline T construct(typename point_traits<T>::coordinate_type +x_value, typename point_traits<T>::coordinate_type y_value) {
+          return T(x_value, y_value); +
+     }
+};

+Example code custom_point.cpp demonstrates +how to map a + user defined point class to the library point_concept

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ coordinate_type get(const T& point, orientation_2d)
Expects a model of point.  Returns + the x or y coordinate of the point, depending on the orientation_2d + value.
template <typename T, typename + coordinate_type>
+ void set(T& point, orientation_2d, coordinate_type)
Expects a model of point.   + Sets the x or y coordinate of the point to the coordinate, depending on + the orientation_2d  value.
template <typename T>
+ T construct(coordinate_type x, coordinate_type y)
Construct an object that is a model of point given x and y + coordinate values.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models point into left object + that models point.
template <typename T, typename + T2>
+ bool equivalence(const T& point1, const T2& point2)
Given two objects that model point, compares and returns true if + their x and y values are respectively equal to each other.
template <typename point_type>
+ coordinate_type x(const point_type& point)
Returns the x coordinate of an object that models point.
template <typename point_type>
+ coordinate_type y(const point_type& point)
Returns the y coordinate of an object that models point.
template <typename point_type>
+ void x(point_type& point, coordinate_type )
Sets the x coordinate of the object that models point to the + coordinate value. 
template <typename point_type>
+ void y(point_type& point, coordinate_type )
Sets the y coordinate of the object that models point to the + coordinate value. 
template <typename point_type>
+ point_type& scale_up(point_type& point,
+                        + unsigned_area_type factor)
Multiplies x and y coordinate of an object that models point by + unsigned factor.
template <typename point_type>
+ point_type& scale_down(point_type& point,
+                          + unsigned_area_type factor)
Divides x and y coordinate of an object that models point by + unsigned factor.
template <typename point_type, + typename scaling_type>
+ point_type& scale(point_type& point,
+                  + const scaling_type& factor)
Calls the scale member function of scaling type on the x and y value + of an object that models point and sets the point to the scaled values.
template <typename point_type, + typename transform_type>
+ point_type& transform(point_type& point,
+                      + const transform_type& transform)
Calls the transform member function of transform type on the x and y + value of an object that models point and sets the point to the + transformed values.
template <typename point_type>
+ point_type& move(point_type& point, orientation_2d
+                 + coordinate_difference displacement)
Adds displacement value to the coordinate of an object that models + point indicated by the orientation_2d.
template <typename T1, typename + T2>
+ T1& convolve(T1& a, const T2& b)
Adds x coordinate of b to x coordinate of a and adds y coordinate of + b to y coordinate of a.
template <typename T1, typename + T2>
+ T1& deconvolve(T1& a, const T2& b)
Subtracts x coordinate of b from x coordinate of a and subtracts y + coordinate of b from y coordinate of a.
template <typename T1, typename + T2>
+ coordinate_distance euclidean_distance(const T1&,
+                                       + const T2&)
Returns the distance from an object that models point to a second + object that models point.
template <typename T>
+ coordinate_difference euclidean_distance(const T&,
+           orientation_2d, + coordinate_type)
Returns the distance from an object that models point to a + coordinate in the given orientation_2d.
template <typename T1, typename + T2>
+ coordinate_difference manhattan_distance(const T1&,
+                                       + const T2&)
Returns the distance in x plus the distance in y from an object that + models point to a second object that models point.
template <typename T1, typename + T2>
+ coordinate_difference distance_squared(const T1&,
+                                       + const T2&)
Returns the square of the distance in x plus the square of the + distance in y from an object that models point to a second object that + models point.
+

Point Data

+ +

+

The library provides a model of point concept declared + +template<typename T> point_data where T is the coordinate type.

+

This data type is used internally when a point is needed and is available to +the library user who finds it convenient to use a library point data type +instead of providing their own.  The data type is implemented to be +convenient to use with the library traits.

+

Example code point_usage.cpp demonstrates using the + library provided point data type and functions

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepoint_concept
coordinate_typeT
point_data()Default constructs the two coordinate + values of the point.
point_data(T x, T y)Constructs an interval with two + coordinates.
point_data(const point_data* + that)Copy construct
point_data& operator=(const + point_data& that)Assignment operator.
template <typename T2>  +
point_data& operator=(const T2& that) const
Assign from an object that is a model of point.
template <typename T2> +
bool + operator==(const T2& that) const
Compare equality to an object that is a model of point.
template <typename T2> +
bool + operator!=(const T2& that) const
Compare inequality to an object that is a model of point.
template <typename T2> +
bool + operator<(const T2& that) const
Compares y coordinates then x coordinates to break ties.
template <typename T2> +
bool + operator<=(const T2& that) const
Compares y coordinates then x coordinates to break ties.
template <typename T2> +
bool + operator>(const T2& that) const
Compares low coordinates then high coordinates to break ties.
template <typename T2> +
bool + operator>=(const T2& that) const
Compares low coordinates then high coordinates to break ties.
T get(orientation_2d + orient) constGet the coordinate in the given orientation.
T x() constGet the coordinate in the horizontal orientation.
T y() constGet the coordinate in the vertical orientation.
void set(orientation_2d + orient, T value)Sets the coordinate in the given orientation to the value.
void x(T value)Sets the coordinate in the horizontal orientation to the value.
void y(T value)Sets the coordinate in the vertical orientation to the value.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_point_usage.htm b/doc/gtl_point_usage.htm new file mode 100644 index 0000000..356c555 --- /dev/null +++ b/doc/gtl_point_usage.htm @@ -0,0 +1,90 @@ + + + + +Point Usage + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+int main() {
+  //constructing a gtl point
+  typedef gtl::point_data<int> Point;
+  int x = 10;
+  int y = 20;
+  Point pt(x, y);
+  assert(gtl::x(pt) == 10);
+  assert(gtl::y(pt) == 20);

+  //a quick primer in isotropic point access
+  typedef gtl::orientation_2d O;
+  using gtl::HORIZONTAL;
+  using gtl::VERTICAL;
+  O o = HORIZONTAL;
+  assert(gtl::x(pt) == gtl::get(pt, o));

+  o = o.get_perpendicular();
+  assert(o == VERTICAL);
+  assert(gtl::y(pt) == gtl::get(pt, o));
+
+  gtl::set(pt, o, 30);
+  assert(gtl::y(pt) == 30);
+
+  //using some of the library functions
+  Point pt2(10, 30);
+  assert(gtl::equivalence(pt, pt2));
+
+  gtl::transformation<int> tr(gtl::axis_transformation::SWAP_XY);
+  gtl::transform(pt, tr);
+  assert(gtl::equivalence(pt, Point(30, 10)));
+
+  gtl::transformation<int> tr2 = tr.inverse();
+  assert(tr == tr2); //SWAP_XY is its own inverse transform
+
+  gtl::transform(pt, tr2);
+  assert(gtl::equivalence(pt, pt2)); //the two points are equal again
+
+  gtl::move(pt, o, 10); //move pt 10 units in y
+  assert(gtl::euclidean_distance(pt, pt2) == 10.0f);
+
+  gtl::move(pt, o.get_perpendicular(), 10); //move pt 10 units in x
+  assert(gtl::manhattan_distance(pt, pt2) == 20);
+
+  return 0;
+}

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_polygon_45_concept.htm b/doc/gtl_polygon_45_concept.htm new file mode 100644 index 0000000..d9d60e8 --- /dev/null +++ b/doc/gtl_polygon_45_concept.htm @@ -0,0 +1,360 @@ + + +Boost Polygon Library: Polygon 45 Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 45 Concept

+ +

+

The polygon_45 concept tag is +polygon_45_concept

+

+To register a user defined type as a model of +polygon_45 concept, specialize the +geometry concept meta-function for that type.  In the example below CPolygon45 is registered as a model of +polygon_45  concept.

+template <>
+struct geometry_concept<CPolygon45> { typedef polygon_45_concept type; };

+The semantic of a polygon_45 is that it can provide +iterators over the points that represent its vertices, angles formed as these +vertices must be multiple of 45-degree relative to the coordinate axis.  It +is acceptable to have the last edge explict with the first and last point equal +to each other or implied by this segement that would connect the first and last +point.  A mutable polygon_45 must also be able to set its geometry based on +an interator range over such points.   A std::vector<point_data<int> > +or std::list<point_data<int> > +could be made models of polygon_45_concept by simply providing access to their +iterators through traits.  Library functions that create polygon objects +require that those objects provide a default constructor.

+Below is shown the default polygon traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.  Note that these traits are also used by several other +polygon concepts through SFINAE enable template parameter.  The SFINAE enable +parameter also allows the library to provide default specialization that work +for any object that models the 90 degree polygon concepts.

+template <typename T, typename enable = gtl_yes>
+struct polygon_traits {};
+
+template <typename T>
+struct polygon_traits<T,
+  typename gtl_or_4<
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_45_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_with_holes_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_45_with_holes_concept>::type
+  >::type> {
+     typedef typename T::coordinate_type coordinate_type;
+     typedef typename T::iterator_type iterator_type;
+     typedef typename T::point_type point_type;
+     static inline iterator_type begin_points(const T& t) {
+          return t.begin();
+     }
+     static inline iterator_type end_points(const T& t) {
+          return t.end();
+     }
+     static inline unsigned int size(const T& t) {
+          return t.size();
+     }
+     static inline winding_direction winding(const T& t) {
+          return unknown_winding;
+     }
+};

+

template <typename T, typename enable = void>
+struct polygon_mutable_traits {
+     template <typename iT>
+     static inline T& set_points(T& t, iT input_begin, iT +input_end) {
+          t.set(input_begin, +input_end);
+          return t;
+     }
+};

+

An object that is a model of +polygon_45_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_45_object)
+view_as<polygon_90_concept>(polygon_45_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of polygon_45.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of polygon_45.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of polygon_45.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a polygon.  Non-45 edges between successive input + points is disallowed.
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + polygon.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon_45 into left object + that models polygon_45.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon_45 and an object that models + point, returns true + if the polygon contains the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon.  Linear wrt. vertices.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon_45.  Linear wrt. vertices.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon_45 and returns true.  Returns false and leaves + bbox unchanged if polygon is empty.  Linear wrt. vertices.
template <typename T>
+ area_type area(const T& polygon)
Returns the area of an object + that models polygon_45.  Linear wrt. vertices.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon_45, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  + Complexity depends upon winding trait.
template <typename T>
+ coordinate_distance perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon_45.  Linear wrt. vertices.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Linear wrt. vertices.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up coordinate of an object that models + polygon_45 by unsigned factor.  Linear wrt. vertices.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down coordinates of an object that models + polygon_45 by unsigned factor.  Linear wrt. vertices.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales coordinates of an object that models polygon_45 by floating + point factor.  Linear wrt. vertices.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon_45.  Linear wrt. + vertices.
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with vertices of an + object that models polygon_45.  Linear wrt. vertices.
+

Polygon 45 Data

+ +

+

The library provides a model of polygon 45 concept declared + +template<typename T> polygon_45_data where T is the coordinate type.

+

This data type is used internally when a 45-degree polygon is needed and is +available to the library user who finds it convenient to use a library polygon +data type instead of providing their own.  The data type is implemented to +be convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_45_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
polygon_45_data()Default constructs the polygon.
polygon_45_data(const + polygon_45_data& that)Copy construct
polygon_45_data& operator=(const + polygon_45_data& that)Assignment operator.
template <typename T2>  +
polygon_45_data& operator=(const T2& that) const
Assign from an object that is a model of polygon 45.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points.  No check is + performed to ensure the points describe corners that are multiples of 45 + degrees relative to the coordinate axis.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_45_set_concept.htm b/doc/gtl_polygon_45_set_concept.htm new file mode 100644 index 0000000..36ef8b6 --- /dev/null +++ b/doc/gtl_polygon_45_set_concept.htm @@ -0,0 +1,739 @@ + + +Boost Polygon Library: Polygon 45 Set Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 45 Set Concept

+ +

+

The polygon_45_set concept tag is +polygon_45_set_concept

+

+The semantic of a polygon_45_set is zero or more +geometry regions which have angles at the vertices that are multiples of +45-degrees relative to the coordinate axis.  A Polygon 45 Set Concept makes +no sense in floating point, but currently does not provide a static assert to +prevent it from being used with floating point coordinates.  The result of +such use is undefined.  When the intersection of two 45 degree edges +results in a vertex that is off the integer grid that case is handled by +inserting a unit length edge between the two 45 degree edges near the off grid +intersection point.  In the case that data represented contains no +45-degree angles and is Manhattan a runtime check will default to the Manhattan +algorithm.  The results of which are identical to what the 45-degree +algorithm would do, but obtained more efficiently.

+The motivation for providing the polygon_45_set is +to extend the special case of Manhattan geometry capability of the library to +encompass the slightly less common, but still important special case of geometry +that is described by angles that are multiples of 45-degress with respect to the +coordinate axis.  This simplifies the implementation of geometry algorithms +and affords many opportunities for optimization.  45-degree algorithms can +be 50X faster than arbitrary angle algorithms and are required to provide a +complete feature set that meets the performance requirements of application +domains in which Manhattan and 45-degree geometry are a common special case.

Users are recommended to use std::vector and std::list of user defined polygons +or library provided polygon_45_set_data<coordinate_type> objects.  Lists +and vectors of models of polygon_45_concept or polygon_45_with_holes_concept are automatically models of polygon_45_set_concept.

+

An object that is a model of +polygon_45_set_concept can be viewed as a model of +polygon_90_set_concept if it is determined at runtime to conform to the +restriction that all edges are axis-parallel.  This concept casting is +accomplished through the view_as<>() function.

+

view_as<polygon_90_set_concept>(polygon_set_object)

+

The return value of view_as<>() can be passed +into any interface that expects an object of the conceptual type specified in +its template parameter.  Polygon sets cannot be viewed as single polygons +or rectangles since it generally cannot be known whether a polygon set contains +only a single polygon without converting to polygons.

+

Operators

+

The return type of some operators is the polygon_45_set_view +operator template type.  This type is itself a model of the polygon 90 set +concept, but furthermore can be used as an argument to the polygon_45_set_data +constructor and assignment operator.  The operator template exists to +eliminate temp copies of intermediate results when Boolean operators are chained +together.

+

Operators are declared inside the namespace boost::polygon::operators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ polygon_45_set_view operator|(const T1& l, const T2& r)
Boolean OR operation (polygon set union).  Accepts two objects + that model polygon_45_set or one of its refinements.  Returns an + operator template that performs the operation on demand when chained or + or nested in a library function call such as assign().  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_45_set_view operator+(const T1& l, const T2& r)
Same as operator|.  The plus sign is also used for OR + operations in Boolean logic expressions.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_45_set_view operator&(const T1& l, const T2& r)
Boolean AND operation (polygon set intersection).  Accepts two + objects that model polygon_45_set or one of its refinements.  O( n + log n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_45_set_view operator*(const T1& l, const T2& r)
Same as operator&.  The multiplication symbol is also used for + AND operations in Boolean logic expressions.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_45_set_view operator^(const T1& l, const T2& r)
Boolean XOR operation (polygon set disjoint-union).  Accepts + two objects that model polygon_45_set or one of its refinements.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T1, typename + T2>
+ polygon_45_set_view operator-(const T1& l, const T2& r)
Boolean SUBTRACT operation (polygon set difference).  Accepts + two objects that model polygon_45_set or one of its refinements.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T1, typename + T2>
+ T1& operator|=(const T1& l, const T2& r)
Same as operator|, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(T1& l, const T2& r)
Same as operator+, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator&=(const T1& l, const T2& r)
Same as operator&, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator*=(T1& l, const T2& r)
Same as operator*, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator^=(const T1& l, const T2& r)
Same as operator^, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(T1& l, const T2& r)
Same as operator-, but with self assignment, left operand must model + polygon_45_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1>
+ T1 operator+(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Note: returns + result by value.  O( n log n) runtime complexity and O(n) memory + wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1 operator-(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Note: returns + result by value.  O( n log n) runtime complexity and O(n) memory + wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Returns + reference to modified argument.  O( n log n) runtime complexity and + O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Returns + reference to modified argument.  O( n log n) runtime complexity and + O(n) memory wrt vertices + intersections.
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ T1& assign(T1& lvalue, const T2& rvalue)
Eliminates overlaps in geometry and copies from an object that + models polygon_45_set or any of its refinements into an object that + models polygon_45_set.  O( n log n) runtime complexity and O(n) + memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ bool equivalence(const T1& lvalue, const T2& rvalue)
Returns true if an object that models polygon_45_set or one of its + refinements covers the exact same geometric regions as another object + that models polygon_45_set or one of its refinements.  For example: + two of polygon_45 objects.  O( n log n) runtime complexity and O(n) + memory wrt vertices + intersections.
template <typename + output_container_type, typename T>
+ void get_trapezoids(output_container_type& output,
+                    + const T& polygon_set)
Output container is expected to be a standard container.  + Slices geometry of an object that models polygon_45_set or one of its + refinements into non overlapping trapezoids along a vertical slicing + orientation and appends them to the + output, which must have a value type that models polygon_45, + polygon_45_with_holes, polygon or polygon_with_holes.   O( n + log n) runtime complexity and O(n) memory wrt vertices.
template <typename + output_container_type, typename T>
+ void get_trapezoids(output_container_type& output,
+                    + const T& polygon_set,
                    orientation_2d orient)
Output container is expected to be a standard container.  + Slices geometry of an object that models polygon_45_set or one of its + refinements into non overlapping trapezoids along a the specified slicing + orientation and appends them to the + output, which must have a value type that models polygon_45, + polygon_45_with_holes, polygon or polygon_with_holes.   O( n + log n) runtime complexity and O(n) memory wrt vertices.
template <typename + polygon_set_type>
+ void clear(polygon_set_type& polygon_set)
Makes the object empty of geometry.
template <typename + polygon_set_type>
+ bool empty(const polygon_set_type& polygon_set)
Checks whether the object is empty of geometry.  Polygons that + are completely covered by holes will result in empty returning true.   + O( n log n) runtime complexity and O(n) memory wrt vertices.
template <typename T, typename + rectangle_type>
+ bool extents(rectangle_type& extents_rectangle,
+             const + T& polygon_set)
Computes bounding box of an object that models polygon_45_set and + stores it in an object that models rectangle.  If the polygon set + is empty returns false.  If there are holes outside of shells they + do not contribute to the extents of the polygon set.   O( n + log n) runtime complexity and O(n) memory wrt vertices.
template <typename T>
+ area_type area(const T& polygon_set)
Computes the area covered by geometry in an object that models + polygon_45_set.   O( n log n) runtime complexity and O(n) + memory wrt vertices.
template <typename T1, typename + T2>
+ T1& interact(T1& a, const T2& b)
Given an object that models polygon_45_set and an object that models + polygon_45_set or one of its refinements, modifies a to retain only + regions that overlap or touch regions in b.   O( n log n) + runtime complexity and O(n) memory wrt vertices plus intersections.
template <typename T>
+ T& self_intersect(T& polygon_set)
Given an object that models polygon_45_set that has self overlapping + regions, modifies the argument to contain only the regions of overlap.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& self_xor(T& polygon_set)
Given an object that models polygon_45_set that has self overlapping + regions, modifies the argument to contain only the regions that do not + overlap.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename T>
+ T& bloat(T& polygon_set, unsigned_area_type bloating)
Same as getting all the polygons, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& shrink(T& polygon_set, unsigned_area_type shrinking)
Same as getting all the polygons, shrinking them and overwriting + the polygon set with the resulting regions.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T, typename + coord_type>
+ T& resize(T& polygon_set, coord_type resizing,
+           + RoundingOption rounding = CLOSEST,
          CornerOption corner = INTERSECTION)
Same as bloat if resizing is positive, same as shrink if resizing is + negative.  RoundingOption is an enum that controls snapping of + non-integer results of resizing 45 degree edges.  CornerOption is + an enum that controls how corner filling is performed.  + polygon_45_set_data.hpp defines these enums.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+T& grow_and(T& polygon_set, unsigned_area_type bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& scale_up(T& polygon_set, unsigned_area_type factor)
Scales geometry up by unsigned factor.  O( n log n) runtime + complexity and O(n) memory wrt vertices.
template <typename T>
+T& scale_down(T& polygon_set, unsigned_area_type factor)
Scales geometry down by unsigned factor.  Snaps 45 degree edges + back to 45 degrees after division truncation leads to small changes in + angle.  O( n log n) runtime complexity and O(n) memory wrt + vertices.
template <typename T, typename scaling_type>
+T& scale(polygon_set_type& polygon_set, double scaling)
Scales geometry by multiplying by floating point factor.   + Snaps 45 degree edges back to 45 degrees after truncation of fractional + results of multiply leads to small changes in angle.  O( n log n) + runtime complexity and O(n) memory wrt vertices.
template <typename T, typename transformation_type>
+T& transform(T& polygon_set,
+             const +transformation_type& transformation)
Applies transformation.transform() on all vertices.  O( n log + n) runtime complexity and O(n) memory wrt vertices.
template <typename T>
+T& keep(T& polygon_set,
+        unsigned_area_type min_area,
+        unsigned_area_type max_area,
+        unsigned_area_type min_width,
+        unsigned_area_type max_width,
+        unsigned_area_type min_height,
+        unsigned_area_type max_height)
Retains only regions that satisfy the min/max criteria in the + argument list.  Note: useful for visualization to cull too small + polygons.  O( n log n) runtime complexity and O(n) memory wrt + vertices.
+

Polygon 45 Set Data Object

+ +

+

The polygon 45 set data type encapsulates the internal data format that +serves as the input to the sweep-line algorithm that implements polygon-clipping +Boolean operations.  It also internally keeps track of whether that data +has been sorted or scanned and maintains the invariant that when its flags +indicate that the data is sorted or scanned the data has not been changed to +violate that assumption.  Using the Polygon 45 Set Data type directly can +be more efficient than using lists and vectors of polygons in the functions +above because of the invariants it can enforce which provide the opportunity to +maintain the data is sorted form rather than going all the way out to polygons +then resorting those vertices for a subsequent operation.

+

The declaration of Polygon 45 Set Data is the following:

+

template <typename T>
+class polygon_45_set_data;

+

The class is parameterized on the coordinate data type.  Algorithms that +benefit from knowledge of the invariants enforced by the class are implemented +as member functions to provide them access to information about those +invariants. 

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
polygon_45_set_data()Default constructor.
template <typename iT>
+ polygon_45_set_data(iT input_begin, iT + input_end)
Construct from an iterator range of + insertable objects.
+ polygon_45_set_data(const polygon_45_set_data& that)Copy construct.
+template <typename l, typename r, typename op>
+polygon_45_set_data(const polygon_45_set_view<l,r,op>& +t)
Copy construct from a Boolean operator template.
+polygon_45_set_data&
operator=(const polygon_45_set_data& that)
Assignment from another polygon set, may change scanning + orientation.
+template <typename l, typename r, typename op>
+polygon_45_set_data&
operator=(const polygon_45_set_view<l, r, +op>& that)
Assignment from a Boolean operator template.
template <typename geometry_object>
+polygon_45_set_data& operator=(const geometry_object& geo)
Assignment from an insertable object.
+ +template <typename iT>
+void insert(iT input_begin, iT input_end,
            bool is_hole = false)
Insert objects of an iterator range.  If is_hole is true + inserts subtractive regions.  Linear wrt the number of vertices + added.
+ +void insert(const polygon_45_set_data& polygon_set,
            bool is_hole += false)
Insert a polygon set.  Linear wrt the number of vertices added.
+ +template <typename geometry_type>
+void insert(const geometry_type& geometry_object,
            bool is_hole += false)
Insert a geometry object, if is_hole is true then the inserted + region is subtractive rather than additive.  Linear wrt the number + of vertices added.
+template <typename output_container>
+void get(output_container& output) const
Expects a standard container of geometry objects.  Will scan + and eliminate overlaps.  Converts polygon set geometry to objects + of that type and appends them to the container.  Polygons will be + output with counterclockwise winding, hole polygons will be output with + clockwise winding.  The last vertex of an output polygon is not the + duplicate of the first, and the number of points is equal to the number + of edges.  O(n log n) runtime and O(n) memory wrt. vertices + + intersections.
+template <typename output_container>
+void get_polygons(output_container& output) const
Expects a standard container of polygon objects.  Will scan and + eliminate overlaps.  Converts polygon set geometry to polygons and + appends them to the container.  Polygons will have holes fractured + out to the outer boundary along the positive y direction.  O(n log + n) runtime and O(n) memory wrt. vertices + intersections.
+template <typename output_container>
+void get_polygons_with_holes(output_container& o) const
Expects a standard container of polygon with holes objects.  Will scan and + eliminate overlaps.  Converts polygon set geometry to polygons and + appends them to the container.  O(n log n) runtime and O(n) memory + wrt. vertices + intersections.
+template <typename output_container>
+void get_trapezoids(output_container& output) const
Expects a standard container of polygon objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to trapezoids + vertically and appends them to the container.  O(n log n) runtime + and O(n) memory wrt. vertices + intersections.
+ +template <typename output_container>
+void get_trapezoids(output_container& output,
  orientation_2d +slicing_orientation) const
+
Expects a standard container of polygon objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to trapezoids + along the given orientation and appends them to the container.  O(n + log n) runtime and O(n) memory wrt. vertices + intersections.
+ +bool operator==(const polygon_45_set_data& p) constOnce scanned the data representation of geometry within a polygon + set is in a mathematically canonical form.  Comparison between two + sets is therefore a linear time operation once they are in the scanned + state. Will scan and eliminate overlaps in both polygon sets.  O(n + log n) runtime and O(n) memory wrt. vertices + intersections the first + time and linear runtime and constant memory subsequently. 
+bool operator!=(const polygon_45_set_data& p) constInverse logic of equivalence operator.
void clear()Make the polygon set empty.  Note: does not de-allocate memory.  + Use shrink to fit idiom and assign default constructed polygon set to + de-allocate.
bool empty() const + Check whether the polygon set contains no geometry.  Will scan + and eliminate overlaps because subtractive regions might make the + polygon set empty.  O(n log n) runtime and O(n) memory wrt. + vertices + intersections the first time and linear runtime and constant + memory subsequently. 
bool is_manhattan() + constReturns in constant time the information about whether the geometry + contains only Manhattan (axis-parallel rectilinear) edges.  + Constant time.
void clean() constScan and eliminate overlaps.  O(n log n) runtime and O(n) + memory wrt. vertices + intersections the first time and linear runtime + and constant memory subsequently. 
+template <typename input_iterator_type>
+void set(input_iterator_type input_begin,
         input_iterator_type input_end)
+
Overwrite geometry in polygon set with insertable objects in the + iterator range. 
+template <typename rectangle_type>
+bool extents(rectangle_type& extents_rectangle) const
Given an object that models rectangle, scans and eliminates overlaps + in the polygon set because subtractive regions may alter its extents + then computes the bounding box and assigns it to extents_rectangle.  + O(n log n) runtime and O(n) memory wrt. vertices the first time and + linear runtime and constant memory subsequently. 
+polygon_45_set_data&
+resize(coord_type resizing,
+        RoundingOption rounding = CLOSEST,
       CornerOption + corner = INTERSECTION)
Same as bloat if resizing is positive, same as shrink if resizing is + negative.  RoundingOption is an enum that controls snapping of + non-integer results of resizing 45 degree edges.  CornerOption is + an enum that controls how corner filling is performed.  + polygon_45_set_data.hpp defines these enums.  O(n log n) runtime + and O(n) memory wrt. vertices + intersections.
+template <typename transformation_type>
+polygon_45_set_data&
transform(const transformation_type& transformation)
+
Applies transformation.transform() on vertices stored within the + polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + + intersections.
+polygon_45_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  + Linear wrt vertices.
+polygon_45_set_data& scale_down(unsigned_area_type +factor) Scales vertices stored within the polygon set down by factor.  + Linear wrt vertices.
polygon_45_set_data& scale(double factor) Scales vertices stored within the polygon set by floating point + factor.  Linear wrt vertices.
polygon_45_set_data& self_xor()Retain only non-overlapping regions of geometry within polygon set.  + O(n log n) runtime and O(n) memory wrt. vertices + intersections.
polygon_45_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  + O(n log n) runtime and O(n) memory wrt. vertices + intersections.
bool has_error_data() + const Returns true if non-integer intersections resulted in small + artifacts in the output of a boolean.  Constant time.
std::size_t error_count() + constReturns the number of artifacts that may potentially be present in + the output due to non-integer intersections.  Constant time.
void get_error_data(polygon_45_set_data& + p) constPopulates the input polygon set with 1x1 unit squares that bound the + error that may be present in the output due to non-integer + intersections.  Linear wrt. vertices of error data.
polygon_45_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  + O(n log n) runtime and O(n) memory wrt. vertices + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_45_with_holes_concept.htm b/doc/gtl_polygon_45_with_holes_concept.htm new file mode 100644 index 0000000..20afcac --- /dev/null +++ b/doc/gtl_polygon_45_with_holes_concept.htm @@ -0,0 +1,399 @@ + + +Boost Polygon Library: Polygon 45 With Holes Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 45 With Holes Concept

+ +

+

The polygon_45_with_holes concept tag is +polygon_45_with_holes_concept

+

+To register a user defined type as a model of +polygon_45_with_holes concept, specialize +the geometry concept meta-function for that type.  In the example below +CPolygon45WithHoles is registered as a model of polygon_45_with_holes  concept.

+template <>
+struct geometry_concept<CPolygon45WithHoles> { typedef polygon_45_with_holes_concept type; };

+The semantic of a polygon_45_with_holes is a +polygon_45 that it can provide iterators over holes that are also polygon_45.  +A mutable polygon_45_with_holes must also be able to set its geometry based on +an interator range over polygon_45 holes.  There is no convention of +winding of holes enforced within the library.

+Below is shown the default polygon with holes +traits.  Specialization of these traits is required for types that don't +conform to the default behavior.

template <typename +T, typename enable = void>
+struct polygon_with_holes_traits {
+     typedef typename T::iterator_holes_type +iterator_holes_type;
+     typedef typename T::hole_type hole_type;
+     static inline iterator_holes_type begin_holes(const T& +t) {
+          return t.begin_holes();
+     }
+     static inline iterator_holes_type end_holes(const T& t) +{
+          return t.end_holes();
+     }
+     static inline unsigned int size_holes(const T& t) {
+          return t.size_holes();
+     }
+};

+

template <typename T, typename enable = void>
+struct polygon_with_holes_mutable_traits {
+     template <typename iT>
+     static inline T& set_holes(T& t, iT inputBegin, iT +inputEnd) {
+          t.set_holes(inputBegin, +inputEnd);
+          return t;
+     }
+};

+

An object that is a model of +polygon_45_with_holes_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_45_with_holes_object)
+view_as<polygon_90_concept>(polygon_45_with_holes_object)
+view_as<polygon_90_with_holes_concept>(polygon_45_with_holes_object)
+view_as<polygon_45_concept>(polygon_45_with_holes_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of + polygon_45_with_holes.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of + polygon_45_with_holes.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ hole_iterator_type begin_holes(const T& polygon)
Expects a model of + polygon_45_with_holes.  + Returns the begin iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ hole_iterator_type end_holes(const T& polygon)
Expects a model of + polygon_45_with_holes.  + Returns the end iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of + polygon_45_with_holes.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a polygon. 
template <typename T, typename + iterator>
+ void set_holes(T& polygon, iterator b, iterator e)
Expects a model of + polygon_45_with_holes.   + Sets the polygon holes to the hole data range [b,e)
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + outer shell of the polygon_45_with_holes.  Does not include sizes + of the holes.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon_45_with_holes or + one of its refinements into left object + that models polygon_45_with_holes.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon_45_with_holes and an object that models + point, returns true + if the polygon shell contains the point and one of its holes does not + contain the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon or one of its holes.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon_45_with_holes.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon_45_with_holes and returns true.  Returns false + and leaves bbox unchanged if polygon is empty.
template <typename T>
+ manhattan_area_type area(const T& polygon)
Returns the area of an object + that models polygon_45_with_holes including subtracting the area of its + holes from the area of the outer shell polygon.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon_45_with_holes, LOW == CLOCKWISE, HIGH = + COUNTERCLOCKWISE.
template <typename T>
+ coordinate_difference perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon_45, including the perimeters of the holes.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Also applies transform() on the holes + of the polygon.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up outer shell and holes of an object that models + polygon_45 by unsigned factor.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down outer shell and holes of an object that models + polygon_45 by unsigned factor.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales outer shell and holes of an object that models polygon_45 by + floating point factor.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon_45 .
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with the outer shell and holes of an + object that models polygon_45_with_holes.
+

Polygon 45 With Holes Data

+ +

+

The library provides a model of polygon 45 with holes concept declared + +template<typename T> polygon_45_with_holes_data where T is the +coordinate type.

+

This data type is used internally when a 45 degree polygon with holes is +needed and is available to the library user who finds it convenient to use a +library polygon data type instead of providing their own.  The data type is +implemented to be convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_45_with_holes_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
iterator_holes_typeIterator over hole polygons of type + polygon_45_data<T>.
polygon_45_with_holes_data()Default constructs the polygon.
polygon_45_with_holes_data(const + polygon_45_with_holes_data& that)Copy construct
polygon_45_with_holes_data& +
operator=
(const polygon_45_with_holes_data& that)
Assignment operator.
template <typename T2> + polygon_45_with_holes_data&  +
operator=
(const T2& that) const
Assign from an object that is a model of polygon 45 with holes.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
iterator_hole_type begin_holes() + constGet the begin compact iterator over non-redundant coordinates of the + polygon.
iterator_hole_type end_holes() + constGet the end compact iterator over non-redundant coordinates of the + polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
std::size_t size_holes() constGet the number of holes in the polygon
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points.  No check is + performed to ensure the points describe a 45 degree figure.
template <typename iT>  +
void set_holes(iT begin_holes, iT end_choless)
Sets the polygon holes the iterator range of hole polygons.  These + polygons in the input range may be either polygon_45_data or + polygon_45_with_holes_data or any type that provides begin and end + member functions to iterate over point_data<T>.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_90_concept.htm b/doc/gtl_polygon_90_concept.htm new file mode 100644 index 0000000..f425e7e --- /dev/null +++ b/doc/gtl_polygon_90_concept.htm @@ -0,0 +1,395 @@ + + +Boost Polygon Library: Polygon 90 Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 90 Concept

+ +

+

The polygon_90 concept tag is +polygon_90_concept

+

+To register a user defined type as a model of +polygon_90 concept, specialize the +geometry concept meta-function for that type.  In the example below CPolygon90 is registered as a model of +polygon_90  concept.

+template <>
+struct geometry_concept<CPolygon90> { typedef polygon_90_concept type; };

+The semantic of a polygon_90 is that it can provide +iterators over the x and y coordinates that correspond to its horizontal and +vertical sides, starting with an x coordinate.  A mutable polygon_90 must +also be able to set its geometry based on an interator range over such +coordinates.  Since most polygons use vertex points in internal storage +iterator adaptors for converting to and from point sequences are provided in +iterator_points_to_compact.hpp and iterator_compact_to_points.hpp to aid in the +specialization of polygon_90_traits.  A std::vector<int> or std::list<int> +could be made models of polygon_90_concept by simply providing access to their +iterators through traits.  Library functions that create polygon objects +require that those objects provide a default constructor.

+Below is shown the default polygon traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.  Note that these traits are also used by the +polygon_90_with_holes concept.

template <typename +T>
+struct polygon_90_traits {
+     typedef typename T::coordinate_type coordinate_type;
+     typedef typename T::compact_iterator_type +compact_iterator_type;
+     static inline compact_iterator_type begin_compact(const +T& t) {
+          return t.begin_compact();
+     }
+     static inline compact_iterator_type end_compact(const +T& t) {
+          return t.end_compact();
+     }
+     static inline unsigned int size(const T& t) {
+          return t.size();
+     }
+     static inline winding_direction winding(const T& t) {
+          return unknown_winding;
+     }
+};

+

template <typename T>
+struct polygon_90_mutable_traits {
+     template <typename iT>
+     static inline T& set_compact(T& t, iT input_begin, iT +input_end) {
+          t.set_compact(input_begin, +input_end);
+          return t;
+     }

+};

+

An object that is a model of +polygon_90_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_90_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ compact_iterator_type begin_compact(const T& polygon)
Expects a model of polygon_90.  + Returns the begin iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ compact_iterator_type end_compact(const T& polygon)
Expects a model of polygon_90.  + Returns the end iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of polygon_90.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of polygon_90.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T, typename + iterator>
+ void set_compact(T& polygon, iterator b, iterator e)
Expects a model of polygon_90.   + Sets the polygon to the coordinate data range [b,e) that corresponds to + .horizontal and vertical edges.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of polygon_90.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a manhattan polygon.  Non-manhattan edges between + successive input points results in undefined behavior.
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + polygon.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon_90 into left object + that models polygon_90.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon_90 and an object that models + point, returns true + if the polygon contains the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon.  Linear wrt. vertices.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon_90.  Linear wrt. vertices.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon_90 and returns true.  Returns false and leaves + bbox unchanged if polygon is empty.  Linear wrt. vertices.
template <typename T>
+ manhattan_area_type area(const T& polygon)
Returns the area of an object + that models polygon_90.  Linear wrt. vertices.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon_90, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  + Complexity depends upon winding trait.
template <typename T>
+ coordinate_difference perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon_90.  Linear wrt. vertices.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Linear wrt. vertices.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up coordinate of an object that models + polygon_90 by unsigned factor.  Linear wrt. vertices.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down coordinates of an object that models + polygon_90 by unsigned factor.  Linear wrt. vertices.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales coordinates of an object that models polygon_90 by floating + point factor.  Linear wrt. vertices.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon_90 .  Linear wrt. + vertices.
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with vertices of an + object that models polygon_90.  Linear wrt. vertices.
+

Polygon 90 Data

+ +

+

The library provides a model of polygon 90 concept declared + +template<typename T> polygon_90_data where T is the coordinate type.

+

This data type is used internally when a Manhattan polygon is needed and is +available to the library user who finds it convenient to use a library polygon +data type instead of providing their own.  The data type is implemented to +be convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_90_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
compact_iterator_typeIterator over non-redundant coordinates + of the polygon, alternating x, y, x, y starting with an x, where each x + corresponds to a vertical edge and each y corresponds to a horizontal + edge.
polygon_90_data()Default constructs the polygon.
polygon_90_data(const + polygon_90_data& that)Copy construct
polygon_90_data& operator=(const + polygon_90_data& that)Assignment operator.
template <typename T2>  +
polygon_90_data& operator=(const T2& that) const
Assign from an object that is a model of polygon 90.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
compact_iterator_type + begin_compact() constGet the begin compact iterator over non-redundant coordinates of the + polygon.
compact_iterator_type + end_compact() constGet the end compact iterator over non-redundant coordinates of the + polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points.  No check is + performed to ensure the points describe a Manhattan figure, every other + x and y value of the points is used to initialize the polygon.
template <typename iT>  +
void set_compact(iT begin_coords, iT end_coords)
Sets the polygon to the iterator range of coordinates.  These + coordinates correspond to the x values of vertical edges and y values of + horizontal edges.  It is expected that the sequence start with an x + value and proceed x then y then x then y.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_90_set_concept.htm b/doc/gtl_polygon_90_set_concept.htm new file mode 100644 index 0000000..12151b1 --- /dev/null +++ b/doc/gtl_polygon_90_set_concept.htm @@ -0,0 +1,901 @@ + + +Boost Polygon Library: Polygon 90 Set Concept + + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 90 Set Concept

+ +

+

The polygon_90_set concept tag is +polygon_90_set_concept

+

+The semantic of a polygon_90_set is zero or more +Manhattan geometry regions.

+The motivation for providing the +polygon_90_set_concept is that it is a very common special case of planar +geometry which afford the implementation of a variety of optimizations on the +general planar geometry algorithms.  Manhattan geometry processing by the +polygon_90_set_concept can be 100X faster than arbitrary angle polygon +manipulation.  Because the performance benefits are so large and the +special case is important enough, the library provides these performance +benefits for those application domains that require them.

Users are recommended to use std::vector and std::list of user defined polygons +or library provided polygon_90_set_data<coordinate_type> objects.  Lists +and vectors of models of polygon_90_concept or polygon_90_with_holes_concept or +rectangle_concept are automatically models of polygon_90_set_concept.

+

Operators

+

The return type of some operators is the polygon_90_set_view +operator template type.  This type is itself a model of the polygon_90_set +concept, but furthermore can be used as an argument to the polygon_90_set_data +constructor and assignment operator.  The operator template exists to +eliminate temp copies of intermediate results when Boolean operators are chained +together.

+

Operators are declared inside the namespace boost::polygon::operators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ polygon_90_set_view operator|(const T1& l, const T2& r)
Boolean OR operation (polygon set union).  Accepts two objects + that model polygon_90_set or one of its refinements.  Returns an + operator template that performs the operation on demand when chained or + or nested in a library function call such as assign().  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_90_set_view operator+(const T1& l, const T2& r)
Same as operator|.  The plus sign is also used for OR + operations in Boolean logic expressions.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_90_set_view operator&(const T1& l, const T2& r)
Boolean AND operation (polygon set intersection).  Accepts two + objects that model polygon_90_set or one of its refinements.  O( n + log n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_90_set_view operator*(const T1& l, const T2& r)
Same as operator&.  The multiplication symbol is also used for + AND operations in Boolean logic expressions.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ polygon_90_set_view operator^(const T1& l, const T2& r)
Boolean XOR operation (polygon set disjoint-union).  Accepts + two objects that model polygon_90_set or one of its refinements.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename T1, typename + T2>
+ polygon_90_set_view operator-(const T1& l, const T2& r)
Boolean SUBTRACT operation (polygon set difference).  Accepts + two objects that model polygon_90_set or one of its refinements.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T1, typename + T2>
+ T1& operator|=(const T1& l, const T2& r)
Same as operator|, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(T1& l, const T2& r)
Same as operator+, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator&=(const T1& l, const T2& r)
Same as operator&, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator*=(T1& l, const T2& r)
Same as operator*, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator^=(const T1& l, const T2& r)
Same as operator^, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(T1& l, const T2& r)
Same as operator-, but with self assignment, left operand must model + polygon_90_set and not one of it's refinements.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T1>
+ T1 operator+(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Note: returns + result by value.  O( n log n) runtime complexity and O(n) memory + wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1 operator-(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Note: returns + result by value.  O( n log n) runtime complexity and O(n) memory + wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Returns + reference to modified argument.  O( n log n) runtime complexity and + O(n) memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Returns + reference to modified argument.  O( n log n) runtime complexity and + O(n) memory wrt vertices + intersections.
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ T1& assign(T1& lvalue, const T2& rvalue)
Eliminates overlaps in geometry and copies from an object that + models polygon_90_set or any of its refinements into an object that + models polygon_90_set.  O( n log n) runtime complexity and O(n) + memory wrt vertices + intersections.
template <typename T1, typename + T2>
+ bool equivalence(const T1& lvalue, const T2& rvalue)
Returns true if an object that models polygon_90_set or one of its + refinements covers the exact same geometric regions as another object + that models polygon_90_set or one of its refinements.  For example: + two of polygon_90 objects.  O( n log n) runtime complexity and O(n) + memory wrt vertices + intersections.
template <typename + output_container_type, typename T>
+ void get_rectangles(output_container_type& output,
+                    + const T& polygon_set)
Output container is expected to be a standard container.  + Slices geometry of an object that models polygon_90_set or one of its + refinements into non overlapping rectangles and appends them to the + output.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename + output_container_type, typename T>
+ void get_max_rectangles(output_container_type& output,
+                        + const T& polygon_set)
Output container is expected to be a standard container.  Given + an object that models polygon_90_set or one of its refinements finds all + overlapping rectangles that are maximal in area and appends them to the + output.  Expected n log n runtime, worst case quadratic rutnime.
template <typename + polygon_set_type>
+ void clear(polygon_set_type& polygon_set)
Makes the object empty of geometry.
template <typename + polygon_set_type>
+ bool empty(const polygon_set_type& polygon_set)
Checks whether the object is empty of geometry.  Polygons that + are completely covered by holes will result in empty returning true.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T, typename + rectangle_type>
+ bool extents(rectangle_type& extents_rectangle,
+             const + T& polygon_set)
Computes bounding box of an object that models polygon_90_set and + stores it in an object that models rectangle.  If the polygon set + is empty returns false.  If there are holes outside of shells they + do not contribute to the extents of the polygon set.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ manhattan_area_type area(const T& polygon_set)
Computes the area covered by geometry in an object that models + polygon_90_set.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename T1, typename + T2>
+ T1& interact(T1& a, const T2& b)
Given an object that models polygon_90_set and an object that models + polygon_90_set or one of its refinements, modifies a to retain only + regions that overlap or touch regions in b.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ T& self_intersect(T& polygon_set)
Given an object that models polygon_90_set that has self overlapping + regions, modifies the argument to contain only the regions of overlap.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& self_xor(T& polygon_set)
Given an object that models polygon_90_set that has self overlapping + regions, modifies the argument to contain only the regions that do not + overlap.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename T>
+ T& bloat(T& polygon_set, unsigned_area_type bloating)
Same as getting all the rectangles, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& bloat(T& polygon_set, orientation_2d orient,
+         unsigned_area_type bloating)
Same as getting all the rectangles, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& bloat(T& polygon_set, orientation_2d orient,
+         unsigned_area_type low_bloating,
+         unsigned_area_type + high_bloating)
Same as getting all the rectangles, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& bloat(T& polygon_set, direction_2d dir,
+         unsigned_area_type bloating)
Same as getting all the rectangles, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& bloat(T& polygon_set,
+         unsigned_area_type + west_bloating,
+         unsigned_area_type + east_bloating,
+         unsigned_area_type + south_bloating,
+         unsigned_area_type + north_bloating)
Same as getting all the rectangles, bloating them and putting them + back.  O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+ T& shrink(T& polygon_set, unsigned_area_type shrinking)
Same as getting all the rectangles of the inverse, bloating them and overwriting + the polygon set with the resulting regions then negating.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ T& shrink(T& polygon_set, orientation_2d orient,
+          unsigned_area_type + shrinking)
Same as getting all the rectangles of the inverse, bloating them and overwriting + the polygon set with the resulting regions then negating.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ T& shrink(T& polygon_set, orientation_2d orient,
+          unsigned_area_type + low_shrinking,
+          unsigned_area_type + high_shrinking)
Same as getting all the rectangles of the inverse, bloating them and overwriting + the polygon set with the resulting regions then negating.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ T& shrink(T& polygon_set, direction_2d dir,
+          unsigned_area_type + shrinking)
Same as getting all the rectangles of the inverse, bloating them and overwriting + the polygon set with the resulting regions then negating.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+ T& shrink(T& polygon_set,
+          unsigned_area_type + west_shrinking,
+          unsigned_area_type + east_shrinking,
+          unsigned_area_type + south_shrinking,
+          unsigned_area_type + north_shrinking)
Same as getting all the rectangles of the inverse, bloating them and overwriting + the polygon set with the resulting regions then negating.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T, typename + coord_type>
+ T& resize(T& polygon_set, coord_type resizing)
Same as bloat if resizing is positive, same as shrink if resizing is + negative.
template <typename T, typename + coord_type>
+ T& resize(polygon_set_type& polygon_set,
+          coord_type west, coord_type east, +
          coord_type south, coord_type north)
Same as bloat if resizing is positive, same as shrink if resizing is + negative.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
template <typename T>
+T& grow_and(T& polygon_set, unsigned_area_type bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& grow_and(T& polygon_set, orientation_2d orient,
+            +unsigned_area_type bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& grow_and(T& polygon_set, orientation_2d orient,
+            +unsigned_area_type low_bloating,
+            +unsigned_area_type high_bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& grow_and(T& polygon_set, direction_2d dir,
+            +unsigned_area_type bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& grow_and(T& polygon_set,
+            +unsigned_area_type west_bloating,
+            +unsigned_area_type east_bloating,
+            +unsigned_area_type south_bloating,
+            +unsigned_area_type north_bloating)
Same as bloating non-overlapping regions and then applying self + intersect to retain only the overlaps introduced by the bloat.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T>
+T& scale_up(T& polygon_set, unsigned_area_type factor)
Scales geometry up by unsigned factor.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+T& scale_down(T& polygon_set, unsigned_area_type factor)
Scales geometry down by unsigned factor.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
template <typename T, typename scaling_type>
+T& scale(polygon_set_type& polygon_set,
+         const scaling_type& scaling)
Scales geometry by applying scaling.scale() on all vertices.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T, typename coord_type>
+T& move(T& polygon_set,
+        orientation_2d orient, coord_type +displacement)
Moves geometry by displacement amount in the orientation.    + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
template <typename T, typename coord_type>
+T& move(T& polygon_set, coord_type x_displacement,
+        coord_type y_displacement)
Moves the geometry by x_dispacement in x and y_displacement in y.  + Note: for consistency should be convolve(polygon_set, point).  O( n + log n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T, typename transformation_type>
+T& transform(T& polygon_set,
+             const +transformation_type& transformation)
Applies transformation.transform() on all vertices.  O( n log + n) runtime complexity and O(n) memory wrt vertices + intersections.
template <typename T>
+T& keep(T& polygon_set,
+        unsigned_area_type min_area,
+        unsigned_area_type max_area,
+        unsigned_area_type min_width,
+        unsigned_area_type max_width,
+        unsigned_area_type min_height,
+        unsigned_area_type max_height)
Retains only regions that satisfy the min/max criteria in the + argument list.  Note: useful for visualization to cull too small + polygons.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
+

Polygon 90 Set Data Object

+ +

+

The polygon 90 set data type encapsulates the internal data format that +serves as the input to the sweep-line algorithm that implements polygon-clipping +boolean operations.  It also internally keeps track of whether that data +has been sorted or scanned and maintains the invariant that when its flags +indicate that the data is sorted or scanned the data has not been changed to +violate that assumption.  Using the Polygon 90 Set Data type directly can +be more efficient than using lists and vectors of polygons in the functions +above because of the invariants it can enforce which provide the opportunity to +maintain the data is sorted form rather than going all the way out to polygons +then resorting those vertices for a subsequent operation.

+

The declaration of Polygon 90 Set Data is the following:

+

template <typename T>
+class polygon_90_set_data;

+

The class is parameterized on the coordinate data type.  Algorithms that +benefit from knowledge of the invariants enforced by the class are implemented +as member functions to provide them access to information about those +invariants. 

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
polygon_90_set_data()Default constructor.  Scanning orientation defaults to + HORIZONTAL
polygon_90_set_data(orientation_2d + orient)Construct with scanning orientation.
template <typename iT>
+ polygon_90_set_data(orientation_2d orient,
                    iT input_begin, iT + input_end)
Construct with scanning orientation from an iterator range of + insertable objects.
+ polygon_90_set_data(const polygon_90_set_data& that)Copy construct.
+template <typename l, typename r, typename op>
+polygon_90_set_data(const polygon_90_set_view<l,r,op>& +t)
Copy construct from a Boolean operator template.
+ +polygon_90_set_data(orientation_2d orient,
                    const polygon_90_set_data& +that)
Construct with scanning orientation and copy from another polygon + set.
+polygon_90_set_data&
operator=(const polygon_90_set_data& that)
Assignment from another polygon set, may change scanning + orientation.
+template <typename l, typename r, typename op>
+polygon_90_set_data&
operator=(const polygon_90_set_view<l, r, +op>& that)
Assignment from a Boolean operator template.
template <typename geometry_object>
+polygon_90_set_data& operator=(const geometry_object& geo)
Assignment from an insertable object.
+ +template <typename iT>
+void insert(iT input_begin, iT input_end)
Insert objects of an iterator range.  Linear wrt. inserted + vertices.
+ +void insert(const polygon_90_set_data& polygon_set)Insert a polygon set.  Linear wrt. inserted vertices.
+ +template <typename geometry_type>
+void insert(const geometry_type& geometry_object,
            bool is_hole += false)
Insert a geometry object, if is_hole is true then the inserted + region is subtractive rather than additive.  Linear wrt. inserted + vertices.
+template <typename output_container>
+void get(output_container& output) const
Expects a standard container of geometry objects.  Will scan + and eliminate overlaps.  Converts polygon set geometry to objects + of that type and appends them to the container.  Polygons will be + output with counterclockwise winding, hole polygons will be output with + clockwise winding.  The last vertex of an output polygon is not the + duplicate of the first, and the number of points is equal to the number + of edges.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
+template <typename output_container>
+void get_polygons(output_container& output) const
Expects a standard container of polygon objects.  Will scan and + eliminate overlaps.  Converts polygon set geometry to polygons and + appends them to the container.  Polygons will have holes fractured + out to the outer boundary along the positive direction of the scanline + orientation of the polygon set.  O( n log n) runtime complexity and + O(n) memory wrt vertices + intersections.
+template <typename output_container>
+void get_rectangles(output_container& output) const
Expects a standard container of rectangle objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to rectangles + along the scanning orientation and appends them to the container.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
+ +template <typename output_container>
+void get_rectangles(output_container& output,
  orientation_2d +slicing_orientation) const
+
Expects a standard container of rectangle objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to rectangles + along the given orientation and appends them to the container.  O( + n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
+ +bool operator==(const polygon_90_set_data& p) constOnce scanned the data representation of geometry within a polygon + set is in a mathematically canonical form.  Comparison between two + sets is therefore a linear time operation once they are in the scanned + state. Will scan and eliminate overlaps in both polygon sets.  O( n + log n) runtime complexity and O(n) memory wrt vertices + intersections + the first time, linear subsequently.
+bool operator!=(const polygon_90_set_data& p) constInverse logic of equivalence operator.
void clear()Make the polygon set empty.  Note: does not de-allocate memory.  + Use shrink to fit idiom and assign default constructed polygon set to + de-allocate.
bool empty() const + Check whether the polygon set contains no geometry.  Will scan + and eliminate overlaps because subtractive regions might make the + polygon set empty.  O( n log n) runtime complexity and O(n) memory + wrt vertices + intersections the first time, linear subsequently.
orientation_2d orient() constGet the scanning orientation.  Depending on the data it is + sometimes more efficient to scan in a specific orientation.  This + is particularly true of Manhattan geometry data.  Constant time.
void clean() constScan and eliminate overlaps.  O( n log n) runtime complexity + and O(n) memory wrt vertices + intersections the first time, constant + time subsequently.
+template <typename input_iterator_type>
+void set(input_iterator_type input_begin,
         input_iterator_type input_end, +
         orientation_2d orient)
+
Overwrite geometry in polygon set with insertable objects in the + iterator range.  Also sets the scanning orientation to that + specified.
+template <typename rectangle_type>
+bool extents(rectangle_type& extents_rectangle) const
Given an object that models rectangle, scans and eliminates overlaps + in the polygon set because subtractive regions may alter its extents + then computes the bounding box and assigns it to extents_rectangle.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections the first time, linear subsequently.
+polygon_90_set_data&
+bloat(unsigned_area_type west_bloating,
+      +unsigned_area_type east_bloating,
+      +unsigned_area_type south_bloating,
+      +unsigned_area_type north_bloating)
Scans to eliminate overlaps and subtractive regions.  Inserts + rectangles of width specified by bloating values to the indicated side + of geometry within the polygon set and fills corners with rectangles of + the length and width specified for the adjacent sides.  O( n log n) + runtime complexity and O(n) memory wrt vertices + intersections.
+polygon_90_set_data&
+shrink(unsigned_area_type west_shrinking,
+       +unsigned_area_type east_shrinking,
+       +unsigned_area_type south_shrinking,
+       +unsigned_area_type north_shrinking)
Scans to eliminate overlaps and subtractive regions.  Inserts + subtractiive rectangles of width specified by bloating values to the + indicated side of geometry within the polygon set and subtractive + rectangle at convex corners of the length and width specified for the + adjacent sides.  Scans to eliminate overlapping subtractive + regions.  O( n log n) runtime complexity and O(n) memory wrt + vertices + intersections.
+polygon_90_set_data&
+resize(coordinate_type west, coordinate_type east,
       coordinate_type south, coordinate_type north)
Call bloat or shrink or shrink then bloat depending on whether the + resizing values are positive or negative.  O( n log n) runtime + complexity and O(n) memory wrt vertices + intersections.
+polygon_90_set_data& move(coordinate_type x_delta,
                          coordinate_type +y_delta)
+
Add x_delta to x values and y_delta to y values of vertices stored + within the polygon set.  Linear wrt. vertices.
+template <typename transformation_type>
+polygon_90_set_data&
transform(const transformation_type& transformation)
+
Applies transformation.transform() on vertices stored within the + polygon set.  Linear wrt. vertices.
+polygon_90_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  + Linear wrt. vertices.
+

polygon_90_set_data& scale_down(unsigned_area_type +factor) 

Scales vertices stored within the polygon set down by factor.  + Linear wrt. vertices.
+template <typename scaling_type>
+polygon_90_set_data&
scale(const anisotropic_scale_factor<scaling_type>& + f)
Scales vertices stored within the polygon set by applying f.scale().  + Linear wrt. vertices.
polygon_90_set_data& scale(double factor) Scales vertices stored within the polygon set by floating point + factor.  Linear wrt. vertices.
polygon_90_set_data& self_xor()Retain only non-overlapping regions of geometry within polygon set.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
polygon_90_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
polygon_90_set_data&
interact(const polygon_90_set_data& that)
Retain only regions that touch or overlap regions in argument.  + O( n log n) runtime complexity and O(n) memory wrt vertices + + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_90_with_holes_concept.htm b/doc/gtl_polygon_90_with_holes_concept.htm new file mode 100644 index 0000000..2683e8a --- /dev/null +++ b/doc/gtl_polygon_90_with_holes_concept.htm @@ -0,0 +1,448 @@ + + +Boost Polygon Library: Polygon 90 With Holes Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon 90 With Holes Concept

+ +

+

The polygon_90_with_holes concept tag is +polygon_90_with_holes_concept

+

+To register a user defined type as a model of +polygon_90_with_holes concept, specialize the +geometry concept meta-function for that type.  In the example below CPolygon90WithHoles is registered as a model of +polygon_90_with_holes  concept.

+template <>
+struct geometry_concept<CPolygon90WithHoles> { typedef polygon_90_with_holes_concept type; };

+The semantic of a polygon_90_with_holes is a +polygon_90 that it can provide iterators over holes that are also polygon_90.  +A mutable polygon_90_with_holes must also be able to set its geometry based on +an interator range over polygon_90 holes.  There is no convention of +winding of holes enforced within the library.

+Below is shown the default polygon with holes +traits.  Specialization of these traits is required for types that don't +conform to the default behavior.

template <typename +T, typename enable = void>
+struct polygon_with_holes_traits {
+     typedef typename T::iterator_holes_type +iterator_holes_type;
+     typedef typename T::hole_type hole_type;
+     static inline iterator_holes_type begin_holes(const T& +t) {
+          return t.begin_holes();
+     }
+     static inline iterator_holes_type end_holes(const T& t) +{
+          return t.end_holes();
+     }
+     static inline unsigned int size_holes(const T& t) {
+          return t.size_holes();
+     }
+};

+

template <typename T, typename enable = void>
+struct polygon_with_holes_mutable_traits {
+     template <typename iT>
+     static inline T& set_holes(T& t, iT inputBegin, iT +inputEnd) {
+          t.set_holes(inputBegin, +inputEnd);
+          return t;
+     }
+};

+

An object that is a model of +polygon_90_with_holes_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_90_with_holes_object)
+view_as<polygon_90_concept>(polygon_90_with_holes_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ compact_iterator_type begin_compact(const T& polygon)
Expects a model of polygon_90.  + Returns the begin iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ compact_iterator_type end_compact(const T& polygon)
Expects a model of polygon_90.  + Returns the end iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of + polygon_90_with_holes.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of + polygon_90_with_holes.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ hole_iterator_type begin_holes(const T& polygon)
Expects a model of + polygon_90_with_holes.  + Returns the begin iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ hole_iterator_type end_holes(const T& polygon)
Expects a model of + polygon_90_with_holes.  + Returns the end iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T, typename + iterator>
+ void set_compact(T& polygon, iterator b, iterator e)
Expects a model of + polygon_90_with_holes.   + Sets the polygon to the coordinate data range [b,e) that corresponds to + .horizontal and vertical edges.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of + polygon_90_with_holes.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a manhattan polygon.  Non-manhattan edges between + successive input points results in undefined behavior.
template <typename T, typename + iterator>
+ void set_holes(T& polygon, iterator b, iterator e)
Expects a model of + polygon_90_with_holes.   + Sets the polygon holes to the hole data range [b,e)
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + outer shell of the polygon_90_with_holes.  Does not include sizes + of the holes.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon_90_with_holes or + one of its refinements into left object + that models polygon_90_with_holes.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon_90_with_holes and an object that models + point, returns true + if the polygon shell contains the point and one of its holes does not + contain the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon or one of its holes.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon_90_with_holes.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon_90_with_holes and returns true.  Returns false + and leaves bbox unchanged if polygon is empty.
template <typename T>
+ manhattan_area_type area(const T& polygon)
Returns the area of an object + that models polygon_90_with_holes including subtracting the area of its + holes from the area of the outer shell polygon.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon_90_with_holes, LOW == CLOCKWISE, HIGH = + COUNTERCLOCKWISE.
template <typename T>
+ coordinate_difference perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon_90, including the perimeters of the holes.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Also applies transform() on the holes + of the polygon.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up outer shell and holes of an object that models + polygon_90 by unsigned factor.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down outer shell and holes of an object that models + polygon_90 by unsigned factor.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales outer shell and holes of an object that models polygon_90 by + floating point factor.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon_90 .
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with the outer shell and holes of an + object that models polygon_90_with_holes.
+

Polygon 90 With Holes Data

+ +

+

The library provides a model of polygon 90 with holes concept declared + +template<typename T> polygon_90_with_holes_data where T is the +coordinate type.

+

This data type is used internally when a Manhattan polygon with holes is +needed and is available to the library user who finds it convenient to use a +library polygon data type instead of providing their own.  The data type is +implemented to be convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_90_with_holes_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
compact_iterator_typeIterator over non-redundant coordinates + of the polygon, alternating x, y, x, y starting with an x, where each x + corresponds to a vertical edge and each y corresponds to a horizontal + edge.
iterator_holes_typeIterator over hole polygons of type + polygon_90_data<T>.
polygon_90_with_holes_data()Default constructs the polygon.
polygon_90_with_holes_data(const + polygon_90_with_holes_data& that)Copy construct
polygon_90_with_holes_data& +
operator=
(const polygon_90_with_holes_data& that)
Assignment operator.
template <typename T2> polygon_90_with_holes_data&  +
operator=
(const T2& that) const
Assign from an object that is a model of polygon 90 with holes.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
compact_iterator_type begin_compact() + constGet the begin compact iterator over non-redundant coordinates of the + polygon.
compact_iterator_type end_compact() + constGet the end compact iterator over non-redundant coordinates of the + polygon.
iterator_hole_type begin_holes() + constGet the begin compact iterator over non-redundant coordinates of the + polygon.
iterator_hole_type end_holes() + constGet the end compact iterator over non-redundant coordinates of the + polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
std::size_t size_holes() constGet the number of holes in the polygon
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points.  No check is + performed to ensure the points describe a Manhattan figure, every other + x and y value of the points is used to initialize the polygon.
template <typename iT>  +
void set_compact(iT begin_coords, iT end_coords)
Sets the polygon to the iterator range of coordinates.  These + coordinates correspond to the x values of vertical edges and y values of + horizontal edges.  It is expected that the sequence start with an x + value and proceed x then y then x then y.
template <typename iT>  +
void set_holes(iT begin_holes, iT end_choless)
Sets the polygon holes the iterator range of hole polygons.  These + polygons in the input range may be either polygon_90_data or + polygon_90_with_holes_data or any type that provides begin_compact and + end_compact member functions.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_concept.htm b/doc/gtl_polygon_concept.htm new file mode 100644 index 0000000..b95a721 --- /dev/null +++ b/doc/gtl_polygon_concept.htm @@ -0,0 +1,362 @@ + + +Boost Polygon Library: Polygon Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon Concept

+ +

+

The polygon concept tag is +polygon_concept

+

+To register a user defined type as a model of +polygon concept, specialize the +geometry concept meta-function for that type.  In the example below CPolygon is registered as a model of +polygon  concept.

+template <>
+struct geometry_concept<CPolygon> { typedef polygon_concept type; };

+The semantic of a polygon is that it can provide +iterators over the points that represent its vertices.  It is acceptable to +have the last edge explict with the first and last point equal to each other or +implied by this segement that would connect the first and last point.  A +mutable polygon must also be able to set its geometry based on an interator +range over such points.  A std::vector<point_data<int> > or std::list<point_data<int> +> +could be made models of polygon_concept by simply providing access to their +iterators through traits.  Library functions that create polygon objects +require that those objects provide a default constructor.

+Below is shown the default polygon traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.  Note that these same traits are also used by several +other polygon concepts through SFINE enable template parameter.  The SFINE +enable parameter also allows the library to provide default specialization that +work for any object that models the 90 degree polygon concepts.

+template <typename T, typename enable = gtl_yes>
+struct polygon_traits {};
+
+template <typename T>
+struct polygon_traits<T,
+  typename gtl_or_4<
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_with_holes_concept>::type,
+    typename gtl_same_type<typename geometry_concept<T>::type, +polygon_with_holes_concept>::type
+  >::type> {
+     typedef typename T::coordinate_type coordinate_type;
+     typedef typename T::iterator_type iterator_type;
+     typedef typename T::point_type point_type;
+     static inline iterator_type begin_points(const T& t) {
+          return t.begin();
+     }
+     static inline iterator_type end_points(const T& t) {
+          return t.end();
+     }
+     static inline unsigned int size(const T& t) {
+          return t.size();
+     }
+     static inline winding_direction winding(const T& t) {
+          return unknown_winding;
+     }
+};

+

template <typename T, typename enable = void>
+struct polygon_mutable_traits {
+     template <typename iT>
+     static inline T& set_points(T& t, iT input_begin, iT +input_end) {
+          t.set(input_begin, +input_end);
+          return t;
+     }
+};

+

Example code custom_polygon.cpp +demonstrates mapping a + user defined polygon class to the library polygon_concept

+

An object that is a model of +polygon_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_object)
+view_as<polygon_90_concept>(polygon_object)
+view_as<polygon_45_concept>(polygon_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of polygon.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of polygon.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of polygon.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a manhattan polygon.
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + polygon.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon into left object + that models polygon.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon and an object that models + point, returns true + if the polygon contains the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon.  Linear wrt. vertices.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon.  Linear wrt. vertices.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon and returns true.  Returns false and leaves + bbox unchanged if polygon is empty.  Linear wrt. vertices.
template <typename T>
+ area_type area(const T& polygon)
Returns the area of an object + that models polygon.  Linear wrt. vertices.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  + Complexity depends upon winding trait.
template <typename T>
+ coordinate_distance perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon.  Linear wrt. vertices.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Linear wrt. vertices.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up coordinate of an object that models + polygon by unsigned factor.  Linear wrt. vertices.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down coordinates of an object that models + polygon by unsigned factor.  Linear wrt. vertices.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales coordinates of an object that models polygon by floating + point factor.  Linear wrt. vertices.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon .  Linear wrt. vertices.
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with vertices of an + object that models polygon.  Linear wrt. vertices.
+

Polygon Data

+ +

+

The library provides a model of polygon concept declared + +template<typename T> polygon_data where T is the coordinate type.

+

This data type is used internally when a polygon is needed and is available +to the library user who finds it convenient to use a library polygon data type +instead of providing their own.  The data type is implemented to be +convenient to use with the library traits.

+

Example code polygon_usage.cpp +demonstrates using + the library provided polygon data types and functions

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
polygon_data()Default constructs the polygon.
polygon_data(const + polygon_data& that)Copy construct
polygon_data& operator=(const + polygon_data& that)Assignment operator.
template <typename T2>  +
polygon_data& operator=(const T2& that) const
Assign from an object that is a model of polygon.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points. 
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm new file mode 100644 index 0000000..6ea39be --- /dev/null +++ b/doc/gtl_polygon_set_concept.htm @@ -0,0 +1,653 @@ + + +Boost Polygon Library: Polygon Set Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon Set Concept

+ +

+

The polygon_set concept tag is +polygon_set_concept

+

+The semantic of a polygon_set is zero or more +geometry regions.  A Polygon Set Concept may be defined with floating point +coordinates, but a snap rounding distance of one integer unit will still be +applied, furthermore, geometry outside the domain where one integer unit is +sufficient to provide robustness may lead to undefined behavior in algorithms.  +It is recommended to use integer coordinates for robust operations.  In the +case that data represented contains only Manhattan geometry a runtime check will +default to the Manhattan algorithm.  The results of which are identical to +what the general algorithm would do, but obtained more efficiently.  In the +case that the data represented contains only Manhattan and 45-degree geometry a +runtime check will default to the faster 45-degree algorithm.  The results +of which may differ slight from what the general algorithm would do because +non-integer intersections will be handled differently.

Users are recommended to use std::vector and std::list of user defined polygons +or library provided polygon_set_data<coordinate_type> objects.  Lists +and vectors of models of polygon_concept or polygon_with_holes_concept are automatically models of polygon_set_concept.

+

Example code custom_polygon_set.cpp + demonstrates mapping a user defined class to the library polygon_set_concept

+

An object that is a model of +polygon_set_concept can be viewed as a model of +polygon_90_set_concept or +polygon_45_set_concept if it is determined at runtime to conform to the +restrictions of those concepts.  This concept casting is accomplished +through the view_as<>() function.

+

view_as<polygon_90_set_concept>(polygon_set_object)
+view_as<polygon_45_set_concept>(polygon_set_object)

+

The return value of view_as<>() can be passed +into any interface that expects an object of the conceptual type specified in +its template parameter.  Polygon sets cannot be viewed as single polygons +or rectangles since it generally cannot be known whether a polygon set contains +only a single polygon without converting to polygons.

+

Operators

+

The return type of some operators is the polygon_set_view +operator template type.  This type is itself a model of the polygon 90 set +concept, but furthermore can be used as an argument to the polygon_set_data +constructor and assignment operator.  The operator template exists to +eliminate temp copies of intermediate results when Boolean operators are chained +together.

+

Operators are declared inside the namespace boost::polygon::operators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ polygon_set_view operator|(const T1& l, const T2& r)
Boolean OR operation (polygon set union).  Accepts two objects + that model polygon_set or one of its refinements.  Returns an + operator template that performs the operation on demand when chained or + or nested in a library function call such as assign().  Expected n + log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T1, typename + T2>
+ polygon_set_view operator+(const T1& l, const T2& r)
Same as operator|.  The plus sign is also used for OR + operations in Boolean logic expressions.  Expected n log n runtime, + worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ polygon_set_view operator&(const T1& l, const T2& r)
Boolean AND operation (polygon set intersection).  Accepts two + objects that model polygon_set or one of its refinements.  Expected + n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T1, typename + T2>
+ polygon_set_view operator*(const T1& l, const T2& r)
Same as operator&.  The multiplication symbol is also used for + AND operations in Boolean logic expressions.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ polygon_set_view operator^(const T1& l, const T2& r)
Boolean XOR operation (polygon set disjoint-union).  Accepts + two objects that model polygon_set or one of its refinements.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T1, typename + T2>
+ polygon_set_view operator-(const T1& l, const T2& r)
Boolean SUBTRACT operation (polygon set difference).  Accepts + two objects that model polygon_set or one of its refinements.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T1, typename + T2>
+ T1& operator|=(const T1& l, const T2& r)
Same as operator|, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(T1& l, const T2& r)
Same as operator+, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator&=(const T1& l, const T2& r)
Same as operator&, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator*=(T1& l, const T2& r)
Same as operator*, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator^=(const T1& l, const T2& r)
Same as operator^, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(T1& l, const T2& r)
Same as operator-, but with self assignment, left operand must model + polygon_set and not one of it's refinements.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T1>
+ T1 operator+(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Note: returns + result by value.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1 operator-(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Note: returns + result by value.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator+=(const T1&, coordinate_type bloating)
Performs resize operation, inflating by bloating ammount.  If + negative the result is a shrink instead of bloat.  Returns + reference to modified argument.  Expected n log n runtime, worst + case quadratic runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ T1& operator-=(const T1&, coordinate_type shrinking)
Performs resize operation, deflating by bloating ammount.  If + negative the result is a bloat instead of shrink.  Returns + reference to modified argument.  Expected n log n runtime, worst + case quadratic runtime wrt. vertices + intersections.
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T1, typename + T2>
+ T1& assign(T1& lvalue, const T2& rvalue)
Eliminates overlaps in geometry and copies from an object that + models polygon_set or any of its refinements into an object that + models polygon_set.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T1, typename + T2>
+ bool equivalence(const T1& lvalue, const T2& rvalue)
Returns true if an object that models polygon_set or one of its + refinements covers the exact same geometric regions as another object + that models polygon_set or one of its refinements.  For example: + two of polygon objects.  Expected n log n runtime, worst case + quadratic runtime wrt. vertices + intersections.
template <typename + output_container_type, typename T>
+ void get_trapezoids(output_container_type& output,
+                    + const T& polygon_set)
Output container is expected to be a standard container.  + Slices geometry of an object that models polygon_set or one of its + refinements into non overlapping trapezoids along a vertical slicing + orientation and appends them to the + output, which must have a value type that models polygon or polygon_with_holes.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename + output_container_type, typename T>
+ void get_trapezoids(output_container_type& output,
+                    + const T& polygon_set,
                    orientation_2d orient)
Output container is expected to be a standard container.  + Slices geometry of an object that models polygon_set or one of its + refinements into non overlapping trapezoids along a the specified slicing + orientation and appends them to the + output, which must have a value type that models polygon or polygon_with_holes.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename + polygon_set_type>
+ void clear(polygon_set_type& polygon_set)
Makes the object empty of geometry.
template <typename + polygon_set_type>
+ bool empty(const polygon_set_type& polygon_set)
Checks whether the object is empty of geometry.  Polygons that + are completely covered by holes will result in empty returning true.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T, typename + rectangle_type>
+ bool extents(rectangle_type& extents_rectangle,
+             const + T& polygon_set)
Computes bounding box of an object that models polygon_set and + stores it in an object that models rectangle.  If the polygon set + is empty returns false.  If there are holes outside of shells they + do not contribute to the extents of the polygon set.  Expected n + log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T>
+ area_type area(const T& polygon_set)
Computes the area covered by geometry in an object that models + polygon_set.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T>
+ T& bloat(T& polygon_set, unsigned_area_type bloating)
Same as getting all the polygons, bloating them and putting them + back.  Expected n log n runtime, worst case quadratic runtime wrt. + vertices + intersections.
template <typename T>
+ T& shrink(T& polygon_set, unsigned_area_type shrinking)
Same as getting all the polygons, shrinking them and overwriting + the polygon set with the resulting regions.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T, typename + coord_type>
+ T& resize(T& polygon_set, coord_type resizing,
+           + bool corner_fill_arc = false,
          + unsigned int num_circle_segments = 0)
Same as bloat if resizing is positive, same as shrink if resizing is + negative.  Original topology at acute angle vertices is preserved + by default, segmented circular arcs are inserted if corner_fill_arc is + true.  num_circle_segments specifies number of segments to + introduce on a full circle when filling acute angle corners with + circular arcs.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T>
+T& scale_up(T& polygon_set, unsigned_area_type factor)
Scales geometry up by unsigned factor.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T>
+T& scale_down(T& polygon_set, unsigned_area_type factor)
Scales geometry down by unsigned factor.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T, typename transformation_type>
+T& transform(T& polygon_set,
+             const +transformation_type& transformation)
Applies transformation.transform() on all vertices.  Expected n + log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
template <typename T>
+T& keep(T& polygon_set,
+        unsigned_area_type min_area,
+        unsigned_area_type max_area,
+        unsigned_area_type min_width,
+        unsigned_area_type max_width,
+        unsigned_area_type min_height,
+        unsigned_area_type max_height)
Retains only regions that satisfy the min/max criteria in the + argument list.  Note: useful for visualization to cull too small + polygons.  Expected n log n runtime, worst case quadratic runtime + wrt. vertices + intersections.
+

Polygon Set Data Object

+ +

+

The polygon set data type encapsulates the internal data format that +serves as the input to the sweep-line algorithm that implements polygon-clipping +Boolean operations.  It also internally keeps track of whether that data +has been sorted or scanned and maintains the invariant that when its flags +indicate that the data is sorted or scanned the data has not been changed to +violate that assumption.  Using the Polygon Set Data type directly can +be more efficient than using lists and vectors of polygons in the functions +above because of the invariants it can enforce which provide the opportunity to +maintain the data is sorted form rather than going all the way out to polygons +then resorting those vertices for a subsequent operation.

+

The declaration of Polygon Set Data is the following:

+

template <typename T>
+class polygon_set_data;

+

The class is parameterized on the coordinate data type.  Algorithms that +benefit from knowledge of the invariants enforced by the class are implemented +as member functions to provide them access to information about those +invariants. 

+

Example code polygon_set_usage.cpp +demonstrates using + the library provided polygon set data types and functions

+

Member Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
polygon_set_data()Default constructor.
template <typename iT>
+ polygon_set_data(iT input_begin, iT + input_end)
Construct with scanning orientation from an iterator range of + insertable objects.
+ polygon_set_data(const polygon_set_data& that)Copy construct.
+template <typename l, typename r, typename op>
+polygon_set_data(const polygon_set_view<l,r,op>& +t)
Copy construct from a Boolean operator template.
+polygon_set_data&
operator=(const polygon_set_data& that)
Assignment from another polygon set, may change scanning + orientation.
+template <typename l, typename r, typename op>
+polygon_set_data&
operator=(const polygon_set_view<l, r, +op>& that)
Assignment from a Boolean operator template.
template <typename geometry_object>
+polygon_set_data& operator=(const geometry_object& geo)
Assignment from an insertable object.
+ +template <typename iT>
+void insert(iT input_begin, iT input_end)
Insert objects of an iterator range.  Linear wrt vertices + inserted.
+ +void insert(const polygon_set_data& polygon_set)Insert a polygon set.  Linear wrt vertices inserted.
+ +template <typename geometry_type>
+void insert(const geometry_type& geometry_object,
            bool is_hole += false)
Insert a geometry object, if is_hole is true then the inserted + region is subtractive rather than additive.  Linear wrt vertices + inserted.
+template <typename output_container>
+void get(output_container& output) const
Expects a standard container of polygons objects.  Will scan + and eliminate overlaps.  Converts polygon set geometry to objects + of the polygon type and appends them to the container.  Polygons + will be output with counterclockwise winding, hole polygons will be + output with clockwise winding.  The last vertex of an output + polygon is the duplicate of the first, and the number of points is equal + to the number of edges plus 1.  If required by the output data + type, polygons will have holes fractured out to the outer boundary along + the positive y direction and off grid intersections on the outer + boundary introduced by this fracture will be truncated downward.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+template <typename output_container>
+void get_trapezoids(output_container& output) const
Expects a standard container of polygon objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to trapezoids + vertically and appends them to the container.  Expected n log n + runtime, worst case quadratic runtime wrt. vertices + intersections.
+ +template <typename output_container>
+void get_trapezoids(output_container& output,
  orientation_2d +slicing_orientation) const
+
Expects a standard container of polygon objects.  Will scan + and eliminate overlaps.  Slices polygon set geometry to trapezoids + along the given orientation and appends them to the container.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+ +bool operator==(const polygon_set_data& p) constOnce scanned the data representation of geometry within a polygon + set is in a mathematically canonical form.  Comparison between two + sets is therefore a linear time operation once they are in the scanned + state. Will scan and eliminate overlaps in both polygon sets.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections. 
+bool operator!=(const polygon_set_data& p) constInverse logic of equivalence operator.
void clear()Make the polygon set empty.  Note: does not de-allocate memory.  + Use shrink to fit idiom and assign default constructed polygon set to + de-allocate.
bool empty() const + Check whether the polygon set contains no geometry.  Will scan + and eliminate overlaps because subtractive regions might make the + polygon set empty.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
void clean() constScan and eliminate overlaps.  Expected n log n runtime, worst + case quadratic runtime wrt. vertices + intersections the first time, + constant time subsequently.
+template <typename input_iterator_type>
+void set(input_iterator_type input_begin,
         input_iterator_type input_end)
+
Overwrite geometry in polygon set with insertable objects in the + iterator range.
+template <typename rectangle_type>
+bool extents(rectangle_type& extents_rectangle) const
Given an object that models rectangle, scans and eliminates overlaps + in the polygon set because subtractive regions may alter its extents + then computes the bounding box and assigns it to extents_rectangle.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections the first time, linear subsequently.
+polygon_set_data&
+resize(coord_type resizing,
+        bool corner_fill_arc = false,
       + unsigned int num_circle_segments = 0)
Inflates if resizing is positive, deflates if resizing is + negative.  Original topology at acute angle vertices is preserved + by default, segmented circular arcs are inserted if corner_fill_arc is + true.  num_circle_segments specifies number of segments to + introduce on a full circle when filling acute angle corners with + circular arcs.  Specifying zero for num_circle_segments results in + only a single segment being inserted at acute corners.  Expected n + log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+template <typename transformation_type>
+polygon_set_data&
transform(const transformation_type& transformation)
+
Applies transformation.transform() on vertices stored within the + polygon set.  Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
+polygon_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+polygon_set_data& scale_down(unsigned_area_type +factor) Scales vertices stored within the polygon set down by factor.  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+template <typename scaling_type>
+polygon_set_data&
scale(const scaling_type& + f)
Scales vertices stored within the polygon set by applying f.scale().  + Expected n log n runtime, worst case quadratic runtime wrt. vertices + + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_polygon_set_usage.htm b/doc/gtl_polygon_set_usage.htm new file mode 100644 index 0000000..d08c475 --- /dev/null +++ b/doc/gtl_polygon_set_usage.htm @@ -0,0 +1,85 @@ + + + + +Polygon Set Usage + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+int main() {
    +//lets declare ourselves a polygon set
    +using namespace gtl; //because of operators
    +typedef std::vector<polygon_data<int> > PolygonSet;
    +PolygonSet ps;
    +
    +//lets put some data in
    +ps += rectangle_data<int>(0, 0, 10, 10);
    +
    +//now lets do something interesting
    +PolygonSet ps2;
    +ps2 += rectangle_data<int>(5, 5, 15, 15);
    +PolygonSet ps3;
    +assign(ps3, ps * ps2); //woah, I just felt the room flex around me
    +PolygonSet ps4;
    +ps4 += ps + ps2;
    +
    +//assert that area of result is equal to sum of areas
    +//of input geometry minus the area of overlap between inputs
    +assert(area(ps4) == area(ps) + area(ps2) - area(ps3));
    +
    +//I don't even see the code anymore, all
    +//I see is bounding box...interval...triangle
    +
    +//lets try that again in slow motion shall we?
    +assert(equivalence((ps + ps2) - (ps * ps2), ps ^ ps2));
+
+    //hmm, subtracting the intersection from the union
+    //is equivalent to the xor, all this in one line of code,
+    //now we're programming in bullet time
+    //(by the way, xor is implemented as one pass, not +composition) 
    +
    +//just for fun
    +rectangle_data<int> rect;
    +assert(extents(rect, ps ^ ps2));
    +assert(area(rect) == 225);
    +assert(area(rect ^ (ps ^ ps2)) == area(rect) - area(ps ^ ps2));
    +return 0;
}
    +
//Now you know how to use the polygon set concept with library polygons
    + 

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_polygon_usage.htm b/doc/gtl_polygon_usage.htm new file mode 100644 index 0000000..fd1006a --- /dev/null +++ b/doc/gtl_polygon_usage.htm @@ -0,0 +1,76 @@ + + + + +Polygon Usage + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;

+int main() {
+    //lets construct a 10x10 rectangle shaped polygon
+    typedef gtl::polygon_data<int> Polygon;
+    typedef gtl::polygon_traits<Polygon>::point_type Point;
+    Point pts[] = {gtl::construct<Point>(0, 0),
+    gtl::construct<Point>(10, 0),
+    gtl::construct<Point>(10, 10),
+    gtl::construct<Point>(0, 10) };
+    Polygon poly;
+    gtl::set_points(poly, pts, pts+4);
+
+    //now lets see what we can do with this polygon
+    assert(gtl::area(poly) == 100.0f);
+    assert(gtl::contains(poly, gtl::construct<Point>(5, 5)));
+    assert(!gtl::contains(poly, gtl::construct<Point>(15, 5)));
+    gtl::rectangle_data<int> rect;
+    assert(gtl::extents(rect, poly)); //get bounding box of poly
+    assert(gtl::equivalence(rect, poly)); //hey, that's slick
+    assert(gtl::winding(poly) == gtl::COUNTERCLOCKWISE);
+    assert(gtl::perimeter(poly) == 40.0f);
+
+    //add 5 to all coords of poly
+    gtl::convolve(poly, gtl::construct<Point>(5, 5));
+    //multiply all coords of poly by 2
+    gtl::scale_up(poly, 2);
+    gtl::set_points(rect, gtl::point_data<int>(10, 10),
+    gtl::point_data<int>(30, 30));
+    assert(gtl::equivalence(poly, rect));
+    return 0;
+}
+//Now you know how to use the built in polygon data type

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_polygon_with_holes_concept.htm b/doc/gtl_polygon_with_holes_concept.htm new file mode 100644 index 0000000..5fb6bc9 --- /dev/null +++ b/doc/gtl_polygon_with_holes_concept.htm @@ -0,0 +1,395 @@ + + +Boost Polygon Library: Polygon With Holes Concept + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Polygon With Holes Concept

+ +

+

The polygon_with_holes concept tag is +polygon_with_holes_concept

+

+To register a user defined type as a model of +polygon_with_holes concept, specialize the +geometry concept meta-function for that type.  In the example below +CPolygonWithHoles is registered as a model of polygon_with_holes  concept.

+template <>
+struct geometry_concept<CPolygonWithHoles> { typedef polygon_with_holes_concept type; };

+The semantic of a polygon_with_holes is a polygon +that it can provide iterators over holes that are also polygon.  A mutable +polygon_with_holes must also be able to set its geometry based on an interator +range over polygon holes.  There is no convention of winding of holes +enforced within the library.

+Below is shown the default polygon with holes +traits.  Specialization of these traits is required for types that don't +conform to the default behavior.  Note, these traits are used by all +polygon with holes concepts.

template <typename +T, typename enable = void>
+struct polygon_with_holes_traits {
+     typedef typename T::iterator_holes_type +iterator_holes_type;
+     typedef typename T::hole_type hole_type;
+     static inline iterator_holes_type begin_holes(const T& +t) {
+          return t.begin_holes();
+     }
+     static inline iterator_holes_type end_holes(const T& t) +{
+          return t.end_holes();
+     }
+     static inline unsigned int size_holes(const T& t) {
+          return t.size_holes();
+     }
+};

+

template <typename T, typename enable = void>
+struct polygon_with_holes_mutable_traits {
+     template <typename iT>
+     static inline T& set_holes(T& t, iT inputBegin, iT +inputEnd) {
+          t.set_holes(inputBegin, +inputEnd);
+          return t;
+     }
+};

+

An object that is a model of +polygon_with_holes_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the restriction of +those concepts.  This concept casting is accomplished through the +view_as<>() function.

+

view_as<rectangle_concept>(polygon_with_holes_object)
+view_as<polygon_90_concept>(polygon_with_holes_object)
+view_as<polygon_90_with_holes_concept>(polygon_with_holes_object)
+view_as<polygon_45_concept>(polygon_with_holes_object)
+view_as<polygon_45_with_holes_concept>(polygon_with_holes_object)
+view_as<polygon_concept>(polygon_with_holes_object)

+

The return value of view_as<>() can be +passed into any interface that expects an object of the conceptual type +specified in its template parameter.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ point_iterator_type begin_points(const T& polygon)
Expects a model of polygon_with_holes.  + Returns the begin iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ point_iterator_type end_points(const T& polygon)
Expects a model of polygon_with_holes.  + Returns the end iterator over the range of points that correspond to + vertices of the polygon.
template <typename T>
+ hole_iterator_type begin_holes(const T& polygon)
Expects a model of polygon_with_holes.  + Returns the begin iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T>
+ hole_iterator_type end_holes(const T& polygon)
Expects a model of polygon_with_holes.  + Returns the end iterator over the range of coordinates that correspond + to horizontal and vertical edges.
template <typename T, typename + iterator>
+ void set_points(T& polygon, iterator b, iterator e)
Expects a model of polygon_with_holes.   + Sets the polygon to the point data range [b,e) that corresponds to + vertices of a polygon. 
template <typename T, typename + iterator>
+ void set_holes(T& polygon, iterator b, iterator e)
Expects a model of polygon_with_holes.   + Sets the polygon holes to the hole data range [b,e)
template <typename T>
+ unsigned int size(const T& polygon)
Returns the number of edges in the + outer shell of the polygon_with_holes.  Does not include sizes of + the holes.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models polygon_with_holes or one + of its refinements into left object + that models polygon_with_holes.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models polygon_with_holes and an object that models + point, returns true + if the polygon shell contains the point and one of its holes does not + contain the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the polygon or one of its holes.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& polygon)
Sets object that models point to the center point of the bounding + box of an object that models polygon_with_holes.
template <typename T, + typename rectangle_type>
+ bool extents(rectangle_type& bbox, const T& polygon)
Sets object that models rectangle to the bounding box of an object + that models polygon_with_holes and returns true.  Returns false and + leaves bbox unchanged if polygon is empty.
template <typename T>
+ manhattan_area_type area(const T& polygon)
Returns the area of an object + that models polygon_with_holes including subtracting the area of its + holes from the area of the outer shell polygon.
template <typename T>
+ direction_1d winding(const T& polygon)
Returns the winding direction of an object + that models polygon_with_holes, LOW == CLOCKWISE, HIGH = + COUNTERCLOCKWISE.
template <typename T>
+ coordinate_difference perimeter(const T& polygon)
Returns the perimeter length of an object + that models polygon, including the perimeters of the holes.
template <typename T, + typename transform_type>
+ T& transform(T& polygon, const transform_type&)
Applies transform() on the vertices of polygon and sets the polygon to that described by the result of + transforming its vertices.  Also applies transform() on the holes + of the polygon.
template <typename T>
+ T& scale_up(T& polygon, unsigned_area_type factor)
Scales up outer shell and holes of an object that models + polygon by unsigned factor.
template <typename T>
+ T& scale_down(T& polygon, unsigned_area_type factor)
Scales down outer shell and holes of an object that models + polygon by unsigned factor.
template <typename T, scaling_type>
+ T& scale(T& rectangle, double scaling)
Scales outer shell and holes of an object that models polygon by + floating point factor.
template <typename T>
+ T& move(T& polygon, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to coordinate indicated by orientation_2d of + vertices of an object that models polygon .
template <typename polygon_type, typename point_type>
+ polygon_type& convolve(polygon_type& polygon,
+                       + const point_type& point)
Convolves coordinate values of point with the outer shell and holes of an + object that models polygon_with_holes.
+

Polygon With Holes Data

+ +

+

The library provides a model of polygon with holes concept declared + +template<typename T> polygon_with_holes_data where T is the +coordinate type.

+

This data type is used internally when a polygon with holes is +needed and is available to the library user who finds it convenient to use a +library polygon data type instead of providing their own.  The data type is +implemented to be convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typepolygon_with_holes_concept
coordinate_typeT
iterator_typeIterator over vertices point_data<T> vertices of polygon
iterator_holes_typeIterator over hole polygons of type + polygon_data<T>.
polygon_with_holes_data()Default constructs the polygon.
polygon_with_holes_data(const + polygon_with_holes_data& that)Copy construct
polygon_with_holes_data& +
operator=
(const polygon_with_holes_data& that)
Assignment operator.
template <typename T2> + polygon_with_holes_data&  +
operator=
(const T2& that) const
Assign from an object that is a model of polygon with holes.
iterator_type begin() + constGet the begin iterator over vertices of the polygon.
iterator_type end() + constGet the end iterator over vertices of the polygon.
iterator_hole_type begin_holes() + constGet the begin compact iterator over non-redundant coordinates of the + polygon.
iterator_hole_type end_holes() + constGet the end compact iterator over non-redundant coordinates of the + polygon.
std::size_t size() constGet the number of elements in the sequence stored to the polygon, + usually equal to the number of edges of the polygon.
std::size_t size_holes() constGet the number of holes in the polygon
template <typename iT>  +
void set(iT begin_points, iT end_points)
Sets the polygon to the iterator range of points.
template <typename iT>  +
void set_holes(iT begin_holes, iT end_choless)
Sets the polygon holes the iterator range of hole polygons.  These + polygons in the input range may be either polygon_data or + polygon_with_holes_data or any type that provides begin and end member + functions to iterate over point_data<T>.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_property_merge.htm b/doc/gtl_property_merge.htm new file mode 100644 index 0000000..684a198 --- /dev/null +++ b/doc/gtl_property_merge.htm @@ -0,0 +1,146 @@ + + +Boost Polygon Library: Property Merge + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Property Merge

+ +

+

The following is the declaration of the property merge algorithm.

+template <typename coordinate_type, typename +property_type>
+class property_merge;

The property algorithm computes the n-layer +map overlay of input polygon sets.  Each input geometry is inserted along +with a property value.  The property type can be anything suitable for use +as an element of a std::set.  Multiple geometry objects can be separately +inserted with the same property value.  To store the result of this +operation a fairly complex container is required.  Resulting geometries are +associated with unique subsets of property values of the input geometry.  +Two suitable containers for storing the result of a property merge operation +are:

std::map<std::set<property_type>, polygon_set_data<coordinate_type> +>
+std::map<std::vector<property_type>, polygon_set_data<coordinate_type> >

+Example code property_merge_usage.cpp + demonstrates using the n-layer map-overlay algorithm on polygon data.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
property_merge()Default constructor.
property_merge(const + property_merge& that)Copy construct.
+void
insert(const polygon_set_data<coordinate_type>& ps,
+       +const property_type& property)
Insert a polygon set with an associated + property.  Linear wrt vertices inserted.
+ +template <class GeoObjT>
+void insert(const GeoObjT& geoObj,
+       +const property_type& property)
Insert a geometry object that is a refinement of polygon set with an + associated property.  Linear wrt vertices inserted.
+ +template <typename result_type>
+void merge(result_type& result)
Accepts a container object that conforms to the expectations defined + above.  Performs property merge and populates the container + object.  Expected n log n runtime, worst case quadratic runtime wrt. + vertices + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_property_merge_45.htm b/doc/gtl_property_merge_45.htm new file mode 100644 index 0000000..7dd551c --- /dev/null +++ b/doc/gtl_property_merge_45.htm @@ -0,0 +1,145 @@ + + +Boost Polygon Library: Property Merge 90 + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Property Merge 45

+ +

+

The following is the declaration of the property merge algorithm.

+template <typename coordinate_type, typename +property_type>
+class property_merge_45;

The property algorithm computes the n-layer +map overlay of input polygon sets.  Each input geometry is inserted along +with a property value.  The property type can be anything suitable for use +as an element of a std::set.  Multiple geometry objects can be separately +inserted with the same property value.  To store the result of this +operation a fairly complex container is required.  Resulting geometries are +associated with unique subsets of property values of the input geometry.  +Two suitable containers for storing the result of a property merge operation +are:

std::map<std::set<property_type>, polygon_45_set_data<coordinate_type> +>
+std::map<std::vector<property_type>, polygon_45_set_data<coordinate_type> >

+Example code property_merge_usage.cpp + demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
property_merge_45()Default constructor.
property_merge_45(const + property_merge_45& that)Copy construct.
+void
insert(const polygon_45_set_data<coordinate_type>& ps,
+       +const property_type& property)
Insert a polygon set with an associated + property.  Linear wrt vertices inserted.
+ +template <class GeoObjT>
+void insert(const GeoObjT& geoObj,
+       +const property_type& property)
Insert a geometry object that is a refinement of polygon 45 set with + an associated property.  Linear wrt vertices inserted.
+ +template <typename result_type>
+void merge(result_type& result)
Accepts a container object that conforms to the expectations defined + above.  Performs property merge and populates the container + object.  O(n log n) runtime wrt. vertices + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_property_merge_90.htm b/doc/gtl_property_merge_90.htm new file mode 100644 index 0000000..9441396 --- /dev/null +++ b/doc/gtl_property_merge_90.htm @@ -0,0 +1,145 @@ + + +Boost Polygon Library: Property Merge 90 + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Property Merge 90

+ +

+

The following is the declaration of the property merge algorithm.

+template <typename coordinate_type, typename +property_type>
+class property_merge_90;

The property algorithm computes the n-layer +map overlay of input polygon sets.  Each input geometry is inserted along +with a property value.  The property type can be anything suitable for use +as an element of a std::set.  Multiple geometry objects can be separately +inserted with the same property value.  To store the result of this +operation a fairly complex container is required.  Resulting geometries are +associated with unique subsets of property values of the input geometry.  +Two suitable containers for storing the result of a property merge operation +are:

std::map<std::set<property_type>, polygon_90_set_data<coordinate_type> +>
+std::map<std::vector<property_type>, polygon_90_set_data<coordinate_type> >

+Example code property_merge_usage.cpp + demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

Member Functions

+ + + + + + + + + + + + + + + + + + + + + +
property_merge_90()Default constructor.
property_merge_90(const + property_merge_90& that)Copy construct.
+void
insert(const polygon_90_set_data<coordinate_type>& ps,
+       +const property_type& property)
Insert a polygon set with an associated + property.  Linear wrt vertices inserted.
+ +template <class GeoObjT>
+void insert(const GeoObjT& geoObj,
+       +const property_type& property)
Insert a geometry object that is a refinement of polygon 90 set with + an associated property.  Linear wrt vertices inserted.
+ +template <typename result_type>
+void merge(result_type& result)
Accepts a container object that conforms to the expectations defined + above.  Performs property merge and populates the container + object.  O(n log n) runtime wrt. vertices + intersections.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_property_merge_usage.htm b/doc/gtl_property_merge_usage.htm new file mode 100644 index 0000000..d46d225 --- /dev/null +++ b/doc/gtl_property_merge_usage.htm @@ -0,0 +1,127 @@ + + + + +Property Merge Usage + + + + +

/*
+Copyright 2008 Intel Corporation
+
+Use, modification and distribution are subject to the Boost Software License,
+Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+http://www.boost.org/LICENSE_1_0.txt).
+*/
+#include <boost/polygon/polygon.hpp>
+#include <cassert>
+namespace gtl = boost::polygon;
+using namespace boost::polygon::operators;
+
//just a little meta-programming to get things off on the right foot
+template <typename T>
+struct lookup_polygon_set_type { typedef gtl::polygon_set_data<int> type; };
+template <typename T, typename T2>
+struct lookup_polygon_set_type<gtl::property_merge_90<T, T2> > {
+  typedef gtl::polygon_90_set_data<int> type; };
+
+//This function works with both the 90 and general versions
+//of property merge/map overlay algorithm
+template <typename pm_type>
+void test_pm() {
+  std::vector<gtl::rectangle_data<int> > test_data;
+  test_data.push_back(gtl::rectangle_data<int>(11, 10, 31, 30));
+  test_data.push_back(gtl::rectangle_data<int>(1, 0, 21, 20));
+  test_data.push_back(gtl::rectangle_data<int>(6, 15, 16, 25));
+
+  pm_type pm;
+
+  //insert our test geometry into the property merge algorithm
+  for(unsigned int i = 0; i < test_data.size(); ++i) {
+    pm.insert(test_data[i], i); //notice I use the index as the +property value
+  }
+
+  typedef typename lookup_polygon_set_type<pm_type>::type polygon_set_type;
+  typedef std::map<std::set<int>, polygon_set_type> +property_merge_result_type;
+
+  std::set<int> key;
+
+  //There are 8 different combinations of our input geometries
+  //null combination is not interesting, so really 7
+
+  property_merge_result_type result;
+  pm.merge(result);
+
+  //lets enumerate boolean combinations of inputs (hold onto your hats)
+  for(unsigned int i = 0; i < 8; ++i) {
+    bool bits[3] = {i & 1, i & 2, i & 4}; //break out bit array
+    polygon_set_type test_set;
+    std::set<int> key;
+    for(unsigned int j = 0; j < 3; ++j) {
+      if(bits[j]) {
+        key.insert(key.end(), j);
+        test_set += test_data[j];
+      }
+    }
+    for(unsigned int j = 0; j < 3; ++j) {
+      if(bits[j]) {
+        test_set *= test_data[j];
+      }
+    }
+    for(unsigned int j = 0; j < 3; ++j) {
+      if(!bits[j])
+        test_set -= test_data[j];
+    }
+    if(test_set.empty()) {
+      //only the null combination should not exist
+      assert(i == 0);
+      //a combination that does not exist should not
+      //be present in result
+      assert(result.find(key) == result.end());
+    } else {
+      assert(gtl::equivalence(result[key], test_set));
+    }
+  }
+
+  //Notice that we have to do O(2^n) booleans to compose the same
+  //result that is produced in one pass of property merge
+  //given n input layers (8 = 2^3 in this example)
+}
+
+int main() {
+  +test_pm<gtl::property_merge_90<int, int> >();
+  +test_pm<gtl::property_merge<int, int> >();
+  +return 0;
+}
+//Now you know how to use the manhattan and arbitrary angle property
+//merge algorithms to perform map overlay on n layers of input geometry

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + diff --git a/doc/gtl_rectangle_concept.htm b/doc/gtl_rectangle_concept.htm new file mode 100644 index 0000000..25505d0 --- /dev/null +++ b/doc/gtl_rectangle_concept.htm @@ -0,0 +1,752 @@ + + +Boost Polygon Library: Rectangle Concept + + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

Rectangle Concept

+ +

+

The rectangle concept tag is +rectangle_concept

+

+To register a user defined type as a model of +rectangle concept, specialize the +geometry concept meta-function for that type.  In the example below CRectangle is registered as a model of +rectangle  concept.

+template <>
+struct geometry_concept<CRectangle> { typedef rectangle_concept type; };

+The semantic of a rectangle is that it has an x and +a y interval and these intervals conform to the semantic of an interval +including its invariant.  This invariant on the intervals of a rectangle is enforced by the generic library functions that +operate on rectangles, and is not expected of the data type itself or the concept +mapping of that data type to the rectangle concept through its traits.  In +this way a boost::tuple<int, int, int, int> or boost::array<int, 4> +could be made models of rectangle by simply providing indirect access to their +elements through traits.

+Below is shown the default rectangle traits.  +Specialization of these traits is required for types that don't conform to the +default behavior.  The interested reader will note SFINAE is used on the +traits to allow only an object that provides a member type definition of +interval_type to work with the default read only traits.  This becomes +necessary when refinements of concepts are used and it is undesirable to attempt +to match default traits to non-rectangle types at compile time.  +Specializing rectangle_traits can be done easily by simply providing gtl_yes as +the enable parameter.

+template <typename T, typename enable = gtl_yes>
+struct rectangle_traits {};

+template <typename T>
+struct rectangle_traits<T, gtl_no> {};
+
+template <typename T>
+struct rectangle_traits<T, typename gtl_same_type<typename T::interval_type, +typename T::interval_type>::type> {
+     typedef typename T::coordinate_type coordinate_type;
+     typedef typename T::interval_type interval_type;
+     static inline interval_type get(const T& rectangle, +orientation_2d orient) {
+          return +rectangle.get(orient); }
+};
+
+template <typename T>
+struct rectangle_mutable_traits {
+     template <typename T2>
+     static inline void set(T& rectangle, orientation_2d +orient, const T2& interval) {
+          rectangle.set(orient, +interval); }
+     template <typename T2, typename T3>
+     static inline T construct(const T2& interval_horizontal, +const T3& interval_vertical) {
+          return +T(interval_horizontal, interval_vertical); }
+};

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
template <typename T>
+ interval_type get(const T& rectangle, orientation_2d)
Expects a model of rectangle.  + Returns the x interval or y interval of the rectangle, depending on the + orientation_2d value.
template <typename T, typename + coordinate_type>
+ void set(T& rectangle, orientation_2d, coordinate_type)
Expects a model of rectangle.   + Sets the x interval or y interval of the rectangle to the + coordinate, depending on the orientation_2d value.
template <typename T>
+ interval_type get(const T& rectangle, orientation_2d, +
                  direction_1d)
Expects a model of rectangle.  + Returns the coordinate specificed by the direction_1d value of the x interval or y interval of the rectangle, depending on the + orientation_2d value.
template <typename T, typename + coordinate_type>
+ void set(T& rectangle, orientation_2d, direction_1d,
         coordinate_type)
Expects a model of rectangle.   + Sets the coordinate specified by the direction_1d value of the x interval or y interval of the rectangle to the + coordinate, depending on the orientation_2d value.
template <typename T, typename + T2>
+ T construct(const T2& h, const T2& v)
Construct an object that is a model of rectangle given x interval + and y intervals.
template <typename T, typename + T2>
+ T construct(coordinate_type xl, coordinate_type yl,
            coordinate_type + xh, coordinate_type yh)
Construct an object that is a model of rectangle given four coordinate values.
template <typename T1, typename + T2>
+ T1& assign(T1& left, const T2& right)
Copies data from right object that models rectangle into left object + that models rectangle.
template <typename T, typename + T2>
+ bool equivalence(const T& rectangle1,
+
                 const T2& rectangle2)
Given two objects that model rectangle, compares and returns true if + their x and y intervals are respectively equivalent.
template <typename T, + typename point_type>
+ bool contains(const T&, const point_type& point,
+              + bool consider_touch=true)
Given an object that models rectangle and an object that models + point, returns true + if the rectangle contains the point.  If the consider_touch + flag is true will return true if the point lies along the boundary of + the rectangle.
template <typename T1, typename + T2>
+ bool contains(const T1& a, const T2& b,
+              + bool consider_touch = true)
Returns true if model of rectangle a contains both intervals of + model of rectangle b.  If the consider_touch flag is true will + consider rectangle b contained even if it touches the boundary of a.
template <typename T>
+ interval_type horizontal(const T& rectangle)
Returns the x interval of an object that models rectangle.
template <typename T>
+ interval_type vertical(const T& rectangle)
Returns the y interval of an object that models rectangle.
template <typename T>
+ coordinate_type xl(const T& rectangle)
Returns the west coordinate of an object that models rectangle.
template <typename T>
+ coordinate_type xh(const T& rectangle)
Returns the east coordinate of an object that models rectangle.
template <typename T>
+ coordinate_type yl(const T& rectangle)
Returns the south coordinate of an object that models rectangle.
template <typename T>
+ coordinate_type yh(const T& rectangle)
Returns the north coordinate of an object that models rectangle.
template <typename T>
+ point_type ll(const T& rectangle)
Returns the lower left corner point of an object that models rectangle.
template <typename T>
+ point_type lr(const T& rectangle)
Returns the lower right corner point of an object that models rectangle.
template <typename T>
+ point_type ul(const T& rectangle)
Returns the upper left corner point of an object that models rectangle.
template <typename T>
+ point_type ur(const T& rectangle)
Returns the upper right corner point of an object that models rectangle.
// get the center coordinate
+ template <typename T, typename point_type>
+ void center(point_type& p, const T& rectangle)
Sets object that models point to the center point of an object that models rectangle.
template <typename T, + typename interval_type>
+ void horizontal(T& rectangle, const interval_type& i)
Sets the x interval of the object that models rectangle to be equal + to the value of an object that models interval.
template <typename T, + typename interval_type>
+ void vertical(T& rectangle, const interval_type& i )
Sets the y interval of the object that models rectangle to be equal + to the value of an object that models interval.
template <typename + rectangle_type>
+ void xl(rectangle_type& rectangle, coordinate_type )
Sets the west coordinate of the object that models rectangle to be equal + to the coordinate value.
template <typename + rectangle_type>
+ void xh(rectangle_type& rectangle, coordinate_type )
Sets the east coordinate of the object that models rectangle to be equal + to the coordinate value.
template <typename + rectangle_type>
+ void yl(rectangle_type& rectangle, coordinate_type )
Sets the south coordinate of the object that models rectangle to be equal + to the coordinate value.
template <typename + rectangle_type>
+ void yh(rectangle_type& rectangle, coordinate_type )
Sets the north coordinate of the object that models rectangle to be equal + to the coordinate value.
template <typename T, + typename T1, typename T2>
+ T& set_points(T& rectangle, const T1& p1, const T2& p2)
Sets the rectangle to the rectangle fully described by the points p1 + and p2.
template <typename T>
+ coordinate_difference delta(const T& rectangle, +
                            orientation_2d)
Returns the delta of the interval specified by orientation_2d of an object + that models rectangle.
template <typename T>
+ manhattan_area_type area(const T& rectangle)
Returns the area of an object + that models rectangle.
template <typename T>
+ coordinate_difference half_perimeter(const T& rectangle)
Returns the length plus width of an object + that models rectangle.
template <typename T>
+ coordinate_difference perimeter(const T& rectangle)
Returns the perimeter length of an object + that models rectangle.
template <typename T>
+ orientation_2d quess_orientation(const T& rectangle)
Returns the orientation in which the rectangle has a longer delta.  + Returns HORIZONTAL if the rectangle is a square.
template <typename + rectangle_type>
+ rectangle_type& transform(rectangle_type& rectangle,
+                          coordinate_type axis = 0)
Applies transform() on the two points that fully describe the + rectangle and sets the rectangle to that described by the result of + transforming those points.
template <typename + rectangle_type>
+ rectangle_type& scale_up(rectangle_type& rectangle,
+                         unsigned_area_type factor)
Scales up x interval and y interval  of an object that models + rectangle by unsigned factor.
template <typename + rectangle_type>
+ rectangle_type& scale_down(rectangle_type& rectangle,
+                           unsigned_area_type factor)
Scales down x interval and y interval  of an object that models + rectangle by unsigned factor.
template <typename + rectangle_type, scaling_type>
+ rectangle_type& scale(rectangle_type& rectangle,
+                      + const scaling_type& scaling)
Applies scale() on the two points that fully describe the rectangle + and sets the rectangle to that described by the result of transforming + those points.
template <typename T>
+ T& move(T& rectangle, orientation_2d,
+        coordinate_difference displacement)
Adds displacement value to interval indicated by orientation_2d of an + object that models rectangle.
template <typename + rectangle_type, typename point_type>
+ rectangle_type& convolve(rectangle_type& rectangle,
+                         + const point_type& point)
Convolves coordinate values of point with x interval and y interval  of an + object that models rectangle.
template <typename + rectangle_type, typename point_type>
+ rectangle_type& deconvolve(rectangle_type& rectangle,
+                           + const point_type& point)
Deconvolves coordinate values of point withx interval and y interval  of + an object that models rectangle.
template <typename T1, typename + T2>
+ T1& convolve(T1& a, const T2& b)
Convolves x interval  of b with x interval  of a and + convolves y + interval  of b with y interval  of a.
template <typename T1, typename + T2>
+ T1& deconvolve(T1& a, const T2& b)
Deconvolves x interval  of b with x interval  of a and + deconvolves y interval  of b with y interval  of a.
template <typename T1, typename + T2>
+ T1& reflected_convolve(T1& a, const T2& b)
Reflected convolves y interval  of b with x interval  of a and + reflected convolves x + interval  of b with y interval  of a.
template <typename T1, typename + T2>
+ T1& reflected_deconvolve(T1& a, const T2& b)
Reflected deconvolves y interval  of b with x interval  of a and + reflected deconvolves x interval  of b with y interval  of a.
template <typename T, + typename point_type>
+ coordinate_difference euclidean_distance(const T&,
+        const point_type& point, + orienation_2d)
Returns the distance from an object that models rectangle to an + object that models point along the given orientation.  Returns zero + if the point is contained within the rectangle along that orientation.
template <typename T1, + typename T2>
+ coordinate_difference euclidean_distance(const T1& a,
+        const T2& b, orienation_2d)
Returns the distance from an object that models rectangle to an + object that models rectangle along the given orientation.  Returns + zero if the intervals of the rectangles overlap along that orientation.
template <typename T, + typename point_type>
+ coordinate_difference square_euclidean_distance(const T&,
+        const point_type& point)
Returns the square of the Euclidean distance between a point and a + rectangle.  Returns zero if the point is contained within the + rectangle.
template <typename T1, + typename T2>
+ coordinate_difference square_euclidean_distance
+        (const T1& a, const T2& b)
Returns the square of the Euclidean distance between rectangles a + and b.  Returns zero if the rectangles intersect.
template <typename T, + typename point_type>
+ coordinate_difference manhattan_distance(const T&,
+        const point_type& point)
Returns the Manhattan distance between a point and a rectangle.  + Returns zero if the point is contained within the rectangle.
template <typename T1, + typename T2>
+ coordinate_difference manhattan_distance(const T1& a,
+                                          + const T2& b)
Returns the Manhattan distance between rectangles a and b.  + Returns zero if the rectangles intersect.
template <typename T, + typename point_type>
+ coordinate_distance euclidean_distance(const T&,
+        const point_type& point)
Returns the Euclidean distance between a point and a rectangle.  + Returns zero if the point is contained within the rectangle.
template <typename T1, + typename T2>
+ coordinate_distance euclidean_distance(const T1& a,
+                                          + const T2& b)
Returns the Euclidean distance between rectangles a and b.  + Returns zero if the rectangles intersect.
template <typename T1, typename + T2>
+ bool intersects(const T1& a, const T2& b,
+                + bool consider_touch = true)
Returns true if two objects that model rectangle overlap.  If + the consider_touch flag is true touching at the sides or corners is + considered overlap.
template <typename T1, typename + T2>
+ bool boundaries_intersect(const T1& a, const T2& b,
+                          + bool consider_touch = true)
Returns true is two objects that model rectangle partially overlap + such that one there is an intersection between the edges of the two + rectangles  If the consider_touch flag is true a coordinate is + considered contained even if the two rectangles touch only along a side + or corner.
template <typename T1, typename + T2>
+ bool abuts(const T1& a, const T2& b,
+           direction_2d dir) +
Returns true if rectangle b abuts but down not overlap rectangle a + on the side of rectangle a specified by dir.
template <typename T1, typename + T2>
+ bool abuts(const T1& a, const T2& b,
+           orientation_2d) +
Returns true if rectangle b abuts but down not overlap rectangle a + on either side of rectangle a specified by the orientation_2d.
template <typename T1, typename + T2>
+ bool abuts(const T1& a, const T2& b)
Returns true if rectangle b abuts but down not overlap rectangle a + on any side.
template <typename T1, typename + T2>
+ bool intersect(T1& a, const T2& b, orientation_2d
+               + bool consider_touch = true)
Sets rectangle a to the intersection of rectangle a and interval b + along the orientation_2d + and returns true.  If the does not intersect the interval, the + rectangle is unchanged and the function returns false.  If the flag consider_touch is true + intervals that abut are considered to intersect.
template <typename T1, typename + T2>
+ bool intersect(T1& a, const T2& b,
+               + bool consider_touch = true)
Sets rectangle a to the intersection of rectangle a and rectangle b + and return true.  If the two rectangles do not intersect rectangle + a is unchanged and the function returns false.  If the flag + consider_touch is true rectangles that abut are considered to intersect.
template <typename T1, typename + T2>
+ T& generalized_intersect(T1& a, const T2& b)
Same as intersect, but if they do not intersect set a to the + rectangle between a and b by applying generalized_intersect() on the + intervals of the rectangles.
template <typename T>
+ T& bloat(T& rectangle, coordinate_type)
Bloats x and y intervals of rectangle by coordinate value.
template <typename T>
+ T& bloat(T& rectangle, direction_2d, coordinate_type)
Bloats side of rectangle specified by direction_2d by coordinate + value.
template <typename T>
+ T& bloat(T& rectangle, orientation_2d, coordinate_type)
Bloats interval of rectangle specified by orientation_2d by + coordinate value.
template <typename T>
+ T& shrink(T& rectangle, coordinate_type)
Shrinks x and y intervals of rectangle by coordinate value.
template <typename T>
+ T& shrink(T& rectangle, direction_2d, coordinate_type)
Shrinks side of rectangle specified by direction_2d by coordinate + value.
template <typename T>
+ T& shrink(T& rectangle, orientation_2d, coordinate_type)
Shrinks interval of rectangle specified by orientation_2d by + coordinate value.
template <typename T1, typename + T2>
+ bool encompass(T1& a, const T2& b)
The x and y intervals of a are set to encompass the x and y + intervals of b respectively.
template <typename T, typename + point_type>
+ bool encompass(T& rectangle, const point_type& point)
The x and y intervals of rectangle are set to encompass the x and y + coordinates of point respectively.
template <typename T, typename + interval_type>
+ bool encompass(T& rectangle, const interval_type& i, +
               orientation_2d)
The interval of rectangle specified by orientation_2d is set to encompass the + interval i.
template <typename T, typename + point_type>
+ bool get_corner(point_type& point, const T& rectangle,  +
                + direction_2d, direction_1d)
Sets point to the corner of the rectangle you reach if you look at + its side specified by direction_2d from within the rectangle and turn in + the direction_1d direction (low == left, high = right).  Always + returns true.
+

Rectangle Data

+ +

+

The library provides a model of rectangle concept declared + +template<typename T> rectangle_data where T is the coordinate type.

+

This data type is used internally when a rectangle is needed and is available +to the library user who finds it convenient to use a library rectangle data type +instead of providing their own.  The data type is implemented to be +convenient to use with the library traits.

+

Members

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
geometry_typerectangle_concept
coordinate_typeT
interval_typeinterval_data<T>
rectangle_data(T xl, T + yl, T xh, T yh)Constructs a rectangle with four + coordinates.
template <typename T1, typename + T2>
+ rectangle_data
(const T1& horizontal_interval,
+               + const T2& vertical_interval)
Constructs a rectangle with two objects + that model interval.
rectangle_data(const + rectangle_data& that)Copy construct
rectangle_data& operator=(const + rectangle_data& that)Assignment operator.
template <typename T2> +
rectangle_data& + operator=(const T2& that) const
Assign from an object that is a model of rectangle.
template <typename T2> +
bool + operator==(const T2& that) const
Compare equality to an object that is a model of rectangle.
template <typename T2> +
bool + operator!=(const T2& that) const
Compare inequality to an object that is a model of rectangle.
interval_data<T> get(orientation_2d + orient) constGet the interval in the given orientation.
template <typename T2>
+ void set(orientation_2d orient, const T2& value)
Sets the interval in the given orientation to the value of an object + that models interval.
+
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/gtl_tutorial.htm b/doc/gtl_tutorial.htm new file mode 100644 index 0000000..151e87c --- /dev/null +++ b/doc/gtl_tutorial.htm @@ -0,0 +1,658 @@ + + + + +Polygon Usage + + + + +

Layout Versus Schematic Tutorial

+

In this tutorial we will implement a toy VLSI layout verification +application.  In VLSI CAD an important step of design is the sign off check +that verifies that the physical layout as drawn by mask designers and automated +tools implements the logical schematic specified by design engineers.  +Physical layout is modeled as polygons on layers that are used to print the +layout to the silicon wafer during manufacture.  It is much better to find +physical design mistakes before spending millions of dollars to prepare +lithography masks and run a test lot of wafers.

+

Real layout file formats are binary and often compressed and represent a +folded hierarchical model of layout where a group of polygons can be grouped +into a cell and instantiated as a group into other cells.  For this +tutorial we assume a simplified ascii layout file format with no design +hierarchy, which we would call "flat" in VLSI jargon.  Similarly we assume +a flat, ascii logical schematic net list file format.  A net is a named +electrical connection in a circuit design.  The goal of the layout +verification tutorial is to parse these two file formats, apply geometry +operations provided by Boost.Polygon on the layout data to generate a logical +schematic that represents what is implemented in the physical layout and then +compare the input schematic with the generated schematic to determine whether +they are the same.

+

First let us define some objects that we will need in the design of our toy +layout verification application:

+

Layout Rectangle: An axis-parallel rectangle with a layer associated
+Layout Pin: An axis-parallel rectangle with a layer and net (electrical signal) +name associated
+Layout Database: An associative container of layer name to polygon set
+Connectivity Database: An associative container of net name to layout database
+Physical Device: A specific geometric arrangement on several layers with one or +more input net and one output net
+Logical Net: A named graph node
+Logical Device: An un-named graph node with a device type
+Logical Pin: A special net that defines an input or output for the circuit
+Schematic Database: A graph consisting of nets and logical +devices

+

Next let's define the sequence of operations performed by our toy +layout versus schematic application:

+

Parse Layout: Stream layout rectangles and polygons into a layout database +and stream layout pins into a connectivity database
+Extract Connectivity: Add polygons from layout database to connectivity database +by physical touch or overlap relationship
+Extract Devices: Populate a schematic database with logical devices based on +physical devices identified within the layout geometry and extract their +terminals from the +connectivity database
+Extract Net List: Complete graph represented in schematic database derived from +layout
+Parse Schematic: Stream logical nets, devices and pins into a schematic +database
+Compare Schematics: Evaluate whether extracted schematic database is equivalent +to input schematic database and output result

+

To test our application we will extract single logic gates.  A logic +gate is several transistors that work together to perform a specific logic +function.  Logic functions include the commonly understood Boolean logic +operations such as Boolean AND, OR, XOR and INVERT.  Also frequently used +are NAND and NOR, which are respectively AND and OR operations followed by an +INVERT operation.  A NAND gate can be implemented in the CMOS circuit +family with four transistors.  The NAND gate has two inputs and one output.  +Each input goes to two transistors, one p-type transistor and one n-type +transistor.  The "p" stands for positive and the "n" stands for negative.  +When the p-type transistor is on +it pulls the output up to the same voltage as the voltage source.  When the +n-type transistor is on it pulls the output down to the same voltage as the +ground.  The process of creating a p-type transistor begins by "doping" the silicon +substrate to create n-type material.  This area of n-type material will be +called the NWELL layer in our test data.  Within the area of NWELL a +p-diffusion area is created by further doping the silicon to create p-type +material.  This area of p-type material will be called PDIFF in our test +data.  Through the middle of a PDIFF area bars of poly-silicon are grown +that create conductive lines over the diffusion area.  The area of +poly-silicon material will be called POLY in our test data.  Under some of these +poly-silicon lines a thin layer of silicon-oxide provides insulation but allows +the voltage field of the poly-silicon to interact with the diffusion.  Each +of these insulated poly-silicon lines is the "gate" of a transistor.  +The gate area will be called GATE in our test data.  When the +voltage at the gate is the same as the ground voltage the p-type transistor is +"on" and can pass current from the voltage source to the output .  The +poly-silicon lines that are not insulated create electrical connections to the +transistor for output signals and source voltage.  The n-type transistor +differs from the p-type in that its diffusion is n-type material outside of NWELL area.  Current can pass from the output to the ground when the +voltage at the gate of the n-type transistor is at the source voltage level.  +Above the poly-silicon layer is a layer of silicon-oxide insulator with holes +cut out of it that get filled in with metal.  These metal filled holes are +called vias and we will refer to this layer as VIA0 in our test data.  On +top of VIA0 is a layer of metal polygons with silicon oxide insulator between +them.  These metal polygons are wires and we will call them METAL1 in our +test data.  The Layout Pins in our test data will be on METAL1.  In a +NAND gate the two n-type transistors are configured in series, meaning that the +output of one is the input voltage source of the other.  Only if both +n-type transistors of a NAND gate are "on" will the output be connected to +ground, signifying a logical "false".  The two p-type transistors in a NAND +gate are configured in parallel.  If either input to the NAND gate is a +logical "false" the p-type transistor it is connected to will be "on" and the +output of the gate will be a logical "true" because the transistor will connect +it to the voltage supply.  The diagram below is an example of how a NAND +gate might be laid out and is not drawn to scale for any real process +technology.  The diffusion material is intended to be cut away under the +gate material by a Boolean NOT operation and is represented as solid bars under +the gates of transistors only for convenience of drawing.

+

+

+

The following is the input layout file for the above NAND gate layout, +rectangle format is XL XH YL YH:

+

Rectangle 0 60 24 48 NWELL
+Rectangle 3 57 32 43 PDIFF
+Rectangle 3 57 5 16 NDIFF
+Rectangle 5 7 0 17 POLY
+Rectangle 5 7 22 45 POLY
+Rectangle 17 19 3 45 POLY
+Rectangle 29 31 31 48 POLY
+Rectangle 41 43 3 45 POLY
+Rectangle 53 55 3 45 POLY
+Rectangle 17 19 4 17 GATE
+Rectangle 17 19 31 44 GATE
+Rectangle 41 43 4 17 GATE
+Rectangle 41 43 31 44 GATE
+Rectangle 5 7 0 2 VIA0
+Rectangle 5 7 23 25 VIA0
+Rectangle 17 19 28 30 VIA0
+Rectangle 29 31 46 48 VIA0
+Rectangle 41 43 18 20 VIA0
+Rectangle 53 55 23 25 VIA0
+Rectangle 0 60 0 2 METAL1
+Rectangle 3 57 28 30 METAL1
+Rectangle 0 60 46 48 METAL1
+Rectangle 3 57 18 20 METAL1
+Rectangle 3 57 23 25 METAL1
+Pin 29 31 0 2 METAL1 GND
+Pin 29 31 23 25 METAL1 OUTPUT

+Pin 29 31 28 30 METAL1 INPUT1

+Pin 29 31 46 48 METAL1 VDD
+Pin 29 31 18 20 METAL1 INPUT2

+

+

+

The following is the logic schematic net list file for the above NAND gate +schematic:

+

Pin OUTPUT
Pin INPUT1
Pin INPUT2
+Pin VDD
Pin GND
Device PTRANS VDD INPUT1 OUTPUT
Device PTRANS VDD +INPUT2 OUTPUT
Device NTRANS GND INPUT1 NET1
Device NTRANS NET1 INPUT2 +OUTPUT

+

A human can look at this schematic and compare it to the drawn layout of the +NAND gate above to verify that the drawn layout matches what the schematic says +in a few seconds.  If you do that now you will probably find the p and +n-type transistors and trace the connectivity of the inputs and power to the +terminals of the transistors and then to the output.  Since there are on +the order of one billion transistors on a single chip these days we need to go a +lot faster than humans can inspect layout and make fewer mistakes.  Using polygon set operations +and polygon connectivity extraction provided by Boost.Polygon we will automate +the identification of transistors and the tracing of connectivity.  Based +on this +analysis of Boost.Polygon performance we can expect +this methodology to easily scale up to million gate blocks on standard +workstations and arbitrarily large designs given sufficient system memory.  +let's start +by implementing some data structures for our application.

+

struct layout_rectangle {
+  int xl, yl, xh, yh;
+  std::string layer;
+};

+

Our layout rectangle is nice and minimal, just enough to store its data.  +It is defined in layout_rectangle.hpp. Next +let's implement the layout +pin in a similar way.

+

struct layout_pin {
+  int xl, yl, xh, yh;
+  std::string layer;
+  std::string net;
+};

+

Our layout pin is defined in layout_pin.hpp.  Now +let's define a layout database object and populate it from our parsed +layout data in in layout_database.hpp.

+

typedef std::map<std::string, +boost::polygon::polygon_90_set_data<int> > layout_database;
+
+//map the layout rectangle data type to the boost::polygon::rectangle_concept
+namespace boost { namespace polygon{
+  template <>
+  struct rectangle_traits<layout_rectangle> {
+    typedef int coordinate_type;
+    typedef interval_data<int> interval_type;
+    static inline interval_type get(const layout_rectangle& +rectangle, orientation_2d orient) {
+      if(orient == HORIZONTAL)
+        return interval_type(rectangle.xl, +rectangle.xh);
+      return interval_type(rectangle.yl, rectangle.yh);
+    }
+  };
+
+  template <>
+  struct geometry_concept<layout_rectangle> { typedef rectangle_concept +type; };
+}}
+
+//insert layout rectangles into a layout database
+inline void populate_layout_database(layout_database& layout, std::vector<layout_rectangle>& +rects) {
+  for(std::size_t i = 0; i < rects.size(); ++i) {
+    layout[rects[i].layer].insert(rects[i]);
+  }
+}

+

We don't need to insert pins into the layout database because it doesn't know +anything about connectivity, just geometry.  However, we do need to know +something about connectivity to compare a schematic to a layout, so we need to +define our connectivity database and some logical objects.  First we define +an object for a logical device in device.hpp.  +Since we are lazy this object does double duty as a pin and both types of +transistor.  A traditional object oriented design might declare a base +class with virtual destructor and derive every device from that.  Since we +aren't paid by the line of code let's just keep things simple.

+

struct device {
+  std::string type;
+  std::vector<std::string> terminals;
+};

+

Now let's define a schematic database object in +schematic_database.hpp and populate it from our parsed +schematic data.

+

struct schematic_database{
+  std::vector<device> devices;
+  std::map<std::string, std::set<std::size_t> > nets;
+};
+
+//given a vector of devices populate the map of net name to set of device index
+inline void extract_netlist(std::map<std::string, std::set<std::size_t> >& nets,
+                            +std::vector<device>& devices) {
+  for(std::size_t i = 0; i < devices.size(); ++i) {
+    for(std::size_t j = 0; j < devices[i].terminals.size(); ++j) +{
+      //create association between net name and device +id
+      +nets[devices[i].terminals[j]].insert(nets[devices[i].terminals[j]].end(), i);
+    }
+  }
+}

+

Our schematic database is just a vector of devices, which are associated to +nets by name through their terminals and a map of net name to set of device +index into the vector, which completes the graph by associating nets with their +devices.  Given the devices and their terminal nets we easily build the +mapping from nets to devices with the extract_netlist operation.  Now we +are ready to start working on extracting our layout to a derived schematic +database.  However, first we need to build a physical connectivity database +with geometry in it before we can build a logical connectivity database from the +layout.  We define a simple connectivity database in +connectivity_database.hpp as a +map of net name to layout database of geometry connected to that net and +populate it with the layout database and pin data.

+

typedef std::map<std::string, +layout_database > connectivity_database;
+
+//map layout pin data type to boost::polygon::rectangle_concept
+namespace boost { namespace polygon{
+  template <>
+  struct rectangle_traits<layout_pin> {
+    typedef int coordinate_type;
+    typedef interval_data<int> interval_type;
+    static inline interval_type get(const layout_pin& pin, +orientation_2d orient) {
+      if(orient == HORIZONTAL)
+        return interval_type(pin.xl, pin.xh);
+      return interval_type(pin.yl, pin.yh);
+    }
+  };
+
+  template <>
+  struct geometry_concept<layout_pin> { typedef rectangle_concept type; };
+}}

+

//given a layout_database we populate a +connectivity database
+inline void populate_connectivity_database(connectivity_database& connectivity,
+                        +std::vector<layout_pin>& pins, layout_database& layout) {
+  using namespace boost::polygon;
+  using namespace boost::polygon::operators;
+  for(std::size_t i = 0; i < pins.size(); ++i) {
+    connectivity[pins[i].net][pins[i].layer].insert(pins[i]);
+  }
+  int internal_net_suffix = 0;
+  //connect metal1 layout to pins which were on metal1
+  connect_layout_to_layer(connectivity, layout["METAL1"], "METAL1",
+                          +"METAL1", "__internal_net_", internal_net_suffix);
+  //connect via0 layout to metal1
+  connect_layout_to_layer(connectivity, layout["VIA0"], "VIA0",
+                          +"METAL1", "__internal_net_", internal_net_suffix);
+  //poly needs to have gates subtracted from it to prevent shorting through +transistors
+  polygon_set poly_not_gate = layout["POLY"] - layout["GATE"];
+  //connect poly minus gate to via0
+  connect_layout_to_layer(connectivity, poly_not_gate, "POLY",
+                          +"VIA0", "__internal_net_", internal_net_suffix);
+  //we don't want to short signals through transistors so we subtract the +gate regions
+  //from the diffusions
+  polygon_set diff_not_gate = (layout["PDIFF"] + layout["NDIFF"]) - +layout["GATE"];
+  //connect diffusion minus gate to poly
+  //Note that I made up the DIFF layer name for combined P and NDIFF
+  connect_layout_to_layer(connectivity, diff_not_gate, "DIFF",
+                          +"POLY", "__internal_net_", internal_net_suffix);
+  //connect gate to poly to make connections through gates on poly
+  connect_layout_to_layer(connectivity, layout["GATE"], "GATE",
+                          +"POLY", "__internal_net_", internal_net_suffix);
+  //now we have traced connectivity of the layout down to the transistor +level
+  //any polygons not connected to pins have been assigned internal net +names
+}

+

This populate connectivity database function is our first real use of +Boost.Polygon in our application.  Here we are doing Boolean (polygon set) +operations on layout layers to merge together the PDIFF and NDIFF layers and cut +away the GATE layer from the result, for example.  We connect up the layout +starting from the pins and working our way down the layer stack to the +transistor level.  It would work equally well to work our way up the layer +stack, or connect things up in any order, really, but this way produces fewer +internal temporary nets that need to be merged when connections between them are +discovered later.  The connect layout to layer function used above needs to +be implemented before we can populate our connectivity database.

+

inline void +connect_layout_to_layer(connectivity_database& connectivity, polygon_set& +layout,
+                                    +std::string layout_layer, std::string layer,
+                                    +std::string net_prefix, int& net_suffix) {
+  if(layout_layer.empty())
+    return;
+  boost::polygon::connectivity_extraction_90<int> ce;
+  std::vector<std::string> net_ids;
+  for(connectivity_database::iterator itr = connectivity.begin(); itr != +connectivity.end(); ++itr) {
+    net_ids.push_back((*itr).first);
+    ce.insert((*itr).second[layer]);
+  }
+  std::vector<polygon> polygons;
+  layout.get_polygons(polygons);
+  std::size_t polygon_id_offset = net_ids.size();
+  for(std::size_t i = 0; i < polygons.size(); ++i) {
+    ce.insert(polygons[i]);
+  }
+  std::vector<std::set<int> > graph(polygons.size() + net_ids.size(), +std::set<int>());
+  ce.extract(graph);
+  std::vector<int> polygon_color(polygons.size() + net_ids.size(), 0);
+  //for each net in net_ids populate connected component with net
+  for(std::size_t node_id = 0; node_id < net_ids.size(); ++node_id) {
+    populate_connected_component(connectivity, polygons, +polygon_color, graph, node_id,
+    polygon_id_offset, net_ids[node_id], net_ids,
+    net_prefix, layout_layer);
+  }
+  //for each polygon_color that is zero populate connected component with +net_prefix + net_suffix++
+  for(std::size_t i = 0; i < polygons.size(); ++i) {
+    if(polygon_color[i + polygon_id_offset] == 0) {
+      std::stringstream ss(std::stringstream::in | +std::stringstream::out);
+      ss << net_prefix << net_suffix++;
+      std::string internal_net;
+      ss >> internal_net;
+      populate_connected_component(connectivity, +polygons, polygon_color, graph,
+      i + polygon_id_offset,
+      polygon_id_offset, internal_net, net_ids,
+      net_prefix, layout_layer);
+    }
+  }
+}

+

The connect layout to layer function uses the connectivity extraction feature +of Boost.Polyon to build a connectivity graph for polygons on the input polygon +set and in the connectivity database on the specified layer.  It then finds +polygons associated with existing nets in the connectivity database through +graph traversal and inserts them into the connectivity database.  Finally, +polygons that weren't connected to existing nets are inserted into the +connectivity database on auto-generated internal net names.  The insertion +of a connected component into the connectivity database is handled by the +recursive traversal of the connectivity graph that we implement next.

+

inline void populate_connected_component
+(connectivity_database& connectivity, std::vector<polygon>& polygons,
+ std::vector<int> polygon_color, std::vector<std::set<int> >& graph,
+ std::size_t node_id, std::size_t polygon_id_offset, std::string& net,
+ std::vector<std::string>& net_ids, std::string net_prefix,
+ std::string& layout_layer) {
+  if(polygon_color[node_id] == 1)
+    return;
+  polygon_color[node_id] = 1;
+  if(node_id < polygon_id_offset && net_ids[node_id] != net) {
+    //merge nets in connectivity database
+    //if one of the nets is internal net merge it into the other
+    std::string net1 = net_ids[node_id];
+    std::string net2 = net;
+    if(net.compare(0, net_prefix.length(), net_prefix) == 0) {
+      net = net1;
+      std::swap(net1, net2);
+    } else {
+      net_ids[node_id] = net;
+    }
+    connectivity_database::iterator itr = +connectivity.find(net1);
+    if(itr != connectivity.end()) {
+      for(layout_database::iterator itr2 = (*itr).second.begin();
+          itr2 != (*itr).second.end(); +++itr2) {
+        connectivity[net2][(*itr2).first].insert((*itr2).second);
+      }
+      connectivity.erase(itr);
+    }
+  }
+  if(node_id >= polygon_id_offset)
+  connectivity[net][layout_layer].insert(polygons[node_id - +polygon_id_offset]);
+  for(std::set<int>::iterator itr = graph[node_id].begin();
+  itr != graph[node_id].end(); ++itr) {
+    populate_connected_component(connectivity, polygons, +polygon_color, graph,
+    *itr, polygon_id_offset, net, net_ids, net_prefix, +layout_layer);
+  }
+}
+
+
We want to merge internally generated nets into pin nets, which is the +most complicated part of this simple procedure.  Now that we have our +connectivity database extracted from pins down to transistors we need to extract +our transistors and establish the relationship between transistor terminals and +nets in our connectivity database.  First let's extract transistors with +the functions defined in defined in +extract_devices.hpp.

+

typedef boost::polygon::connectivity_extraction_90<int> +connectivity_extraction;
+inline std::vector<std::set<int> >
+extract_layer(connectivity_extraction& ce, std::vector<std::string>& net_ids,
+              +connectivity_database& connectivity, polygon_set& layout,
+              +std::string layer) {
+  for(connectivity_database::iterator itr = connectivity.begin(); itr != +connectivity.end(); ++itr) {
+    net_ids.push_back((*itr).first);
+    ce.insert((*itr).second[layer]);
+  }
+  std::vector<polygon> polygons;
+  layout.get_polygons(polygons);
+  for(std::size_t i = 0; i < polygons.size(); ++i) {
+    ce.insert(polygons[i]);
+  }
+  std::vector<std::set<int> > graph(polygons.size() + net_ids.size(), +std::set<int>());
+  ce.extract(graph);
+  return graph;
+}

+

This extract layer algorithm constructs a connectivity graph between polygons +in the input polygon set and polygons in the given layer of the connectivity +database.  It is used to form the association between transistors and their +terminal nets in the function for extracting a specific transistor type.

+

inline void extract_device_type(std::vector<device>& +devices, connectivity_database& connectivity,
+                                +polygon_set& layout, std::string type) {
+  //recall that P and NDIFF were merged into one DIFF layer in the +connectivity database
+  //find the two nets on the DIFF layer that interact with each transistor
+  //and then find the net on the poly layer that interacts with each +transistor
+  boost::polygon::connectivity_extraction_90<int> cediff;
+  std::vector<std::string> net_ids_diff;
+  std::vector<std::set<int> > graph_diff =
+    extract_layer(cediff, net_ids_diff, connectivity, layout, +"DIFF");
+  boost::polygon::connectivity_extraction_90<int> cepoly;
+  std::vector<std::string> net_ids_poly;
+  std::vector<std::set<int> > graph_poly =
+    extract_layer(cepoly, net_ids_poly, connectivity, layout, +"POLY");
+  std::vector<device> tmp_devices(graph_diff.size() - net_ids_poly.size());
+  for(std::size_t i = net_ids_poly.size(); i < graph_diff.size(); ++i) {
+    tmp_devices[i - net_ids_diff.size()].type = type;
+    tmp_devices[i - net_ids_diff.size()].terminals = std::vector<std::string>(3, +std::string());
+    std::size_t j = 0;
+    for(std::set<int>::iterator itr = graph_diff[i].begin();
+        itr != graph_diff[i].end(); ++itr, +++j) {
+      if(j == 0) {
+        tmp_devices[i - net_ids_diff.size()].terminals[0] += net_ids_diff[*itr];
+      } else if(j == 1) {
+        tmp_devices[i - net_ids_diff.size()].terminals[2] += net_ids_diff[*itr];
+      } else {
+        //error, too many diff connections
+        tmp_devices[i - net_ids_diff.size()].terminals += std::vector<std::string>(3, std::string());
+      }
+    }
+    j = 0;
+    for(std::set<int>::iterator itr = graph_poly[i].begin();
+        itr != graph_poly[i].end(); ++itr, +++j) {
+      if(j == 0) {
+        tmp_devices[i - net_ids_diff.size()].terminals[1] += net_ids_poly[*itr];
+      } else {
+        //error, too many poly connections
+        tmp_devices[i - net_ids_poly.size()].terminals += std::vector<std::string>(3, std::string());
+      }
+    }
+  }
+
+  devices.insert(devices.end(), tmp_devices.begin(), tmp_devices.end());
+}

+

We append transistors onto the vector of devices with their terminals +populated with net names extracted from the connectivity database.  +Transistors' terminals are connected through the POLY and DIFF layers where DIFF +contains both PDIFF and NDIFF.  The connection to POLY layer is the gate of +the transistor while the connections to DIFF on either side of the channel of +the transistor are the source and drain.  We can use this to extract are p +and n-type transistors.
+
+//populates vector of devices based on connectivity and layout data
+inline void extract_devices(std::vector<device>& devices, connectivity_database& +connectivity,
+                            +layout_database& layout) {
+  using namespace boost::polygon::operators;
+  //p-type transistors are gate that interact with p diffusion and nwell
+  polygon_set ptransistors = layout["GATE"];
+  ptransistors.interact(layout["PDIFF"]);
+  ptransistors.interact(layout["NWELL"]);
+  //n-type transistors are gate that interact with n diffusion and not +nwell
+  polygon_set ntransistors = layout["GATE"];
+  ntransistors.interact(layout["NDIFF"]);
+  polygon_set not_ntransistors = ntransistors;
+  not_ntransistors.interact(layout["NWELL"]);
+  ntransistors -= not_ntransistors;
+  extract_device_type(devices, connectivity, ptransistors, "PTRANS");
+  extract_device_type(devices, connectivity, ntransistors, "NTRANS");
+}

+

The extract devices procedure makes some more use of Boost.Polygon Boolean +operations on the layout data when we exclude GATE material over NDIFF that +isn't also over NWELL to extract our n-type transistors.  We also are using +the "interact" operation on polygon gets, which is implemented in terms of +connectivity extraction and retains all polygons of a polygon set that touch or +overlap polygons from another polygon set.  Now that we have a vector of +devices we can build a schematic database by calling the extract_netlist +function.  We can then compare the extracted schematic from the schematic +read in from file with the functions defined in +compare_schematics.hpp.  +Since comparing two schematics has no geometric aspect we won't go into that +procedure here in the tutorial and will skip to the integration of all these +procedures in defined in extract.cpp to build +the layout to schematic comparison algorithm.

+

bool compare_files(std::string layout_file, +std::string schematic_file) {
+  std::ifstream sin(schematic_file.c_str());
+  std::ifstream lin(layout_file.c_str());
+
+  std::vector<layout_rectangle> rects;
+  std::vector<layout_pin> pins;
+  parse_layout(rects, pins, lin);
+
+  schematic_database reference_schematic;
+  parse_schematic_database(reference_schematic, sin);
+
+  layout_database layout;
+  populate_layout_database(layout, rects);
+
+  connectivity_database connectivity;
+  populate_connectivity_database(connectivity, pins, layout);
+
+  schematic_database schematic;
+  std::vector<device>& devices = schematic.devices;
+  for(std::size_t i = 0; i < pins.size(); ++i) {
+    devices.push_back(device());
+    devices.back().type = "PIN";
+    devices.back().terminals.push_back(pins[i].net);
+  }
+  extract_devices(devices, connectivity, layout);
+  extract_netlist(schematic.nets, devices);
+  return compare_schematics(reference_schematic, schematic);
+}

+

int main(int argc, char **argv) {
+  if(argc < 3) {
+    std::cout << "usage: " << argv[0] << " <layout_file> <schematic_file>" +<< std::endl;
+    return -1;
+  }
+  bool result = compare_files(argv[1], argv[2]);
+  if(result == false) {
+    std::cout << "Layout does not match schematic." << std::endl;
+    return 1;
+  }
+  std::cout << "Layout does match schematic." << std::endl;
+  return 0;
+}
+
+
We test the program with two schematics and three layouts.  These +include a nand and a nor gate layout and schematic as well as an incorrect nand +gate layout.  The nand layout and schematic are the same as shown above. +

+

> lvs
+usage: lvs <layout_file> <schematic_file>
+> lvs nand.layout nand.schematic
+Layout does match schematic.
+> lvs nand_short.layout nand.schematic
+Layout does not match schematic.
+> lvs nand.layout nor.schematic
+Layout does not match schematic.
+> lvs nor.layout nor.schematic
+Layout does match schematic.
+> lvs nor.layout nand.schematic
+Layout does not match schematic.

+

This concludes our tutorial on how to build a simple layout to schematic +verification application based on Boost.Polygon library capabilities.  The +implementation of this application made many simplifying assumptions that are +not valid in the real world and hard coded a lot of things that need to be +configurable in a real layout verification application.  However, it does +give an idea of how to use Boost.Polygon to solve real problems and points in +the direction of how a real application might use Boost.Polygon.

+ + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + + + \ No newline at end of file diff --git a/doc/images/NAND.PNG b/doc/images/NAND.PNG new file mode 100644 index 0000000000000000000000000000000000000000..e6b27220f28feadef6f9042c95df2fa083d27099 GIT binary patch literal 10878 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 literal 0 HcmV?d00001 diff --git a/doc/images/concept_table.png b/doc/images/concept_table.png new file mode 100644 index 0000000000000000000000000000000000000000..a101a40d635f5a38090f41a858ff19816b1b054c GIT binary patch literal 21276 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 Y+MUsGNRE#Cn3e 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
x6F(WXvGEwH*c~|a?Lx-!jv2rx!M0?8{ zIxc;3`g-{3RVRAdRJI=qXsQ+L+ao;hC)33Inn{;Ft((Xam3YSIl*FW;i8YBaCreZ( zdfT<9B%W+;Qb>7{-+Wqs@qw(Xf~U@ZoaF1aF39(s^d8=rf z=5d-V3$;`4827=|S*VAvB~`88q1s-@O7H=J(%KCmZd=CTa0L#w<` zycb{zi(*R9N)_sTT;rbbX3Z=>1`LYuD3DTa30-D94#uxG=KfGvLyZn!7Ju$XyrN9X4Q zCbpqGhXY=HYG|^Xz%2RM`P<fE`VNoV@J`i*6av+Tr!8X~PW$*5gn zZ|mVnbb9qi@I)88%gGNDXU?`1c`Ni_#XPBbQ<^ya+NuuDGhDo!?<0@x!(^T|UB&-A zOvSB#URWDS?A*}Bxv=i~`IEvIu221#^Yv-zlWJ{-_iHYkKIpQ#wAAU?i;4RfU!*ZT z{yue^fzg^>TnDb7NO`h&ue9~UkQ1Bc7`9h(`#z7#({9E$&+V#r?Qw2a zj6QdkMQ;_uo}G)rjU@y2WwG-I{aZWh@{zpG89$1(Vkfm~?q@k1?!N3Xb6wA_f)BGV z?G8@i=$|{yq0{D2!RZ)%1G|&O+7SoN+g3Pp=CMWG(AvGL_0fGJ)19*y-a0vBX7=~r zw>S-BnC2;PPfqfDYdqOVX-dM6MJGyX4)CXZ+U^wYi z#{A!o-qR&#)ij?!rYC<>ur7eHqT4mTdwE+*MDA2JdxM-C2Um#j?+IX??8;HSQ@MvP zR3c8sPFeo*g{y|Qe>u9H`(btCmou~e+_ISyriaEY4HbOzyhSi*-2F=g{Bj~nMF@`Y!dckTCieJ5gmrpcTaued&Ri>;l~|EEtTJ+o@UqNThaWJBeb zDGQ5EE1Mdy#HcdDV?w~LfG7MP5*HnwZZ-MoZylWpp6tzYLXWf5C!Ww*I77Ng)c&|d zNzlI82h~g@w9FctgJWVDEnM%)AN(V`ck}$msXk$jYP)_#Jo`D>DK$ZH(nXhr4=yCs z?!R*K$EWnRnhj6B8*k#4edN=(^7qaapH)rwGUhmOOHNh0P|)SAeZc1;^Wv)>Z1&A_ zYfZ9JPWhj_%IR|=#_7p!IYrUQiGg>WIu{-E{4<%E^IC$>%=GHBb3}hkPHa6f%jNEJ zu0JuGocBBucPiViyXvQm-MJ!5)*o|)ydF1y_Gol_C^+x=nfs!7pQS|0w5puB=JIar zJ;u*^pX-c&ormy3H@kfTHRqL6>)wUR=|6fqu{i47X^Zy$%`x7M?|wdf?EEApQBhuK z!9}&^+h+_veM)MZ;PdLtX^F1-zz-1xJ2m$87j^OSU;DlD%#TmDI|PdSu2(uf`%pM7 zThrlOe~gIa{+C7R8Pg4F_z$Vr9{!MG6j}FKXT5GSPv!}hC-wKamew`IPn^%5y`RNs z3x8^7*m6mJ%hU7NrT^ZkK6p#!{>v+KzD@2rtN2*wdQif-4-+DPXxj;Ic$u^8y`tAl z7rWnig-)B&_jJ!Oxxb$OmXUCr_Po#S*Prm$DOBcdEelhNsV% zTA%sRH9?(Ox#y-@{ru*e_Zb84>b1nbd458!eOD>xhckkWO=nad$4n1kIOp@}pXi*M z3-fHw^QDApFTS(tlhrv@5s7~G_(Se8iR_D;x$2MF@SF%&x$!9A!|BHD--@}fp5fOM zPE2bIoqovY+_|j*jA;$0WA8p_x_A7%sF|ut(cANjT0<>Dj!9>}a$NmIaN2QhDi`qqIM~ zT<~y)FIUU2=tGGQepK2YkJj6CVDqIJkC`K9Jg(gy?79C`^NsVVs=aSIU zUB8%>#fKde9zJFGR;;Tl%+?p*%=1`aqmR=3y_1<1Zk%a+^5pTffWYj>EUM8zEq<`D zmSyisD?Fj)R5i)aeqZ{J;QikeQ|!g1>}6%74qnsjG0Ie3%>8QeWl;gO<)syi>@9nK zmY?1^yXx*&tGZ9>ORwFn{P$tn%ZtBlP8ZHtD#0HAHBoK)ovI6U>q6rMZ0yf6Rja*} zbn|$wY#!_|dp@7wqPlg>%snelPOZsS)MlQhvEix#&$aYh)BO_{3DxgR(c+qX>%3^! zOs-Iio1fTyU+nS>eSKIwT){-kH~j6hx;*wyJ-gKJOZJ~kIPkU6=JQ)ipNagxHw(Ub z{w?e8D$%COznj0sHE&{~V`7 z>RJ}%H}0|Kxq4D5&m(ga)B2Kc#jB_AKhd2Nt`;Jy7O-$(dEkPqiW%QM>n49n3ZFVN z{Sn9Zzy(<=)ZXxUZryFF(pw&3zI5xyx6iM=l0V^h?p>tIrwVqRfF%pJ2P~-R+7~ML zuPrd>)~!X8QfmIJn@dgy~9<7dtQx}m#ftxHL7>MTlglh!1DG}#<$O>ZC}vfP|_#< zhB5#ncTaZTh<#&RH}83#;G5@VuRG4ApW{>6 z{Nm})C$SO#*r zNVff(#B`ET+GA=@O~s$-R*$2~!xiiw`qt%rC^!2&=d)nh`|Jtx|HcGt@ILtY@jbzZ zK|-_MFtKh~Is5T*u@eucgefd?c>62k;tc-w;e(U_(dkdrLX71FtiH@GK z_--^~(T7=o?(E%KTKYY#;m%z4H7~zgYUrQez|8qFmOH_|d~My;4R0fO?9zOB`#yc< zs_B{Y;CWq~6ZeP3Ts866o91g@>8rQPn%JuPM&MLkUc26!hXK1KYPOhOwOTE@fhp_& z*PFEr|NEvWd>2zbbFNNL=jLC&DLQQOPwJR4esy*+(|czr958 zb*74Vv;Dq(A;w_+5shy}AIukJ+*$iIvFTfJ;>o;vhX|g3C*EEyZVWpBIyfX?1;hV+ zEfZRK%sEr-w|gpYTPzsGBey4Zu38E!_yCgI+6VR<@f7_o5^efc+?BPzxGj=L?z8o- zok0*6ya;HhFXWpjJH@Os6J$Wy@`s|g_BuaH2WkJI%DQO%rMFu*&fi_z-Oc@lOO*Rn z0mR}3S_XBKuB@1DlWt#ra+|LDThXX{Ou|rCPiHzG{&G6&#`(XWz7xOlPE5MvTR)jT@LOS>HS_`t@@QlFl&g1pDo~n9t>dj0S6rXq?0Jt=RH!%`GIIt3@}= zkG{+Jd^?jm*PmPUH5ZzpMs8vPjltSwuvUp~nE(3f^^0pk2f3IB9jJTfcD6+GJBShY zx5O0WfkrphH_xSxmS$*A2s}`yw|L(9D3IgpycmD)oS(J5d+#KsZ^hxSrtJg^Pty|k zR{a0p`~P)6&e;4rU;poUeOy%c#HVkju(c_fG!*NBQHkKmS^NecF*XYY)hAO?drm@9o90X@=2^b&hGq z#dg{ooEWd2|2X@z%eoauE!Q4cE7GAi_xroBx8;V;tcz|ZTCP3tR&>FiJNy5f{@<i|7W(pTW0Z(kBejV$L02aGufX#OJMyavf$604L0A3Yi*04$Oj&% z{;u3xHdB%H-`Dv6Uvo_VeVV?X=U+^KM)$$62Sr><{@mGo>v(zpf5$ziP4BgQ4^Q}z zVS8f!->b*%H*TrVOv_+RVLhkzUsQnU$rZZ{*0QjMPsRQ9E-!xP@7(uqr=tG(bG&BT zUu!X#b2F`r-aRwA(U|qY4f}h`)Sva&|9Sja+*&)6wa$g{)cM-%k3W*FKIF6g?P$`w z%w?ikup{Zc{r-dPYddEgj%sY>lIi>VIR4S*36p}O8)Zc}epntmyf^&Z<@m%T;d9-d-rj&=^xW~(gm5ZKKHnE!Ws5Oe=9y+ox=24 zw4vH?{v_k5Mp=;sf9@POWBdOvN8AS4s!TrfV1{*5|K2%k^{z;QmGAh!$MNo;4*iG^ zKID;g##ZD&-Mf$OUi{yme?9L!=dXD9JH-jBH!!UhvADDQd;Q@#fA6fiX7S#Mb;d^f zBR2OowQiYvi>pMt;jc`L9LI}w2S2Voperhof9+H2B+sR?zFW=^WB7yp&Aa8D+MAg8S=s&zc5GhzQGUtiCwJl) z-#mZPzwr9{``g7YvPL!Xv9j1-cRXyk_COogoWBR(9bQ}c=k5|-Zv$2BfYl7&ifdyVw`ZHgOU%dKT|D#%+zVC+?e^Leo@xr4wpZ&RP|M&9a_4EF= zeOFf6<)eLJ;emzot$$BkFxx5YX`5P1pHYyfuR4Ux4T)0W4Xp?I3CbiLr^sN;hkkZqX{+qFuH{r+lk!#a6wFt@@SQ463#nR&6t?-fmpI-K1u_Y3&ZP+8t(f zJIw2MS~cvlZro+twA-$Ew?oSw$JRYgt$Uo?_PVz3b?eyY(YfEVYrj|5e(&xBK0OC~ zdk*;Z9`x@!7}$R(pzmN%|DoUshe9SE4xM;7Z1R!t$wwlm9F3ZKG-led*y+dOrXP!+ zaXew>@x+)m?2XX~}TZPzDkzcF#gjmbN2PThTL%C4I; z_THYp=hm!!cV_RuGiU#u1&8j$_ zM{7?#T7UZShBJ>hoqe+L%;U}Ho@_b)bo<3;+b%raaq-#i%g^^+eR1I0%R@I_9lZYX z@QqhTZ@oTp^VP9iuTS22bLQULbNAn!fAH?&!}k{+yu0-1{pH6Wu0Q>F>-ndE`efeqGu+ye#mwn6bh$%;+ryVU>cCLKI`KnbH`nO-7yzAzq zoj0cKxixd&?Rf|9E+8=yUw-_4 z_~y%#cVFLp{_)}4uOGkve*g97^N-)Z|Ni^+=kMQt|Nj5~&p-$${$ycfVEDqI15yae z6AT>x8D4VAcx+g3u$hBh=)qN9MlJsi5zjdt9>Q8I4;obOoY=Vdc)x+rrkkcXg@shy6l%J-n7?Dw9)Vmq2!FsmLm+Owij0IezsxCL3iK&*3G*^SfFZ}Y`46)>?J`|alNVDU7y2S)LJ zt0yEXD1EGX&ckDT-~x~B=NEx2lJ|CgcJ@Ba(=pjdmo?DAI zqkQ>{@Fab^EnE5~dZ=x2_1=6k^MYQ|Jwwq2x=+gm7@tgNj&w{jYIx=tqp&K&k;Uhr zgUCCMFDLm|>{8^ny{*#tYV~@l|C7%;OxU#LFu%(ebph?j8xNYe&Gu~McAS})bzz~7 z==YZnRR#i1=FGa6f&}H|3>t%ULK8Y2w(erNYMry@%OuX_JRv$x9~3T5(mKs0!p+LV z;&h>pN9UuW*`dVK2e=ALPfucgeR82b=RJ;+ca9IAoMy0md+sp{vzCaZz}|0{n%_@p z_#((59kj`X)AsJEkL?OyHZbWk3-l=R8tZIvX*<{|=i=#YY4cN4)A?_pz|rr|xS1XE zwoG9^(YWbJw*y9Jcbi0+RaZElKghQCWRT3;Q;S)d<&Ie9dyB@OIl#?Qcp^yJ zgHHlJ-DDgSJigCl`>7=7?f&9dri#u>MvEJ^n_YG|q!~9vf#~iomSh5o9*i74m`TyazKbhG$P>O=L_Krl&&&8eHdh@rWd`O<-$9k zT@RKCpTG3VRbF2}Pho=zv)Q%_kM@~u%TV^77;-qd$6M>gqH4>C$PZ?YF-h@f4|5aQkFn1JGFdHs(ICVjY zYtI3;&j;ApRFc~)L>g5k4;)Fd2-Jw*!ehGsvaH?`6~L`P_95=aYceKe^fWLY{&7J&>Jnp_6+d<;5$UN>Ph?a;l0I zHfAt*ha{X$l|3MEUxkD5%F#*MKRg3>XfU(qP4H`qaf;!IIJ_!n%YQEOEv^z@WjJgS zE>B9D(r){3IjtODn zHEoFHx3ZcLRPaDm%)v?N*v9iKMGlBxZeSJ+VX$ViNZ`1hkm()1K!iuYk$>?DR(+e} z6DwF07;kQHGrA7ZVECWaNwG?e2}=$Nxof|1f8f|< zR#UjqcCMqi%tS6$FEMo{hX#d70?dLM@7MF+IKY{8pv5-iko4P%=jqFv`f}B4773PF qu!*fZaQj}|L9W<_X4x4VIm0`gw{8A<)@Iu2JCy~dJLNe!7_0%eXO1rb literal 0 HcmV?d00001 diff --git a/doc/images/nands.PNG b/doc/images/nands.PNG new file mode 100644 index 0000000000000000000000000000000000000000..d0087451cdd0a3cff6b82439445b140778ed8c90 GIT binary patch literal 9605 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 B`91&u literal 0 HcmV?d00001 diff --git a/doc/images/perf_graph.PNG b/doc/images/perf_graph.PNG new file mode 100644 index 0000000000000000000000000000000000000000..f1e8f8a188bb740b580b3836749146ad60c17120 GIT binary patch literal 21294 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 literal 0 HcmV?d00001 diff --git a/doc/images/refinements.png b/doc/images/refinements.png new file mode 100644 index 0000000000000000000000000000000000000000..6e91160fdf4121bd5a1ead0bb9c2290732c2bb2c GIT binary patch literal 29725 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 literal 0 HcmV?d00001 diff --git a/doc/index.htm b/doc/index.htm new file mode 100644 index 0000000..33d5130 --- /dev/null +++ b/doc/index.htm @@ -0,0 +1,236 @@ + + +Boost Polygon Library: Main Page + + + + + + +
+
+ + +
+ + +
+ + +
+
+ + + +
+

+

THE BOOST.POLYGON LIBRARY

+

The Boost.Polygon library provides algorithms focused on manipulating planar +polygon geometry data.  Specific algorithms provided are the polygon set +operations (intersection, union, difference, disjoint-union) and related +algorithms such as polygon connectivity graph extraction, offsetting and map-overlay.  +An example of the disjoint-union (XOR) of figure a and figure b is shown below +in figure c.  +These so-called Boolean algorithms are of significant interest in GIS (Geospatial Information +Systems), VLSI CAD as well al other fields of CAD, and many more application +areas, and providing them is the primary focus of this library.  The +Boost.Polygon library is not intended to cover all of computational +geometry in its scope, and provides a set of capabilities for working with +coordinates, points, intervals and rectangles that are needed to support +implementing and interacting with polygon data structures and algorithms. 

+The coordinate data type is a template parameter of all data types and +algorithms provided by the library, and is expected to be integral.  +Floating point coordinate data types are not supported by the algorithms +implemented in the library due to the fact that the achieving floating point +robustness implies a different set of algorithms and generally platform specific +assumptions about floating point representations.  +For additional detailed discussion of the library and its implementation +including benchmark comparisons with other open source alternatives please see +the paper and +presentation from +boostcon 2009 as well as a detailed +analysis of the runtime complexity of +the library's core algorithms.

+

The design philosophy behind the polygon library was to create an API for +invoking the library algorithms it provides on user geometry data types that is maximally +intuitive, minimally error-prone and easy to integrate into pre-existing +applications.  C++-concepts based template meta-programming combined with +generic operator overloading meets these design goals without sacrificing the +runtime or memory efficiency of the underlying algorithms.  The API is +intended to demonstrate what could be achieved with ease by a C++-concepts based +library interface, but is implemented based on current language features.  This API makes +the following code snippet that operates on non-library geometry types possible:

+ + +
+
+ + + void foo(list<CPolygon>& result, const list<CPolygon>& a,
+          + + + const list<CPolygon>& + b, int deflateValue) {
+
+ +     + CBoundingBox domainExtent;
+
+ + +      using namespace boost::polygon::operators;
+
+ + +      + boost::polygon::extents(domainExtent, a);
+
+ + +      result += (b & + domainExtent) ^ (a - deflateValue);
+
+ + + }
+
+

In the code snippet above the hypothetical polygon type CPolygon has been +mapped to the library polygon concept and is used with library APIs to clip +polygon list b against the bounding box of polygon list a and apply the +disjoint-union of that with polygon list a deflated by some integer amount.  +The end result is accumulated into a list of polygons with a union operation.  +It is considerably more typing to describe this usage of the API than to code +it, and the description is not much clearer than the code itself.  +A picture is worth a thousand words.

+

+

In Boost.Polygon operations such as those shown above are free functions named for what they do, or are overloads of C++ operators that make it +easy to infer from reading the code what to expect.  Operators are +contained in the namespace boost::polygon::operators +so that they can be used outside the boost::polygon +namespace without bringing in the entire boost::polygon +namespace.  Following the +principle of least astonishment, the inferred behavior should generally match +the actual behavior.  Conventions such as argument ordering (output +arguments come first) and consistently applying the same semantics across +different functions (accumulate) reduces the learning curve for new users while reducing the +need to memorize semantics and argument ordering of many different functions for +advanced users.

+

While the internal library code that implements this API is usually complex and +cryptic due to heavy use of template meta-programming, the application of the library +API in user code is usually simple and clear because it is free of any +extraneous syntax.  The one exception to this is the mapping of user types +to library concepts, which necessitates that the user perform some simple +template programming and understand some of the internals of how the library +concept type system works.  The examples below should aid the user in +performing these programming tasks.

+
    + +
  • Example files: + + +
  • Tutorials: +
      +
    • Layout Versus Schematic Learn how to + apply Boost.Polygon capabilities to implement a simplified circuit + extraction application
    • +
    • Minkowski Sum Learn how to + apply Boost.Polygon capabilities to implement Minkowski sum of polygon sets
    • +
    + +
+ + +

We would like to thank: Thomas Klimpel, Frank Mori Hess, Barend Gehrels, +Andreas Fabri, Jeffrey Hellrung, Tim Keitt, Markus Werle, Paul A. Bristow, +Robert Stewart, Mathias Gaunard, Michael Fawcett, Steven Watanabe, Joachim +Faulhaber, John Bytheway, Sebastian Redl, Mika Heiskanen, John Phillips, Kai +Benndorf, Hartmut Kaiser, Arash Partow, Maurizio Vitale, Brandon Kohn, David +Abrahams, Gordon Woodhull, Daniel James, John Maddock, Tom Brinkman, Bo Persson, +Mateusz Loskot, Christian Henning, Jean-Sebastien Stoezel, for providing +feedback and or formal review of the library as part of the boost submission +process and Fernando Cacciola for graciously serving as review manager.

+ + +
+   + + + + + + + + + + + + + + + +
Copyright:Copyright © Intel Corporation 2008-2010.
License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
+ + \ No newline at end of file diff --git a/doc/tutorial/compare_schematics.hpp b/doc/tutorial/compare_schematics.hpp new file mode 100644 index 0000000..2fd9cf4 --- /dev/null +++ b/doc/tutorial/compare_schematics.hpp @@ -0,0 +1,96 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ +//compare_schematics.hpp +#ifndef BOOST_POLYGON_TUTORIAL_COMPARE_SCHEMATICS_HPP +#define BOOST_POLYGON_TUTORIAL_COMPARE_SCHEMATICS_HPP +#include +#include "schematic_database.hpp" + +bool compare_connectivity(std::string& ref_net, std::string& net, + schematic_database& reference_schematic, + schematic_database& schematic, + std::vector& reference_to_internal_device_map, + std::size_t node_id) { + std::set& ref_nodes = reference_schematic.nets[ref_net]; + std::set& nodes = schematic.nets[net]; + for(std::set::iterator itr = ref_nodes.begin(); + itr != ref_nodes.end() && *itr < node_id; ++itr) { + if(nodes.find(reference_to_internal_device_map[*itr]) == nodes.end()) + return false; + } + return true; +} + +bool compare_schematics_recursive +(schematic_database& reference_schematic, + schematic_database& schematic, + std::vector& reference_to_internal_device_map, + std::set& assigned_devices, std::size_t node_id){ + //do check of equivalence up to this node + for(std::size_t i = 0; i < node_id; ++i) { + for(std::size_t j = 0; j < reference_schematic.devices[i].terminals.size(); ++j) { + device& rd = reference_schematic.devices[i]; + device& xd = schematic.devices[reference_to_internal_device_map[i]]; + if(rd.type == "PIN") { + if(rd.terminals[j] != xd.terminals[j]) + return false; + } else { + //connectivity must be the same + if(j == 1) { + //gate has to be the same net + if(!compare_connectivity(rd.terminals[1], xd.terminals[1], reference_schematic, schematic, + reference_to_internal_device_map, node_id)) + return false; + } else { + //order of nets in source and drain is not important so check both ways and accept either + if(!compare_connectivity(rd.terminals[j], xd.terminals[0], reference_schematic, schematic, + reference_to_internal_device_map, node_id) && + !compare_connectivity(rd.terminals[j], xd.terminals[2], reference_schematic, schematic, + reference_to_internal_device_map, node_id)) + return false; + } + } + } + } + if(node_id >= reference_schematic.devices.size()) + return true; //final success + + //recurse into subsequent nodes + for(std::size_t i = 0; i < schematic.devices.size(); ++i) { + if(reference_schematic.devices[node_id].type != + schematic.devices[i].type) + continue; //skip dissimilar devices + //avoid multi-assignment of devices + if(assigned_devices.find(i) == assigned_devices.end()) { + reference_to_internal_device_map[node_id] = i; + std::set::iterator itr = assigned_devices.insert(assigned_devices.end(), i); + if(compare_schematics_recursive(reference_schematic, schematic, + reference_to_internal_device_map, + assigned_devices, node_id + 1)) + return true; + assigned_devices.erase(itr); + } + } + //could not find match between schematics + return false; +} + +//this is a trivial brute force comparison algorithm because comparing +//schematics does not require the use of Boost.Polygon and doing it more +//optimally does not add to the tutorial +inline bool compare_schematics(schematic_database& reference_schematic, + schematic_database& schematic) { + std::vector + reference_to_internal_device_map(reference_schematic.devices.size(), 0); + std::set assigned_devices; + return compare_schematics_recursive(reference_schematic, schematic, + reference_to_internal_device_map, + assigned_devices, 0); +} + +#endif diff --git a/doc/tutorial/connectivity_database.hpp b/doc/tutorial/connectivity_database.hpp new file mode 100644 index 0000000..ba824b5 --- /dev/null +++ b/doc/tutorial/connectivity_database.hpp @@ -0,0 +1,149 @@ +/* + Copyright 2010 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +//connectivity_database.hpp +#ifndef BOOST_POLYGON_TUTORIAL_CONNECTIVITY_DATABASE_HPP +#define BOOST_POLYGON_TUTORIAL_CONNECTIVITY_DATABASE_HPP +#include +#include +#include +#include "layout_database.hpp" +#include "layout_pin.hpp" + +typedef std::map connectivity_database; + +//map layout pin data type to boost::polygon::rectangle_concept +namespace boost { namespace polygon{ + template <> + struct rectangle_traits { + typedef int coordinate_type; + typedef interval_data interval_type; + static inline interval_type get(const layout_pin& pin, orientation_2d orient) { + if(orient == HORIZONTAL) + return interval_type(pin.xl, pin.xh); + return interval_type(pin.yl, pin.yh); + } + }; + + template <> + struct geometry_concept { typedef rectangle_concept type; }; +}} + +typedef boost::polygon::polygon_90_data polygon; +typedef boost::polygon::polygon_90_set_data polygon_set; + +inline void populate_connected_component +(connectivity_database& connectivity, std::vector& polygons, + std::vector polygon_color, std::vector >& graph, + std::size_t node_id, std::size_t polygon_id_offset, std::string& net, + std::vector& net_ids, std::string net_prefix, + std::string& layout_layer) { + if(polygon_color[node_id] == 1) + return; + polygon_color[node_id] = 1; + if(node_id < polygon_id_offset && net_ids[node_id] != net) { + //merge nets in connectivity database + //if one of the nets is internal net merge it into the other + std::string net1 = net_ids[node_id]; + std::string net2 = net; + if(net.compare(0, net_prefix.length(), net_prefix) == 0) { + net = net1; + std::swap(net1, net2); + } else { + net_ids[node_id] = net; + } + connectivity_database::iterator itr = connectivity.find(net1); + if(itr != connectivity.end()) { + for(layout_database::iterator itr2 = (*itr).second.begin(); + itr2 != (*itr).second.end(); ++itr2) { + connectivity[net2][(*itr2).first].insert((*itr2).second); + } + connectivity.erase(itr); + } + } + if(node_id >= polygon_id_offset) + connectivity[net][layout_layer].insert(polygons[node_id - polygon_id_offset]); + for(std::set::iterator itr = graph[node_id].begin(); + itr != graph[node_id].end(); ++itr) { + populate_connected_component(connectivity, polygons, polygon_color, graph, + *itr, polygon_id_offset, net, net_ids, net_prefix, layout_layer); + } +} + +inline void connect_layout_to_layer(connectivity_database& connectivity, polygon_set& layout, std::string layout_layer, std::string layer, std::string net_prefix, int& net_suffix) { + if(layout_layer.empty()) + return; + boost::polygon::connectivity_extraction_90 ce; + std::vector net_ids; + for(connectivity_database::iterator itr = connectivity.begin(); itr != connectivity.end(); ++itr) { + net_ids.push_back((*itr).first); + ce.insert((*itr).second[layer]); + } + std::vector polygons; + layout.get_polygons(polygons); + std::size_t polygon_id_offset = net_ids.size(); + for(std::size_t i = 0; i < polygons.size(); ++i) { + ce.insert(polygons[i]); + } + std::vector > graph(polygons.size() + net_ids.size(), std::set()); + ce.extract(graph); + std::vector polygon_color(polygons.size() + net_ids.size(), 0); + //for each net in net_ids populate connected component with net + for(std::size_t node_id = 0; node_id < net_ids.size(); ++node_id) { + populate_connected_component(connectivity, polygons, polygon_color, graph, node_id, + polygon_id_offset, net_ids[node_id], net_ids, + net_prefix, layout_layer); + } + //for each polygon_color that is zero populate connected compontent with net_prefix + net_suffix++ + for(std::size_t i = 0; i < polygons.size(); ++i) { + if(polygon_color[i + polygon_id_offset] == 0) { + std::stringstream ss(std::stringstream::in | std::stringstream::out); + ss << net_prefix << net_suffix++; + std::string internal_net; + ss >> internal_net; + populate_connected_component(connectivity, polygons, polygon_color, graph, + i + polygon_id_offset, + polygon_id_offset, internal_net, net_ids, + net_prefix, layout_layer); + } + } +} + +//given a layout_database we populate a connectivity database +inline void populate_connectivity_database(connectivity_database& connectivity, std::vector& pins, layout_database& layout) { + using namespace boost::polygon; + using namespace boost::polygon::operators; + for(std::size_t i = 0; i < pins.size(); ++i) { + connectivity[pins[i].net][pins[i].layer].insert(pins[i]); + } + int internal_net_suffix = 0; + //connect metal1 layout to pins which were on metal1 + connect_layout_to_layer(connectivity, layout["METAL1"], "METAL1", + "METAL1", "__internal_net_", internal_net_suffix); + //connect via0 layout to metal1 + connect_layout_to_layer(connectivity, layout["VIA0"], "VIA0", + "METAL1", "__internal_net_", internal_net_suffix); + //poly needs to have gates subtracted from it to prevent shorting through transistors + polygon_set poly_not_gate = layout["POLY"] - layout["GATE"]; + //connect poly minus gate to via0 + connect_layout_to_layer(connectivity, poly_not_gate, "POLY", + "VIA0", "__internal_net_", internal_net_suffix); + //we don't want to short signals through transistors so we subtract the gate regions + //from the diffusions + polygon_set diff_not_gate = (layout["PDIFF"] + layout["NDIFF"]) - layout["GATE"]; + //connect diffusion minus gate to poly + //Note that I made up the DIFF layer name for combined P and NDIFF + connect_layout_to_layer(connectivity, diff_not_gate, "DIFF", + "POLY", "__internal_net_", internal_net_suffix); + //connect gate to poly to make connections through gates on poly + connect_layout_to_layer(connectivity, layout["GATE"], "GATE", + "POLY", "__internal_net_", internal_net_suffix); + //now we have traced connectivity of the layout down to the transistor level + //any polygons not connected to pins have been assigned internal net names +} + +#endif diff --git a/doc/tutorial/device.hpp b/doc/tutorial/device.hpp new file mode 100644 index 0000000..ab225b6 --- /dev/null +++ b/doc/tutorial/device.hpp @@ -0,0 +1,38 @@ +/* + Copyright 2010 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ + +//device.hpp +#ifndef BOOST_POLYGON_TUTORIAL_DEVICE_HPP +#define BOOST_POLYGON_TUTORIAL_DEVICE_HPP +#include +#include +#include + +struct device { + std::string type; + std::vector terminals; +}; + +inline std::ostream& operator << (std::ostream& o, const device& r) +{ + o << r.type << " "; + for(std::size_t i = 0; i < r.terminals.size(); ++i) { + o << r.terminals[i] << " "; + } + return o; +} + +inline std::istream& operator >> (std::istream& i, device& r) +{ + i >> r.type; + r.terminals = std::vector(3, std::string()); + i >> r.terminals[0] >> r.terminals[1] >> r.terminals[2]; + return i; +} + +#endif diff --git a/doc/tutorial/extract.cpp b/doc/tutorial/extract.cpp new file mode 100644 index 0000000..7a8eae9 --- /dev/null +++ b/doc/tutorial/extract.cpp @@ -0,0 +1,63 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ +#include "schematic_database.hpp" +#include "layout_pin.hpp" +#include "layout_rectangle.hpp" +#include "connectivity_database.hpp" +#include "compare_schematics.hpp" +#include "extract_devices.hpp" +#include "parse_layout.hpp" +#include "layout_database.hpp" +#include "device.hpp" +#include +#include +#include + +bool compare_files(std::string layout_file, std::string schematic_file) { + std::ifstream sin(schematic_file.c_str()); + std::ifstream lin(layout_file.c_str()); + + std::vector rects; + std::vector pins; + parse_layout(rects, pins, lin); + + schematic_database reference_schematic; + parse_schematic_database(reference_schematic, sin); + + layout_database layout; + populate_layout_database(layout, rects); + + connectivity_database connectivity; + populate_connectivity_database(connectivity, pins, layout); + + schematic_database schematic; + std::vector& devices = schematic.devices; + for(std::size_t i = 0; i < pins.size(); ++i) { + devices.push_back(device()); + devices.back().type = "PIN"; + devices.back().terminals.push_back(pins[i].net); + } + extract_devices(devices, connectivity, layout); + extract_netlist(schematic.nets, devices); + + return compare_schematics(reference_schematic, schematic); +} + +int main(int argc, char **argv) { + if(argc < 3) { + std::cout << "usage: " << argv[0] << " " << std::endl; + return -1; + } + bool result = compare_files(argv[1], argv[2]); + if(result == false) { + std::cout << "Layout does not match schematic." << std::endl; + return 1; + } + std::cout << "Layout does match schematic." << std::endl; + return 0; +} diff --git a/doc/tutorial/extract_devices.hpp b/doc/tutorial/extract_devices.hpp new file mode 100644 index 0000000..15bb6e9 --- /dev/null +++ b/doc/tutorial/extract_devices.hpp @@ -0,0 +1,99 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ +//extract_devices.hpp +#ifndef BOOST_POLYGON_TUTORIAL_EXTRACT_DEVICES_HPP +#define BOOST_POLYGON_TUTORIAL_EXTRACT_DEVICES_HPP +#include +#include +#include +#include +#include "connectivity_database.hpp" +#include "device.hpp" + +typedef boost::polygon::connectivity_extraction_90 connectivity_extraction; +inline std::vector > +extract_layer(connectivity_extraction& ce, std::vector& net_ids, + connectivity_database& connectivity, polygon_set& layout, + std::string layer) { + for(connectivity_database::iterator itr = connectivity.begin(); itr != connectivity.end(); ++itr) { + net_ids.push_back((*itr).first); + ce.insert((*itr).second[layer]); + } + std::vector polygons; + layout.get_polygons(polygons); + for(std::size_t i = 0; i < polygons.size(); ++i) { + ce.insert(polygons[i]); + } + std::vector > graph(polygons.size() + net_ids.size(), std::set()); + ce.extract(graph); + return graph; +} + +inline void extract_device_type(std::vector& devices, connectivity_database& connectivity, + polygon_set& layout, std::string type) { + //recall that P and NDIFF were merged into one DIFF layer in the connectivity database + //find the two nets on the DIFF layer that interact with each transistor + //and then find the net on the poly layer that interacts with each transistor + boost::polygon::connectivity_extraction_90 cediff; + std::vector net_ids_diff; + std::vector > graph_diff = + extract_layer(cediff, net_ids_diff, connectivity, layout, "DIFF"); + boost::polygon::connectivity_extraction_90 cepoly; + std::vector net_ids_poly; + std::vector > graph_poly = + extract_layer(cepoly, net_ids_poly, connectivity, layout, "POLY"); + std::vector tmp_devices(graph_diff.size() - net_ids_poly.size()); + for(std::size_t i = net_ids_poly.size(); i < graph_diff.size(); ++i) { + tmp_devices[i - net_ids_diff.size()].type = type; + tmp_devices[i - net_ids_diff.size()].terminals = std::vector(3, std::string()); + std::size_t j = 0; + for(std::set::iterator itr = graph_diff[i].begin(); + itr != graph_diff[i].end(); ++itr, ++j) { + if(j == 0) { + tmp_devices[i - net_ids_diff.size()].terminals[0] = net_ids_diff[*itr]; + } else if(j == 1) { + tmp_devices[i - net_ids_diff.size()].terminals[2] = net_ids_diff[*itr]; + } else { + //error, too many diff connections + tmp_devices[i - net_ids_diff.size()].terminals = std::vector(3, std::string()); + } + } + j = 0; + for(std::set::iterator itr = graph_poly[i].begin(); + itr != graph_poly[i].end(); ++itr, ++j) { + if(j == 0) { + tmp_devices[i - net_ids_diff.size()].terminals[1] = net_ids_poly[*itr]; + } else { + //error, too many poly connections + tmp_devices[i - net_ids_poly.size()].terminals = std::vector(3, std::string()); + } + } + } + + devices.insert(devices.end(), tmp_devices.begin(), tmp_devices.end()); +} + +//populates vector of devices based on connectivity and layout data +inline void extract_devices(std::vector& devices, connectivity_database& connectivity, + layout_database& layout) { + using namespace boost::polygon::operators; + //p-type transistors are gate that interact with p diffusion and nwell + polygon_set ptransistors = layout["GATE"]; + ptransistors.interact(layout["PDIFF"]); + ptransistors.interact(layout["NWELL"]); + //n-type transistors are gate that interact with n diffusion and not nwell + polygon_set ntransistors = layout["GATE"]; + ntransistors.interact(layout["NDIFF"]); + polygon_set not_ntransistors = ntransistors; + not_ntransistors.interact(layout["NWELL"]); + ntransistors -= not_ntransistors; + extract_device_type(devices, connectivity, ptransistors, "PTRANS"); + extract_device_type(devices, connectivity, ntransistors, "NTRANS"); +} + +#endif diff --git a/doc/tutorial/layout_database.hpp b/doc/tutorial/layout_database.hpp new file mode 100644 index 0000000..d3cc2b3 --- /dev/null +++ b/doc/tutorial/layout_database.hpp @@ -0,0 +1,41 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ + +//layout_database.hpp +#ifndef BOOST_POLYGON_TUTORIAL_LAYOUT_DATABASE_HPP +#define BOOST_POLYGON_TUTORIAL_LAYOUT_DATABASE_HPP +#include +#include +#include "layout_rectangle.hpp" + +typedef std::map > layout_database; + +//map the layout rectangle data type to the boost::polygon::rectangle_concept +namespace boost { namespace polygon{ + template <> + struct rectangle_traits { + typedef int coordinate_type; + typedef interval_data interval_type; + static inline interval_type get(const layout_rectangle& rectangle, orientation_2d orient) { + if(orient == HORIZONTAL) + return interval_type(rectangle.xl, rectangle.xh); + return interval_type(rectangle.yl, rectangle.yh); + } + }; + + template <> + struct geometry_concept { typedef rectangle_concept type; }; +}} + +//insert layout rectangles into a layout database +inline void populate_layout_database(layout_database& layout, std::vector& rects) { + for(std::size_t i = 0; i < rects.size(); ++i) { + layout[rects[i].layer].insert(rects[i]); + } +} +#endif diff --git a/doc/tutorial/layout_pin.hpp b/doc/tutorial/layout_pin.hpp new file mode 100644 index 0000000..8c2f561 --- /dev/null +++ b/doc/tutorial/layout_pin.hpp @@ -0,0 +1,33 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ + +//layout_pin.hpp +#ifndef BOOST_POLYGON_TUTORIAL_LAYOUT_PIN_HPP +#define BOOST_POLYGON_TUTORIAL_LAYOUT_PIN_HPP +#include +#include + +struct layout_pin { + int xl, yl, xh, yh; + std::string layer; + std::string net; +}; + +inline std::ostream& operator << (std::ostream& o, const layout_pin& r) +{ + o << r.xl << " " << r.xh << " " << r.yl << " " << r.yh << " " << r.layer << " " << r.net; + return o; +} + +inline std::istream& operator >> (std::istream& i, layout_pin& r) +{ + i >> r.xl >> r.xh >> r.yl >> r.yh >> r.layer >> r.net; + return i; +} + +#endif diff --git a/doc/tutorial/layout_rectangle.hpp b/doc/tutorial/layout_rectangle.hpp new file mode 100644 index 0000000..faf34d4 --- /dev/null +++ b/doc/tutorial/layout_rectangle.hpp @@ -0,0 +1,32 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ + +//layout_rectangle.hpp +#ifndef BOOST_POLYGON_TUTORIAL_LAYOUT_RECTANGLE_HPP +#define BOOST_POLYGON_TUTORIAL_LAYOUT_RECTANGLE_HPP +#include +#include + +struct layout_rectangle { + int xl, yl, xh, yh; + std::string layer; +}; + +inline std::ostream& operator << (std::ostream& o, const layout_rectangle& r) +{ + o << r.xl << " " << r.xh << " " << r.yl << " " << r.yh << " " << r.layer; + return o; +} + +inline std::istream& operator >> (std::istream& i, layout_rectangle& r) +{ + i >> r.xl >> r.xh >> r.yl >> r.yh >> r.layer; + return i; +} + +#endif diff --git a/doc/tutorial/nand.layout b/doc/tutorial/nand.layout new file mode 100644 index 0000000..b0a757a --- /dev/null +++ b/doc/tutorial/nand.layout @@ -0,0 +1,29 @@ +Rectangle 0 60 24 48 NWELL +Rectangle 3 57 32 43 PDIFF +Rectangle 3 57 5 16 NDIFF +Rectangle 5 7 0 17 POLY +Rectangle 5 7 22 45 POLY +Rectangle 17 19 3 45 POLY +Rectangle 29 31 31 48 POLY +Rectangle 41 43 3 45 POLY +Rectangle 53 55 3 45 POLY +Rectangle 17 19 4 17 GATE +Rectangle 17 19 31 44 GATE +Rectangle 41 43 4 17 GATE +Rectangle 41 43 31 44 GATE +Rectangle 5 7 0 2 VIA0 +Rectangle 5 7 23 25 VIA0 +Rectangle 17 19 28 30 VIA0 +Rectangle 29 31 46 48 VIA0 +Rectangle 41 43 18 20 VIA0 +Rectangle 53 55 23 25 VIA0 +Rectangle 0 60 0 2 METAL1 +Rectangle 3 57 28 30 METAL1 +Rectangle 0 60 46 48 METAL1 +Rectangle 3 57 18 20 METAL1 +Rectangle 3 57 23 25 METAL1 +Pin 29 31 0 2 METAL1 GND +Pin 29 31 23 25 METAL1 OUTPUT +Pin 29 31 28 30 METAL1 INPUT1 +Pin 29 31 46 48 METAL1 VDD +Pin 29 31 18 20 METAL1 INPUT2 diff --git a/doc/tutorial/nand.schematic b/doc/tutorial/nand.schematic new file mode 100644 index 0000000..3c80857 --- /dev/null +++ b/doc/tutorial/nand.schematic @@ -0,0 +1,9 @@ +Pin OUTPUT +Pin INPUT1 +Pin INPUT2 +Pin VDD +Pin GND +Device PTRANS VDD INPUT1 OUTPUT +Device PTRANS VDD INPUT2 OUTPUT +Device NTRANS GND INPUT1 NET1 +Device NTRANS NET1 INPUT2 OUTPUT diff --git a/doc/tutorial/nand_short.layout b/doc/tutorial/nand_short.layout new file mode 100644 index 0000000..7357216 --- /dev/null +++ b/doc/tutorial/nand_short.layout @@ -0,0 +1,29 @@ +Rectangle 0 60 24 48 NWELL +Rectangle 3 57 32 43 PDIFF +Rectangle 3 57 5 16 NDIFF +Rectangle 5 7 0 17 POLY +Rectangle 5 7 22 45 POLY +Rectangle 17 19 3 45 POLY +Rectangle 29 31 31 48 POLY +Rectangle 41 43 3 45 POLY +Rectangle 53 55 3 45 POLY +Rectangle 17 19 4 17 GATE +Rectangle 17 19 31 44 GATE +Rectangle 53 55 4 17 GATE +Rectangle 53 55 31 44 GATE +Rectangle 5 7 0 2 VIA0 +Rectangle 5 7 23 25 VIA0 +Rectangle 17 19 28 30 VIA0 +Rectangle 29 31 46 48 VIA0 +Rectangle 41 43 18 20 VIA0 +Rectangle 53 55 23 25 VIA0 +Rectangle 0 60 0 2 METAL1 +Rectangle 3 57 28 30 METAL1 +Rectangle 0 60 46 48 METAL1 +Rectangle 3 57 18 20 METAL1 +Rectangle 3 57 23 25 METAL1 +Pin 29 31 0 2 METAL1 GND +Pin 29 31 23 25 METAL1 OUTPUT +Pin 29 31 28 30 METAL1 INPUT1 +Pin 29 31 46 48 METAL1 VDD +Pin 29 31 18 20 METAL1 INPUT2 diff --git a/doc/tutorial/nor.layout b/doc/tutorial/nor.layout new file mode 100644 index 0000000..3e5041c --- /dev/null +++ b/doc/tutorial/nor.layout @@ -0,0 +1,29 @@ +Rectangle 0 60 0 24 NWELL +Rectangle 3 57 32 43 NDIFF +Rectangle 3 57 5 16 PDIFF +Rectangle 5 7 0 17 POLY +Rectangle 5 7 22 45 POLY +Rectangle 17 19 3 45 POLY +Rectangle 29 31 31 48 POLY +Rectangle 41 43 3 45 POLY +Rectangle 53 55 3 45 POLY +Rectangle 17 19 4 17 GATE +Rectangle 17 19 31 44 GATE +Rectangle 41 43 4 17 GATE +Rectangle 41 43 31 44 GATE +Rectangle 5 7 0 2 VIA0 +Rectangle 5 7 23 25 VIA0 +Rectangle 17 19 28 30 VIA0 +Rectangle 29 31 46 48 VIA0 +Rectangle 41 43 18 20 VIA0 +Rectangle 53 55 23 25 VIA0 +Rectangle 0 60 0 2 METAL1 +Rectangle 3 57 28 30 METAL1 +Rectangle 0 60 46 48 METAL1 +Rectangle 3 57 18 20 METAL1 +Rectangle 3 57 23 25 METAL1 +Pin 29 31 0 2 METAL1 GND +Pin 29 31 23 25 METAL1 OUTPUT +Pin 29 31 28 30 METAL1 INPUT1 +Pin 29 31 46 48 METAL1 VDD +Pin 29 31 18 20 METAL1 INPUT2 diff --git a/doc/tutorial/nor.schematic b/doc/tutorial/nor.schematic new file mode 100644 index 0000000..c892c17 --- /dev/null +++ b/doc/tutorial/nor.schematic @@ -0,0 +1,9 @@ +Pin OUTPUT +Pin INPUT1 +Pin INPUT2 +Pin VDD +Pin GND +Device NTRANS VDD INPUT1 OUTPUT +Device NTRANS VDD INPUT2 OUTPUT +Device PTRANS GND INPUT1 NET1 +Device PTRANS NET1 INPUT2 OUTPUT diff --git a/doc/tutorial/parse_layout.hpp b/doc/tutorial/parse_layout.hpp new file mode 100644 index 0000000..704864c --- /dev/null +++ b/doc/tutorial/parse_layout.hpp @@ -0,0 +1,39 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ + +//parse_layout.hpp +#ifndef BOOST_POLYGON_TUTORIAL_PARSE_LAYOUT_HPP +#define BOOST_POLYGON_TUTORIAL_PARSE_LAYOUT_HPP +#include +#include +#include +#include +#include "layout_rectangle.hpp" +#include "layout_pin.hpp" + +//populates vectors of layout rectangles and pins +inline void parse_layout(std::vector& rects, std::vector& pins, + std::ifstream& sin) { + while(!sin.eof()) { + std::string type_id; + sin >> type_id; + if(type_id == "Rectangle") { + layout_rectangle rect; + sin >> rect; + rects.push_back(rect); + } else if (type_id == "Pin") { + layout_pin pin; + sin >> pin; + pins.push_back(pin); + } else if (type_id == "") { + break; + } + } +} + +#endif diff --git a/doc/tutorial/schematic_database.hpp b/doc/tutorial/schematic_database.hpp new file mode 100644 index 0000000..8a930a0 --- /dev/null +++ b/doc/tutorial/schematic_database.hpp @@ -0,0 +1,58 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ + +//schematic_database.hpp +#ifndef BOOST_POLYGON_TUTORIAL_SCHEMATIC_DATABASE_HPP +#define BOOST_POLYGON_TUTORIAL_SCHEMATIC_DATABASE_HPP +#include +#include +#include +#include +#include "device.hpp" + +struct schematic_database{ + std::vector devices; + std::map > nets; +}; + +//given a vector of devices populate the map of net name to set of device index +inline void extract_netlist(std::map >& nets, + std::vector& devices) { + for(std::size_t i = 0; i < devices.size(); ++i) { + for(std::size_t j = 0; j < devices[i].terminals.size(); ++j) { + //create association between net name and device id + nets[devices[i].terminals[j]].insert(nets[devices[i].terminals[j]].end(), i); + } + } +} + +inline void parse_schematic_database(schematic_database& schematic, + std::ifstream& sin) { + std::vector& devices = schematic.devices; + while(!sin.eof()) { + std::string type_id; + sin >> type_id; + if(type_id == "Device") { + device d; + sin >> d; + devices.push_back(d); + } else if (type_id == "Pin") { + std::string net; + sin >> net; + device d; + d.type = "PIN"; + d.terminals.push_back(net); + devices.push_back(d); + } else if (type_id == "") { + break; + } + } + extract_netlist(schematic.nets, devices); +} + +#endif diff --git a/include/boost/polygon/detail/boolean_op.hpp b/include/boost/polygon/detail/boolean_op.hpp new file mode 100644 index 0000000..400825e --- /dev/null +++ b/include/boost/polygon/detail/boolean_op.hpp @@ -0,0 +1,448 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_BOOLEAN_OP_HPP +#define BOOST_POLYGON_BOOLEAN_OP_HPP +namespace boost { namespace polygon{ +namespace boolean_op { + + //BooleanOp is the generic boolean operation scanline algorithm that provides + //all the simple boolean set operations on manhattan data. By templatizing + //the intersection count of the input and algorithm internals it is extensible + //to multi-layer scans, properties and other advanced scanline operations above + //and beyond simple booleans. + //T must cast to int + template + class BooleanOp { + public: + typedef std::map ScanData; + typedef std::pair ElementType; + protected: + ScanData scanData_; + typename ScanData::iterator nextItr_; + T nullT_; + public: + inline BooleanOp () : scanData_(), nextItr_(), nullT_() { nextItr_ = scanData_.end(); nullT_ = 0; } + inline BooleanOp (T nullT) : scanData_(), nextItr_(), nullT_(nullT) { nextItr_ = scanData_.end(); } + inline BooleanOp (const BooleanOp& that) : scanData_(that.scanData_), nextItr_(), + nullT_(that.nullT_) { nextItr_ = scanData_.begin(); } + inline BooleanOp& operator=(const BooleanOp& that); + + //moves scanline forward + inline void advanceScan() { nextItr_ = scanData_.begin(); } + + //proceses the given interval and T data + //appends output edges to cT + template + inline void processInterval(cT& outputContainer, interval_data ivl, T deltaCount); + + private: + inline typename ScanData::iterator lookup_(Unit pos){ + if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { + return nextItr_; + } + return nextItr_ = scanData_.lower_bound(pos); + } + inline typename ScanData::iterator insert_(Unit pos, T count){ + return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count)); + } + template + inline void evaluateInterval_(cT& outputContainer, interval_data ivl, T beforeCount, T afterCount); + }; + + class BinaryAnd { + public: + inline BinaryAnd() {} + inline bool operator()(int a, int b) { return (a > 0) & (b > 0); } + }; + class BinaryOr { + public: + inline BinaryOr() {} + inline bool operator()(int a, int b) { return (a > 0) | (b > 0); } + }; + class BinaryNot { + public: + inline BinaryNot() {} + inline bool operator()(int a, int b) { return (a > 0) & !(b > 0); } + }; + class BinaryXor { + public: + inline BinaryXor() {} + inline bool operator()(int a, int b) { return (a > 0) ^ (b > 0); } + }; + + //BinaryCount is an array of two deltaCounts coming from two different layers + //of scan event data. It is the merged count of the two suitable for consumption + //as the template argument of the BooleanOp algorithm because BinaryCount casts to int. + //T is a binary functor object that evaluates the array of counts and returns a logical + //result of some operation on those values. + //BinaryCount supports many of the operators that work with int, particularly the + //binary operators, but cannot support less than or increment. + template + class BinaryCount { + public: + inline BinaryCount() +#ifndef BOOST_POLYGON_MSVC + : counts_() +#endif + { counts_[0] = counts_[1] = 0; } + // constructs from two integers + inline BinaryCount(int countL, int countR) +#ifndef BOOST_POLYGON_MSVC + : counts_() +#endif + { counts_[0] = countL, counts_[1] = countR; } + inline BinaryCount& operator=(int count) { counts_[0] = count, counts_[1] = count; return *this; } + inline BinaryCount& operator=(const BinaryCount& that); + inline BinaryCount(const BinaryCount& that) +#ifndef BOOST_POLYGON_MSVC + : counts_() +#endif + { *this = that; } + inline bool operator==(const BinaryCount& that) const; + inline bool operator!=(const BinaryCount& that) const { return !((*this) == that);} + inline BinaryCount& operator+=(const BinaryCount& that); + inline BinaryCount& operator-=(const BinaryCount& that); + inline BinaryCount operator+(const BinaryCount& that) const; + inline BinaryCount operator-(const BinaryCount& that) const; + inline BinaryCount operator-() const; + inline int& operator[](bool index) { return counts_[index]; } + + //cast to int operator evaluates data using T binary functor + inline operator int() const { return T()(counts_[0], counts_[1]); } + private: + int counts_[2]; + }; + + class UnaryCount { + public: + inline UnaryCount() : count_(0) {} + // constructs from two integers + inline explicit UnaryCount(int count) : count_(count) {} + inline UnaryCount& operator=(int count) { count_ = count; return *this; } + inline UnaryCount& operator=(const UnaryCount& that) { count_ = that.count_; return *this; } + inline UnaryCount(const UnaryCount& that) : count_(that.count_) {} + inline bool operator==(const UnaryCount& that) const { return count_ == that.count_; } + inline bool operator!=(const UnaryCount& that) const { return !((*this) == that);} + inline UnaryCount& operator+=(const UnaryCount& that) { count_ += that.count_; return *this; } + inline UnaryCount& operator-=(const UnaryCount& that) { count_ -= that.count_; return *this; } + inline UnaryCount operator+(const UnaryCount& that) const { UnaryCount tmp(*this); tmp += that; return tmp; } + inline UnaryCount operator-(const UnaryCount& that) const { UnaryCount tmp(*this); tmp -= that; return tmp; } + inline UnaryCount operator-() const { UnaryCount tmp; return tmp - *this; } + + //cast to int operator evaluates data using T binary functor + inline operator int() const { return count_ % 2; } + private: + int count_; + }; + + template + inline BooleanOp& BooleanOp::operator=(const BooleanOp& that) { + scanData_ = that.scanData_; + nextItr_ = scanData_.begin(); + nullT_ = that.nullT_; + return *this; + } + + //appends output edges to cT + template + template + inline void BooleanOp::processInterval(cT& outputContainer, interval_data ivl, T deltaCount) { + typename ScanData::iterator lowItr = lookup_(ivl.low()); + typename ScanData::iterator highItr = lookup_(ivl.high()); + //add interval to scan data if it is past the end + if(lowItr == scanData_.end()) { + lowItr = insert_(ivl.low(), deltaCount); + highItr = insert_(ivl.high(), nullT_); + evaluateInterval_(outputContainer, ivl, nullT_, deltaCount); + return; + } + //ensure that highItr points to the end of the ivl + if(highItr == scanData_.end() || (*highItr).first > ivl.high()) { + T value = nullT_; + if(highItr != scanData_.begin()) { + --highItr; + value = highItr->second; + } + nextItr_ = highItr; + highItr = insert_(ivl.high(), value); + } + //split the low interval if needed + if(lowItr->first > ivl.low()) { + if(lowItr != scanData_.begin()) { + --lowItr; + nextItr_ = lowItr; + lowItr = insert_(ivl.low(), lowItr->second); + } else { + nextItr_ = lowItr; + lowItr = insert_(ivl.low(), nullT_); + } + } + //process scan data intersecting interval + for(typename ScanData::iterator itr = lowItr; itr != highItr; ){ + T beforeCount = itr->second; + T afterCount = itr->second += deltaCount; + Unit low = itr->first; + ++itr; + Unit high = itr->first; + evaluateInterval_(outputContainer, interval_data(low, high), beforeCount, afterCount); + } + //merge the bottom interval with the one below if they have the same count + if(lowItr != scanData_.begin()){ + typename ScanData::iterator belowLowItr = lowItr; + --belowLowItr; + if(belowLowItr->second == lowItr->second) { + scanData_.erase(lowItr); + } + } + //merge the top interval with the one above if they have the same count + if(highItr != scanData_.begin()) { + typename ScanData::iterator beforeHighItr = highItr; + --beforeHighItr; + if(beforeHighItr->second == highItr->second) { + scanData_.erase(highItr); + highItr = beforeHighItr; + ++highItr; + } + } + nextItr_ = highItr; + } + + template + template + inline void BooleanOp::evaluateInterval_(cT& outputContainer, interval_data ivl, + T beforeCount, T afterCount) { + bool before = (int)beforeCount > 0; + bool after = (int)afterCount > 0; + int value = (!before & after) - (before & !after); + if(value) { + outputContainer.insert(outputContainer.end(), std::pair, int>(ivl, value)); + } + } + + template + inline BinaryCount& BinaryCount::operator=(const BinaryCount& that) { + counts_[0] = that.counts_[0]; + counts_[1] = that.counts_[1]; + return *this; + } + template + inline bool BinaryCount::operator==(const BinaryCount& that) const { + return counts_[0] == that.counts_[0] && + counts_[1] == that.counts_[1]; + } + template + inline BinaryCount& BinaryCount::operator+=(const BinaryCount& that) { + counts_[0] += that.counts_[0]; + counts_[1] += that.counts_[1]; + return *this; + } + template + inline BinaryCount& BinaryCount::operator-=(const BinaryCount& that) { + counts_[0] += that.counts_[0]; + counts_[1] += that.counts_[1]; + return *this; + } + template + inline BinaryCount BinaryCount::operator+(const BinaryCount& that) const { + BinaryCount retVal(*this); + retVal += that; + return retVal; + } + template + inline BinaryCount BinaryCount::operator-(const BinaryCount& that) const { + BinaryCount retVal(*this); + retVal -= that; + return retVal; + } + template + inline BinaryCount BinaryCount::operator-() const { + return BinaryCount() - *this; + } + + + template + inline void applyBooleanBinaryOp(std::vector > >& output, + //const std::vector > >& input1, + //const std::vector > >& input2, + iterator_type_1 itr1, iterator_type_1 itr1_end, + iterator_type_2 itr2, iterator_type_2 itr2_end, + T defaultCount) { + BooleanOp boolean(defaultCount); + //typename std::vector > >::const_iterator itr1 = input1.begin(); + //typename std::vector > >::const_iterator itr2 = input2.begin(); + std::vector, int> > container; + //output.reserve((std::max)(input1.size(), input2.size())); + + //consider eliminating dependecy on limits with bool flag for initial state + Unit UnitMax = (std::numeric_limits::max)(); + Unit prevCoord = UnitMax; + Unit prevPosition = UnitMax; + T count(defaultCount); + //define the starting point + if(itr1 != itr1_end) { + prevCoord = (*itr1).first; + prevPosition = (*itr1).second.first; + count[0] += (*itr1).second.second; + } + if(itr2 != itr2_end) { + if((*itr2).first < prevCoord || + ((*itr2).first == prevCoord && (*itr2).second.first < prevPosition)) { + prevCoord = (*itr2).first; + prevPosition = (*itr2).second.first; + count = defaultCount; + count[1] += (*itr2).second.second; + ++itr2; + } else if((*itr2).first == prevCoord && (*itr2).second.first == prevPosition) { + count[1] += (*itr2).second.second; + ++itr2; + if(itr1 != itr1_end) ++itr1; + } else { + if(itr1 != itr1_end) ++itr1; + } + } else { + if(itr1 != itr1_end) ++itr1; + } + + while(itr1 != itr1_end || itr2 != itr2_end) { + Unit curCoord = UnitMax; + Unit curPosition = UnitMax; + T curCount(defaultCount); + if(itr1 != itr1_end) { + curCoord = (*itr1).first; + curPosition = (*itr1).second.first; + curCount[0] += (*itr1).second.second; + } + if(itr2 != itr2_end) { + if((*itr2).first < curCoord || + ((*itr2).first == curCoord && (*itr2).second.first < curPosition)) { + curCoord = (*itr2).first; + curPosition = (*itr2).second.first; + curCount = defaultCount; + curCount[1] += (*itr2).second.second; + ++itr2; + } else if((*itr2).first == curCoord && (*itr2).second.first == curPosition) { + curCount[1] += (*itr2).second.second; + ++itr2; + if(itr1 != itr1_end) ++itr1; + } else { + if(itr1 != itr1_end) ++itr1; + } + } else { + ++itr1; + } + + if(prevCoord != curCoord) { + boolean.advanceScan(); + prevCoord = curCoord; + prevPosition = curPosition; + count = curCount; + continue; + } + if(curPosition != prevPosition && count != defaultCount) { + interval_data ivl(prevPosition, curPosition); + container.clear(); + boolean.processInterval(container, ivl, count); + for(std::size_t i = 0; i < container.size(); ++i) { + std::pair, int>& element = container[i]; + if(!output.empty() && output.back().first == prevCoord && + output.back().second.first == element.first.low() && + output.back().second.second == element.second * -1) { + output.pop_back(); + } else { + output.push_back(std::pair >(prevCoord, std::pair(element.first.low(), + element.second))); + } + output.push_back(std::pair >(prevCoord, std::pair(element.first.high(), + element.second * -1))); + } + } + prevPosition = curPosition; + count += curCount; + } + } + + template + inline void applyBooleanBinaryOp(std::vector > >& inputOutput, + const std::vector > >& input2, + T defaultCount) { + std::vector > > output; + applyBooleanBinaryOp(output, inputOutput, input2, defaultCount); + if(output.size() < inputOutput.size() / 2) { + inputOutput = std::vector > >(); + } else { + inputOutput.clear(); + } + inputOutput.insert(inputOutput.end(), output.begin(), output.end()); + } + + template + inline void applyUnaryXOr(std::vector > >& input) { + BooleanOp booleanXOr; + + } + + template + struct default_arg_workaround { + template + static inline void applyBooleanOr(std::vector > >& input) { + BooleanOp booleanOr; + std::vector, int> > container; + std::vector > > output; + output.reserve(input.size()); + //consider eliminating dependecy on limits with bool flag for initial state + Unit UnitMax = (std::numeric_limits::max)(); + Unit prevPos = UnitMax; + Unit prevY = UnitMax; + int count = 0; + for(typename std::vector > >::iterator itr = input.begin(); + itr != input.end(); ++itr) { + Unit pos = (*itr).first; + Unit y = (*itr).second.first; + if(pos != prevPos) { + booleanOr.advanceScan(); + prevPos = pos; + prevY = y; + count = (*itr).second.second; + continue; + } + if(y != prevY && count != 0) { + interval_data ivl(prevY, y); + container.clear(); + booleanOr.processInterval(container, ivl, count_type(count)); + for(std::size_t i = 0; i < container.size(); ++i) { + std::pair, int>& element = container[i]; + if(!output.empty() && output.back().first == prevPos && + output.back().second.first == element.first.low() && + output.back().second.second == element.second * -1) { + output.pop_back(); + } else { + output.push_back(std::pair >(prevPos, std::pair(element.first.low(), + element.second))); + } + output.push_back(std::pair >(prevPos, std::pair(element.first.high(), + element.second * -1))); + } + } + prevY = y; + count += (*itr).second.second; + } + if(output.size() < input.size() / 2) { + input = std::vector > >(); + } else { + input.clear(); + } + input.insert(input.end(), output.begin(), output.end()); + } + }; + +} + +} + +} +#endif diff --git a/include/boost/polygon/detail/boolean_op_45.hpp b/include/boost/polygon/detail/boolean_op_45.hpp new file mode 100644 index 0000000..f5d4d90 --- /dev/null +++ b/include/boost/polygon/detail/boolean_op_45.hpp @@ -0,0 +1,1394 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_BOOLEAN_OP_45_HPP +#define BOOST_POLYGON_BOOLEAN_OP_45_HPP +namespace boost { namespace polygon{ + + template + struct boolean_op_45 { + typedef point_data Point; + typedef typename coordinate_traits::manhattan_area_type LongUnit; + + class Count2 { + public: + inline Count2() +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = counts[1] = 0; } + //inline Count2(int count) { counts[0] = counts[1] = count; } + inline Count2(int count1, int count2) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = count1; counts[1] = count2; } + inline Count2(const Count2& count) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = count.counts[0]; counts[1] = count.counts[1]; } + inline bool operator==(const Count2& count) const { return counts[0] == count.counts[0] && counts[1] == count.counts[1]; } + inline bool operator!=(const Count2& count) const { return !((*this) == count); } + inline Count2& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline Count2& operator=(const Count2& count) { counts[0] = count.counts[0]; counts[1] = count.counts[1]; return *this; } + inline int& operator[](bool index) { return counts[index]; } + inline int operator[](bool index) const {return counts[index]; } + inline Count2& operator+=(const Count2& count){ + counts[0] += count[0]; + counts[1] += count[1]; + return *this; + } + inline Count2& operator-=(const Count2& count){ + counts[0] -= count[0]; + counts[1] -= count[1]; + return *this; + } + inline Count2 operator+(const Count2& count) const { + return Count2(*this)+=count; + } + inline Count2 operator-(const Count2& count) const { + return Count2(*this)-=count; + } + inline Count2 invert() const { + return Count2(-counts[0], -counts[1]); + } + private: + int counts[2]; + }; + + class Count1 { + public: + inline Count1() : count_(0) { } + inline Count1(int count) : count_(count) { } + inline Count1(const Count1& count) : count_(count.count_) { } + inline bool operator==(const Count1& count) const { return count_ == count.count_; } + inline bool operator!=(const Count1& count) const { return !((*this) == count); } + inline Count1& operator=(int count) { count_ = count; return *this; } + inline Count1& operator=(const Count1& count) { count_ = count.count_; return *this; } + inline Count1& operator+=(const Count1& count){ + count_ += count.count_; + return *this; + } + inline Count1& operator-=(const Count1& count){ + count_ -= count.count_; + return *this; + } + inline Count1 operator+(const Count1& count) const { + return Count1(*this)+=count; + } + inline Count1 operator-(const Count1& count) const { + return Count1(*this)-=count; + } + inline Count1 invert() const { + return Count1(-count_); + } + int count_; + }; + + // inline std::ostream& operator<< (std::ostream& o, const Count2& c) { + // o << c[0] << " " << c[1]; + // return o; + // } + + template + class Scan45ElementT { + public: + Unit x; + Unit y; + int rise; //-1, 0, +1 + mutable CountType count; + inline Scan45ElementT() : x(), y(), rise(), count() {} + inline Scan45ElementT(Unit xIn, Unit yIn, int riseIn, CountType countIn = CountType()) : + x(xIn), y(yIn), rise(riseIn), count(countIn) {} + inline Scan45ElementT(const Scan45ElementT& that) : + x(that.x), y(that.y), rise(that.rise), count(that.count) {} + inline Scan45ElementT& operator=(const Scan45ElementT& that) { + x = that.x; y = that.y; rise = that.rise; count = that.count; + return *this; + } + inline Unit evalAtX(Unit xIn) const { + return y + rise * (xIn - x); + } + + inline bool cross(Point& crossPoint, const Scan45ElementT& edge, Unit currentX) const { + Unit y1 = evalAtX(currentX); + Unit y2 = edge.evalAtX(currentX); + int rise1 = rise; + int rise2 = edge.rise; + if(rise > edge.rise){ + if(y1 > y2) return false; + } else if(rise < edge.rise){ + if(y2 > y1) return false; + std::swap(y1, y2); + std::swap(rise1, rise2); + } else { return false; } + if(rise1 == 1) { + if(rise2 == 0) { + crossPoint = Point(currentX + y2 - y1, y2); + } else { + //rise2 == -1 + Unit delta = (y2 - y1)/2; + crossPoint = Point(currentX + delta, y1 + delta); + } + } else { + //rise1 == 0 and rise2 == -1 + crossPoint = Point(currentX + y2 - y1, y1); + } + return true; + } + }; + + typedef Scan45ElementT Scan45Element; + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Element& c) { + // o << c.x << " " << c.y << " " << c.rise << " " << c.count; + // return o; + // } + + class lessScan45ElementRise : public std::binary_function { + public: + inline lessScan45ElementRise() {} //default constructor is only constructor + inline bool operator () (Scan45Element elm1, Scan45Element elm2) const { + return elm1.rise < elm2.rise; + } + }; + + template + class lessScan45Element { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline lessScan45Element() : x_(0), justBefore_(0) {} + inline lessScan45Element(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + inline lessScan45Element(const lessScan45Element& that) : x_(that.x_), justBefore_(that.justBefore_) {} + inline lessScan45Element& operator=(const lessScan45Element& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + inline bool operator () (const Scan45ElementT& elm1, + const Scan45ElementT& elm2) const { + Unit y1 = elm1.evalAtX(*x_); + Unit y2 = elm2.evalAtX(*x_); + if(y1 < y2) return true; + if(y1 == y2) { + //if justBefore is true we invert the result of the comparison of slopes + if(*justBefore_) { + return elm1.rise > elm2.rise; + } else { + return elm1.rise < elm2.rise; + } + } + return false; + } + }; + + template + class Scan45CountT { + public: + inline Scan45CountT() : counts() {} //counts[0] = counts[1] = counts[2] = counts[3] = 0; } + inline Scan45CountT(CountType count) : counts() { counts[0] = counts[1] = counts[2] = counts[3] = count; } + inline Scan45CountT(const CountType& count1, const CountType& count2, const CountType& count3, + const CountType& count4) : counts() { + counts[0] = count1; + counts[1] = count2; + counts[2] = count3; + counts[3] = count4; + } + inline Scan45CountT(const Scan45CountT& count) : counts() { + (*this) = count; + } + inline bool operator==(const Scan45CountT& count) const { + for(unsigned int i = 0; i < 4; ++i) { + if(counts[i] != count.counts[i]) return false; + } + return true; + } + inline bool operator!=(const Scan45CountT& count) const { return !((*this) == count); } + inline Scan45CountT& operator=(CountType count) { + counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } + inline Scan45CountT& operator=(const Scan45CountT& count) { + for(unsigned int i = 0; i < 4; ++i) { + counts[i] = count.counts[i]; + } + return *this; + } + inline CountType& operator[](int index) { return counts[index]; } + inline CountType operator[](int index) const {return counts[index]; } + inline Scan45CountT& operator+=(const Scan45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] += count.counts[i]; + } + return *this; + } + inline Scan45CountT& operator-=(const Scan45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] -= count.counts[i]; + } + return *this; + } + inline Scan45CountT operator+(const Scan45CountT& count) const { + return Scan45CountT(*this)+=count; + } + inline Scan45CountT operator-(const Scan45CountT& count) const { + return Scan45CountT(*this)-=count; + } + inline Scan45CountT invert() const { + return Scan45CountT(CountType())-=(*this); + } + inline Scan45CountT& operator+=(const Scan45ElementT& element){ + counts[element.rise+1] += element.count; return *this; + } + private: + CountType counts[4]; + }; + + typedef Scan45CountT Scan45Count; + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Count& c) { + // o << c[0] << ", " << c[1] << ", "; + // o << c[2] << ", " << c[3]; + // return o; + // } + + + // inline std::ostream& operator<< (std::ostream& o, const Scan45Vertex& c) { + // o << c.first << ": " << c.second; + // return o; + // } + + + //vetex45 is sortable + template + class Vertex45T { + public: + Point pt; + int rise; // 1, 0 or -1 + ct count; //dxdydTheta + inline Vertex45T() : pt(), rise(), count() {} + inline Vertex45T(const Point& point, int riseIn, ct countIn) : pt(point), rise(riseIn), count(countIn) {} + inline Vertex45T(const Vertex45T& vertex) : pt(vertex.pt), rise(vertex.rise), count(vertex.count) {} + inline Vertex45T& operator=(const Vertex45T& vertex){ + pt = vertex.pt; rise = vertex.rise; count = vertex.count; return *this; } + inline Vertex45T(const std::pair& vertex) : pt(), rise(), count() {} + inline Vertex45T& operator=(const std::pair& vertex){ return *this; } + inline bool operator==(const Vertex45T& vertex) const { + return pt == vertex.pt && rise == vertex.rise && count == vertex.count; } + inline bool operator!=(const Vertex45T& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair& vertex) const { return false; } + inline bool operator!=(const std::pair& vertex) const { return !((*this) == vertex); } + inline bool operator<(const Vertex45T& vertex) const { + if(pt.x() < vertex.pt.x()) return true; + if(pt.x() == vertex.pt.x()) { + if(pt.y() < vertex.pt.y()) return true; + if(pt.y() == vertex.pt.y()) { return rise < vertex.rise; } + } + return false; + } + inline bool operator>(const Vertex45T& vertex) const { return vertex < (*this); } + inline bool operator<=(const Vertex45T& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const Vertex45T& vertex) const { return !((*this) < vertex); } + inline Unit evalAtX(Unit xIn) const { return pt.y() + rise * (xIn - pt.x()); } + }; + + typedef Vertex45T Vertex45; + + // inline std::ostream& operator<< (std::ostream& o, const Vertex45& c) { + // o << c.pt << " " << c.rise << " " << c.count; + // return o; + // } + + //when scanning Vertex45 for polygon formation we need a scanline comparator functor + class lessVertex45 { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline lessVertex45() : x_(0), justBefore_() {} + + inline lessVertex45(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + + inline lessVertex45(const lessVertex45& that) : x_(that.x_), justBefore_(that.justBefore_) {} + + inline lessVertex45& operator=(const lessVertex45& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + + template + inline bool operator () (const Vertex45T& elm1, const Vertex45T& elm2) const { + Unit y1 = elm1.evalAtX(*x_); + Unit y2 = elm2.evalAtX(*x_); + if(y1 < y2) return true; + if(y1 == y2) { + //if justBefore is true we invert the result of the comparison of slopes + if(*justBefore_) { + return elm1.rise > elm2.rise; + } else { + return elm1.rise < elm2.rise; + } + } + return false; + } + }; + + // 0 right to left + // 1 upper right to lower left + // 2 high to low + // 3 upper left to lower right + // 4 left to right + // 5 lower left to upper right + // 6 low to high + // 7 lower right to upper left + static inline int classifyEdge45(const Point& prevPt, const Point& nextPt) { + if(prevPt.x() == nextPt.x()) { + //2 or 6 + return predicated_value(prevPt.y() < nextPt.y(), 6, 2); + } + if(prevPt.y() == nextPt.y()) { + //0 or 4 + return predicated_value(prevPt.x() < nextPt.x(), 4, 0); + } + if(prevPt.x() < nextPt.x()) { + //3 or 5 + return predicated_value(prevPt.y() < nextPt.y(), 5, 3); + } + //prevPt.x() > nextPt.y() + //1 or 7 + return predicated_value(prevPt.y() < nextPt.y(), 7, 1); + } + + template + static int applyLogic(CountType count1, CountType count2){ + bool l1 = applyLogic(count1); + bool l2 = applyLogic(count2); + if(l1 && !l2) + return -1; //was true before and became false like a trailing edge + if(!l1 && l2) + return 1; //was false before and became true like a leading edge + return 0; //no change in logic between the two counts + } + template + static bool applyLogic(Count2 count) { +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { //apply or + return count[0] > 0 || count[1] > 0; + } else if(op == 1) { //apply and + return count[0] > 0 && count[1] > 0; + } else if(op == 2) { //apply not + return count[0] > 0 && !(count[1] > 0); + } else if(op == 3) { //apply xor + return (count[0] > 0) ^ (count[1] > 0); + } else + return false; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + + template + struct boolean_op_45_output_functor { + template + void operator()(cT& output, const Count2& count1, const Count2& count2, + const Point& pt, int rise, direction_1d end) { + int edgeType = applyLogic(count1, count2); + if(edgeType) { + int multiplier = end == LOW ? -1 : 1; + //std::cout << "cross logic: " << edgeType << std::endl; + output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + } + } + }; + + template + static bool applyLogic(Count1 count) { +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { //apply or + return count.count_ > 0; + } else if(op == 1) { //apply and + return count.count_ > 1; + } else if(op == 3) { //apply xor + return (count.count_ % 2) != 0; + } else + return false; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + + template + struct unary_op_45_output_functor { + template + void operator()(cT& output, const Count1& count1, const Count1& count2, + const Point& pt, int rise, direction_1d end) { + int edgeType = applyLogic(count1, count2); + if(edgeType) { + int multiplier = end == LOW ? -1 : 1; + //std::cout << "cross logic: " << edgeType << std::endl; + output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + } + } + }; + + class lessScan45Vertex { + public: + inline lessScan45Vertex() {} //default constructor is only constructor + template + inline bool operator () (const Scan45Vertex& v1, const Scan45Vertex& v2) const { + return (v1.first.x() < v2.first.x()) || (v1.first.x() == v2.first.x() && v1.first.y() < v2.first.y()); + } + }; + template + static inline void sortScan45Vector(S45V& vec) { + std::sort(vec.begin(), vec.end(), lessScan45Vertex()); + } + + template + class Scan45 { + public: + typedef Scan45CountT Scan45Count; + typedef std::pair Scan45Vertex; + + //index is the index into the vertex + static inline Scan45Element getElement(const Scan45Vertex& vertex, int index) { + return Scan45Element(vertex.first.x(), vertex.first.y(), index - 1, vertex.second[index]); + } + + class lessScan45Point : public std::binary_function { + public: + inline lessScan45Point() {} //default constructor is only constructor + inline bool operator () (const Point& v1, const Point& v2) const { + return (v1.x() < v2.x()) || (v1.x() == v2.x() && v1.y() < v2.y()); + } + }; + + typedef std::vector Scan45Vector; + + //definitions + typedef std::set, lessScan45Element > Scan45Data; + typedef typename Scan45Data::iterator iterator; + typedef typename Scan45Data::const_iterator const_iterator; + typedef std::set CrossQueue; + + //data + Scan45Data scanData_; + CrossQueue crossQueue_; + Scan45Vector crossVector_; + Unit x_; + int justBefore_; + public: + inline Scan45() : scanData_(), crossQueue_(), crossVector_(), + x_((std::numeric_limits::min)()), justBefore_(false) { + lessScan45Element lessElm(&x_, &justBefore_); + scanData_ = std::set, lessScan45Element >(lessElm); + } + inline Scan45(const Scan45& that) : scanData_(), crossQueue_(), crossVector_(), + x_((std::numeric_limits::min)()), justBefore_(false) { + (*this) = that; } + inline Scan45& operator=(const Scan45& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + crossQueue_ = that.crossQueue_; + crossVector_ = that.crossVector_; + lessScan45Element lessElm(&x_, &justBefore_); + scanData_ = std::set, lessScan45Element >(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Vertex45 + //iT is an iterator over Scan45Vertex elements + template + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + //for(iterator iter = scanData_.begin(); + // iter != scanData_.end(); ++iter) { + // std::cout << "scan element\n"; + // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + // } + // std::cout << "cross queue size: " << crossQueue_.size() << std::endl; + // std::cout << "cross vector size: " << crossVector_.size() << std::endl; + //for(CrossQueue::iterator cqitr = crossQueue_.begin(); cqitr != crossQueue_.end(); ++cqitr) { + // std::cout << *cqitr << " "; + //} std::cout << std::endl; + Unit nextX = (*inputBegin).first.x(); + if(!crossVector_.empty() && crossVector_[0].first.x() < nextX) nextX = crossVector_[0].first.x(); + if(nextX != x_) { + //std::cout << "3\n"; + //we need to move to the next scanline stop + //we need to process end events then cross events + //process end events + if(!crossQueue_.empty() && + (*crossQueue_.begin()).x() < nextX) { + //std::cout << "4\n"; + nextX = (std::min)(nextX, (*crossQueue_.begin()).x()); + } + //std::cout << "6\n"; + justBefore_ = true; + x_ = nextX; + advance_(output); + justBefore_ = false; + if(!crossVector_.empty() && + nextX == (*inputBegin).first.x()) { + inputBegin = mergeCross_(inputBegin, inputEnd); + } + processEvent_(output, crossVector_.begin(), crossVector_.end()); + crossVector_.clear(); + } else { + //std::cout << "7\n"; + //our scanline has progressed to the event that is next in the queue + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + //std::cout << "done scanning\n"; + } + + private: + //functions + + template + inline void advance_(cT& output) { + //process all cross points on the cross queue at the current x_ + //std::cout << "advance_\n"; + std::vector eraseVec; + while(!crossQueue_.empty() && + (*crossQueue_.begin()).x() == x_){ + //std::cout << "loop\n"; + //pop point off the cross queue + Point crossPoint = *(crossQueue_.begin()); + //std::cout << crossPoint << std::endl; + //for(iterator iter = scanData_.begin(); + // iter != scanData_.end(); ++iter) { + // std::cout << "scan element\n"; + // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + //} + crossQueue_.erase(crossQueue_.begin()); + Scan45Vertex vertex(crossPoint, Scan45Count()); + iterator lowIter = lookUp_(vertex.first.y()); + //std::cout << "searching at: " << vertex.first.y() << std::endl; + //if(lowIter == scanData_.end()) std::cout << "could not find\n"; + //else std::cout << "found: " << *lowIter << std::endl; + if(lowIter == scanData_.end() || + lowIter->evalAtX(x_) != vertex.first.y()) { + // std::cout << "skipping\n"; + //there weren't any edges at this potential cross point + continue; + } + CountType countBelow; + iterator searchDownItr = lowIter; + while(searchDownItr != scanData_.begin() + && searchDownItr->evalAtX(x_) == vertex.first.y()) { + //get count from below + --searchDownItr; + countBelow = searchDownItr->count; + } + //std::cout << "Below Count: " << countBelow << std::endl; + Scan45Count count(countBelow); + std::size_t numEdges = 0; + iterator eraseItrs[3]; + while(lowIter != scanData_.end() && + lowIter->evalAtX(x_) == vertex.first.y()) { + for(int index = lowIter->rise +1; index >= 0; --index) + count[index] = lowIter->count; + //std::cout << count << std::endl; + eraseItrs[numEdges] = lowIter; + ++numEdges; + ++lowIter; + } + if(numEdges == 1) { + //look for the next crossing point and continue + //std::cout << "found only one edge\n"; + findCross_(eraseItrs[0]); + continue; + } + //before we erase the elements we need to decide if they should be written out + CountType currentCount = countBelow; + for(std::size_t i = 0; i < numEdges; ++i) { + output_functor f; + f(output, currentCount, eraseItrs[i]->count, crossPoint, eraseItrs[i]->rise, LOW); + currentCount = eraseItrs[i]->count; + } + //schedule erase of the elements + for(std::size_t i = 0; i < numEdges; ++i) { + eraseVec.push_back(eraseItrs[i]); + } + + //take the derivative wrt theta of the count at the crossing point + vertex.second[2] = count[2] - countBelow; + vertex.second[1] = count[1] - count[2]; + vertex.second[0] = count[0] - count[1]; + //add the point, deriviative pair into the cross vector + //std::cout << "LOOK HERE!\n"; + //std::cout << count << std::endl; + //std::cout << vertex << std::endl; + crossVector_.push_back(vertex); + } + //erase crossing elements + std::vector searchVec; + for(std::size_t i = 0; i < eraseVec.size(); ++i) { + if(eraseVec[i] != scanData_.begin()) { + iterator searchItr = eraseVec[i]; + --searchItr; + if(searchVec.empty() || + searchVec.back() != searchItr) + searchVec.push_back(searchItr); + } + scanData_.erase(eraseVec[i]); + } + for(std::size_t i = 0; i < searchVec.size(); ++i) { + findCross_(searchVec[i]); + } + } + + template + inline iT mergeCross_(iT inputBegin, iT inputEnd) { + Scan45Vector vec; + swap(vec, crossVector_); + iT mergeEnd = inputBegin; + std::size_t mergeCount = 0; + while(mergeEnd != inputEnd && + (*mergeEnd).first.x() == x_) { + ++mergeCount; + ++mergeEnd; + } + crossVector_.reserve((std::max)(vec.capacity(), vec.size() + mergeCount)); + for(std::size_t i = 0; i < vec.size(); ++i){ + while(inputBegin != mergeEnd && + (*inputBegin).first.y() < vec[i].first.y()) { + crossVector_.push_back(*inputBegin); + ++inputBegin; + } + crossVector_.push_back(vec[i]); + } + while(inputBegin != mergeEnd){ + crossVector_.push_back(*inputBegin); + ++inputBegin; + } + return inputBegin; + } + + template + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + CountType verticalCount = CountType(); + Point prevPoint; + iterator prevIter = scanData_.end(); + while(inputBegin != inputEnd && + (*inputBegin).first.x() == x_) { + //std::cout << (*inputBegin) << std::endl; + //std::cout << "loop\n"; + Scan45Vertex vertex = *inputBegin; + //std::cout << vertex.first << std::endl; + //if vertical count propigating up fake a null event at the next element + if(verticalCount != CountType() && (prevIter != scanData_.end() && + prevIter->evalAtX(x_) < vertex.first.y())) { + //std::cout << "faking null event\n"; + vertex = Scan45Vertex(Point(x_, prevIter->evalAtX(x_)), Scan45Count()); + } else { + ++inputBegin; + //std::cout << "after increment\n"; + //accumulate overlapping changes in Scan45Count + while(inputBegin != inputEnd && + (*inputBegin).first.x() == x_ && + (*inputBegin).first.y() == vertex.first.y()) { + //std::cout << "accumulate\n"; + vertex.second += (*inputBegin).second; + ++inputBegin; + } + } + //std::cout << vertex.second << std::endl; + //integrate vertex + CountType currentCount = verticalCount;// + vertex.second[0]; + for(unsigned int i = 0; i < 3; ++i) { + vertex.second[i] = currentCount += vertex.second[i]; + } + //std::cout << vertex.second << std::endl; + //vertex represents the change in state at this point + + //get counts at current vertex + CountType countBelow; + iterator lowIter = lookUp_(vertex.first.y()); + if(lowIter != scanData_.begin()) { + //get count from below + --lowIter; + countBelow = lowIter->count; + ++lowIter; + } + //std::cout << "Count Below: " << countBelow[0] << " " << countBelow[1] << std::endl; + //std::cout << "vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + Scan45Count countAt(countBelow - verticalCount); + //check if the vertical edge should be written out + if(verticalCount != CountType()) { + output_functor f; + f(output, countBelow - verticalCount, countBelow, prevPoint, 2, HIGH); + f(output, countBelow - verticalCount, countBelow, vertex.first, 2, LOW); + } + currentCount = countBelow - verticalCount; + while(lowIter != scanData_.end() && + lowIter->evalAtX(x_) == vertex.first.y()) { + for(unsigned int i = lowIter->rise + 1; i < 3; ++i) { + countAt[i] = lowIter->count; + } + Point lp(lowIter->x, lowIter->y); + if(lp != vertex.first) { + output_functor f; + f(output, currentCount, lowIter->count, vertex.first, lowIter->rise, LOW); + } + currentCount = lowIter->count; + iterator nextIter = lowIter; + ++nextIter; + //std::cout << "erase\n"; + scanData_.erase(lowIter); + if(nextIter != scanData_.end()) + findCross_(nextIter); + lowIter = nextIter; + } + verticalCount += vertex.second[3]; + prevPoint = vertex.first; + //std::cout << "new vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + prevIter = lowIter; + //count represents the current state at this point + //std::cout << vertex.second << std::endl; + //std::cout << countAt << std::endl; + //std::cout << "ADD\n"; + vertex.second += countAt; + //std::cout << vertex.second << std::endl; + + //add elements to the scanline + for(int i = 0; i < 3; ++i) { + if(vertex.second[i] != countBelow) { + //std::cout << "insert: " << vertex.first.x() << " " << vertex.first.y() << " " << i-1 << + // " " << vertex.second[i][0] << " " << vertex.second[i][1] << std::endl; + iterator insertIter = scanData_.insert(scanData_.end(), + Scan45ElementT(vertex.first.x(), + vertex.first.y(), + i - 1, vertex.second[i])); + findCross_(insertIter); + output_functor f; + f(output, countBelow, vertex.second[i], vertex.first, i - 1, HIGH); + } + countBelow = vertex.second[i]; + } + } + //std::cout << "end processEvent\n"; + return inputBegin; + } + + //iter1 is horizontal + inline void scheduleCross0_(iterator iter1, iterator iter2) { + //std::cout << "0, "; + Unit y1 = iter1->evalAtX(x_); + Unit y2 = iter2->evalAtX(x_); + LongUnit delta = local_abs(LongUnit(y1) - LongUnit(y2)); + if(delta + static_cast(x_) <= (std::numeric_limits::max)()) + crossQueue_.insert(crossQueue_.end(), Point(x_ + static_cast(delta), y1)); + //std::cout << Point(x_ + delta, y1); + } + + //neither iter is horizontal + inline void scheduleCross1_(iterator iter1, iterator iter2) { + //std::cout << "1, "; + Unit y1 = iter1->evalAtX(x_); + Unit y2 = iter2->evalAtX(x_); + //std::cout << y1 << " " << y2 << ": "; + //note that half the delta cannot exceed the positive inter range + LongUnit delta = y1; + delta -= y2; + Unit UnitMax = (std::numeric_limits::max)(); + if((delta & 1) == 1) { + //delta is odd, division by 2 will result in integer trunctaion + if(delta == 1) { + //the cross point is not on the integer grid and cannot be represented + //we must throw an exception + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + throw(msg); + } else { + //note that result of this subtraction is always positive because itr1 is above itr2 in scanline + LongUnit halfDelta2 = (LongUnit)((((LongUnit)y1) - y2)/2); + //note that halfDelta2 has been truncated + if(halfDelta2 + x_ <= UnitMax && halfDelta2 + y2 <= UnitMax) { + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast(halfDelta2), y2+static_cast(halfDelta2))); + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast(halfDelta2), y2+static_cast(halfDelta2)+1)); + } + } + } else { + LongUnit halfDelta = (LongUnit)((((LongUnit)y1) - y2)/2); + if(halfDelta + x_ <= UnitMax && halfDelta + y2 <= UnitMax) + crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast(halfDelta), y2+static_cast(halfDelta))); + //std::cout << Point(x_+halfDelta, y2+halfDelta); + } + } + + inline void findCross_(iterator iter) { + //std::cout << "find cross "; + iterator iteratorBelow = iter; + iterator iteratorAbove = iter; + if(iter != scanData_.begin() && iter->rise < 1) { + --iteratorBelow; + if(iter->rise == 0){ + if(iteratorBelow->rise == 1) { + scheduleCross0_(iter, iteratorBelow); + } + } else { + //iter->rise == -1 + if(iteratorBelow->rise == 1) { + scheduleCross1_(iter, iteratorBelow); + } else if(iteratorBelow->rise == 0) { + scheduleCross0_(iteratorBelow, iter); + } + } + } + ++iteratorAbove; + if(iteratorAbove != scanData_.end() && iter->rise > -1) { + if(iter->rise == 0) { + if(iteratorAbove->rise == -1) { + scheduleCross0_(iter, iteratorAbove); + } + } else { + //iter->rise == 1 + if(iteratorAbove->rise == -1) { + scheduleCross1_(iteratorAbove, iter); + } else if(iteratorAbove->rise == 0) { + scheduleCross0_(iteratorAbove, iter); + } + } + } + //std::cout << std::endl; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Scan45ElementT(x_, y, -1+2*justBefore_)); + } + }; + + //template + //static inline void print45Data(const std::set, + // lessScan45Element >& data) { + // typename std::set, lessScan45Element >::const_iterator iter; + // for(iter = data.begin(); iter != data.end(); ++iter) { + // std::cout << iter->x << " " << iter->y << " " << iter->rise << std::endl; + // } + //} + + template + static inline bool testScan45Data(streamtype& stdcout) { + Unit x = 0; + int justBefore = false; + lessScan45Element lessElm(&x, &justBefore); + std::set, lessScan45Element > testData(lessElm); + //Unit size = testData.size(); + typedef std::set, lessScan45Element > Scan45Data; + typename Scan45Data::iterator itr10 = testData.insert(testData.end(), Scan45Element(0, 10, 1)); + typename Scan45Data::iterator itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); + typename Scan45Data::iterator itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); + typename Scan45Data::iterator itr40 = testData.insert(testData.end(), Scan45Element(0, 40, -1)); + typename Scan45Data::iterator itrA = testData.lower_bound(Scan45Element(0, 29, -1)); + typename Scan45Data::iterator itr1 = testData.lower_bound(Scan45Element(0, 10, -1)); + x = 4; + //now at 14 24 26 36 + typename Scan45Data::iterator itrB = testData.lower_bound(Scan45Element(4, 29, -1)); + typename Scan45Data::iterator itr2 = testData.lower_bound(Scan45Element(4, 14, -1)); + if(itr1 != itr2) stdcout << "test1 failed\n"; + if(itrA == itrB) stdcout << "test2 failed\n"; + //remove crossing elements + testData.erase(itr20); + testData.erase(itr30); + x = 5; + itr20 = testData.insert(testData.end(), Scan45Element(0, 20, 1)); + itr30 = testData.insert(testData.end(), Scan45Element(0, 30, -1)); + //now at 15 25 25 35 + typename Scan45Data::iterator itr = testData.begin(); + if(itr != itr10) stdcout << "test3 failed\n"; + ++itr; + if(itr != itr30) stdcout << "test4 failed\n"; + ++itr; + if(itr != itr20) stdcout << "test5 failed\n"; + ++itr; + if(itr != itr40) stdcout << "test6 failed\n"; + stdcout << "done testing Scan45Data\n"; + return true; + } + + template + static inline bool testScan45Rect(stream_type& stdcout) { + stdcout << "testing Scan45Rect\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 0 1 + // result == 0 0 2 1 + // result == 0 10 2 -1 + // result == 0 10 0 -1 + // result == 10 0 0 -1 + // result == 10 0 2 -1 + // result == 10 10 2 1 + // result == 10 10 0 1 + std::vector reference; + reference.push_back(Vertex45(Point(0, 0), 0, 1)); + reference.push_back(Vertex45(Point(0, 0), 2, 1)); + reference.push_back(Vertex45(Point(0, 10), 2, -1)); + reference.push_back(Vertex45(Point(0, 10), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 2, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //std::cout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //std::cout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45Rect\n"; + return true; + } + + template + static inline bool testScan45P1(stream_type& stdcout) { + stdcout << "testing Scan45P1\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), Count2(0, 0), ncount, ncount))); + vertices.push_back(Scan45Vertex(Point(10,20), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 1 1 + // result == 0 0 2 1 + // result == 0 10 2 -1 + // result == 0 10 1 -1 + // result == 10 10 1 -1 + // result == 10 10 2 -1 + // result == 10 20 2 1 + // result == 10 20 1 1 + std::vector reference; + reference.push_back(Vertex45(Point(0, 0), 1, 1)); + reference.push_back(Vertex45(Point(0, 0), 2, 1)); + reference.push_back(Vertex45(Point(0, 10), 2, -1)); + reference.push_back(Vertex45(Point(0, 10), 1, -1)); + reference.push_back(Vertex45(Point(10, 10), 1, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, -1)); + reference.push_back(Vertex45(Point(10, 20), 2, 1)); + reference.push_back(Vertex45(Point(10, 20), 1, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //std::cout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //std::cout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45P1\n"; + return true; + } + + template + static inline bool testScan45P2(stream_type& stdcout) { + stdcout << "testing Scan45P2\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), ncount, count, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(20,10), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 8 + // result == 0 0 0 1 + // result == 0 0 1 -1 + // result == 10 0 0 -1 + // result == 10 0 1 1 + // result == 10 10 1 1 + // result == 10 10 0 -1 + // result == 20 10 1 -1 + // result == 20 10 0 1 + std::vector reference; + reference.push_back(Vertex45(Point(0, 0), 0, 1)); + reference.push_back(Vertex45(Point(0, 0), 1, -1)); + reference.push_back(Vertex45(Point(10, 0), 0, -1)); + reference.push_back(Vertex45(Point(10, 0), 1, 1)); + reference.push_back(Vertex45(Point(10, 10), 1, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, -1)); + reference.push_back(Vertex45(Point(20, 10), 1, -1)); + reference.push_back(Vertex45(Point(20, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //stdcout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //stdcout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45P2\n"; + return true; + } + + template + static inline bool testScan45And(streamtype& stdcout) { + stdcout << "testing Scan45And\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,10), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(10,10), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(2,2), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(2,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,2), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + //result size == 8 + //result == 2 2 0 1 + //result == 2 2 2 1 + //result == 2 10 2 -1 + //result == 2 10 0 -1 + //result == 10 2 0 -1 + //result == 10 2 2 -1 + //result == 10 10 2 1 + //result == 10 10 0 1 + std::vector reference; + reference.push_back(Vertex45(Point(2, 2), 0, 1)); + reference.push_back(Vertex45(Point(2, 2), 2, 1)); + reference.push_back(Vertex45(Point(2, 10), 2, -1)); + reference.push_back(Vertex45(Point(2, 10), 0, -1)); + reference.push_back(Vertex45(Point(10, 2), 0, -1)); + reference.push_back(Vertex45(Point(10, 2), 2, -1)); + reference.push_back(Vertex45(Point(10, 10), 2, 1)); + reference.push_back(Vertex45(Point(10, 10), 0, 1)); + if(result != reference) { + stdcout << "result size == " << result.size() << std::endl; + for(std::size_t i = 0; i < result.size(); ++i) { + //stdcout << "result == " << result[i]<< std::endl; + } + stdcout << "reference size == " << reference.size() << std::endl; + for(std::size_t i = 0; i < reference.size(); ++i) { + //stdcout << "reference == " << reference[i]<< std::endl; + } + return false; + } + stdcout << "done testing Scan45And\n"; + return true; + } + + template + static inline bool testScan45Star1(stream_type& stdcout) { + stdcout << "testing Scan45Star1\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 24 + // result == 0 8 -1 1 + // result == 0 8 1 -1 + // result == 4 0 1 1 + // result == 4 0 2 1 + // result == 4 4 2 -1 + // result == 4 4 -1 -1 + // result == 4 12 1 1 + // result == 4 12 2 1 + // result == 4 16 2 -1 + // result == 4 16 -1 -1 + // result == 6 2 1 -1 + // result == 6 14 -1 1 + // result == 6 2 -1 1 + // result == 6 14 1 -1 + // result == 8 0 -1 -1 + // result == 8 0 2 -1 + // result == 8 4 2 1 + // result == 8 4 1 1 + // result == 8 12 -1 -1 + // result == 8 12 2 -1 + // result == 8 16 2 1 + // result == 8 16 1 1 + // result == 12 8 1 -1 + // result == 12 8 -1 1 + if(result.size() != 24) { + //stdcout << "result size == " << result.size() << std::endl; + //stdcout << "reference size == " << 24 << std::endl; + return false; + } + stdcout << "done testing Scan45Star1\n"; + return true; + } + + template + static inline bool testScan45Star2(stream_type& stdcout) { + stdcout << "testing Scan45Star2\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 24 + // result == 0 4 0 1 + // result == 0 4 1 -1 + // result == 0 8 -1 1 + // result == 0 8 0 -1 + // result == 2 6 1 1 + // result == 2 6 -1 -1 + // result == 4 4 0 -1 + // result == 4 8 0 1 + // result == 4 4 -1 1 + // result == 4 8 1 -1 + // result == 8 0 -1 -1 + // result == 8 0 1 1 + // result == 8 12 1 1 + // result == 8 12 -1 -1 + // result == 12 4 1 -1 + // result == 12 8 -1 1 + // result == 12 4 0 1 + // result == 12 8 0 -1 + // result == 14 6 -1 -1 + // result == 14 6 1 1 + // result == 16 4 0 -1 + // result == 16 4 -1 1 + // result == 16 8 1 -1 + // result == 16 8 0 1 + if(result.size() != 24) { + //std::cout << "result size == " << result.size() << std::endl; + //std::cout << "reference size == " << 24 << std::endl; + return false; + } + stdcout << "done testing Scan45Star2\n"; + return true; + } + + template + static inline bool testScan45Star3(stream_type& stdcout) { + stdcout << "testing Scan45Star3\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(8,16), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + + vertices.push_back(Scan45Vertex(Point(6,0), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(6,14), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,0), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(12,14), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(12,8), Scan45Count(count, Count2(0, 0), ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(4,0), Scan45Count(Count2(0, 0), Count2(0, 0), count, count))); + vertices.push_back(Scan45Vertex(Point(4,16), Scan45Count(ncount, Count2(0, 0), Count2(0, 0), ncount))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 28 + // result == 0 8 -1 1 + // result == 0 8 1 -1 + // result == 4 0 1 1 + // result == 4 0 2 1 + // result == 4 4 2 -1 + // result == 4 4 -1 -1 + // result == 4 12 1 1 + // result == 4 12 2 1 + // result == 4 16 2 -1 + // result == 4 16 -1 -1 + // result == 6 2 1 -1 + // result == 6 14 -1 1 + // result == 6 0 0 1 + // result == 6 0 2 1 + // result == 6 2 2 -1 + // result == 6 14 1 -1 + // result == 8 0 0 -1 + // result == 8 0 0 1 + // result == 8 14 0 -1 + // result == 8 14 2 -1 + // result == 8 16 2 1 + // result == 8 16 1 1 + // result == 12 0 0 -1 + // result == 12 0 2 -1 + // result == 12 8 2 1 + // result == 12 8 2 -1 + // result == 12 14 2 1 + // result == 12 14 0 1 + if(result.size() != 28) { + //std::cout << "result size == " << result.size() << std::endl; + //std::cout << "reference size == " << 28 << std::endl; + return false; + } + + stdcout << "done testing Scan45Star3\n"; + return true; + } + + + template + static inline bool testScan45Star4(stream_type& stdcout) { + stdcout << "testing Scan45Star4\n"; + Scan45 > scan45; + std::vector result; + typedef std::pair Scan45Vertex; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + + vertices.push_back(Scan45Vertex(Point(0,6), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + vertices.push_back(Scan45Vertex(Point(0,12), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(16,6), Scan45Count(Count2(0, 0), ncount, Count2(0, 0), ncount))); + vertices.push_back(Scan45Vertex(Point(16,12), Scan45Count(Count2(0, 0), count, Count2(0, 0), count))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + stdcout << "done scanning\n"; + // result size == 28 + // result == 0 4 0 1 + // result == 0 4 1 -1 + // result == 0 6 0 1 + // result == 0 6 2 1 + // result == 0 8 2 -1 + // result == 0 8 2 1 + // result == 0 12 2 -1 + // result == 0 12 0 -1 + // result == 2 6 1 1 + // result == 2 6 0 -1 + // result == 4 4 0 -1 + // result == 4 4 -1 1 + // result == 8 12 0 1 + // result == 8 0 -1 -1 + // result == 8 0 1 1 + // result == 8 12 0 -1 + // result == 12 4 1 -1 + // result == 12 4 0 1 + // result == 14 6 -1 -1 + // result == 14 6 0 1 + // result == 16 4 0 -1 + // result == 16 4 -1 1 + // result == 16 6 0 -1 + // result == 16 6 2 -1 + // result == 16 8 2 1 + // result == 16 8 2 -1 + // result == 16 12 2 1 + // result == 16 12 0 1 + if(result.size() != 28) { + //stdcout << "result size == " << result.size() << std::endl; + //stdcout << "reference size == " << 28 << std::endl; + return false; + } + + stdcout << "done testing Scan45Star4\n"; + return true; + } + + template + static inline bool testScan45(stream_type& stdcout) { + if(!testScan45Rect(stdcout)) return false; + if(!testScan45P1(stdcout)) return false; + if(!testScan45P2(stdcout)) return false; + if(!testScan45And(stdcout)) return false; + if(!testScan45Star1(stdcout)) return false; + if(!testScan45Star2(stdcout)) return false; + if(!testScan45Star3(stdcout)) return false; + if(!testScan45Star4(stdcout)) return false; + return true; + } + + }; + +} + +} +#endif diff --git a/include/boost/polygon/detail/iterator_compact_to_points.hpp b/include/boost/polygon/detail/iterator_compact_to_points.hpp new file mode 100644 index 0000000..9634e6f --- /dev/null +++ b/include/boost/polygon/detail/iterator_compact_to_points.hpp @@ -0,0 +1,69 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_ITERATOR_COMPACT_TO_POINTS_HPP +#define BOOST_POLYGON_ITERATOR_COMPACT_TO_POINTS_HPP +namespace boost { namespace polygon{ +template +class iterator_compact_to_points { +private: + iterator_type iter_; + iterator_type iter_end_; + point_type pt_; + typename point_traits::coordinate_type firstX_; + orientation_2d orient_; +public: + typedef std::forward_iterator_tag iterator_category; + typedef point_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const point_type* pointer; //immutable + typedef const point_type& reference; //immutable + + inline iterator_compact_to_points() : iter_(), iter_end_(), pt_(), firstX_(), orient_() {} + inline iterator_compact_to_points(iterator_type iter, iterator_type iter_end) : + iter_(iter), iter_end_(iter_end), pt_(), firstX_(), orient_(HORIZONTAL) { + if(iter_ != iter_end_) { + firstX_ = *iter_; + x(pt_, firstX_); + ++iter_; + if(iter_ != iter_end_) { + y(pt_, *iter_); + } + } + } + //use bitwise copy and assign provided by the compiler + inline iterator_compact_to_points& operator++() { + iterator_type prev_iter = iter_; + ++iter_; + if(iter_ == iter_end_) { + if(x(pt_) != firstX_) { + iter_ = prev_iter; + x(pt_, firstX_); + } + } else { + set(pt_, orient_, *iter_); + orient_.turn_90(); + } + return *this; + } + inline const iterator_compact_to_points operator++(int) { + iterator_compact_to_points tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_compact_to_points& that) const { + return (iter_ == that.iter_); + } + inline bool operator!=(const iterator_compact_to_points& that) const { + return (iter_ != that.iter_); + } + inline reference operator*() const { return pt_; } +}; +} +} +#endif + diff --git a/include/boost/polygon/detail/iterator_geometry_to_set.hpp b/include/boost/polygon/detail/iterator_geometry_to_set.hpp new file mode 100644 index 0000000..f784a8b --- /dev/null +++ b/include/boost/polygon/detail/iterator_geometry_to_set.hpp @@ -0,0 +1,309 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_ITERATOR_GEOMETRY_TO_SET_HPP +#define BOOST_POLYGON_ITERATOR_GEOMETRY_TO_SET_HPP +namespace boost { namespace polygon{ +template +class iterator_geometry_to_set {}; + +template +class iterator_geometry_to_set { +public: + typedef typename rectangle_traits::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable +private: + rectangle_data rectangle_; + mutable value_type vertex_; + unsigned int corner_; + orientation_2d orient_; + bool is_hole_; +public: + iterator_geometry_to_set() : rectangle_(), vertex_(), corner_(4), orient_(), is_hole_() {} + iterator_geometry_to_set(const rectangle_type& rectangle, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + rectangle_(), vertex_(), corner_(0), orient_(orient), is_hole_(is_hole) { + assign(rectangle_, rectangle); + if(dir == HIGH) corner_ = 4; + } + inline iterator_geometry_to_set& operator++() { + ++corner_; + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return corner_ == that.corner_; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + if(corner_ == 0) { + vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), LOW); + vertex_.second.first = get(get(rectangle_, orient_), LOW); + vertex_.second.second = 1; + if(is_hole_) vertex_.second.second *= -1; + } else if(corner_ == 1) { + vertex_.second.first = get(get(rectangle_, orient_), HIGH); + vertex_.second.second = -1; + if(is_hole_) vertex_.second.second *= -1; + } else if(corner_ == 2) { + vertex_.first = get(get(rectangle_, orient_.get_perpendicular()), HIGH); + vertex_.second.first = get(get(rectangle_, orient_), LOW); + } else { + vertex_.second.first = get(get(rectangle_, orient_), HIGH); + vertex_.second.second = 1; + if(is_hole_) vertex_.second.second *= -1; + } + return vertex_; + } +}; + +template +class iterator_geometry_to_set { +public: + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable + typedef typename polygon_traits::iterator_type coord_iterator_type; +private: + value_type vertex_; + typename polygon_traits::iterator_type itrb, itre; + bool last_vertex_; + bool is_hole_; + int multiplier_; + point_data first_pt, second_pt, pts[3]; + bool use_wrap; + orientation_2d orient_; + int polygon_index; +public: + iterator_geometry_to_set() : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) {} + iterator_geometry_to_set(const polygon_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool winding_override = false, direction_1d w = CLOCKWISE) : + vertex_(), itrb(), itre(), last_vertex_(), + is_hole_(is_hole), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), + orient_(orient), polygon_index(0) { + itrb = begin_points(polygon); + itre = end_points(polygon); + use_wrap = false; + if(itrb == itre || dir == HIGH || size(polygon) < 4) { + polygon_index = -1; + } else { + direction_1d wdir = w; + if(!winding_override) + wdir = winding(polygon); + multiplier_ = wdir == LOW ? -1 : 1; + if(is_hole_) multiplier_ *= -1; + first_pt = pts[0] = *itrb; + ++itrb; + second_pt = pts[1] = *itrb; + ++itrb; + pts[2] = *itrb; + evaluate_(); + } + } + iterator_geometry_to_set(const iterator_geometry_to_set& that) : + vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), + second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) { + vertex_ = that.vertex_; + itrb = that.itrb; + itre = that.itre; + last_vertex_ = that.last_vertex_; + is_hole_ = that.is_hole_; + multiplier_ = that.multiplier_; + first_pt = that.first_pt; + second_pt = that.second_pt; + pts[0] = that.pts[0]; + pts[1] = that.pts[1]; + pts[2] = that.pts[2]; + use_wrap = that.use_wrap; + orient_ = that.orient_; + polygon_index = that.polygon_index; + } + inline iterator_geometry_to_set& operator++() { + ++polygon_index; + if(itrb == itre) { + if(first_pt == pts[1]) polygon_index = -1; + else { + pts[0] = pts[1]; + pts[1] = pts[2]; + if(first_pt == pts[2]) { + pts[2] = second_pt; + } else { + pts[2] = first_pt; + } + } + } else { + ++itrb; + pts[0] = pts[1]; + pts[1] = pts[2]; + if(itrb == itre) { + if(first_pt == pts[2]) { + pts[2] = second_pt; + } else { + pts[2] = first_pt; + } + } else { + pts[2] = *itrb; + } + } + evaluate_(); + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return polygon_index == that.polygon_index; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + return vertex_; + } + + inline void evaluate_() { + vertex_.first = pts[1].get(orient_.get_perpendicular()); + vertex_.second.first =pts[1].get(orient_); + if(pts[1] == pts[2]) { + vertex_.second.second = 0; + } else if(pts[0].get(HORIZONTAL) != pts[1].get(HORIZONTAL)) { + vertex_.second.second = -1; + } else if(pts[0].get(VERTICAL) != pts[1].get(VERTICAL)) { + vertex_.second.second = 1; + } else { + vertex_.second.second = 0; + } + vertex_.second.second *= multiplier_; + } +}; + +template +class iterator_geometry_to_set { +public: + typedef typename polygon_90_traits::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::pair > value_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable +private: + iterator_geometry_to_set itrb, itre; + iterator_geometry_to_set::hole_type> itrhib, itrhie; + typename polygon_with_holes_traits::iterator_holes_type itrhb, itrhe; + orientation_2d orient_; + bool is_hole_; + bool started_holes; +public: + iterator_geometry_to_set() : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() {} + iterator_geometry_to_set(const polygon_with_holes_type& polygon, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(orient), is_hole_(is_hole), started_holes() { + itre = iterator_geometry_to_set(polygon, HIGH, orient, is_hole_); + itrhe = end_holes(polygon); + if(dir == HIGH) { + itrb = itre; + itrhb = itrhe; + started_holes = true; + } else { + itrb = iterator_geometry_to_set(polygon, LOW, orient, is_hole_); + itrhb = begin_holes(polygon); + started_holes = false; + } + } + iterator_geometry_to_set(const iterator_geometry_to_set& that) : + itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() { + itrb = that.itrb; + itre = that.itre; + if(that.itrhib != that.itrhie) { + itrhib = that.itrhib; + itrhie = that.itrhie; + } + itrhb = that.itrhb; + itrhe = that.itrhe; + orient_ = that.orient_; + is_hole_ = that.is_hole_; + started_holes = that.started_holes; + } + inline iterator_geometry_to_set& operator++() { + //this code can be folded with flow control factoring + if(itrb == itre) { + if(itrhib == itrhie) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } else { + itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + } + } else { + ++itrhib; + if(itrhib == itrhie) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } else { + itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + } + } + } + } else { + ++itrb; + if(itrb == itre) { + if(itrhb != itrhe) { + itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); + itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); + ++itrhb; + } + } + } + return *this; + } + inline const iterator_geometry_to_set operator++(int) { + iterator_geometry_to_set tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_geometry_to_set& that) const { + return itrb == that.itrb && itrhb == that.itrhb && itrhib == that.itrhib; + } + inline bool operator!=(const iterator_geometry_to_set& that) const { + return !(*this == that); + } + inline reference operator*() const { + if(itrb != itre) return *itrb; + return *itrhib; + } +}; + + +} +} +#endif + diff --git a/include/boost/polygon/detail/iterator_points_to_compact.hpp b/include/boost/polygon/detail/iterator_points_to_compact.hpp new file mode 100644 index 0000000..25ddb15 --- /dev/null +++ b/include/boost/polygon/detail/iterator_points_to_compact.hpp @@ -0,0 +1,60 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_ITERATOR_POINTS_TO_COMPACT_HPP +#define BOOST_POLYGON_ITERATOR_POINTS_TO_COMPACT_HPP +namespace boost { namespace polygon{ +template +class iterator_points_to_compact { +private: + iT iter_, iterEnd_; + orientation_2d orient_; + mutable typename point_traits::coordinate_type coord_; +public: + typedef typename point_traits::coordinate_type coordinate_type; + typedef std::forward_iterator_tag iterator_category; + typedef coordinate_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const coordinate_type* pointer; //immutable + typedef const coordinate_type& reference; //immutable + + inline iterator_points_to_compact() : iter_(), iterEnd_(), orient_(), coord_() {} + inline iterator_points_to_compact(iT iter, iT iterEnd) : + iter_(iter), iterEnd_(iterEnd), orient_(HORIZONTAL), coord_() {} + inline iterator_points_to_compact(const iterator_points_to_compact& that) : + iter_(that.iter_), iterEnd_(that.iterEnd_), orient_(that.orient_), coord_(that.coord_) {} + //use bitwise copy and assign provided by the compiler + inline iterator_points_to_compact& operator++() { + //iT tmp = iter_; + ++iter_; + //iT tmp2 = iter_; + orient_.turn_90(); + //while(tmp2 != iterEnd_ && get(*tmp2, orient_) == get(*tmp, orient_)) { + // iter_ = tmp2; + // ++tmp2; + //} + return *this; + } + inline const iterator_points_to_compact operator++(int) { + iT tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_points_to_compact& that) const { + return (iter_ == that.iter_); + } + inline bool operator!=(const iterator_points_to_compact& that) const { + return (iter_ != that.iter_); + } + inline reference operator*() const { coord_ = get(*iter_, orient_); + return coord_; + } +}; +} +} +#endif + diff --git a/include/boost/polygon/detail/max_cover.hpp b/include/boost/polygon/detail/max_cover.hpp new file mode 100644 index 0000000..68ef4b6 --- /dev/null +++ b/include/boost/polygon/detail/max_cover.hpp @@ -0,0 +1,278 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_MAX_COVER_HPP +#define BOOST_POLYGON_MAX_COVER_HPP +namespace boost { namespace polygon{ + + template + struct MaxCover { + typedef interval_data Interval; + typedef rectangle_data Rectangle; + + class Node { + private: + std::vector children_; + std::set tracedPaths_; + public: + Rectangle rect; + Node() : children_(), tracedPaths_(), rect() {} + Node(const Rectangle rectIn) : children_(), tracedPaths_(), rect(rectIn) {} + typedef typename std::vector::iterator iterator; + inline iterator begin() { return children_.begin(); } + inline iterator end() { return children_.end(); } + inline void add(Node* child) { children_.push_back(child); } + inline bool tracedPath(const Interval& ivl) const { + return tracedPaths_.find(ivl) != tracedPaths_.end(); + } + inline void addPath(const Interval& ivl) { + tracedPaths_.insert(tracedPaths_.end(), ivl); + } + }; + + typedef std::pair, Node* > EdgeAssociation; + + class lessEdgeAssociation : public std::binary_function { + public: + inline lessEdgeAssociation() {} + inline bool operator () (const EdgeAssociation& elem1, const EdgeAssociation& elem2) const { + if(elem1.first.first < elem2.first.first) return true; + if(elem1.first.first > elem2.first.first) return false; + return elem1.first.second < elem2.first.second; + } + }; + + template + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient) { + Interval rectIvl = node->rect.get(orient); + if(node->tracedPath(rectIvl)) { + return; + } + node->addPath(rectIvl); + if(node->begin() == node->end()) { + //std::cout << "WRITE OUT 3: " << node->rect << std::endl; + outputContainer.push_back(copy_construct(node->rect)); + return; + } + bool writeOut = true; + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + getMaxCover(outputContainer, *itr, orient, node->rect); //get rectangles down path + Interval nodeIvl = (*itr)->rect.get(orient); + if(contains(nodeIvl, rectIvl, true)) writeOut = false; + } + if(writeOut) { + //std::cout << "WRITE OUT 2: " << node->rect << std::endl; + outputContainer.push_back(copy_construct(node->rect)); + } + } + + struct stack_element { + inline stack_element() : + node(), rect(), itr() {} + inline stack_element(Node* n, + const Rectangle& r, + typename Node::iterator i) : + node(n), rect(r), itr(i) {} + Node* node; + Rectangle rect; + typename Node::iterator itr; + }; + + template + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + Rectangle rect) { + //std::cout << "New Root\n"; + std::vector stack; + typename Node::iterator itr = node->begin(); + do { + //std::cout << "LOOP\n"; + //std::cout << node->rect << std::endl; + Interval rectIvl = rect.get(orient); + Interval nodeIvl = node->rect.get(orient); + bool iresult = intersect(rectIvl, nodeIvl, false); + bool tresult = !node->tracedPath(rectIvl); + //std::cout << (itr != node->end()) << " " << iresult << " " << tresult << std::endl; + Rectangle nextRect1 = Rectangle(rectIvl, rectIvl); + Unit low = rect.get(orient.get_perpendicular()).low(); + Unit high = node->rect.get(orient.get_perpendicular()).high(); + nextRect1.set(orient.get_perpendicular(), Interval(low, high)); + if(iresult && tresult) { + node->addPath(rectIvl); + bool writeOut = true; + //check further visibility beyond this node + for(typename Node::iterator itr2 = node->begin(); itr2 != node->end(); ++itr2) { + Interval nodeIvl3 = (*itr2)->rect.get(orient); + //if a child of this node can contain the interval then we can extend through + if(contains(nodeIvl3, rectIvl, true)) writeOut = false; + //std::cout << "child " << (*itr2)->rect << std::endl; + } + Rectangle nextRect2 = Rectangle(rectIvl, rectIvl); + Unit low2 = rect.get(orient.get_perpendicular()).low(); + Unit high2 = node->rect.get(orient.get_perpendicular()).high(); + nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); + if(writeOut) { + //std::cout << "write out " << nextRect << std::endl; + outputContainer.push_back(copy_construct(nextRect2)); + } else { + //std::cout << "supress " << nextRect << std::endl; + } + } + if(itr != node->end() && iresult && tresult) { + //std::cout << "recurse into child\n"; + stack.push_back(stack_element(node, rect, itr)); + rect = nextRect1; + node = *itr; + itr = node->begin(); + } else { + if(!stack.empty()) { + //std::cout << "recurse out of child\n"; + node = stack.back().node; + rect = stack.back().rect; + itr = stack.back().itr; + stack.pop_back(); + } else { + //std::cout << "empty stack\n"; + //if there were no children of the root node +// Rectangle nextRect = Rectangle(rectIvl, rectIvl); +// Unit low = rect.get(orient.get_perpendicular()).low(); +// Unit high = node->rect.get(orient.get_perpendicular()).high(); +// nextRect.set(orient.get_perpendicular(), Interval(low, high)); +// outputContainer.push_back(copy_construct(nextRect)); + } + //std::cout << "increment " << (itr != node->end()) << std::endl; + if(itr != node->end()) { + ++itr; + if(itr != node->end()) { + //std::cout << "recurse into next child.\n"; + stack.push_back(stack_element(node, rect, itr)); + Interval rectIvl2 = rect.get(orient); + Interval nodeIvl2 = node->rect.get(orient); + /*bool iresult =*/ intersect(rectIvl2, nodeIvl2, false); + Rectangle nextRect2 = Rectangle(rectIvl2, rectIvl2); + Unit low2 = rect.get(orient.get_perpendicular()).low(); + Unit high2 = node->rect.get(orient.get_perpendicular()).high(); + nextRect2.set(orient.get_perpendicular(), Interval(low2, high2)); + rect = nextRect2; + //std::cout << "rect for next child" << rect << std::endl; + node = *itr; + itr = node->begin(); + } + } + } + } while(!stack.empty() || itr != node->end()); + } + + /* Function recursive version of getMaxCover + Because the code is so much simpler than the loop algorithm I retain it for clarity + + template + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + const Rectangle& rect) { + Interval rectIvl = rect.get(orient); + Interval nodeIvl = node->rect.get(orient); + if(!intersect(rectIvl, nodeIvl, false)) { + return; + } + if(node->tracedPath(rectIvl)) { + return; + } + node->addPath(rectIvl); + Rectangle nextRect(rectIvl, rectIvl); + Unit low = rect.get(orient.get_perpendicular()).low(); + Unit high = node->rect.get(orient.get_perpendicular()).high(); + nextRect.set(orient.get_perpendicular(), Interval(low, high)); + bool writeOut = true; + rectIvl = nextRect.get(orient); + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + nodeIvl = (*itr)->rect.get(orient); + if(contains(nodeIvl, rectIvl, true)) writeOut = false; + } + if(writeOut) { + outputContainer.push_back(copy_construct(nextRect)); + } + for(typename Node::iterator itr = node->begin(); itr != node->end(); ++itr) { + getMaxCover(outputContainer, *itr, orient, nextRect); + } + } + */ + + //iterator range is assummed to be in topological order meaning all node's trailing + //edges are in sorted order + template + static inline void computeDag(iT beginNode, iT endNode, orientation_2d orient, + std::size_t size) { + std::vector leadingEdges; + leadingEdges.reserve(size); + for(iT iter = beginNode; iter != endNode; ++iter) { + Node* nodep = &(*iter); + Unit leading = nodep->rect.get(orient.get_perpendicular()).low(); + Interval rectIvl = nodep->rect.get(orient); + leadingEdges.push_back(EdgeAssociation(std::pair(leading, rectIvl), nodep)); + } + std::sort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); + typename std::vector::iterator leadingBegin = leadingEdges.begin(); + iT trailingBegin = beginNode; + while(leadingBegin != leadingEdges.end()) { + EdgeAssociation& leadingSegment = (*leadingBegin); + Unit trailing = (*trailingBegin).rect.get(orient.get_perpendicular()).high(); + Interval ivl = (*trailingBegin).rect.get(orient); + std::pair trailingSegment(trailing, ivl); + if(leadingSegment.first.first < trailingSegment.first) { + ++leadingBegin; + continue; + } + if(leadingSegment.first.first > trailingSegment.first) { + ++trailingBegin; + continue; + } + if(leadingSegment.first.second.high() <= trailingSegment.second.low()) { + ++leadingBegin; + continue; + } + if(trailingSegment.second.high() <= leadingSegment.first.second.low()) { + ++trailingBegin; + continue; + } + //leading segment intersects trailing segment + (*trailingBegin).add((*leadingBegin).second); + if(leadingSegment.first.second.high() > trailingSegment.second.high()) { + ++trailingBegin; + continue; + } + if(trailingSegment.second.high() > leadingSegment.first.second.high()) { + ++leadingBegin; + continue; + } + ++leadingBegin; + ++trailingBegin; + } + } + + template + static inline void getMaxCover(cT& outputContainer, + const std::vector& rects, orientation_2d orient) { + if(rects.empty()) return; + std::vector nodes; + { + if(rects.size() == 1) { + outputContainer.push_back(copy_construct(rects[0])); + return; + } + nodes.reserve(rects.size()); + for(std::size_t i = 0; i < rects.size(); ++i) { nodes.push_back(Node(rects[i])); } + } + computeDag(nodes.begin(), nodes.end(), orient, nodes.size()); + for(std::size_t i = 0; i < nodes.size(); ++i) { + getMaxCover(outputContainer, &(nodes[i]), orient); + } + } + + }; +} +} + +#endif diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp new file mode 100644 index 0000000..8596c8b --- /dev/null +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -0,0 +1,2251 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_45_FORMATION_HPP +namespace boost { namespace polygon{ + + template + struct PolyLineByConcept {}; + + template + class PolyLine45PolygonData; + template + class PolyLine45HoleData; + + //polygon45formation algorithm + template + struct polygon_45_formation : public boolean_op_45 { + typedef point_data Point; + typedef polygon_45_data Polygon45; + typedef polygon_45_with_holes_data Polygon45WithHoles; + typedef typename boolean_op_45::Vertex45 Vertex45; + typedef typename boolean_op_45::lessVertex45 lessVertex45; + typedef typename boolean_op_45::Count2 Count2; + typedef typename boolean_op_45::Scan45Count Scan45Count; + typedef std::pair Scan45Vertex; + typedef typename boolean_op_45::template + Scan45::template boolean_op_45_output_functor<0> > Scan45; + + class PolyLine45 { + public: + typedef typename std::list::const_iterator iterator; + + // default constructor of point does not initialize x and y + inline PolyLine45() : points() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline PolyLine45& set(iT inputBegin, iT inputEnd) { + points.clear(); //just in case there was some old data there + while(inputBegin != inputEnd) { + points.insert(points.end(), *inputBegin); + ++inputBegin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline PolyLine45(const PolyLine45& that) : points(that.points) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline PolyLine45& operator=(const PolyLine45& that) { + points = that.points; + return *this; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator begin() const { return points.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator end() const { return points.end(); } + + inline std::size_t size() const { return points.size(); } + + //public data member + std::list points; + }; + + class ActiveTail45 { + private: + //data + PolyLine45* tailp_; + ActiveTail45 *otherTailp_; + std::list holesList_; + bool head_; + public: + + /** + * @brief iterator over coordinates of the figure + */ + typedef typename PolyLine45::iterator iterator; + + /** + * @brief iterator over holes contained within the figure + */ + typedef typename std::list::const_iterator iteratorHoles; + + //default constructor + inline ActiveTail45() : tailp_(0), otherTailp_(0), holesList_(), head_(0) {} + + //constructor + inline ActiveTail45(const Vertex45& vertex, ActiveTail45* otherTailp = 0) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = new PolyLine45; + tailp_->points.push_back(vertex.pt); + bool headArray[4] = {false, true, true, true}; + bool inverted = vertex.count == -1; + head_ = headArray[vertex.rise+1] ^ inverted; + otherTailp_ = otherTailp; + } + + inline ActiveTail45(Point point, ActiveTail45* otherTailp, bool head = true) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = new PolyLine45; + tailp_->points.push_back(point); + head_ = head; + otherTailp_ = otherTailp; + + } + inline ActiveTail45(ActiveTail45* otherTailp) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { + tailp_ = otherTailp->tailp_; + otherTailp_ = otherTailp; + } + + //copy constructor + inline ActiveTail45(const ActiveTail45& that) : + tailp_(0), otherTailp_(0), holesList_(), head_(0) { (*this) = that; } + + //destructor + inline ~ActiveTail45() { + destroyContents(); + } + + //assignment operator + inline ActiveTail45& operator=(const ActiveTail45& that) { + tailp_ = new PolyLine45(*(that.tailp_)); + head_ = that.head_; + otherTailp_ = that.otherTailp_; + holesList_ = that.holesList_; + return *this; + } + + //equivalence operator + inline bool operator==(const ActiveTail45& b) const { + return tailp_ == b.tailp_ && head_ == b.head_; + } + + /** + * @brief get the pointer to the polyline that this is an active tail of + */ + inline PolyLine45* getTail() const { return tailp_; } + + /** + * @brief get the pointer to the polyline at the other end of the chain + */ + inline PolyLine45* getOtherTail() const { return otherTailp_->tailp_; } + + /** + * @brief get the pointer to the activetail at the other end of the chain + */ + inline ActiveTail45* getOtherActiveTail() const { return otherTailp_; } + + /** + * @brief test if another active tail is the other end of the chain + */ + inline bool isOtherTail(const ActiveTail45& b) const { return &b == otherTailp_; } + + /** + * @brief update this end of chain pointer to new polyline + */ + inline ActiveTail45& updateTail(PolyLine45* newTail) { tailp_ = newTail; return *this; } + + inline bool join(ActiveTail45* tail) { + if(tail == otherTailp_) { + //std::cout << "joining to other tail!\n"; + return false; + } + if(tail->head_ == head_) { + //std::cout << "joining head to head!\n"; + return false; + } + if(!tailp_) { + //std::cout << "joining empty tail!\n"; + return false; + } + if(!(otherTailp_->head_)) { + otherTailp_->copyHoles(*tail); + otherTailp_->copyHoles(*this); + } else { + tail->otherTailp_->copyHoles(*this); + tail->otherTailp_->copyHoles(*tail); + } + PolyLine45* tail1 = tailp_; + PolyLine45* tail2 = tail->tailp_; + if(head_) std::swap(tail1, tail2); + tail1->points.splice(tail1->points.end(), tail2->points); + delete tail2; + otherTailp_->tailp_ = tail1; + tail->otherTailp_->tailp_ = tail1; + otherTailp_->otherTailp_ = tail->otherTailp_; + tail->otherTailp_->otherTailp_ = otherTailp_; + tailp_ = 0; + tail->tailp_ = 0; + tail->otherTailp_ = 0; + otherTailp_ = 0; + return true; + } + + /** + * @brief associate a hole to this active tail by the specified policy + */ + inline ActiveTail45* addHole(ActiveTail45* hole) { + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->otherTailp_)); + return this; + } + + /** + * @brief get the list of holes + */ + inline const std::list& getHoles() const { return holesList_; } + + /** + * @brief copy holes from that to this + */ + inline void copyHoles(ActiveTail45& that) { holesList_.splice(holesList_.end(), that.holesList_); } + + /** + * @brief find out if solid to right + */ + inline bool solidToRight() const { return !head_; } + inline bool solidToLeft() const { return head_; } + + /** + * @brief get vertex + */ + inline Point getPoint() const { + if(head_) return tailp_->points.front(); + return tailp_->points.back(); + } + + /** + * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + inline void pushPoint(Point point) { + if(head_) { + //if(tailp_->points.size() < 2) { + // tailp_->points.push_front(point); + // return; + //} + typename std::list::iterator iter = tailp_->points.begin(); + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + Unit firstY = (*iter).y(); + ++iter; + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + if(iter->y() == point.y() && firstY == point.y()) { + --iter; + *iter = point; + } else { + tailp_->points.push_front(point); + } + return; + } + //if(tailp_->points.size() < 2) { + // tailp_->points.push_back(point); + // return; + //} + typename std::list::reverse_iterator iter = tailp_->points.rbegin(); + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + Unit firstY = (*iter).y(); + ++iter; + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + if(iter->y() == point.y() && firstY == point.y()) { + --iter; + *iter = point; + } else { + tailp_->points.push_back(point); + } + } + + /** + * @brief joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + + template + static inline ActiveTail45* joinChains(Point point, ActiveTail45* at1, ActiveTail45* at2, bool solid, + cT& output) { + if(at1->otherTailp_ == at2) { + //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; + //we are closing a figure + at1->pushPoint(point); + at2->pushPoint(point); + if(solid) { + //we are closing a solid figure, write to output + //std::cout << "test1\n"; + at1->copyHoles(*(at1->otherTailp_)); + //std::cout << "test2\n"; + //Polygon45WithHolesImpl poly(polyData); + //std::cout << poly << std::endl; + //std::cout << "test3\n"; + typedef typename cT::value_type pType; + output.push_back(pType()); + typedef typename geometry_concept::type cType; + typename PolyLineByConcept::type polyData(at1); + assign(output.back(), polyData); + //std::cout << "test4\n"; + //std::cout << "delete " << at1->otherTailp_ << std::endl; + //at1->print(); + //at1->otherTailp_->print(); + delete at1->otherTailp_; + //at1->print(); + //at1->otherTailp_->print(); + //std::cout << "test5\n"; + //std::cout << "delete " << at1 << std::endl; + delete at1; + //std::cout << "test6\n"; + return 0; + } else { + //we are closing a hole, return the tail end active tail of the figure + return at1; + } + } + //we are not closing a figure + at1->pushPoint(point); + at1->join(at2); + delete at1; + delete at2; + return 0; + } + + inline void destroyContents() { + if(otherTailp_) { + //std::cout << "delete p " << tailp_ << std::endl; + if(tailp_) delete tailp_; + tailp_ = 0; + otherTailp_->otherTailp_ = 0; + otherTailp_->tailp_ = 0; + otherTailp_ = 0; + } + for(typename std::list::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { + //std::cout << "delete p " << (*itr) << std::endl; + if(*itr) { + if((*itr)->otherTailp_) { + delete (*itr)->otherTailp_; + (*itr)->otherTailp_ = 0; + } + delete (*itr); + } + (*itr) = 0; + } + holesList_.clear(); + } + +// inline void print() { +// std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; +// } + + static inline std::pair createActiveTail45sAsPair(Point point, bool solid, + ActiveTail45* phole, bool fractureHoles) { + ActiveTail45* at1 = 0; + ActiveTail45* at2 = 0; + if(phole && fractureHoles) { + //std::cout << "adding hole\n"; + at1 = phole; + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at2 = at1->getOtherActiveTail(); + at2->pushPoint(point); + at1->pushPoint(point); + } else { + at1 = new ActiveTail45(point, at2, solid); + at2 = new ActiveTail45(at1); + at1->otherTailp_ = at2; + at2->head_ = !solid; + if(phole) + at2->addHole(phole); //assert fractureHoles == false + } + return std::pair(at1, at2); + } + + }; + + template + class Vertex45CountT { + public: + typedef ct count_type; + inline Vertex45CountT() +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = counts[1] = counts[2] = counts[3] = 0; } + //inline Vertex45CountT(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; } + inline Vertex45CountT(const ct& count1, const ct& count2, const ct& count3, + const ct& count4) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + counts[0] = count1; + counts[1] = count2; + counts[2] = count3; + counts[3] = count4; + } + inline Vertex45CountT(const Vertex45& vertex) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + counts[0] = counts[1] = counts[2] = counts[3] = 0; + (*this) += vertex; + } + inline Vertex45CountT(const Vertex45CountT& count) +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + (*this) = count; + } + inline bool operator==(const Vertex45CountT& count) const { + for(unsigned int i = 0; i < 4; ++i) { + if(counts[i] != count.counts[i]) return false; + } + return true; + } + inline bool operator!=(const Vertex45CountT& count) const { return !((*this) == count); } + inline Vertex45CountT& operator=(ct count) { + counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } + inline Vertex45CountT& operator=(const Vertex45CountT& count) { + for(unsigned int i = 0; i < 4; ++i) { + counts[i] = count.counts[i]; + } + return *this; + } + inline ct& operator[](int index) { return counts[index]; } + inline ct operator[](int index) const {return counts[index]; } + inline Vertex45CountT& operator+=(const Vertex45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] += count.counts[i]; + } + return *this; + } + inline Vertex45CountT& operator-=(const Vertex45CountT& count){ + for(unsigned int i = 0; i < 4; ++i) { + counts[i] -= count.counts[i]; + } + return *this; + } + inline Vertex45CountT operator+(const Vertex45CountT& count) const { + return Vertex45CountT(*this)+=count; + } + inline Vertex45CountT operator-(const Vertex45CountT& count) const { + return Vertex45CountT(*this)-=count; + } + inline Vertex45CountT invert() const { + return Vertex45CountT()-=(*this); + } + inline Vertex45CountT& operator+=(const Vertex45& element){ + counts[element.rise+1] += element.count; return *this; + } + inline bool is_45() const { + return counts[0] != 0 || counts[2] != 0; + } + private: + ct counts[4]; + }; + + typedef Vertex45CountT Vertex45Count; + +// inline std::ostream& operator<< (std::ostream& o, const Vertex45Count& c) { +// o << c[0] << ", " << c[1] << ", "; +// o << c[2] << ", " << c[3]; +// return o; +// } + + template + class Vertex45CompactT { + public: + Point pt; + ct count; + typedef typename boolean_op_45::template Vertex45T Vertex45T; + inline Vertex45CompactT() : pt(), count() {} + inline Vertex45CompactT(const Point& point, int riseIn, int countIn) : pt(point), count() { + count[riseIn+1] = countIn; + } + template + inline Vertex45CompactT(const typename boolean_op_45::template Vertex45T& vertex) : pt(vertex.pt), count() { + count[vertex.rise+1] = vertex.count; + } + inline Vertex45CompactT(const Vertex45CompactT& vertex) : pt(vertex.pt), count(vertex.count) {} + inline Vertex45CompactT& operator=(const Vertex45CompactT& vertex){ + pt = vertex.pt; count = vertex.count; return *this; } + inline bool operator==(const Vertex45CompactT& vertex) const { + return pt == vertex.pt && count == vertex.count; } + inline bool operator!=(const Vertex45CompactT& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair& vertex) const { return false; } + inline bool operator!=(const std::pair& vertex) const { return !((*this) == vertex); } + inline bool operator<(const Vertex45CompactT& vertex) const { + if(pt.x() < vertex.pt.x()) return true; + if(pt.x() == vertex.pt.x()) { + return pt.y() < vertex.pt.y(); + } + return false; + } + inline bool operator>(const Vertex45CompactT& vertex) const { return vertex < (*this); } + inline bool operator<=(const Vertex45CompactT& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const Vertex45CompactT& vertex) const { return !((*this) < vertex); } + inline bool haveVertex45(int index) const { return count[index]; } + inline Vertex45T operator[](int index) const { + return Vertex45T(pt, index-1, count[index]); } + }; + + typedef Vertex45CompactT Vertex45Compact; + +// inline std::ostream& operator<< (std::ostream& o, const Vertex45Compact& c) { +// o << c.pt << ", " << c.count; +// return o; +// } + + class Polygon45Formation { + private: + //definitions + typedef std::map Polygon45FormationData; + typedef typename Polygon45FormationData::iterator iterator; + typedef typename Polygon45FormationData::const_iterator const_iterator; + + //data + Polygon45FormationData scanData_; + Unit x_; + int justBefore_; + int fractureHoles_; + public: + inline Polygon45Formation() : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Formation(bool fractureHoles) : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(fractureHoles) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Formation(const Polygon45Formation& that) : + scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } + inline Polygon45Formation& operator=(const Polygon45Formation& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + fractureHoles_ = that.fractureHoles_; + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over Vertex45 elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.x(); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + + private: + //functions + template + inline std::pair processPoint_(cT& output, cT2& elements, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + //std::cout << point << std::endl; + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + //join any closing solid corners + ActiveTail45* returnValue = 0; + int returnCount = 0; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == 3) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount = 1; + } else { + Vertex45 vertex(point, i -1, incoming[i]); + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + elements.push_back(std::pair(Vertex45(point, j -1, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + elements.push_back(std::pair(Vertex45(point, i -1, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + //std::cout << "checking case 3\n"; + for(int i = 0; i < 4; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = 3; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == 3) { + returnValue = tails[i]; + returnCount = -1; + } else { + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + for(int i = 3; i >= 0; --i) { + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < 4; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + tails[i]->pushPoint(point); + if(j == 3) { + returnValue = tails[i]; + returnCount = 1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + + //find the end of a hole or the beginning of a hole + + //find end of a hole + for(int i = 0; i < 3; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + returnValue = ActiveTail45::joinChains(point, tails[i], tails[j], false, output); + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + //find beginning of a hole + for(int i = 0; i < 3; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + ActiveTail45* holep = 0; + if(counts[3] == 0) holep = tails[3]; + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(point, false, holep, fractureHoles_ != 0); + if(j == 3) { + returnValue = tailPair.first; + returnCount = -1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + elements.push_back(std::pair(Vertex45(point, i -1, incoming[i]), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + //assert that tails, counts and incoming are all null + return std::pair(returnCount, returnValue); + } + + template + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + ActiveTail45* verticalTail = 0; + int verticalCount = 0; + iT currentIter = inputBegin; + std::vector elementIters; + std::vector > elements; + while(currentIter != inputEnd && currentIter->pt.x() == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.y(); + iterator iter = lookUp_(currentY); + //int counts[4] = {0, 0, 0, 0}; + Vertex45Count counts; + ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; + //std::cout << "finding elements in tree\n"; + while(iter != scanData_.end() && + iter->first.evalAtX(x_) == currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + int index = iter->first.rise + 1; + //std::cout << index << " " << iter->first.count << std::endl; + counts[index] = iter->first.count; + tails[index] = iter->second; + ++iter; + } + //int incoming[4] = {0, 0, 0, 0}; + Vertex45Count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + Vertex45Compact currentVertex(*currentIter); + incoming += currentVertex.count; + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.y() == currentY && + currentIter->pt.x() == x_); + //now counts and tails have the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + if(verticalTail) { + counts[3] = -verticalCount; + } + incoming[3] *= -1; + for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; + //std::cout << "calling processPoint_\n"; + std::pair result = processPoint_(output, elements, Point(x_, currentY), counts, tails, incoming); + verticalCount = result.first; + verticalTail = result.second; + //if(verticalTail) std::cout << "have vertical tail\n"; + //std::cout << "verticalCount: " << verticalCount << std::endl; + if(verticalTail && !verticalCount) { + //we got a hole out of the point we just processed + //iter is still at the next y element above the current y value in the tree + //std::cout << "checking whether ot handle hole\n"; + if(currentIter == inputEnd || + currentIter->pt.x() != x_ || + currentIter->pt.y() >= iter->first.evalAtX(x_)) { + //std::cout << "handle hole here\n"; + if(fractureHoles_) { + //std::cout << "fracture hole here\n"; + //we need to handle the hole now and not at the next input vertex + ActiveTail45* at = iter->second; + Point point(x_, iter->first.evalAtX(x_)); + verticalTail->getOtherActiveTail()->pushPoint(point); + iter->second = verticalTail->getOtherActiveTail(); + at->pushPoint(point); + verticalTail->join(at); + delete at; + delete verticalTail; + verticalTail = 0; + } else { + //std::cout << "push hole onto list\n"; + iter->second->addHole(verticalTail); + verticalTail = 0; + } + } + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); + } + + }; + + template + static inline bool testPolygon45FormationRect(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygon45FormationP1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 1, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 20), 2, 1)); + data.push_back(Vertex45(Point(10, 20), 1, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + //polygon45set class + + template + static inline bool testPolygon45FormationP2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 1, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 1, -1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + //polygon45set class + + template + static inline bool testPolygon45FormationStar1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygon45FormationStar2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + Scan45 scan45; + std::vector result; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + + std::sort(result.begin(), result.end()); + pf.scan(polys, result.begin(), result.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygon45FormationStarHole1(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(true); + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 8), -1, 1)); + data.push_back(Vertex45(Point(6, 8), 2, 1)); + data.push_back(Vertex45(Point(8, 6), -1, -1)); + data.push_back(Vertex45(Point(8, 6), 1, 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygon45FormationStarHole2(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(false); + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 12), -1, 1)); + data.push_back(Vertex45(Point(6, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 8), -1, -1)); + data.push_back(Vertex45(Point(10, 8), 1, 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygon45Formation(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + Polygon45Formation pf(false); + std::vector polys; + std::vector data; + + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 100), 2, -1)); + data.push_back(Vertex45(Point(0, 100), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 2, -1)); + data.push_back(Vertex45(Point(100, 100), 2, 1)); + data.push_back(Vertex45(Point(100, 100), 0, 1)); + + data.push_back(Vertex45(Point(2, 2), 0, -1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 10), 2, 1)); + data.push_back(Vertex45(Point(2, 10), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + + data.push_back(Vertex45(Point(2, 12), 0, -1)); + data.push_back(Vertex45(Point(2, 12), 2, -1)); + data.push_back(Vertex45(Point(2, 22), 2, 1)); + data.push_back(Vertex45(Point(2, 22), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 22), 2, -1)); + data.push_back(Vertex45(Point(10, 22), 0, -1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + + class Polygon45Tiling { + private: + //definitions + typedef std::map Polygon45FormationData; + typedef typename Polygon45FormationData::iterator iterator; + typedef typename Polygon45FormationData::const_iterator const_iterator; + + //data + Polygon45FormationData scanData_; + Unit x_; + int justBefore_; + public: + inline Polygon45Tiling() : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false) { + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + } + inline Polygon45Tiling(const Polygon45Tiling& that) : + scanData_(), x_((std::numeric_limits::min)()), justBefore_(false) { (*this) = that; } + inline Polygon45Tiling& operator=(const Polygon45Tiling& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + lessVertex45 lessElm(&x_, &justBefore_); + scanData_ = Polygon45FormationData(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over Vertex45 elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.x(); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + } + + private: + //functions + + inline void getVerticalPair_(std::pair& verticalPair, + iterator previter) { + ActiveTail45* iterTail = (*previter).second; + Point prevPoint(x_, previter->first.evalAtX(x_)); + iterTail->pushPoint(prevPoint); + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(prevPoint, true, 0, false); + verticalPair.first = iterTail; + verticalPair.second = tailPair.first; + (*previter).second = tailPair.second; + } + + template + inline std::pair processPoint_(cT& output, cT2& elements, + std::pair& verticalPair, + iterator previter, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + //std::cout << point << std::endl; + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + //join any closing solid corners + ActiveTail45* returnValue = 0; + std::pair verticalPairOut; + verticalPairOut.first = 0; + verticalPairOut.second = 0; + int returnCount = 0; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + for(int i = 0; i < 3; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < 4; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == 3) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount = 1; + } else { + Vertex45 vertex(point, i -1, incoming[i]); + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + elements.push_back(std::pair(Vertex45(point, j -1, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + elements.push_back(std::pair(Vertex45(point, i -1, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + //std::cout << "checking case 3\n"; + for(int i = 0; i < 4; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = 3; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + if(i != 3) + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == 3) { + returnValue = tails[i]; + returnCount = -1; + } else { + verticalPairOut.first = tails[i]; + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + verticalPairOut.second = tailPair.first; + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), + tailPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + for(int i = 3; i >= 0; --i) { + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < 4; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + if(i == 3) { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + if(j == 3) { + returnValue = tails[i]; + returnCount = 1; + } else { + tails[i]->pushPoint(point); + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tails[i])); + } + } else if(j == 3) { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + returnValue = verticalPair.second; + returnCount = 1; + } else { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + verticalPair.second->pushPoint(point); + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), + verticalPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + + //find the end of a hole or the beginning of a hole + + //find end of a hole + for(int i = 0; i < 3; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + tails[i]->pushPoint(point); + verticalPairOut.first = tails[i]; + if(j == 3) { + verticalPairOut.second = tails[j]; + } else { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + ActiveTail45::joinChains(point, tails[j], verticalPair.first, true, output); + verticalPairOut.second = verticalPair.second; + } + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + //find beginning of a hole + for(int i = 0; i < 3; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < 4; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + verticalPair.second->pushPoint(point); + if(j == 3) { + returnValue = verticalPair.first; + returnCount = -1; + } else { + std::pair tailPair = + ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.second)); + verticalPairOut.second = tailPair.first; + verticalPairOut.first = verticalPair.first; + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + elements.push_back(std::pair(Vertex45(point, i -1, incoming[i]), verticalPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + verticalPair = verticalPairOut; + //assert that verticalPair is either both null, or neither null + //assert that returnValue is null if verticalPair is not null + //assert that tails, counts and incoming are all null + return std::pair(returnCount, returnValue); + } + + template + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + ActiveTail45* verticalTail = 0; + std::pair verticalPair; + verticalPair.first = 0; + verticalPair.second = 0; + int verticalCount = 0; + iT currentIter = inputBegin; + std::vector elementIters; + std::vector > elements; + while(currentIter != inputEnd && currentIter->pt.x() == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.y(); + iterator iter = lookUp_(currentY); + //int counts[4] = {0, 0, 0, 0}; + Vertex45Count counts; + ActiveTail45* tails[4] = {0, 0, 0, verticalTail}; + //std::cout << "finding elements in tree\n"; + iterator previter = iter; + if(previter != scanData_.end() && + previter->first.evalAtX(x_) >= currentY && + previter != scanData_.begin()) + --previter; + while(iter != scanData_.end() && + iter->first.evalAtX(x_) == currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + int index = iter->first.rise + 1; + //std::cout << index << " " << iter->first.count << std::endl; + counts[index] = iter->first.count; + tails[index] = iter->second; + ++iter; + } + //int incoming[4] = {0, 0, 0, 0}; + Vertex45Count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + Vertex45Compact currentVertex(*currentIter); + incoming += currentVertex.count; + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.y() == currentY && + currentIter->pt.x() == x_); + //now counts and tails have the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + //std::cout << counts[0] << " "; + //std::cout << counts[1] << " "; + //std::cout << counts[2] << " "; + //std::cout << counts[3] << "\n"; + //std::cout << incoming[0] << " "; + //std::cout << incoming[1] << " "; + //std::cout << incoming[2] << " "; + //std::cout << incoming[3] << "\n"; + if(verticalTail) { + counts[3] = -verticalCount; + } + incoming[3] *= -1; + for(unsigned int i = 0; i < 4; ++i) incoming[i] += counts[i]; + //std::cout << "calling processPoint_\n"; + std::pair result = processPoint_(output, elements, verticalPair, previter, + Point(x_, currentY), counts, tails, incoming); + verticalCount = result.first; + verticalTail = result.second; + if(verticalPair.first != 0 && iter != scanData_.end() && + (currentIter == inputEnd || currentIter->pt.x() != x_ || + currentIter->pt.y() > (*iter).first.evalAtX(x_))) { + //splice vertical pair into edge above + ActiveTail45* tailabove = (*iter).second; + Point point(x_, (*iter).first.evalAtX(x_)); + verticalPair.second->pushPoint(point); + ActiveTail45::joinChains(point, tailabove, verticalPair.first, true, output); + (*iter).second = verticalPair.second; + verticalPair.first = 0; + verticalPair.second = 0; + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); + } + + }; + + template + static inline bool testPolygon45TilingRect(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP1(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 1, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 20), 2, 1)); + data.push_back(Vertex45(Point(10, 20), 1, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP2(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 1, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 1, 1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 1, -1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP3(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(20, 0), 0, -1)); + data.push_back(Vertex45(Point(20, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 1, -1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + data.push_back(Vertex45(Point(20, 20), 1, 1)); + data.push_back(Vertex45(Point(20, 20), 2, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP4(stream_type& stdcout) { + stdcout << "testing polygon tiling p4\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), -1, 1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(20, 10), 2, 1)); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + data.push_back(Vertex45(Point(20, -10), -1, -1)); + data.push_back(Vertex45(Point(20, -10), 2, -1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP5(stream_type& stdcout) { + stdcout << "testing polygon tiling P5\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + + data.push_back(Vertex45(Point(1, 1), 0, -1)); + data.push_back(Vertex45(Point(1, 1), 1, 1)); + data.push_back(Vertex45(Point(2, 1), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 1, -1)); + data.push_back(Vertex45(Point(2, 2), 1, -1)); + data.push_back(Vertex45(Point(2, 2), 0, 1)); + data.push_back(Vertex45(Point(3, 2), 1, 1)); + data.push_back(Vertex45(Point(3, 2), 0, -1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingP6(stream_type& stdcout) { + stdcout << "testing polygon tiling P6\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 10), 2, -1)); + data.push_back(Vertex45(Point(0, 10), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 0, -1)); + data.push_back(Vertex45(Point(10, 0), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 0, 1)); + + data.push_back(Vertex45(Point(1, 1), 0, -1)); + data.push_back(Vertex45(Point(1, 1), 2, -1)); + data.push_back(Vertex45(Point(1, 2), 2, 1)); + data.push_back(Vertex45(Point(1, 2), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 0, 1)); + data.push_back(Vertex45(Point(2, 1), 2, 1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 2), 0, -1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingStar1(stream_type& stdcout) { + stdcout << "testing polygon tiling star1\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingStar2(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + + Scan45 scan45; + std::vector result; + std::vector vertices; + //is a Rectnagle(0, 0, 10, 10); + Count2 count(1, 0); + Count2 ncount(-1, 0); + vertices.push_back(Scan45Vertex(Point(0,4), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,4), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,12), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + count = Count2(0, 1); + ncount = count.invert(); + vertices.push_back(Scan45Vertex(Point(0,8), Scan45Count(count, ncount, Count2(0, 0), Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(16,8), Scan45Count(Count2(0, 0), count, ncount, Count2(0, 0)))); + vertices.push_back(Scan45Vertex(Point(8,0), Scan45Count(ncount, Count2(0, 0), count, Count2(0, 0)))); + sortScan45Vector(vertices); + stdcout << "scanning\n"; + scan45.scan(result, vertices.begin(), vertices.end()); + + std::sort(result.begin(), result.end()); + pf.scan(polys, result.begin(), result.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingStarHole1(stream_type& stdcout) { + stdcout << "testing polygon tiling star hole 1\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 8), -1, 1)); + data.push_back(Vertex45(Point(6, 8), 2, 1)); + data.push_back(Vertex45(Point(8, 6), -1, -1)); + data.push_back(Vertex45(Point(8, 6), 1, 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45TilingStarHole2(stream_type& stdcout) { + stdcout << "testing polygon tiling star hole 2\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(Point(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(Point(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(Point(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(Point(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(Point(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(Point(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(Point(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(Point(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(Point(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(Point(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(Point(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(Point(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(Point(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(Point(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(Point(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(Point(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(Point(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(Point(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(Point(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(Point(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(Point(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(Point(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(Point(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(Point(12, 8), -1, 1)); + + data.push_back(Vertex45(Point(6, 4), 1, -1)); + data.push_back(Vertex45(Point(6, 4), 2, -1)); + data.push_back(Vertex45(Point(6, 12), -1, 1)); + data.push_back(Vertex45(Point(6, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 8), -1, -1)); + data.push_back(Vertex45(Point(10, 8), 1, 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + + template + static inline bool testPolygon45Tiling(stream_type& stdcout) { + stdcout << "testing polygon tiling\n"; + Polygon45Tiling pf; + std::vector polys; + std::vector data; + + data.push_back(Vertex45(Point(0, 0), 0, 1)); + data.push_back(Vertex45(Point(0, 0), 2, 1)); + data.push_back(Vertex45(Point(0, 100), 2, -1)); + data.push_back(Vertex45(Point(0, 100), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 0, -1)); + data.push_back(Vertex45(Point(100, 0), 2, -1)); + data.push_back(Vertex45(Point(100, 100), 2, 1)); + data.push_back(Vertex45(Point(100, 100), 0, 1)); + + data.push_back(Vertex45(Point(2, 2), 0, -1)); + data.push_back(Vertex45(Point(2, 2), 2, -1)); + data.push_back(Vertex45(Point(2, 10), 2, 1)); + data.push_back(Vertex45(Point(2, 10), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 0, 1)); + data.push_back(Vertex45(Point(10, 2), 2, 1)); + data.push_back(Vertex45(Point(10, 10), 2, -1)); + data.push_back(Vertex45(Point(10, 10), 0, -1)); + + data.push_back(Vertex45(Point(2, 12), 0, -1)); + data.push_back(Vertex45(Point(2, 12), 2, -1)); + data.push_back(Vertex45(Point(2, 22), 2, 1)); + data.push_back(Vertex45(Point(2, 22), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 0, 1)); + data.push_back(Vertex45(Point(10, 12), 2, 1)); + data.push_back(Vertex45(Point(10, 22), 2, -1)); + data.push_back(Vertex45(Point(10, 22), 0, -1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon tiling\n"; + return true; + } + }; + + template + class PolyLine45HoleData { + public: + typedef typename polygon_45_formation::ActiveTail45 ActiveTail45; + typedef typename ActiveTail45::iterator iterator; + + typedef polygon_45_concept geometry_type; + typedef Unit coordinate_type; + typedef point_data Point; + typedef Point point_type; + // typedef iterator_points_to_compact compact_iterator_type; + typedef iterator iterator_type; + typedef typename coordinate_traits::area_type area_type; + + inline PolyLine45HoleData() : p_(0) {} + inline PolyLine45HoleData(ActiveTail45* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + inline std::size_t size() const { return 0; } + template + inline PolyLine45HoleData& set(iT inputBegin, iT inputEnd) { + return *this; + } + private: + ActiveTail45* p_; + }; + + template + class PolyLine45PolygonData { + public: + typedef typename polygon_45_formation::ActiveTail45 ActiveTail45; + typedef typename ActiveTail45::iterator iterator; + typedef PolyLine45HoleData holeType; + + typedef polygon_45_with_holes_concept geometry_type; + typedef Unit coordinate_type; + typedef point_data Point; + typedef Point point_type; + // typedef iterator_points_to_compact compact_iterator_type; + typedef iterator iterator_type; + typedef holeType hole_type; + typedef typename coordinate_traits::area_type area_type; + class iteratorHoles { + private: + typename ActiveTail45::iteratorHoles itr_; + public: + typedef PolyLine45HoleData holeType; + typedef holeType value_type; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + typedef const value_type* pointer; //immutable + typedef const value_type& reference; //immutable + inline iteratorHoles() : itr_() {} + inline iteratorHoles(typename ActiveTail45::iteratorHoles itr) : itr_(itr) {} + inline iteratorHoles(const iteratorHoles& that) : itr_(that.itr_) {} + inline iteratorHoles& operator=(const iteratorHoles& that) { + itr_ = that.itr_; + return *this; + } + inline bool operator==(const iteratorHoles& that) { return itr_ == that.itr_; } + inline bool operator!=(const iteratorHoles& that) { return itr_ != that.itr_; } + inline iteratorHoles& operator++() { + ++itr_; + return *this; + } + inline const iteratorHoles operator++(int) { + iteratorHoles tmp = *this; + ++(*this); + return tmp; + } + inline holeType operator*() { + return *itr_; + } + }; + typedef iteratorHoles iterator_holes_type; + + + inline PolyLine45PolygonData() : p_(0) {} + inline PolyLine45PolygonData(ActiveTail45* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + inline iteratorHoles begin_holes() const { return iteratorHoles(p_->getHoles().begin()); } + inline iteratorHoles end_holes() const { return iteratorHoles(p_->getHoles().end()); } + inline ActiveTail45* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template + inline PolyLine45PolygonData& set(iT inputBegin, iT inputEnd) { + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline PolyLine45PolygonData& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + private: + ActiveTail45* p_; + }; + + template + struct PolyLineByConcept { typedef PolyLine45PolygonData type; }; + template + struct PolyLineByConcept { typedef PolyLine45PolygonData type; }; + template + struct PolyLineByConcept { typedef PolyLine45HoleData type; }; + template + struct PolyLineByConcept { typedef PolyLine45HoleData type; }; + + template + struct geometry_concept > { typedef polygon_45_with_holes_concept type; }; + template + struct geometry_concept > { typedef polygon_45_concept type; }; + +} +} +#endif diff --git a/include/boost/polygon/detail/polygon_45_set_view.hpp b/include/boost/polygon/detail/polygon_45_set_view.hpp new file mode 100644 index 0000000..1a66f51 --- /dev/null +++ b/include/boost/polygon/detail/polygon_45_set_view.hpp @@ -0,0 +1,378 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_45_SET_VIEW_HPP +namespace boost { namespace polygon{ + + template + class polygon_45_set_view; + + template + struct polygon_45_set_traits > { + typedef typename polygon_45_set_view::coordinate_type coordinate_type; + typedef typename polygon_45_set_view::iterator_type iterator_type; + typedef typename polygon_45_set_view::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_45_set_view& polygon_45_set); + static inline iterator_type end(const polygon_45_set_view& polygon_45_set); + + template + static inline void set(polygon_45_set_view& polygon_45_set, + input_iterator_type input_begin, input_iterator_type input_end); + + static inline bool clean(const polygon_45_set_view& polygon_45_set); + + }; + + template + struct compute_45_set_value { + static + void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_) { + output_.set(polygon_45_set_traits::begin(lvalue_), + polygon_45_set_traits::end(lvalue_)); + value_type rinput_; + rinput_.set(polygon_45_set_traits::begin(rvalue_), + polygon_45_set_traits::end(rvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rinput_; + else if(op_type == 1) + output_ &= rinput_; + else if(op_type == 2) + output_ ^= rinput_; + else + output_ -= rinput_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + }; + + template + struct compute_45_set_value, op_type> { + static + void value(value_type& output_, const ltype& lvalue_, const polygon_45_set_data& rvalue_) { + output_.set(polygon_45_set_traits::begin(lvalue_), + polygon_45_set_traits::end(lvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rvalue_; + else if(op_type == 1) + output_ &= rvalue_; + else if(op_type == 2) + output_ ^= rvalue_; + else + output_ -= rvalue_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + } + }; + + template + class polygon_45_set_view { + public: + typedef typename polygon_45_set_traits::coordinate_type coordinate_type; + typedef polygon_45_set_data value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_45_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + mutable value_type output_; + mutable bool evaluated_; + + polygon_45_set_view& operator=(const polygon_45_set_view&); + public: + polygon_45_set_view(const ltype& lvalue, + const rtype& rvalue ) : + lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} + + // get iterator to begin vertex data + public: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + compute_45_set_value::value(output_, lvalue_, rvalue_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + bool dirty() const { return value().dirty(); } //result of a boolean is clean + bool sorted() const { return value().sorted(); } //result of a boolean is sorted + + // template + // void set(input_iterator_type input_begin, input_iterator_type input_end, + // orientation_2d orient) const { + // orient_ = orient; + // output_.clear(); + // output_.insert(output_.end(), input_begin, input_end); + // std::sort(output_.begin(), output_.end()); + // } + }; + + template + typename polygon_45_set_traits >::iterator_type + polygon_45_set_traits >:: + begin(const polygon_45_set_view& polygon_45_set) { + return polygon_45_set.begin(); + } + template + typename polygon_45_set_traits >::iterator_type + polygon_45_set_traits >:: + end(const polygon_45_set_view& polygon_45_set) { + return polygon_45_set.end(); + } + template + bool polygon_45_set_traits >:: + clean(const polygon_45_set_view& polygon_45_set) { + return polygon_45_set.value().clean(); } + + template + geometry_type_1& self_assignment_boolean_op_45(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_45_set_traits::coordinate_type coordinate_type; + typedef polygon_45_set_data value_type; + value_type output_; + value_type rinput_; + output_.set(polygon_45_set_traits::begin(lvalue_), + polygon_45_set_traits::end(lvalue_)); + rinput_.set(polygon_45_set_traits::begin(rvalue_), + polygon_45_set_traits::end(rvalue_)); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) + output_ |= rinput_; + else if(op_type == 1) + output_ &= rinput_; + else if(op_type == 2) + output_ ^= rinput_; + else + output_ -= rinput_; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + polygon_45_set_mutable_traits::set(lvalue_, output_.begin(), output_.end()); + return lvalue_; + } + + template + struct fracture_holes_option_by_type { + static const bool value = true; + }; + template <> + struct fracture_holes_option_by_type { + static const bool value = false; + }; + template <> + struct fracture_holes_option_by_type { + static const bool value = false; + }; + + template + struct geometry_concept > { typedef polygon_45_set_concept type; }; + + namespace operators { + struct y_ps45_b : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_b, + typename is_polygon_45_or_90_set_type::type, + typename is_polygon_45_or_90_set_type::type, + typename is_either_polygon_45_set_type::type>::type, + polygon_45_set_view >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_p : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_p, + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_45_set_view >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_s : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_s, typename is_polygon_45_or_90_set_type::type, + typename is_polygon_45_or_90_set_type::type, + typename is_either_polygon_45_set_type::type>::type, + polygon_45_set_view >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_a : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_a, typename is_polygon_45_or_90_set_type::type, + typename is_polygon_45_or_90_set_type::type, + typename is_either_polygon_45_set_type::type>::type, + polygon_45_set_view >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_x : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_x, typename is_polygon_45_or_90_set_type::type, + typename is_polygon_45_or_90_set_type::type, + typename is_either_polygon_45_set_type::type>::type, + polygon_45_set_view >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_m : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< y_ps45_m, + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_45_set_view >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_45_set_view + (lvalue, rvalue); + } + + struct y_ps45_pe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4::type, gtl_yes, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_be : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_se : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps45_se, + typename is_mutable_polygon_45_set_type::type, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_ae : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_xe : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_me : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op_45(lvalue, rvalue); + } + + struct y_ps45_rpe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps45_rpe, typename is_mutable_polygon_45_set_type::type, + typename gtl_same_type::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps45_rme : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps45_rp : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps45_rm : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + } +} +} +#endif + diff --git a/include/boost/polygon/detail/polygon_45_touch.hpp b/include/boost/polygon/detail/polygon_45_touch.hpp new file mode 100644 index 0000000..705accf --- /dev/null +++ b/include/boost/polygon/detail/polygon_45_touch.hpp @@ -0,0 +1,236 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_TOUCH_HPP +#define BOOST_POLYGON_POLYGON_45_TOUCH_HPP +namespace boost { namespace polygon{ + + template + struct polygon_45_touch { + + typedef point_data Point; + typedef typename coordinate_traits::manhattan_area_type LongUnit; + + template + static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { + property_map newmp; + newmp.reserve(mp.size() + mp2.size()); + std::size_t i = 0; + std::size_t j = 0; + while(i != mp.size() && j != mp2.size()) { + if(mp[i].first < mp2[j].first) { + newmp.push_back(mp[i]); + ++i; + } else if(mp[i].first > mp2[j].first) { + newmp.push_back(mp2[j]); + if(subtract) newmp.back().second *= -1; + ++j; + } else { + int count = mp[i].second; + if(subtract) count -= mp2[j].second; + else count += mp2[j].second; + if(count) { + newmp.push_back(mp[i]); + newmp.back().second = count; + } + ++i; + ++j; + } + } + while(i != mp.size()) { + newmp.push_back(mp[i]); + ++i; + } + while(j != mp2.size()) { + newmp.push_back(mp2[j]); + if(subtract) newmp.back().second *= -1; + ++j; + } + mp.swap(newmp); + } + + class CountTouch { + public: + inline CountTouch() : counts() {} + //inline CountTouch(int count) { counts[0] = counts[1] = count; } + //inline CountTouch(int count1, int count2) { counts[0] = count1; counts[1] = count2; } + inline CountTouch(const CountTouch& count) : counts(count.counts) {} + inline bool operator==(const CountTouch& count) const { return counts == count.counts; } + inline bool operator!=(const CountTouch& count) const { return !((*this) == count); } + //inline CountTouch& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } + inline int& operator[](int index) { + std::vector >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); + if(itr != counts.end() && itr->first == index) { + return itr->second; + } + itr = counts.insert(itr, std::make_pair(index, int(0))); + return itr->second; + } +// inline int operator[](int index) const { +// std::vector >::const_iterator itr = counts.begin(); +// for( ; itr != counts.end() && itr->first <= index; ++itr) { +// if(itr->first == index) { +// return itr->second; +// } +// } +// return 0; +// } + inline CountTouch& operator+=(const CountTouch& count){ + merge_property_maps(counts, count.counts, false); + return *this; + } + inline CountTouch& operator-=(const CountTouch& count){ + merge_property_maps(counts, count.counts, true); + return *this; + } + inline CountTouch operator+(const CountTouch& count) const { + return CountTouch(*this)+=count; + } + inline CountTouch operator-(const CountTouch& count) const { + return CountTouch(*this)-=count; + } + inline CountTouch invert() const { + CountTouch retval; + retval -= *this; + return retval; + } + std::vector > counts; + }; + + typedef std::pair > >, std::map > > map_graph_o; + typedef std::pair > >, std::vector > > vector_graph_o; + + template + static void process_previous_x(cT& output) { + std::map >& y_prop_map = output.first.second; + for(typename std::map >::iterator itr = y_prop_map.begin(); + itr != y_prop_map.end(); ++itr) { + for(std::set::iterator inner_itr = itr->second.begin(); + inner_itr != itr->second.end(); ++inner_itr) { + std::set& output_edges = (*(output.second))[*inner_itr]; + std::set::iterator inner_inner_itr = inner_itr; + ++inner_inner_itr; + for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { + output_edges.insert(output_edges.end(), *inner_inner_itr); + std::set& output_edges_2 = (*(output.second))[*inner_inner_itr]; + output_edges_2.insert(output_edges_2.end(), *inner_itr); + } + } + } + y_prop_map.clear(); + } + + struct touch_45_output_functor { + template + void operator()(cT& output, const CountTouch& count1, const CountTouch& count2, + const Point& pt, int , direction_1d ) { + Unit& x = output.first.first; + std::map >& y_prop_map = output.first.second; + if(pt.x() != x) process_previous_x(output); + x = pt.x(); + std::set& output_set = y_prop_map[pt.y()]; + for(std::vector >::const_iterator itr1 = count1.counts.begin(); + itr1 != count1.counts.end(); ++itr1) { + if(itr1->second > 0) { + output_set.insert(output_set.end(), itr1->first); + } + } + for(std::vector >::const_iterator itr2 = count2.counts.begin(); + itr2 != count2.counts.end(); ++itr2) { + if(itr2->second > 0) { + output_set.insert(output_set.end(), itr2->first); + } + } + } + }; + typedef typename std::pair::template Scan45CountT > Vertex45Compact; + typedef std::vector TouchSetData; + + struct lessVertex45Compact { + bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { + return l.first < r.first; + } + }; + +// template +// static void print_tsd(TSD& tsd) { +// for(std::size_t i = 0; i < tsd.size(); ++i) { +// std::cout << tsd[i].first << ": "; +// for(unsigned int r = 0; r < 4; ++r) { +// std::cout << r << " { "; +// for(std::vector >::iterator itr = tsd[i].second[r].counts.begin(); +// itr != tsd[i].second[r].counts.end(); ++itr) { +// std::cout << itr->first << "," << itr->second << " "; +// } std::cout << "} "; +// } +// } std::cout << std::endl; +// } + +// template +// static void print_scanline(T& t) { +// for(typename T::iterator itr = t.begin(); itr != t.end(); ++itr) { +// std::cout << itr->x << "," << itr->y << " " << itr->rise << " "; +// for(std::vector >::iterator itr2 = itr->count.counts.begin(); +// itr2 != itr->count.counts.end(); ++itr2) { +// std::cout << itr2->first << ":" << itr2->second << " "; +// } std::cout << std::endl; +// } +// } + + template + static void performTouch(graph_type& graph, TouchSetData& tsd) { + + std::sort(tsd.begin(), tsd.end(), lessVertex45Compact()); + typedef std::vector::template Scan45CountT > > TSD; + TSD tsd_; + tsd_.reserve(tsd.size()); + for(typename TouchSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { + typename TouchSetData::iterator itr2 = itr; + ++itr2; + for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { + (itr->second) += (itr2->second); //accumulate + } + tsd_.push_back(std::make_pair(itr->first, itr->second)); + itr = itr2; + } + std::pair > >, graph_type*> output + (std::make_pair(std::make_pair((std::numeric_limits::max)(), std::map >()), &graph)); + typename boolean_op_45::template Scan45 scanline; + for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { + typename TSD::iterator itr2 = itr; + ++itr2; + while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { + ++itr2; + } + scanline.scan(output, itr, itr2); + itr = itr2; + } + process_previous_x(output); + } + + template + static void populateTouchSetData(TouchSetData& tsd, iT begin, iT end, int nodeCount) { + for( ; begin != end; ++begin) { + Vertex45Compact vertex; + vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); + tsd.push_back(vertex); + for(unsigned int i = 0; i < 4; ++i) { + if(begin->count[i]) { + tsd.back().second[i][nodeCount] += begin->count[i]; + } + } + } + } + + }; + + +} +} +#endif diff --git a/include/boost/polygon/detail/polygon_90_set_view.hpp b/include/boost/polygon/detail/polygon_90_set_view.hpp new file mode 100644 index 0000000..72b9708 --- /dev/null +++ b/include/boost/polygon/detail/polygon_90_set_view.hpp @@ -0,0 +1,445 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_90_SET_VIEW_HPP +namespace boost { namespace polygon{ + struct operator_provides_storage {}; + struct operator_requires_copy {}; + + template + inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient); + + template + class polygon_90_set_view; + + template + struct polygon_90_set_traits > { + typedef typename polygon_90_set_view::coordinate_type coordinate_type; + typedef typename polygon_90_set_view::iterator_type iterator_type; + typedef typename polygon_90_set_view::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_90_set_view& polygon_set); + static inline iterator_type end(const polygon_90_set_view& polygon_set); + + static inline orientation_2d orient(const polygon_90_set_view& polygon_set); + + static inline bool clean(const polygon_90_set_view& polygon_set); + + static inline bool sorted(const polygon_90_set_view& polygon_set); + }; + + template + struct compute_90_set_value { + static + void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + value_type rinput_(orient_); + insert_into_view_arg(linput_, lvalue_, orient_); + insert_into_view_arg(rinput_, rvalue_, orient_); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + } + }; + + template + struct compute_90_set_value, polygon_90_set_data, op_type> { + static + void value(value_type& output_, const polygon_90_set_data& lvalue_, + const polygon_90_set_data& rvalue_, orientation_2d) { + lvalue_.sort(); + rvalue_.sort(); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + } + }; + + template + struct compute_90_set_value, rtype, op_type> { + static + void value(value_type& output_, const polygon_90_set_data& lvalue_, + const rtype& rvalue_, orientation_2d orient_) { + value_type rinput_(orient_); + lvalue_.sort(); + insert_into_view_arg(rinput_, rvalue_, orient_); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + } + }; + + template + struct compute_90_set_value, op_type> { + static + void value(value_type& output_, const ltype& lvalue_, + const polygon_90_set_data& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + insert_into_view_arg(linput_, lvalue_, orient_); + rvalue_.sort(); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + } + }; + + template + class polygon_90_set_view { + public: + typedef typename polygon_90_set_traits::coordinate_type coordinate_type; + typedef polygon_90_set_data value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_90_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + orientation_2d orient_; + op_type op_; + mutable value_type output_; + mutable bool evaluated_; + polygon_90_set_view& operator=(const polygon_90_set_view&); + public: + polygon_90_set_view(const ltype& lvalue, + const rtype& rvalue, + orientation_2d orient, + op_type op) : + lvalue_(lvalue), rvalue_(rvalue), orient_(orient), op_(op), output_(orient), evaluated_(false) {} + + // get iterator to begin vertex data + private: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + compute_90_set_value::value(output_, lvalue_, rvalue_, orient_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + orientation_2d orient() const { return orient_; } + bool dirty() const { return false; } //result of a boolean is clean + bool sorted() const { return true; } //result of a boolean is sorted + +// template +// void set(input_iterator_type input_begin, input_iterator_type input_end, +// orientation_2d orient) const { +// orient_ = orient; +// output_.clear(); +// output_.insert(output_.end(), input_begin, input_end); +// std::sort(output_.begin(), output_.end()); +// } + void sort() const {} //is always sorted + }; + + template + struct geometry_concept > { + typedef polygon_90_set_concept type; + }; + + template + typename polygon_90_set_traits >::iterator_type + polygon_90_set_traits >:: + begin(const polygon_90_set_view& polygon_set) { + return polygon_set.begin(); + } + template + typename polygon_90_set_traits >::iterator_type + polygon_90_set_traits >:: + end(const polygon_90_set_view& polygon_set) { + return polygon_set.end(); + } +// template +// template +// void polygon_90_set_traits >:: +// set(polygon_90_set_view& polygon_set, +// input_iterator_type input_begin, input_iterator_type input_end, +// orientation_2d orient) { +// polygon_set.set(input_begin, input_end, orient); +// } + template + orientation_2d polygon_90_set_traits >:: + orient(const polygon_90_set_view& polygon_set) { + return polygon_set.orient(); } + template + bool polygon_90_set_traits >:: + clean(const polygon_90_set_view& polygon_set) { + return true; } + template + bool polygon_90_set_traits >:: + sorted(const polygon_90_set_view& polygon_set) { + return true; } + + template + inline void insert_into_view_arg(value_type& dest, const arg_type& arg, orientation_2d orient) { + typedef typename polygon_90_set_traits::iterator_type literator; + literator itr1, itr2; + itr1 = polygon_90_set_traits::begin(arg); + itr2 = polygon_90_set_traits::end(arg); + dest.insert(itr1, itr2, orient); + dest.sort(); + } + + template + template + inline polygon_90_set_data& polygon_90_set_data::operator=(const polygon_90_set_view& that) { + set(that.begin(), that.end(), that.orient()); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template + template + inline polygon_90_set_data::polygon_90_set_data(const polygon_90_set_view& that) : + orient_(that.orient()), data_(that.begin(), that.end()), dirty_(false), unsorted_(false) {} + + template + struct self_assign_operator_lvalue { + typedef geometry_type_1& type; + }; + + template + struct by_value_binary_operator { + typedef type_1 type; + }; + + template + geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_90_set_traits::coordinate_type coordinate_type; + typedef polygon_90_set_data value_type; + orientation_2d orient_ = polygon_90_set_traits::orient(lvalue_); + value_type linput_(orient_); + value_type rinput_(orient_); + value_type output_(orient_); + insert_into_view_arg(linput_, lvalue_, orient_); + insert_into_view_arg(rinput_, rvalue_, orient_); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + polygon_90_set_mutable_traits::set(lvalue_, output_.begin(), output_.end(), orient_); + return lvalue_; + } + + namespace operators { + struct y_ps90_b : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_b, + typename is_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + polygon_90_set_view >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryOr()); + } + + struct y_ps90_p : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3< y_ps90_p, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_90_set_view >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryOr()); + } + + struct y_ps90_s : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_s, + typename is_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + polygon_90_set_view >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryAnd()); + } + + struct y_ps90_a : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_a, + typename is_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + polygon_90_set_view >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryAnd()); + } + + struct y_ps90_x : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_x, + typename is_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + polygon_90_set_view >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryXor()); + } + + struct y_ps90_m : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_m, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_90_set_view >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_90_set_view + (lvalue, rvalue, + polygon_90_set_traits::orient(lvalue), + boolean_op::BinaryNot()); + } + + struct y_ps90_pe : gtl_yes {}; + + template + typename enable_if< typename gtl_and< y_ps90_pe, typename is_polygon_90_set_type::type>::type, + polygon_90_set_data >::type & + operator+=(polygon_90_set_data& lvalue, const geometry_type_2& rvalue) { + lvalue.insert(polygon_90_set_traits::begin(rvalue), polygon_90_set_traits::end(rvalue), + polygon_90_set_traits::orient(rvalue)); + return lvalue; + } + + struct y_ps90_be : gtl_yes {}; + // + template + typename enable_if< typename gtl_and< y_ps90_be, typename is_polygon_90_set_type::type>::type, + polygon_90_set_data >::type & + operator|=(polygon_90_set_data& lvalue, const geometry_type_2& rvalue) { + return lvalue += rvalue; + } + + struct y_ps90_pe2 : gtl_yes {}; + + //normal self assignment boolean operations + template + typename enable_if< typename gtl_and_3< y_ps90_pe2, typename is_mutable_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_be2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_se : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_ae : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_xe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_me : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps90_me, typename is_mutable_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct y_ps90_rpe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename gtl_same_type::type, coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps90_rme : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type, + typename gtl_same_type::type, coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps90_rp : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_if::type, coordinate_concept>::type>::type>::type, + geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps90_rm : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_if::type, coordinate_concept>::type>::type>::type, + geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + } +} +} +#endif + diff --git a/include/boost/polygon/detail/polygon_90_touch.hpp b/include/boost/polygon/detail/polygon_90_touch.hpp new file mode 100644 index 0000000..7671602 --- /dev/null +++ b/include/boost/polygon/detail/polygon_90_touch.hpp @@ -0,0 +1,418 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_TOUCH_HPP +#define BOOST_POLYGON_POLYGON_90_TOUCH_HPP +namespace boost { namespace polygon{ + + template + struct touch_90_operation { + typedef interval_data Interval; + + class TouchScanEvent { + private: + typedef std::map > EventData; + EventData eventData_; + public: + + // The TouchScanEvent::iterator is a lazy algorithm that accumulates + // polygon ids in a set as it is incremented through the + // scan event data structure. + // The iterator provides a forward iterator semantic only. + class iterator { + private: + typename EventData::const_iterator itr_; + std::pair > ivlIds_; + bool incremented_; + public: + inline iterator() : itr_(), ivlIds_(), incremented_(false) {} + inline iterator(typename EventData::const_iterator itr, + Unit prevPos, Unit curPos, const std::set& ivlIds) : itr_(itr), ivlIds_(), incremented_(false) { + ivlIds_.second = ivlIds; + ivlIds_.first = Interval(prevPos, curPos); + } + inline iterator(const iterator& that) : itr_(), ivlIds_(), incremented_(false) { (*this) = that; } + inline iterator& operator=(const iterator& that) { + itr_ = that.itr_; + ivlIds_.first = that.ivlIds_.first; + ivlIds_.second = that.ivlIds_.second; + incremented_ = that.incremented_; + return *this; + } + inline bool operator==(const iterator& that) { return itr_ == that.itr_; } + inline bool operator!=(const iterator& that) { return itr_ != that.itr_; } + inline iterator& operator++() { + //std::cout << "increment\n"; + //std::cout << "state\n"; + //for(std::set::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { + // std::cout << (*itr) << " "; + //} std::cout << std::endl; + //std::cout << "update\n"; + for(std::set::const_iterator itr = (*itr_).second.begin(); + itr != (*itr_).second.end(); ++itr) { + //std::cout << (*itr) << " "; + std::set::iterator lb = ivlIds_.second.find(*itr); + if(lb != ivlIds_.second.end()) { + ivlIds_.second.erase(lb); + } else { + ivlIds_.second.insert(*itr); + } + } + //std::cout << std::endl; + //std::cout << "new state\n"; + //for(std::set::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { + // std::cout << (*itr) << " "; + //} std::cout << std::endl; + ++itr_; + //ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = true; + return *this; + } + inline const iterator operator++(int){ + iterator tmpItr(*this); + ++(*this); + return tmpItr; + } + inline std::pair >& operator*() { + if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = false; + if(ivlIds_.second.empty())(++(*this)); + if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); + incremented_ = false; + return ivlIds_; } + }; + + inline TouchScanEvent() : eventData_() {} + template + inline TouchScanEvent(iT begin, iT end) : eventData_() { + for( ; begin != end; ++begin){ + insert(*begin); + } + } + inline TouchScanEvent(const TouchScanEvent& that) : eventData_(that.eventData_) {} + inline TouchScanEvent& operator=(const TouchScanEvent& that){ + eventData_ = that.eventData_; + return *this; + } + + //Insert an interval polygon id into the EventData + inline void insert(const std::pair& intervalId){ + insert(intervalId.first.low(), intervalId.second); + insert(intervalId.first.high(), intervalId.second); + } + + //Insert an position and polygon id into EventData + inline void insert(Unit pos, int id) { + typename EventData::iterator lb = eventData_.lower_bound(pos); + if(lb != eventData_.end() && lb->first == pos) { + std::set& mr (lb->second); + std::set::iterator mri = mr.find(id); + if(mri == mr.end()) { + mr.insert(id); + } else { + mr.erase(id); + } + } else { + lb = eventData_.insert(lb, std::pair >(pos, std::set())); + (*lb).second.insert(id); + } + } + + //merge this scan event with that by inserting its data + inline void insert(const TouchScanEvent& that){ + typename EventData::const_iterator itr; + for(itr = that.eventData_.begin(); itr != that.eventData_.end(); ++itr) { + eventData_[(*itr).first].insert(itr->second.begin(), itr->second.end()); + } + } + + //Get the begin iterator over event data + inline iterator begin() const { + //std::cout << "begin\n"; + if(eventData_.empty()) return end(); + typename EventData::const_iterator itr = eventData_.begin(); + Unit pos = itr->first; + const std::set& idr = itr->second; + ++itr; + return iterator(itr, pos, itr->first, idr); + } + + //Get the end iterator over event data + inline iterator end() const { return iterator(eventData_.end(), 0, 0, std::set()); } + + inline void clear() { eventData_.clear(); } + + inline Interval extents() const { + if(eventData_.empty()) return Interval(); + return Interval((*(eventData_.begin())).first, (*(eventData_.rbegin())).first); + } + }; + + //declaration of a map of scan events by coordinate value used to store all the + //polygon data for a single layer input into the scanline algorithm + typedef std::pair, std::map > TouchSetData; + + class TouchOp { + public: + typedef std::map > ScanData; + typedef std::pair > ElementType; + protected: + ScanData scanData_; + typename ScanData::iterator nextItr_; + public: + inline TouchOp () : scanData_(), nextItr_() { nextItr_ = scanData_.end(); } + inline TouchOp (const TouchOp& that) : scanData_(that.scanData_), nextItr_() { nextItr_ = scanData_.begin(); } + inline TouchOp& operator=(const TouchOp& that); + + //moves scanline forward + inline void advanceScan() { nextItr_ = scanData_.begin(); } + + //proceses the given interval and std::set data + //the output data structre is a graph, the indicies in the vector correspond to graph nodes, + //the integers in the set are vector indicies and are the nodes with which that node shares an edge + template + inline void processInterval(graphT& outputContainer, Interval ivl, const std::set& ids, bool leadingEdge) { + //print(); + typename ScanData::iterator lowItr = lookup_(ivl.low()); + typename ScanData::iterator highItr = lookup_(ivl.high()); + //std::cout << "Interval: " << ivl << std::endl; + //for(std::set::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) + // std::cout << (*itr) << " "; + //std::cout << std::endl; + //add interval to scan data if it is past the end + if(lowItr == scanData_.end()) { + //std::cout << "case0" << std::endl; + lowItr = insert_(ivl.low(), ids); + evaluateBorder_(outputContainer, ids, ids); + highItr = insert_(ivl.high(), std::set()); + return; + } + //ensure that highItr points to the end of the ivl + if(highItr == scanData_.end() || (*highItr).first > ivl.high()) { + //std::cout << "case1" << std::endl; + //std::cout << highItr->first << std::endl; + std::set value = std::set(); + if(highItr != scanData_.begin()) { + --highItr; + //std::cout << highItr->first << std::endl; + //std::cout << "high set size " << highItr->second.size() << std::endl; + value = highItr->second; + } + nextItr_ = highItr; + highItr = insert_(ivl.high(), value); + } else { + //evaluate border with next higher interval + //std::cout << "case1a" << std::endl; + if(leadingEdge)evaluateBorder_(outputContainer, highItr->second, ids); + } + //split the low interval if needed + if(lowItr->first > ivl.low()) { + //std::cout << "case2" << std::endl; + if(lowItr != scanData_.begin()) { + //std::cout << "case3" << std::endl; + --lowItr; + nextItr_ = lowItr; + //std::cout << lowItr->first << " " << lowItr->second.size() << std::endl; + lowItr = insert_(ivl.low(), lowItr->second); + } else { + //std::cout << "case4" << std::endl; + nextItr_ = lowItr; + lowItr = insert_(ivl.low(), std::set()); + } + } else { + //evaluate border with next higher interval + //std::cout << "case2a" << std::endl; + typename ScanData::iterator nextLowerItr = lowItr; + if(leadingEdge && nextLowerItr != scanData_.begin()){ + --nextLowerItr; + evaluateBorder_(outputContainer, nextLowerItr->second, ids); + } + } + //std::cout << "low: " << lowItr->first << " high: " << highItr->first << std::endl; + //print(); + //process scan data intersecting interval + for(typename ScanData::iterator itr = lowItr; itr != highItr; ){ + //std::cout << "case5" << std::endl; + //std::cout << itr->first << std::endl; + std::set& beforeIds = itr->second; + ++itr; + evaluateInterval_(outputContainer, beforeIds, ids, leadingEdge); + } + //print(); + //merge the bottom interval with the one below if they have the same count + if(lowItr != scanData_.begin()){ + //std::cout << "case6" << std::endl; + typename ScanData::iterator belowLowItr = lowItr; + --belowLowItr; + if(belowLowItr->second == lowItr->second) { + //std::cout << "case7" << std::endl; + scanData_.erase(lowItr); + } + } + //merge the top interval with the one above if they have the same count + if(highItr != scanData_.begin()) { + //std::cout << "case8" << std::endl; + typename ScanData::iterator beforeHighItr = highItr; + --beforeHighItr; + if(beforeHighItr->second == highItr->second) { + //std::cout << "case9" << std::endl; + scanData_.erase(highItr); + highItr = beforeHighItr; + ++highItr; + } + } + //print(); + nextItr_ = highItr; + } + +// inline void print() const { +// for(typename ScanData::const_iterator itr = scanData_.begin(); itr != scanData_.end(); ++itr) { +// std::cout << itr->first << ": "; +// for(std::set::const_iterator sitr = itr->second.begin(); +// sitr != itr->second.end(); ++sitr){ +// std::cout << *sitr << " "; +// } +// std::cout << std::endl; +// } +// } + + private: + inline typename ScanData::iterator lookup_(Unit pos){ + if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { + return nextItr_; + } + return nextItr_ = scanData_.lower_bound(pos); + } + + inline typename ScanData::iterator insert_(Unit pos, const std::set& ids){ + //std::cout << "inserting " << ids.size() << " ids at: " << pos << std::endl; + return nextItr_ = scanData_.insert(nextItr_, std::pair >(pos, ids)); + } + + template + inline void evaluateInterval_(graphT& outputContainer, std::set& ids, + const std::set& changingIds, bool leadingEdge) { + for(std::set::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ + //std::cout << "evaluateInterval " << (*ciditr) << std::endl; + evaluateId_(outputContainer, ids, *ciditr, leadingEdge); + } + } + template + inline void evaluateBorder_(graphT& outputContainer, const std::set& ids, const std::set& changingIds) { + for(std::set::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ + //std::cout << "evaluateBorder " << (*ciditr) << std::endl; + evaluateBorderId_(outputContainer, ids, *ciditr); + } + } + template + inline void evaluateBorderId_(graphT& outputContainer, const std::set& ids, int changingId) { + for(std::set::const_iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { + //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; + if(changingId != *scanItr){ + outputContainer[changingId].insert(*scanItr); + outputContainer[*scanItr].insert(changingId); + } + } + } + template + inline void evaluateId_(graphT& outputContainer, std::set& ids, int changingId, bool leadingEdge) { + //std::cout << "changingId: " << changingId << std::endl; + //for( std::set::iterator itr = ids.begin(); itr != ids.end(); ++itr){ + // std::cout << *itr << " "; + //}std::cout << std::endl; + std::set::iterator lb = ids.lower_bound(changingId); + if(lb == ids.end() || (*lb) != changingId) { + if(leadingEdge) { + //std::cout << "insert\n"; + //insert and add to output + for(std::set::iterator scanItr = ids.begin(); scanItr != ids.end(); ++scanItr) { + //std::cout << "create edge: " << changingId << " " << *scanItr << std::endl; + if(changingId != *scanItr){ + outputContainer[changingId].insert(*scanItr); + outputContainer[*scanItr].insert(changingId); + } + } + ids.insert(changingId); + } + } else { + if(!leadingEdge){ + //std::cout << "erase\n"; + ids.erase(lb); + } + } + } + }; + + template + static inline void processEvent(graphT& outputContainer, TouchOp& op, const TouchScanEvent& data, bool leadingEdge) { + for(typename TouchScanEvent::iterator itr = data.begin(); itr != data.end(); ++itr) { + //std::cout << "processInterval" << std::endl; + op.processInterval(outputContainer, (*itr).first, (*itr).second, leadingEdge); + } + } + + template + static inline void performTouch(graphT& outputContainer, const TouchSetData& data) { + typename std::map::const_iterator leftItr = data.first.begin(); + typename std::map::const_iterator rightItr = data.second.begin(); + typename std::map::const_iterator leftEnd = data.first.end(); + typename std::map::const_iterator rightEnd = data.second.end(); + TouchOp op; + while(leftItr != leftEnd || rightItr != rightEnd) { + //std::cout << "loop" << std::endl; + op.advanceScan(); + //rightItr cannont be at end if leftItr is not at end + if(leftItr != leftEnd && rightItr != rightEnd && + leftItr->first <= rightItr->first) { + //std::cout << "case1" << std::endl; + //std::cout << leftItr ->first << std::endl; + processEvent(outputContainer, op, leftItr->second, true); + ++leftItr; + } else { + //std::cout << "case2" << std::endl; + //std::cout << rightItr ->first << std::endl; + processEvent(outputContainer, op, rightItr->second, false); + ++rightItr; + } + } + } + + template + static inline void populateTouchSetData(TouchSetData& data, iT beginData, iT endData, int id) { + Unit prevPos = ((std::numeric_limits::max)()); + Unit prevY = prevPos; + int count = 0; + for(iT itr = beginData; itr != endData; ++itr) { + Unit pos = (*itr).first; + if(pos != prevPos) { + prevPos = pos; + prevY = (*itr).second.first; + count = (*itr).second.second; + continue; + } + Unit y = (*itr).second.first; + if(count != 0 && y != prevY) { + std::pair element(Interval(prevY, y), id); + if(count > 0) { + data.first[pos].insert(element); + } else { + data.second[pos].insert(element); + } + } + prevY = y; + count += (*itr).second.second; + } + } + + static inline void populateTouchSetData(TouchSetData& data, const std::vector > >& inputData, int id) { + populateTouchSetData(data, inputData.begin(), inputData.end(), id); + } + + }; +} +} +#endif diff --git a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp new file mode 100644 index 0000000..0372d96 --- /dev/null +++ b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -0,0 +1,2916 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_ARBITRARY_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_ARBITRARY_FORMATION_HPP +namespace boost { namespace polygon{ + template + struct PolyLineArbitraryByConcept {}; + + template + class poly_line_arbitrary_polygon_data; + template + class poly_line_arbitrary_hole_data; + + template + struct scanline_base { + + typedef point_data Point; + typedef std::pair half_edge; + + class less_point : public std::binary_function { + public: + inline less_point() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + static inline bool between(Point pt, Point pt1, Point pt2) { + less_point lp; + if(lp(pt1, pt2)) + return lp(pt, pt2) && lp(pt1, pt); + return lp(pt, pt1) && lp(pt2, pt); + } + + template + static inline Unit compute_intercept(const area_type& dy2, + const area_type& dx1, + const area_type& dx2) { + //intercept = dy2 * dx1 / dx2 + //return (Unit)(((area_type)dy2 * (area_type)dx1) / (area_type)dx2); + area_type dx1_q = dx1 / dx2; + area_type dx1_r = dx1 % dx2; + return dx1_q * dy2 + (dy2 * dx1_r)/dx2; + } + + template + static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); + } + + template + static inline bool equal_slope_hp(const T& dx1, const T& dy1, const T& dx2, const T& dy2) { + return dx1 * dy2 == dx2 * dy1; + } + + static inline bool equal_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + typedef typename coordinate_traits::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return equal_slope(dx1, dy1, dx2, dy2); + } + + template + static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + //reflext x and y slopes to right hand side half plane + if(dx1 < 0) { + dy1 *= -1; + dx1 *= -1; + } else if(dx1 == 0) { + //if the first slope is vertical the first cannot be less + return false; + } + if(dx2 < 0) { + dy2 *= -1; + dx2 *= -1; + } else if(dx2 == 0) { + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + return dx1 != 0; + } + typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + if(cross_1_sign < cross_2_sign) return true; + if(cross_2_sign < cross_1_sign) return false; + if(cross_1_sign == -1) return cross_2 < cross_1; + return cross_1 < cross_2; + } + + static inline bool less_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + //compute y value on edge from pt_ to pts[1] at the x value of pts[0] + typedef typename coordinate_traits::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return less_slope(dx1, dy1, dx2, dy2); + } + + //return -1 below, 0 on and 1 above line + static inline int on_above_or_below(Point pt, const half_edge& he) { + if(pt == he.first || pt == he.second) return 0; + if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; + bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); + int retval = less_result ? -1 : 1; + less_point lp; + if(lp(he.second, he.first)) retval *= -1; + if(!between(pt, he.first, he.second)) retval *= -1; + return retval; + } + + //returns true is the segment intersects the integer grid square with lower + //left corner at point + static inline bool intersects_grid(Point pt, const half_edge& he) { + if(pt == he.second) return true; + if(pt == he.first) return true; + rectangle_data rect1; + set_points(rect1, he.first, he.second); + if(contains(rect1, pt, true)) { + if(is_vertical(he) || is_horizontal(he)) return true; + } else { + return false; //can't intersect a grid not within bounding box + } + Unit x = pt.get(HORIZONTAL); + Unit y = pt.get(VERTICAL); + if(equal_slope(x, y, he.first, he.second) && + between(pt, he.first, he.second)) return true; + Point pt01(pt.get(HORIZONTAL), pt.get(VERTICAL) + 1); + Point pt10(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL)); + Point pt11(pt.get(HORIZONTAL) + 1, pt.get(VERTICAL) + 1); +// if(pt01 == he.first) return true; +// if(pt10 == he.first) return true; +// if(pt11 == he.first) return true; +// if(pt01 == he.second) return true; +// if(pt10 == he.second) return true; +// if(pt11 == he.second) return true; + //check non-integer intersections + half_edge widget1(pt, pt11); + //intersects but not just at pt11 + if(intersects(widget1, he) && on_above_or_below(pt11, he)) return true; + half_edge widget2(pt01, pt10); + //intersects but not just at pt01 or 10 + if(intersects(widget2, he) && on_above_or_below(pt01, he) && on_above_or_below(pt10, he)) return true; + return false; + } + + static inline Unit evalAtXforYlazy(Unit xIn, Point pt, Point other_pt) { + long double + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + if(pt.y() == other_pt.y()) + return pt.y(); + evalAtXforYxIn = xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = 0; + if(evalAtXforYdx1 == evalAtXforY0) return (Unit)evalAtXforYy1; + evalAtXforYx2 = other_pt.get(HORIZONTAL); + evalAtXforYy2 = other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return (Unit)evalAtXforYret; + } + + static inline typename high_precision_type::type evalAtXforY(Unit xIn, Point pt, Point other_pt) { + typename high_precision_type::type + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + typedef typename high_precision_type::type high_precision; + if(pt.y() == other_pt.y()) + return (high_precision)pt.y(); + evalAtXforYxIn = (high_precision)xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = high_precision(0); + if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; + evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); + evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return evalAtXforYret; + } + + struct evalAtXforYPack { + typename high_precision_type::type + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; + inline const typename high_precision_type::type& evalAtXforY(Unit xIn, Point pt, Point other_pt) { + //y = (x - x1)dy/dx + y1 + //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y + //assert pt.x != other_pt.x + typedef typename high_precision_type::type high_precision; + if(pt.y() == other_pt.y()) { + evalAtXforYret = (high_precision)pt.y(); + return evalAtXforYret; + } + evalAtXforYxIn = (high_precision)xIn; + evalAtXforYx1 = pt.get(HORIZONTAL); + evalAtXforYy1 = pt.get(VERTICAL); + evalAtXforYdx1 = evalAtXforYxIn - evalAtXforYx1; + evalAtXforY0 = high_precision(0); + if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; + evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); + evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); + + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; + evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; + evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); + return evalAtXforYret; + } + }; + + static inline bool is_vertical(const half_edge& he) { + return he.first.get(HORIZONTAL) == he.second.get(HORIZONTAL); + } + + static inline bool is_horizontal(const half_edge& he) { + return he.first.get(VERTICAL) == he.second.get(VERTICAL); + } + + static inline bool is_45_degree(const half_edge& he) { + return euclidean_distance(he.first, he.second, HORIZONTAL) == euclidean_distance(he.first, he.second, VERTICAL); + } + + //scanline comparator functor + class less_half_edge : public std::binary_function { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + evalAtXforYPack * pack_; + public: + inline less_half_edge() : x_(0), justBefore_(0), pack_(0) {} + inline less_half_edge(Unit *x, int *justBefore, evalAtXforYPack * packIn) : x_(x), justBefore_(justBefore), pack_(packIn) {} + inline less_half_edge(const less_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_), + pack_(that.pack_){} + inline less_half_edge& operator=(const less_half_edge& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + pack_ = that.pack_; + return *this; } + inline bool operator () (const half_edge& elm1, const half_edge& elm2) const { + if((std::max)(elm1.first.y(), elm1.second.y()) < (std::min)(elm2.first.y(), elm2.second.y())) + return true; + if((std::min)(elm1.first.y(), elm1.second.y()) > (std::max)(elm2.first.y(), elm2.second.y())) + return false; + + //check if either x of elem1 is equal to x_ + Unit localx = *x_; + Unit elm1y = 0; + bool elm1_at_x = false; + if(localx == elm1.first.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.first.get(VERTICAL); + } else if(localx == elm1.second.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.second.get(VERTICAL); + } + Unit elm2y = 0; + bool elm2_at_x = false; + if(localx == elm2.first.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.first.get(VERTICAL); + } else if(localx == elm2.second.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.second.get(VERTICAL); + } + bool retval = false; + if(!(elm1_at_x && elm2_at_x)) { + //at least one of the segments doesn't have an end point a the current x + //-1 below, 1 above + int pt1_oab = on_above_or_below(elm1.first, half_edge(elm2.first, elm2.second)); + int pt2_oab = on_above_or_below(elm1.second, half_edge(elm2.first, elm2.second)); + if(pt1_oab == pt2_oab) { + if(pt1_oab == -1) + retval = true; //pt1 is below elm2 so elm1 is below elm2 + } else { + //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is + int pt3_oab = on_above_or_below(elm2.first, half_edge(elm1.first, elm1.second)); + if(pt3_oab == 1) + retval = true; //elm1's point is above elm1 + } + } else { + if(elm1y < elm2y) { + retval = true; + } else if(elm1y == elm2y) { + if(elm1 == elm2) + return false; + retval = less_slope(elm1.second.get(HORIZONTAL) - elm1.first.get(HORIZONTAL), + elm1.second.get(VERTICAL) - elm1.first.get(VERTICAL), + elm2.second.get(HORIZONTAL) - elm2.first.get(HORIZONTAL), + elm2.second.get(VERTICAL) - elm2.first.get(VERTICAL)); + retval = ((*justBefore_) != 0) ^ retval; + } + } + return retval; + } + }; + + template + static inline void unsigned_mod(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { + result = a % b; + result_sign = a_sign; + } + + template + static inline void unsigned_add(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { + int switcher = 0; + if(a_sign < 0) switcher += 1; + if(b_sign < 0) switcher += 2; + if(a < b) switcher += 4; + switch (switcher) { + case 0: //both positive + result = a + b; + result_sign = 1; + break; + case 1: //a is negative + result = a - b; + result_sign = -1; + break; + case 2: //b is negative + result = a - b; + result_sign = 1; + break; + case 3: //both negative + result = a + b; + result_sign = -1; + break; + case 4: //both positive + result = a + b; + result_sign = 1; + break; + case 5: //a is negative + result = b - a; + result_sign = 1; + break; + case 6: //b is negative + result = b - a; + result_sign = -1; + break; + case 7: //both negative + result = b + a; + result_sign = -1; + break; + }; + } + + struct compute_intersection_pack { + typedef typename high_precision_type::type high_precision; + high_precision y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; + static inline bool compute_lazy_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + long double y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; + typedef rectangle_data Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!projected && !::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + y_high = evalAtXforYlazy(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y_local = (Unit)y_high; + if(y_high < y_local) --y_local; + if(projected || contains(rect1.get(VERTICAL), y_local, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y_local); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + y_high = evalAtXforYlazy(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y_local = (Unit)y_high; + if(y_high < y_local) --y_local; + if(projected || contains(rect2.get(VERTICAL), y_local, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y_local); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + dy2 = (he2.second.get(VERTICAL)) - + (he2.first.get(VERTICAL)); + dy1 = (he1.second.get(VERTICAL)) - + (he1.first.get(VERTICAL)); + dx2 = (he2.second.get(HORIZONTAL)) - + (he2.first.get(HORIZONTAL)); + dx1 = (he1.second.get(HORIZONTAL)) - + (he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + x11 = (he1.first.get(HORIZONTAL)); + x21 = (he2.first.get(HORIZONTAL)); + y11 = (he1.first.get(VERTICAL)); + y21 = (he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_den = (dy1 * dx2 - dy2 * dx1); + y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + y_den = (dx1 * dy2 - dx2 * dy1); + x = x_num / x_den; + y = y_num / y_den; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + if(round_closest) { + x = x + 0.5; + y = y + 0.5; + } + Unit x_unit = (Unit)(x); + Unit y_unit = (Unit)(y); + //truncate downward if it went up due to negative number + if(x < x_unit) --x_unit; + if(y < y_unit) --y_unit; + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!projected && !contains(rect1, result, true)) return false; + if(!projected && !contains(rect2, result, true)) return false; + if(projected) { + rectangle_data inf_rect((long double)(std::numeric_limits::min)(), + (long double) (std::numeric_limits::min)(), + (long double)(std::numeric_limits::max)(), + (long double) (std::numeric_limits::max)() ); + if(contains(inf_rect, intersection, true)) { + intersection = result; + return true; + } else + return false; + } + intersection = result; + return true; + } + inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + if(!projected && !intersects(he1, he2)) + return false; + bool lazy_success = compute_lazy_intersection(intersection, he1, he2, projected); + if(!projected) { + if(lazy_success) { + if(intersects_grid(intersection, he1) && + intersects_grid(intersection, he2)) + return true; + } + } else { + return lazy_success; + } + typedef rectangle_data Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y = convert_high_precision_type(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect1.get(VERTICAL), y, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y = convert_high_precision_type(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect2.get(VERTICAL), y, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + dy2 = (high_precision)(he2.second.get(VERTICAL)) - + (high_precision)(he2.first.get(VERTICAL)); + dy1 = (high_precision)(he1.second.get(VERTICAL)) - + (high_precision)(he1.first.get(VERTICAL)); + dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + (high_precision)(he2.first.get(HORIZONTAL)); + dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + (high_precision)(he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + x11 = (high_precision)(he1.first.get(HORIZONTAL)); + x21 = (high_precision)(he2.first.get(HORIZONTAL)); + y11 = (high_precision)(he1.first.get(VERTICAL)); + y21 = (high_precision)(he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_den = (dy1 * dx2 - dy2 * dx1); + y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + y_den = (dx1 * dy2 - dx2 * dy1); + x = x_num / x_den; + y = y_num / y_den; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + if(round_closest) { + x = x + (high_precision)0.5; + y = y + (high_precision)0.5; + } + Unit x_unit = convert_high_precision_type(x); + Unit y_unit = convert_high_precision_type(y); + //truncate downward if it went up due to negative number + if(x < (high_precision)x_unit) --x_unit; + if(y < (high_precision)y_unit) --y_unit; + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!contains(rect1, result, true)) return false; + if(!contains(rect2, result, true)) return false; + if(projected) { + rectangle_data inf_rect((long double)(std::numeric_limits::min)(), + (long double) (std::numeric_limits::min)(), + (long double)(std::numeric_limits::max)(), + (long double) (std::numeric_limits::max)() ); + if(contains(inf_rect, intersection, true)) { + intersection = result; + return true; + } else + return false; + } + intersection = result; + return true; + } + }; + + static inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2) { + typedef typename high_precision_type::type high_precision; + typedef rectangle_data Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(!::boost::polygon::intersects(rect1, rect2, true)) return false; + if(is_vertical(he1)) { + if(is_vertical(he2)) return false; + high_precision y_high = evalAtXforY(he1.first.get(HORIZONTAL), he2.first, he2.second); + Unit y = convert_high_precision_type(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect1.get(VERTICAL), y, true)) { + intersection = Point(he1.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } else if(is_vertical(he2)) { + high_precision y_high = evalAtXforY(he2.first.get(HORIZONTAL), he1.first, he1.second); + Unit y = convert_high_precision_type(y_high); + if(y_high < (high_precision)y) --y; + if(contains(rect2.get(VERTICAL), y, true)) { + intersection = Point(he2.first.get(HORIZONTAL), y); + return true; + } else { + return false; + } + } + //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point + high_precision dy2 = (high_precision)(he2.second.get(VERTICAL)) - + (high_precision)(he2.first.get(VERTICAL)); + high_precision dy1 = (high_precision)(he1.second.get(VERTICAL)) - + (high_precision)(he1.first.get(VERTICAL)); + high_precision dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + (high_precision)(he2.first.get(HORIZONTAL)); + high_precision dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + (high_precision)(he1.first.get(HORIZONTAL)); + if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; + //the line segments have different slopes + //we can assume that the line segments are not vertical because such an intersection is handled elsewhere + high_precision x11 = (high_precision)(he1.first.get(HORIZONTAL)); + high_precision x21 = (high_precision)(he2.first.get(HORIZONTAL)); + high_precision y11 = (high_precision)(he1.first.get(VERTICAL)); + high_precision y21 = (high_precision)(he2.first.get(VERTICAL)); + //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); + //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); + high_precision x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + high_precision x_den = (dy1 * dx2 - dy2 * dx1); + high_precision y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); + high_precision y_den = (dx1 * dy2 - dx2 * dy1); + high_precision x = x_num / x_den; + high_precision y = y_num / y_den; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); + //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); + Unit x_unit = convert_high_precision_type(x); + Unit y_unit = convert_high_precision_type(y); + //truncate downward if it went up due to negative number + if(x < (high_precision)x_unit) --x_unit; + if(y < (high_precision)y_unit) --y_unit; + //if(x != exp_x || y != exp_y) + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); + //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + Point result(x_unit, y_unit); + if(!contains(rect1, result, true)) return false; + if(!contains(rect2, result, true)) return false; + intersection = result; + return true; + } + + static inline bool intersects(const half_edge& he1, const half_edge& he2) { + typedef rectangle_data Rectangle; + Rectangle rect1, rect2; + set_points(rect1, he1.first, he1.second); + set_points(rect2, he2.first, he2.second); + if(::boost::polygon::intersects(rect1, rect2, false)) { + if(he1.first == he2.first) { + if(he1.second != he2.second && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), + he1.second, he2.second)) { + return true; + } else { + return false; + } + } + if(he1.first == he2.second) { + if(he1.second != he2.first && equal_slope(he1.first.get(HORIZONTAL), he1.first.get(VERTICAL), + he1.second, he2.first)) { + return true; + } else { + return false; + } + } + if(he1.second == he2.first) { + if(he1.first != he2.second && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), + he1.first, he2.second)) { + return true; + } else { + return false; + } + } + if(he1.second == he2.second) { + if(he1.first != he2.first && equal_slope(he1.second.get(HORIZONTAL), he1.second.get(VERTICAL), + he1.first, he2.first)) { + return true; + } else { + return false; + } + } + int oab1 = on_above_or_below(he1.first, he2); + if(oab1 == 0 && between(he1.first, he2.first, he2.second)) return true; + int oab2 = on_above_or_below(he1.second, he2); + if(oab2 == 0 && between(he1.second, he2.first, he2.second)) return true; + if(oab1 == oab2 && oab1 != 0) return false; //both points of he1 are on same side of he2 + int oab3 = on_above_or_below(he2.first, he1); + if(oab3 == 0 && between(he2.first, he1.first, he1.second)) return true; + int oab4 = on_above_or_below(he2.second, he1); + if(oab4 == 0 && between(he2.second, he1.first, he1.second)) return true; + if(oab3 == oab4) return false; //both points of he2 are on same side of he1 + return true; //they must cross + } + if(is_vertical(he1) && is_vertical(he2) && he1.first.get(HORIZONTAL) == he2.first.get(HORIZONTAL)) + return ::boost::polygon::intersects(rect1.get(VERTICAL), rect2.get(VERTICAL), false) && + rect1.get(VERTICAL) != rect2.get(VERTICAL); + if(is_horizontal(he1) && is_horizontal(he2) && he1.first.get(VERTICAL) == he2.first.get(VERTICAL)) + return ::boost::polygon::intersects(rect1.get(HORIZONTAL), rect2.get(HORIZONTAL), false) && + rect1.get(HORIZONTAL) != rect2.get(HORIZONTAL); + return false; + } + + class vertex_half_edge { + public: + typedef typename high_precision_type::type high_precision; + Point pt; + Point other_pt; // 1, 0 or -1 + int count; //dxdydTheta + inline vertex_half_edge() : pt(), other_pt(), count() {} + inline vertex_half_edge(const Point& point, const Point& other_point, int countIn) : pt(point), other_pt(other_point), count(countIn) {} + inline vertex_half_edge(const vertex_half_edge& vertex) : pt(vertex.pt), other_pt(vertex.other_pt), count(vertex.count) {} + inline vertex_half_edge& operator=(const vertex_half_edge& vertex){ + pt = vertex.pt; other_pt = vertex.other_pt; count = vertex.count; return *this; } + inline vertex_half_edge(const std::pair& vertex) : pt(), other_pt(), count() {} + inline vertex_half_edge& operator=(const std::pair& vertex){ return *this; } + inline bool operator==(const vertex_half_edge& vertex) const { + return pt == vertex.pt && other_pt == vertex.other_pt && count == vertex.count; } + inline bool operator!=(const vertex_half_edge& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair& vertex) const { return false; } + inline bool operator!=(const std::pair& vertex) const { return !((*this) == vertex); } + inline bool operator<(const vertex_half_edge& vertex) const { + if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; + if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { + if(pt.get(VERTICAL) < vertex.pt.get(VERTICAL)) return true; + if(pt.get(VERTICAL) == vertex.pt.get(VERTICAL)) { return less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), + other_pt, vertex.other_pt); + } + } + return false; + } + inline bool operator>(const vertex_half_edge& vertex) const { return vertex < (*this); } + inline bool operator<=(const vertex_half_edge& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const vertex_half_edge& vertex) const { return !((*this) < vertex); } + inline high_precision evalAtX(Unit xIn) const { return evalAtXforYlazy(xIn, pt, other_pt); } + inline bool is_vertical() const { + return pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL); + } + inline bool is_begin() const { + return pt.get(HORIZONTAL) < other_pt.get(HORIZONTAL) || + (pt.get(HORIZONTAL) == other_pt.get(HORIZONTAL) && + (pt.get(VERTICAL) < other_pt.get(VERTICAL))); + } + }; + + //when scanning Vertex45 for polygon formation we need a scanline comparator functor + class less_vertex_half_edge : public std::binary_function { + private: + Unit *x_; //x value at which to apply comparison + int *justBefore_; + public: + inline less_vertex_half_edge() : x_(0), justBefore_(0) {} + inline less_vertex_half_edge(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} + inline less_vertex_half_edge(const less_vertex_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_) {} + inline less_vertex_half_edge& operator=(const less_vertex_half_edge& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } + inline bool operator () (const vertex_half_edge& elm1, const vertex_half_edge& elm2) const { + if((std::max)(elm1.pt.y(), elm1.other_pt.y()) < (std::min)(elm2.pt.y(), elm2.other_pt.y())) + return true; + if((std::min)(elm1.pt.y(), elm1.other_pt.y()) > (std::max)(elm2.pt.y(), elm2.other_pt.y())) + return false; + //check if either x of elem1 is equal to x_ + Unit localx = *x_; + Unit elm1y = 0; + bool elm1_at_x = false; + if(localx == elm1.pt.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.pt.get(VERTICAL); + } else if(localx == elm1.other_pt.get(HORIZONTAL)) { + elm1_at_x = true; + elm1y = elm1.other_pt.get(VERTICAL); + } + Unit elm2y = 0; + bool elm2_at_x = false; + if(localx == elm2.pt.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.pt.get(VERTICAL); + } else if(localx == elm2.other_pt.get(HORIZONTAL)) { + elm2_at_x = true; + elm2y = elm2.other_pt.get(VERTICAL); + } + bool retval = false; + if(!(elm1_at_x && elm2_at_x)) { + //at least one of the segments doesn't have an end point a the current x + //-1 below, 1 above + int pt1_oab = on_above_or_below(elm1.pt, half_edge(elm2.pt, elm2.other_pt)); + int pt2_oab = on_above_or_below(elm1.other_pt, half_edge(elm2.pt, elm2.other_pt)); + if(pt1_oab == pt2_oab) { + if(pt1_oab == -1) + retval = true; //pt1 is below elm2 so elm1 is below elm2 + } else { + //the segments can't cross so elm2 is on whatever side of elm1 that one of its ends is + int pt3_oab = on_above_or_below(elm2.pt, half_edge(elm1.pt, elm1.other_pt)); + if(pt3_oab == 1) + retval = true; //elm1's point is above elm1 + } + } else { + if(elm1y < elm2y) { + retval = true; + } else if(elm1y == elm2y) { + if(elm1.pt == elm2.pt && elm1.other_pt == elm2.other_pt) + return false; + retval = less_slope(elm1.other_pt.get(HORIZONTAL) - elm1.pt.get(HORIZONTAL), + elm1.other_pt.get(VERTICAL) - elm1.pt.get(VERTICAL), + elm2.other_pt.get(HORIZONTAL) - elm2.pt.get(HORIZONTAL), + elm2.other_pt.get(VERTICAL) - elm2.pt.get(VERTICAL)); + retval = ((*justBefore_) != 0) ^ retval; + } + } + return retval; + } + }; + + }; + + template + class polygon_arbitrary_formation : public scanline_base { + public: + typedef typename scanline_base::Point Point; + typedef typename scanline_base::half_edge half_edge; + typedef typename scanline_base::vertex_half_edge vertex_half_edge; + typedef typename scanline_base::less_vertex_half_edge less_vertex_half_edge; + + class poly_line_arbitrary { + public: + typedef typename std::list::const_iterator iterator; + + // default constructor of point does not initialize x and y + inline poly_line_arbitrary() : points() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline poly_line_arbitrary& set(iT inputBegin, iT inputEnd) { + points.clear(); //just in case there was some old data there + while(inputBegin != inputEnd) { + points.insert(points.end(), *inputBegin); + ++inputBegin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline poly_line_arbitrary(const poly_line_arbitrary& that) : points(that.points) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline poly_line_arbitrary& operator=(const poly_line_arbitrary& that) { + points = that.points; + return *this; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator begin() const { return points.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator end() const { return points.end(); } + + inline std::size_t size() const { return points.size(); } + + //public data member + std::list points; + }; + + class active_tail_arbitrary { + protected: + //data + poly_line_arbitrary* tailp_; + active_tail_arbitrary *otherTailp_; + std::list holesList_; + bool head_; + public: + + /** + * @brief iterator over coordinates of the figure + */ + typedef typename poly_line_arbitrary::iterator iterator; + + /** + * @brief iterator over holes contained within the figure + */ + typedef typename std::list::const_iterator iteratorHoles; + + //default constructor + inline active_tail_arbitrary() : tailp_(), otherTailp_(), holesList_(), head_() {} + + //constructor + inline active_tail_arbitrary(const vertex_half_edge& vertex, active_tail_arbitrary* otherTailp = 0) : tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = new poly_line_arbitrary; + tailp_->points.push_back(vertex.pt); + //bool headArray[4] = {false, true, true, true}; + bool inverted = vertex.count == -1; + head_ = (!vertex.is_vertical) ^ inverted; + otherTailp_ = otherTailp; + } + + inline active_tail_arbitrary(Point point, active_tail_arbitrary* otherTailp, bool head = true) : + tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = new poly_line_arbitrary; + tailp_->points.push_back(point); + head_ = head; + otherTailp_ = otherTailp; + + } + inline active_tail_arbitrary(active_tail_arbitrary* otherTailp) : + tailp_(), otherTailp_(), holesList_(), head_() { + tailp_ = otherTailp->tailp_; + otherTailp_ = otherTailp; + } + + //copy constructor + inline active_tail_arbitrary(const active_tail_arbitrary& that) : + tailp_(), otherTailp_(), holesList_(), head_() { (*this) = that; } + + //destructor + inline ~active_tail_arbitrary() { + destroyContents(); + } + + //assignment operator + inline active_tail_arbitrary& operator=(const active_tail_arbitrary& that) { + tailp_ = new poly_line_arbitrary(*(that.tailp_)); + head_ = that.head_; + otherTailp_ = that.otherTailp_; + holesList_ = that.holesList_; + return *this; + } + + //equivalence operator + inline bool operator==(const active_tail_arbitrary& b) const { + return tailp_ == b.tailp_ && head_ == b.head_; + } + + /** + * @brief get the pointer to the polyline that this is an active tail of + */ + inline poly_line_arbitrary* getTail() const { return tailp_; } + + /** + * @brief get the pointer to the polyline at the other end of the chain + */ + inline poly_line_arbitrary* getOtherTail() const { return otherTailp_->tailp_; } + + /** + * @brief get the pointer to the activetail at the other end of the chain + */ + inline active_tail_arbitrary* getOtherActiveTail() const { return otherTailp_; } + + /** + * @brief test if another active tail is the other end of the chain + */ + inline bool isOtherTail(const active_tail_arbitrary& b) const { return &b == otherTailp_; } + + /** + * @brief update this end of chain pointer to new polyline + */ + inline active_tail_arbitrary& updateTail(poly_line_arbitrary* newTail) { tailp_ = newTail; return *this; } + + inline bool join(active_tail_arbitrary* tail) { + if(tail == otherTailp_) { + //std::cout << "joining to other tail!\n"; + return false; + } + if(tail->head_ == head_) { + //std::cout << "joining head to head!\n"; + return false; + } + if(!tailp_) { + //std::cout << "joining empty tail!\n"; + return false; + } + if(!(otherTailp_->head_)) { + otherTailp_->copyHoles(*tail); + otherTailp_->copyHoles(*this); + } else { + tail->otherTailp_->copyHoles(*this); + tail->otherTailp_->copyHoles(*tail); + } + poly_line_arbitrary* tail1 = tailp_; + poly_line_arbitrary* tail2 = tail->tailp_; + if(head_) std::swap(tail1, tail2); + typename std::list >::reverse_iterator riter = tail1->points.rbegin(); + typename std::list >::iterator iter = tail2->points.begin(); + if(*riter == *iter) { + tail1->points.pop_back(); //remove duplicate point + } + tail1->points.splice(tail1->points.end(), tail2->points); + delete tail2; + otherTailp_->tailp_ = tail1; + tail->otherTailp_->tailp_ = tail1; + otherTailp_->otherTailp_ = tail->otherTailp_; + tail->otherTailp_->otherTailp_ = otherTailp_; + tailp_ = 0; + tail->tailp_ = 0; + tail->otherTailp_ = 0; + otherTailp_ = 0; + return true; + } + + /** + * @brief associate a hole to this active tail by the specified policy + */ + inline active_tail_arbitrary* addHole(active_tail_arbitrary* hole) { + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->otherTailp_)); + return this; + } + + /** + * @brief get the list of holes + */ + inline const std::list& getHoles() const { return holesList_; } + + /** + * @brief copy holes from that to this + */ + inline void copyHoles(active_tail_arbitrary& that) { holesList_.splice(holesList_.end(), that.holesList_); } + + /** + * @brief find out if solid to right + */ + inline bool solidToRight() const { return !head_; } + inline bool solidToLeft() const { return head_; } + + /** + * @brief get vertex + */ + inline Point getPoint() const { + if(head_) return tailp_->points.front(); + return tailp_->points.back(); + } + + /** + * @brief add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + inline void pushPoint(Point point) { + if(head_) { + //if(tailp_->points.size() < 2) { + // tailp_->points.push_front(point); + // return; + //} + typename std::list::iterator iter = tailp_->points.begin(); + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + ++iter; + if(iter == tailp_->points.end()) { + tailp_->points.push_front(point); + return; + } + --iter; + if(*iter != point) { + tailp_->points.push_front(point); + } + return; + } + //if(tailp_->points.size() < 2) { + // tailp_->points.push_back(point); + // return; + //} + typename std::list::reverse_iterator iter = tailp_->points.rbegin(); + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + ++iter; + if(iter == tailp_->points.rend()) { + tailp_->points.push_back(point); + return; + } + --iter; + if(*iter != point) { + tailp_->points.push_back(point); + } + } + + /** + * @brief joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + template + static inline active_tail_arbitrary* joinChains(Point point, active_tail_arbitrary* at1, active_tail_arbitrary* at2, bool solid, + cT& output) { + if(at1->otherTailp_ == at2) { + //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; + //we are closing a figure + at1->pushPoint(point); + at2->pushPoint(point); + if(solid) { + //we are closing a solid figure, write to output + //std::cout << "test1\n"; + at1->copyHoles(*(at1->otherTailp_)); + typename PolyLineArbitraryByConcept::type>::type polyData(at1); + //poly_line_arbitrary_polygon_data polyData(at1); + //std::cout << "test2\n"; + //std::cout << poly << std::endl; + //std::cout << "test3\n"; + typedef typename cT::value_type result_type; + typedef typename geometry_concept::type result_concept; + output.push_back(result_type()); + assign(output.back(), polyData); + //std::cout << "test4\n"; + //std::cout << "delete " << at1->otherTailp_ << std::endl; + //at1->print(); + //at1->otherTailp_->print(); + delete at1->otherTailp_; + //at1->print(); + //at1->otherTailp_->print(); + //std::cout << "test5\n"; + //std::cout << "delete " << at1 << std::endl; + delete at1; + //std::cout << "test6\n"; + return 0; + } else { + //we are closing a hole, return the tail end active tail of the figure + return at1; + } + } + //we are not closing a figure + at1->pushPoint(point); + at1->join(at2); + delete at1; + delete at2; + return 0; + } + + inline void destroyContents() { + if(otherTailp_) { + //std::cout << "delete p " << tailp_ << std::endl; + if(tailp_) delete tailp_; + tailp_ = 0; + otherTailp_->otherTailp_ = 0; + otherTailp_->tailp_ = 0; + otherTailp_ = 0; + } + for(typename std::list::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { + //std::cout << "delete p " << (*itr) << std::endl; + if(*itr) { + if((*itr)->otherTailp_) { + delete (*itr)->otherTailp_; + (*itr)->otherTailp_ = 0; + } + delete (*itr); + } + (*itr) = 0; + } + holesList_.clear(); + } + + inline void print() { + //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; + } + + static inline std::pair createActiveTailsAsPair(Point point, bool solid, + active_tail_arbitrary* phole, bool fractureHoles) { + active_tail_arbitrary* at1 = 0; + active_tail_arbitrary* at2 = 0; + if(phole && fractureHoles) { + //std::cout << "adding hole\n"; + at1 = phole; + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at2 = at1->getOtherActiveTail(); + at2->pushPoint(point); + at1->pushPoint(point); + } else { + at1 = new active_tail_arbitrary(point, at2, solid); + at2 = new active_tail_arbitrary(at1); + at1->otherTailp_ = at2; + at2->head_ = !solid; + if(phole) + at2->addHole(phole); //assert fractureHoles == false + } + return std::pair(at1, at2); + } + + }; + + + typedef std::vector > vertex_arbitrary_count; + + class less_half_edge_count : public std::binary_function { + private: + Point pt_; + public: + inline less_half_edge_count() : pt_() {} + inline less_half_edge_count(Point point) : pt_(point) {} + inline bool operator () (const std::pair& elm1, const std::pair& elm2) const { + return scanline_base::less_slope(pt_.get(HORIZONTAL), pt_.get(VERTICAL), elm1.first, elm2.first); + } + }; + + static inline void sort_vertex_arbitrary_count(vertex_arbitrary_count& count, const Point& pt) { + less_half_edge_count lfec(pt); + std::sort(count.begin(), count.end(), lfec); + } + + typedef std::vector, int>, active_tail_arbitrary*> > incoming_count; + + class less_incoming_count : public std::binary_function, int>, active_tail_arbitrary*>, + std::pair, int>, active_tail_arbitrary*>, bool> { + private: + Point pt_; + public: + inline less_incoming_count() : pt_() {} + inline less_incoming_count(Point point) : pt_(point) {} + inline bool operator () (const std::pair, int>, active_tail_arbitrary*>& elm1, + const std::pair, int>, active_tail_arbitrary*>& elm2) const { + Unit dx1 = elm1.first.first.first.get(HORIZONTAL) - elm1.first.first.second.get(HORIZONTAL); + Unit dx2 = elm2.first.first.first.get(HORIZONTAL) - elm2.first.first.second.get(HORIZONTAL); + Unit dy1 = elm1.first.first.first.get(VERTICAL) - elm1.first.first.second.get(VERTICAL); + Unit dy2 = elm2.first.first.first.get(VERTICAL) - elm2.first.first.second.get(VERTICAL); + return scanline_base::less_slope(dx1, dy1, dx2, dy2); + } + }; + + static inline void sort_incoming_count(incoming_count& count, const Point& pt) { + less_incoming_count lfec(pt); + std::sort(count.begin(), count.end(), lfec); + } + + static inline void compact_vertex_arbitrary_count(const Point& pt, vertex_arbitrary_count &count) { + if(count.empty()) return; + vertex_arbitrary_count tmp; + tmp.reserve(count.size()); + tmp.push_back(count[0]); + //merge duplicates + for(std::size_t i = 1; i < count.size(); ++i) { + if(!equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), tmp[i-1].first, count[i].first)) { + tmp.push_back(count[i]); + } else { + tmp.back().second += count[i].second; + } + } + count.clear(); + count.swap(tmp); + } + + // inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_count& c) { +// for(unsinged int i = 0; i < c.size(); ++i) { +// o << c[i].first << " " << c[i].second << " "; +// } +// return o; +// } + + class vertex_arbitrary_compact { + public: + Point pt; + vertex_arbitrary_count count; + inline vertex_arbitrary_compact() : pt(), count() {} + inline vertex_arbitrary_compact(const Point& point, const Point& other_point, int countIn) : pt(point), count() { + count.push_back(std::pair(other_point, countIn)); + } + inline vertex_arbitrary_compact(const vertex_half_edge& vertex) : pt(vertex.pt), count() { + count.push_back(std::pair(vertex.other_pt, vertex.count)); + } + inline vertex_arbitrary_compact(const vertex_arbitrary_compact& vertex) : pt(vertex.pt), count(vertex.count) {} + inline vertex_arbitrary_compact& operator=(const vertex_arbitrary_compact& vertex){ + pt = vertex.pt; count = vertex.count; return *this; } + //inline vertex_arbitrary_compact(const std::pair& vertex) {} + inline vertex_arbitrary_compact& operator=(const std::pair& vertex){ return *this; } + inline bool operator==(const vertex_arbitrary_compact& vertex) const { + return pt == vertex.pt && count == vertex.count; } + inline bool operator!=(const vertex_arbitrary_compact& vertex) const { return !((*this) == vertex); } + inline bool operator==(const std::pair& vertex) const { return false; } + inline bool operator!=(const std::pair& vertex) const { return !((*this) == vertex); } + inline bool operator<(const vertex_arbitrary_compact& vertex) const { + if(pt.get(HORIZONTAL) < vertex.pt.get(HORIZONTAL)) return true; + if(pt.get(HORIZONTAL) == vertex.pt.get(HORIZONTAL)) { + return pt.get(VERTICAL) < vertex.pt.get(VERTICAL); + } + return false; + } + inline bool operator>(const vertex_arbitrary_compact& vertex) const { return vertex < (*this); } + inline bool operator<=(const vertex_arbitrary_compact& vertex) const { return !((*this) > vertex); } + inline bool operator>=(const vertex_arbitrary_compact& vertex) const { return !((*this) < vertex); } + inline bool have_vertex_half_edge(int index) const { return count[index]; } + inline vertex_half_edge operator[](int index) const { return vertex_half_edge(pt, count[index]); } + }; + +// inline std::ostream& operator<< (std::ostream& o, const vertex_arbitrary_compact& c) { +// o << c.pt << ", " << c.count; +// return o; +// } + + protected: + //definitions + typedef std::map scanline_data; + typedef typename scanline_data::iterator iterator; + typedef typename scanline_data::const_iterator const_iterator; + + //data + scanline_data scanData_; + Unit x_; + int justBefore_; + int fractureHoles_; + public: + inline polygon_arbitrary_formation() : + scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + } + inline polygon_arbitrary_formation(bool fractureHoles) : + scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(fractureHoles) { + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + } + inline polygon_arbitrary_formation(const polygon_arbitrary_formation& that) : + scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } + inline polygon_arbitrary_formation& operator=(const polygon_arbitrary_formation& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + fractureHoles_ = that.fractureHoles_; + less_vertex_half_edge lessElm(&x_, &justBefore_); + scanData_ = scanline_data(lessElm); + for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ + scanData_.insert(scanData_.end(), *itr); + } + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over vertex_half_edge elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + x_ = (*inputBegin).pt.get(HORIZONTAL); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + //std::cout << "scan line size: " << scanData_.size() << std::endl; + } + + protected: + //functions + template + inline std::pair, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, + incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { + //std::cout << "\nAT POINT: " << point << std::endl; + //join any closing solid corners + std::vector counts; + std::vector incoming; + std::vector tails; + counts.reserve(counts_from_scanline.size()); + tails.reserve(counts_from_scanline.size()); + incoming.reserve(incoming_count.size()); + for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { + counts.push_back(counts_from_scanline[i].first.second); + tails.push_back(counts_from_scanline[i].second); + } + for(std::size_t i = 0; i < incoming_count.size(); ++i) { + incoming.push_back(incoming_count[i].second); + if(incoming_count[i].first < point) { + incoming.back() = 0; + } + } + + active_tail_arbitrary* returnValue = 0; + std::pair returnCount(Point(0, 0), 0); + int i_size_less_1 = (int)(incoming.size()) -1; + int c_size_less_1 = (int)(counts.size()) -1; + int i_size = incoming.size(); + int c_size = counts.size(); + + bool have_vertical_tail_from_below = false; + if(c_size && + scanline_base::is_vertical(counts_from_scanline.back().first.first)) { + have_vertical_tail_from_below = true; + } + //assert size = size_less_1 + 1 + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + // for(std::size_t i = 0; i < counts.size(); ++i) { + // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; + // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; + // std::cout << counts_from_scanline[i].first.second << " "; + // } std::cout << std::endl; + // print(incoming_count); + { + for(int i = 0; i < c_size_less_1; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < c_size; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + { + for(int i = 0; i < i_size_less_1; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < i_size; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + //std::cout << incoming[j] << std::endl; + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[i].first, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + } + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + { + //std::cout << "checking case 3\n"; + for(int i = 0; i < c_size; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i_size_less_1; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = -1; + } else { + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + { + for(int i = c_size_less_1; i >= 0; --i) { + //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < i_size; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + tails[i]->pushPoint(point); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //find the end of a hole or the beginning of a hole + + //find end of a hole + { + for(int i = 0; i < c_size_less_1; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < c_size; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + returnValue = active_tail_arbitrary::joinChains(point, tails[i], tails[j], false, output); + if(returnValue) returnCount.first = point; + //std::cout << returnValue << std::endl; + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + } + //find beginning of a hole + { + for(int i = 0; i < i_size_less_1; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < i_size; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + active_tail_arbitrary* holep = 0; + //if(c_size && counts[c_size_less_1] == 0 && + // counts_from_scanline[c_size_less_1].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) + if(have_vertical_tail_from_below) { + holep = tails[c_size_less_1]; + tails[c_size_less_1] = 0; + have_vertical_tail_from_below = false; + } + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, false, holep, fractureHoles_ != 0); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //std::cout << "vertical element " << point << std::endl; + returnValue = tailPair.first; + returnCount.first = point; + //returnCount = incoming_count[j]; + returnCount.second = -1; + } else { + //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[i].first, incoming[i]), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + } + if(have_vertical_tail_from_below) { + if(tails.back()) { + tails.back()->pushPoint(point); + returnValue = tails.back(); + returnCount.first = point; + returnCount.second = counts.back(); + } + } + //assert that tails, counts and incoming are all null + return std::pair, active_tail_arbitrary*>(returnCount, returnValue); + } + + static inline void print(const vertex_arbitrary_count& count) { + for(unsigned i = 0; i < count.size(); ++i) { + //std::cout << count[i].first.get(HORIZONTAL) << ","; + //std::cout << count[i].first.get(VERTICAL) << ":"; + //std::cout << count[i].second << " "; + } //std::cout << std::endl; + } + + static inline void print(const scanline_data& data) { + for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ + //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; + } //std::cout << std::endl; + } + + template + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + typedef typename high_precision_type::type high_precision; + //std::cout << "processEvent_\n"; + justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + active_tail_arbitrary* verticalTail = 0; + std::pair verticalCount(Point(0, 0), 0); + iT currentIter = inputBegin; + std::vector elementIters; + std::vector > elements; + while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.get(VERTICAL); + //std::cout << "current Y " << currentY << std::endl; + //std::cout << "scanline size " << scanData_.size() << std::endl; + //print(scanData_); + iterator iter = lookUp_(currentY); + //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //int counts[4] = {0, 0, 0, 0}; + incoming_count counts_from_scanline; + //std::cout << "finding elements in tree\n"; + //if(iter != scanData_.end()) + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + while(iter != scanData_.end() && + ((iter->first.pt.x() == x_ && iter->first.pt.y() == currentY) || + (iter->first.other_pt.x() == x_ && iter->first.other_pt.y() == currentY))) { + //iter->first.evalAtX(x_) == (high_precision)currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> + (std::pair, int>(std::pair(iter->first.pt, + iter->first.other_pt), + iter->first.count), + iter->second)); + ++iter; + } + Point currentPoint(x_, currentY); + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + sort_incoming_count(counts_from_scanline, currentPoint); + + vertex_arbitrary_count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + const vertex_half_edge& elem = *currentIter; + incoming.push_back(std::pair(elem.other_pt, elem.count)); + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && + currentIter->pt.get(HORIZONTAL) == x_); + //print(incoming); + sort_vertex_arbitrary_count(incoming, currentPoint); + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //print(incoming); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //compact_vertex_arbitrary_count(currentPoint, incoming); + vertex_arbitrary_count tmp; + tmp.reserve(incoming.size()); + for(std::size_t i = 0; i < incoming.size(); ++i) { + if(currentPoint < incoming[i].first) { + tmp.push_back(incoming[i]); + } + } + incoming.swap(tmp); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //now counts_from_scanline has the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + if(verticalTail) { + //std::cout << "adding vertical tail to counts from scanline\n"; + //std::cout << -verticalCount.second << std::endl; + counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> + (std::pair, int>(std::pair(verticalCount.first, + currentPoint), + -verticalCount.second), + verticalTail)); + } + if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == x_) { + //std::cout << "inverted vertical event\n"; + incoming.back().second *= -1; + } + //std::cout << "calling processPoint_\n"; + std::pair, active_tail_arbitrary*> result = processPoint_(output, elements, Point(x_, currentY), counts_from_scanline, incoming); + verticalCount = result.first; + verticalTail = result.second; + //if(verticalTail) { + // std::cout << "have vertical tail\n"; + // std::cout << verticalCount.second << std::endl; + //} + if(verticalTail && !(verticalCount.second)) { + //we got a hole out of the point we just processed + //iter is still at the next y element above the current y value in the tree + //std::cout << "checking whether ot handle hole\n"; + if(currentIter == inputEnd || + currentIter->pt.get(HORIZONTAL) != x_ || + scanline_base::on_above_or_below(currentIter->pt, half_edge(iter->first.pt, iter->first.other_pt)) != -1) { + //(high_precision)(currentIter->pt.get(VERTICAL)) >= iter->first.evalAtX(x_)) { + + //std::cout << "handle hole here\n"; + if(fractureHoles_) { + //std::cout << "fracture hole here\n"; + //we need to handle the hole now and not at the next input vertex + active_tail_arbitrary* at = iter->second; + high_precision precise_y = iter->first.evalAtX(x_); + Unit fracture_y = convert_high_precision_type(precise_y); + if(precise_y < fracture_y) --fracture_y; + Point point(x_, fracture_y); + verticalTail->getOtherActiveTail()->pushPoint(point); + iter->second = verticalTail->getOtherActiveTail(); + at->pushPoint(point); + verticalTail->join(at); + delete at; + delete verticalTail; + verticalTail = 0; + } else { + //std::cout << "push hole onto list\n"; + iter->second->addHole(verticalTail); + verticalTail = 0; + } + } + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + scanData_.erase(*iter); + } + //switch comparison tie breaking policy + justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + scanData_.insert(scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + + inline iterator lookUp_(Unit y){ + //if just before then we need to look from 1 not -1 + //std::cout << "just before " << justBefore_ << std::endl; + return scanData_.lower_bound(vertex_half_edge(Point(x_, y), Point(x_, y+1), 0)); + } + + public: //test functions + + template + static inline bool testPolygonArbitraryFormationRect(stream_type& stdcout) { + stdcout << "testing polygon formation\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationP1(stream_type& stdcout) { + stdcout << "testing polygon formation P1\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationP2(stream_type& stdcout) { + stdcout << "testing polygon formation P2\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); + data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + + template + static inline bool testPolygonArbitraryFormationPolys(stream_type& stdcout) { + stdcout << "testing polygon formation polys\n"; + polygon_arbitrary_formation pf(false); + std::vector > polys; + polygon_arbitrary_formation pf2(true); + std::vector > polys2; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); + + data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); + + data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + pf2.scan(polys2, data.begin(), data.end()); + stdcout << "result size: " << polys2.size() << std::endl; + for(std::size_t i = 0; i < polys2.size(); ++i) { + stdcout << polys2[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationSelfTouch1(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 1\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationSelfTouch2(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 2\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(4, 1), -1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(4, 1), Point(5, 10), 1)); + data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationSelfTouch3(stream_type& stdcout) { + stdcout << "testing polygon formation self touch 3\n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(6, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(6, 10), Point(4, 1), -1)); + data.push_back(vertex_half_edge(Point(6, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(4, 1), Point(6, 10), 1)); + data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testPolygonArbitraryFormationColinear(stream_type& stdcout) { + stdcout << "testing polygon formation colinear 3\n"; + stdcout << "Polygon Set Data { <-3 2, -2 2>:1 <-3 2, -1 4>:-1 <-2 2, 0 2>:1 <-1 4, 0 2>:-1 } \n"; + polygon_arbitrary_formation pf(true); + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(-3, 2), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 2), -1)); + + data.push_back(vertex_half_edge(Point(-3, 2), Point(-1, 4), -1)); + data.push_back(vertex_half_edge(Point(-1, 4), Point(-3, 2), 1)); + + data.push_back(vertex_half_edge(Point(-2, 2), Point(0, 2), 1)); + data.push_back(vertex_half_edge(Point(0, 2), Point(-2, 2), -1)); + + data.push_back(vertex_half_edge(Point(-1, 4), Point(0, 2), -1)); + data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing polygon formation\n"; + return true; + } + + template + static inline bool testSegmentIntersection(stream_type& stdcout) { + stdcout << "testing segment intersection\n"; + half_edge he1, he2; + he1.first = Point(0, 0); + he1.second = Point(10, 10); + he2.first = Point(0, 0); + he2.second = Point(10, 20); + Point result; + bool b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(0, 0)) return false; + he1.first = Point(0, 10); + b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(5, 10)) return false; + he1.first = Point(0, 11); + b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(5, 10)) return false; + he1.first = Point(0, 0); + he1.second = Point(1, 9); + he2.first = Point(0, 9); + he2.second = Point(1, 0); + b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(0, 4)) return false; + + he1.first = Point(0, -10); + he1.second = Point(1, -1); + he2.first = Point(0, -1); + he2.second = Point(1, -10); + b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(0, -5)) return false; + he1.first = Point((std::numeric_limits::max)(), (std::numeric_limits::max)()-1); + he1.second = Point((std::numeric_limits::min)(), (std::numeric_limits::max)()); + //he1.second = Point(0, (std::numeric_limits::max)()); + he2.first = Point((std::numeric_limits::max)()-1, (std::numeric_limits::max)()); + he2.second = Point((std::numeric_limits::max)(), (std::numeric_limits::min)()); + //he2.second = Point((std::numeric_limits::max)(), 0); + b = scanline_base::compute_intersection(result, he1, he2); + //b is false because of overflow error + he1.first = Point(1000, 2000); + he1.second = Point(1010, 2010); + he2.first = Point(1000, 2000); + he2.second = Point(1010, 2020); + b = scanline_base::compute_intersection(result, he1, he2); + if(!b || result != Point(1000, 2000)) return false; + + return b; + } + + }; + + template + class poly_line_arbitrary_hole_data { + private: + typedef typename polygon_arbitrary_formation::active_tail_arbitrary active_tail_arbitrary; + active_tail_arbitrary* p_; + public: + typedef point_data Point; + typedef Point point_type; + typedef Unit coordinate_type; + typedef typename active_tail_arbitrary::iterator iterator_type; + //typedef iterator_points_to_compact compact_iterator_type; + + typedef iterator_type iterator; + inline poly_line_arbitrary_hole_data() : p_(0) {} + inline poly_line_arbitrary_hole_data(active_tail_arbitrary* p) : p_(p) {} + //use default copy and assign + inline iterator begin() const { return p_->getTail()->begin(); } + inline iterator end() const { return p_->getTail()->end(); } + //inline compact_iterator_type begin_compact() const { return compact_iterator_type(begin()); } + //inline compact_iterator_type end_compact() const { return compact_iterator_type(end()); } + inline std::size_t size() const { return 0; } + template + inline poly_line_arbitrary_hole_data& set(iT inputBegin, iT inputEnd) { + //assert this is not called + return *this; + } + template + inline poly_line_arbitrary_hole_data& set_compact(iT inputBegin, iT inputEnd) { + //assert this is not called + return *this; + } + }; + + template + class poly_line_arbitrary_polygon_data { + private: + typedef typename polygon_arbitrary_formation::active_tail_arbitrary active_tail_arbitrary; + active_tail_arbitrary* p_; + public: + typedef point_data Point; + typedef Point point_type; + typedef Unit coordinate_type; + typedef typename active_tail_arbitrary::iterator iterator_type; + //typedef iterator_points_to_compact compact_iterator_type; + typedef typename coordinate_traits::coordinate_distance area_type; + + class iterator_holes_type { + private: + typedef poly_line_arbitrary_hole_data holeType; + mutable holeType hole_; + typename active_tail_arbitrary::iteratorHoles itr_; + + public: + typedef std::forward_iterator_tag iterator_category; + typedef holeType value_type; + typedef std::ptrdiff_t difference_type; + typedef const holeType* pointer; //immutable + typedef const holeType& reference; //immutable + inline iterator_holes_type() : hole_(), itr_() {} + inline iterator_holes_type(typename active_tail_arbitrary::iteratorHoles itr) : hole_(), itr_(itr) {} + inline iterator_holes_type(const iterator_holes_type& that) : hole_(that.hole_), itr_(that.itr_) {} + inline iterator_holes_type& operator=(const iterator_holes_type& that) { + itr_ = that.itr_; + return *this; + } + inline bool operator==(const iterator_holes_type& that) { return itr_ == that.itr_; } + inline bool operator!=(const iterator_holes_type& that) { return itr_ != that.itr_; } + inline iterator_holes_type& operator++() { + ++itr_; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp = *this; + ++(*this); + return tmp; + } + inline reference operator*() { + hole_ = holeType(*itr_); + return hole_; + } + }; + + typedef poly_line_arbitrary_hole_data hole_type; + + inline poly_line_arbitrary_polygon_data() : p_(0) {} + inline poly_line_arbitrary_polygon_data(active_tail_arbitrary* p) : p_(p) {} + //use default copy and assign + inline iterator_type begin() const { return p_->getTail()->begin(); } + inline iterator_type end() const { return p_->getTail()->end(); } + //inline compact_iterator_type begin_compact() const { return p_->getTail()->begin(); } + //inline compact_iterator_type end_compact() const { return p_->getTail()->end(); } + inline iterator_holes_type begin_holes() const { return iterator_holes_type(p_->getHoles().begin()); } + inline iterator_holes_type end_holes() const { return iterator_holes_type(p_->getHoles().end()); } + inline active_tail_arbitrary* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template + inline poly_line_arbitrary_polygon_data& set(iT inputBegin, iT inputEnd) { + return *this; + } + template + inline poly_line_arbitrary_polygon_data& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + template + inline poly_line_arbitrary_polygon_data& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + }; + + template + class trapezoid_arbitrary_formation : public polygon_arbitrary_formation { + private: + typedef typename scanline_base::Point Point; + typedef typename scanline_base::half_edge half_edge; + typedef typename scanline_base::vertex_half_edge vertex_half_edge; + typedef typename scanline_base::less_vertex_half_edge less_vertex_half_edge; + + typedef typename polygon_arbitrary_formation::poly_line_arbitrary poly_line_arbitrary; + + typedef typename polygon_arbitrary_formation::active_tail_arbitrary active_tail_arbitrary; + + typedef std::vector > vertex_arbitrary_count; + + typedef typename polygon_arbitrary_formation::less_half_edge_count less_half_edge_count; + + typedef std::vector, int>, active_tail_arbitrary*> > incoming_count; + + typedef typename polygon_arbitrary_formation::less_incoming_count less_incoming_count; + + typedef typename polygon_arbitrary_formation::vertex_arbitrary_compact vertex_arbitrary_compact; + + private: + //definitions + typedef std::map scanline_data; + typedef typename scanline_data::iterator iterator; + typedef typename scanline_data::const_iterator const_iterator; + + //data + public: + inline trapezoid_arbitrary_formation() : polygon_arbitrary_formation() {} + inline trapezoid_arbitrary_formation(const trapezoid_arbitrary_formation& that) : polygon_arbitrary_formation(that) {} + inline trapezoid_arbitrary_formation& operator=(const trapezoid_arbitrary_formation& that) { + * static_cast*>(this) = * static_cast*>(&that); + return *this; + } + + //cT is an output container of Polygon45 or Polygon45WithHoles + //iT is an iterator over vertex_half_edge elements + //inputBegin - inputEnd is a range of sorted iT that represents + //one or more scanline stops worth of data + template + void scan(cT& output, iT inputBegin, iT inputEnd) { + //std::cout << "1\n"; + while(inputBegin != inputEnd) { + //std::cout << "2\n"; + polygon_arbitrary_formation::x_ = (*inputBegin).pt.get(HORIZONTAL); + //std::cout << "SCAN FORMATION " << x_ << std::endl; + //std::cout << "x_ = " << x_ << std::endl; + //std::cout << "scan line size: " << scanData_.size() << std::endl; + inputBegin = processEvent_(output, inputBegin, inputEnd); + } + //std::cout << "scan line size: " << scanData_.size() << std::endl; + } + + private: + //functions + inline void getVerticalPair_(std::pair& verticalPair, + iterator previter) { + active_tail_arbitrary* iterTail = (*previter).second; + Point prevPoint(polygon_arbitrary_formation::x_, + convert_high_precision_type(previter->first.evalAtX(polygon_arbitrary_formation::x_))); + iterTail->pushPoint(prevPoint); + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(prevPoint, true, 0, false); + verticalPair.first = iterTail; + verticalPair.second = tailPair.first; + (*previter).second = tailPair.second; + } + + template + inline std::pair, active_tail_arbitrary*> + processPoint_(cT& output, cT2& elements, + std::pair& verticalPair, + iterator previter, Point point, incoming_count& counts_from_scanline, + vertex_arbitrary_count& incoming_count) { + //std::cout << "\nAT POINT: " << point << std::endl; + //join any closing solid corners + std::vector counts; + std::vector incoming; + std::vector tails; + counts.reserve(counts_from_scanline.size()); + tails.reserve(counts_from_scanline.size()); + incoming.reserve(incoming_count.size()); + for(std::size_t i = 0; i < counts_from_scanline.size(); ++i) { + counts.push_back(counts_from_scanline[i].first.second); + tails.push_back(counts_from_scanline[i].second); + } + for(std::size_t i = 0; i < incoming_count.size(); ++i) { + incoming.push_back(incoming_count[i].second); + if(incoming_count[i].first < point) { + incoming.back() = 0; + } + } + + active_tail_arbitrary* returnValue = 0; + std::pair verticalPairOut; + verticalPairOut.first = 0; + verticalPairOut.second = 0; + std::pair returnCount(Point(0, 0), 0); + int i_size_less_1 = (int)(incoming.size()) -1; + int c_size_less_1 = (int)(counts.size()) -1; + int i_size = incoming.size(); + int c_size = counts.size(); + + bool have_vertical_tail_from_below = false; + if(c_size && + scanline_base::is_vertical(counts_from_scanline.back().first.first)) { + have_vertical_tail_from_below = true; + } + //assert size = size_less_1 + 1 + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + // for(std::size_t i = 0; i < counts.size(); ++i) { + // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; + // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; + // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; + // std::cout << counts_from_scanline[i].first.second << " "; + // } std::cout << std::endl; + // print(incoming_count); + { + for(int i = 0; i < c_size_less_1; ++i) { + //std::cout << i << std::endl; + if(counts[i] == -1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < c_size; ++j) { + //std::cout << j << std::endl; + if(counts[j]) { + if(counts[j] == 1) { + //std::cout << "case1: " << i << " " << j << std::endl; + //if a figure is closed it will be written out by this function to output + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + counts[i] = 0; + counts[j] = 0; + tails[i] = 0; + tails[j] = 0; + } + break; + } + } + } + } + } + //find any pairs of incoming edges that need to create pair for leading solid + //std::cout << "checking case2\n"; + { + for(int i = 0; i < i_size_less_1; ++i) { + //std::cout << i << std::endl; + if(incoming[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i + 1; j < i_size; ++j) { + //std::cout << j << std::endl; + if(incoming[j]) { + //std::cout << incoming[j] << std::endl; + if(incoming[j] == -1) { + //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "creating active tail pair\n"; + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, polygon_arbitrary_formation::fractureHoles_ != 0); + //tailPair.first->print(); + //tailPair.second->print(); + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + //vertical active tail becomes return value + returnValue = tailPair.first; + returnCount.first = point; + returnCount.second = 1; + } else { + //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << point << " " << incoming_count[j].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, -1), tailPair.first)); + } + //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << point << " " << incoming_count[i].first << std::endl; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[i].first, 1), tailPair.second)); + incoming[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + } + } + //find any active tail that needs to pass through to an incoming edge + //we expect to find no more than two pass through + + //find pass through with solid on top + { + //std::cout << "checking case 3\n"; + for(int i = 0; i < c_size; ++i) { + //std::cout << i << std::endl; + if(counts[i] != 0) { + if(counts[i] == 1) { + //std::cout << "fixed i\n"; + for(int j = i_size_less_1; j >= 0; --j) { + if(incoming[j] != 0) { + if(incoming[j] == 1) { + //std::cout << "case3: " << i << " " << j << std::endl; + //tails[i]->print(); + //pass through solid on top + tails[i]->pushPoint(point); + //std::cout << "after push\n"; + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = -1; + } else { + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, false); + verticalPairOut.first = tails[i]; + verticalPairOut.second = tailPair.first; + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //std::cout << "checking case 4\n"; + //find pass through with solid on bottom + { + for(int i = c_size_less_1; i >= 0; --i) { + //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + if(counts[i] != 0) { + if(counts[i] == -1) { + for(int j = 0; j < i_size; ++j) { + if(incoming[j] != 0) { + if(incoming[j] == -1) { + //std::cout << "case4: " << i << " " << j << std::endl; + //pass through solid on bottom + + //if count from scanline is vertical + if(i == c_size_less_1 && + counts_from_scanline[i].first.first.first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + //if incoming count is vertical + if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = tails[i]; + returnCount.first = point; + returnCount.second = 1; + } else { + tails[i]->pushPoint(point); + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tails[i])); + } + } else if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + returnValue = verticalPair.second; + returnCount.first = point; + returnCount.second = 1; + } else { + //neither is vertical + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + verticalPair.second->pushPoint(point); + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), verticalPair.second)); + } + tails[i] = 0; + counts[i] = 0; + incoming[j] = 0; + } + break; + } + } + } + break; + } + } + } + //find the end of a hole or the beginning of a hole + + //find end of a hole + { + for(int i = 0; i < c_size_less_1; ++i) { + if(counts[i] != 0) { + for(int j = i+1; j < c_size; ++j) { + if(counts[j] != 0) { + //std::cout << "case5: " << i << " " << j << std::endl; + //we are ending a hole and may potentially close a figure and have to handle the hole + tails[i]->pushPoint(point); + verticalPairOut.first = tails[i]; + if(j == c_size_less_1 && + counts_from_scanline[j].first.first.first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { + verticalPairOut.second = tails[j]; + } else { + //need to close a trapezoid below + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + active_tail_arbitrary::joinChains(point, tails[j], verticalPair.first, true, output); + verticalPairOut.second = verticalPair.second; + } + tails[i] = 0; + tails[j] = 0; + counts[i] = 0; + counts[j] = 0; + break; + } + } + break; + } + } + } + //find beginning of a hole + { + for(int i = 0; i < i_size_less_1; ++i) { + if(incoming[i] != 0) { + for(int j = i+1; j < i_size; ++j) { + if(incoming[j] != 0) { + //std::cout << "case6: " << i << " " << j << std::endl; + //we are beginning a empty space + if(verticalPair.first == 0) { + getVerticalPair_(verticalPair, previter); + } + verticalPair.second->pushPoint(point); + if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { + returnValue = verticalPair.first; + returnCount.first = point; + returnCount.second = -1; + } else { + std::pair tailPair = + active_tail_arbitrary::createActiveTailsAsPair(point, false, 0, false); + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[j].first, incoming[j]), tailPair.second)); + verticalPairOut.second = tailPair.first; + verticalPairOut.first = verticalPair.first; + } + elements.push_back(std::pair(vertex_half_edge(point, + incoming_count[i].first, incoming[i]), verticalPair.second)); + incoming[i] = 0; + incoming[j] = 0; + break; + } + } + break; + } + } + } + if(have_vertical_tail_from_below) { + if(tails.back()) { + tails.back()->pushPoint(point); + returnValue = tails.back(); + returnCount.first = point; + returnCount.second = counts.back(); + } + } + verticalPair = verticalPairOut; + //assert that tails, counts and incoming are all null + return std::pair, active_tail_arbitrary*>(returnCount, returnValue); + } + + static inline void print(const vertex_arbitrary_count& count) { + for(unsigned i = 0; i < count.size(); ++i) { + //std::cout << count[i].first.get(HORIZONTAL) << ","; + //std::cout << count[i].first.get(VERTICAL) << ":"; + //std::cout << count[i].second << " "; + } //std::cout << std::endl; + } + + static inline void print(const scanline_data& data) { + for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ + //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; + } //std::cout << std::endl; + } + + template + inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { + typedef typename high_precision_type::type high_precision; + //std::cout << "processEvent_\n"; + polygon_arbitrary_formation::justBefore_ = true; + //collect up all elements from the tree that are at the y + //values of events in the input queue + //create vector of new elements to add into tree + active_tail_arbitrary* verticalTail = 0; + std::pair verticalPair; + std::pair verticalCount(Point(0, 0), 0); + iT currentIter = inputBegin; + std::vector elementIters; + std::vector > elements; + while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation::x_) { + //std::cout << "loop\n"; + Unit currentY = (*currentIter).pt.get(VERTICAL); + //std::cout << "current Y " << currentY << std::endl; + //std::cout << "scanline size " << scanData_.size() << std::endl; + //print(scanData_); + iterator iter = this->lookUp_(currentY); + //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //int counts[4] = {0, 0, 0, 0}; + incoming_count counts_from_scanline; + //std::cout << "finding elements in tree\n"; + //if(iter != scanData_.end()) + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + iterator previter = iter; + if(previter != polygon_arbitrary_formation::scanData_.end() && + previter->first.evalAtX(polygon_arbitrary_formation::x_) >= currentY && + previter != polygon_arbitrary_formation::scanData_.begin()) + --previter; + while(iter != polygon_arbitrary_formation::scanData_.end() && + ((iter->first.pt.x() == polygon_arbitrary_formation::x_ && iter->first.pt.y() == currentY) || + (iter->first.other_pt.x() == polygon_arbitrary_formation::x_ && iter->first.other_pt.y() == currentY))) { + //iter->first.evalAtX(polygon_arbitrary_formation::x_) == (high_precision)currentY) { + //std::cout << "loop2\n"; + elementIters.push_back(iter); + counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> + (std::pair, int>(std::pair(iter->first.pt, + iter->first.other_pt), + iter->first.count), + iter->second)); + ++iter; + } + Point currentPoint(polygon_arbitrary_formation::x_, currentY); + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + this->sort_incoming_count(counts_from_scanline, currentPoint); + + vertex_arbitrary_count incoming; + //std::cout << "aggregating\n"; + do { + //std::cout << "loop3\n"; + const vertex_half_edge& elem = *currentIter; + incoming.push_back(std::pair(elem.other_pt, elem.count)); + ++currentIter; + } while(currentIter != inputEnd && currentIter->pt.get(VERTICAL) == currentY && + currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation::x_); + //print(incoming); + this->sort_vertex_arbitrary_count(incoming, currentPoint); + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //print(incoming); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //compact_vertex_arbitrary_count(currentPoint, incoming); + vertex_arbitrary_count tmp; + tmp.reserve(incoming.size()); + for(std::size_t i = 0; i < incoming.size(); ++i) { + if(currentPoint < incoming[i].first) { + tmp.push_back(incoming[i]); + } + } + incoming.swap(tmp); + //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //now counts_from_scanline has the data from the left and + //incoming has the data from the right at this point + //cancel out any end points + if(verticalTail) { + //std::cout << "adding vertical tail to counts from scanline\n"; + //std::cout << -verticalCount.second << std::endl; + counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> + (std::pair, int>(std::pair(verticalCount.first, + currentPoint), + -verticalCount.second), + verticalTail)); + } + if(!incoming.empty() && incoming.back().first.get(HORIZONTAL) == polygon_arbitrary_formation::x_) { + //std::cout << "inverted vertical event\n"; + incoming.back().second *= -1; + } + //std::cout << "calling processPoint_\n"; + std::pair, active_tail_arbitrary*> result = processPoint_(output, elements, verticalPair, previter, Point(polygon_arbitrary_formation::x_, currentY), counts_from_scanline, incoming); + verticalCount = result.first; + verticalTail = result.second; + if(verticalPair.first != 0 && iter != polygon_arbitrary_formation::scanData_.end() && + (currentIter == inputEnd || currentIter->pt.x() != polygon_arbitrary_formation::x_ || + currentIter->pt.y() > (*iter).first.evalAtX(polygon_arbitrary_formation::x_))) { + //splice vertical pair into edge above + active_tail_arbitrary* tailabove = (*iter).second; + Point point(polygon_arbitrary_formation::x_, + convert_high_precision_type((*iter).first.evalAtX(polygon_arbitrary_formation::x_))); + verticalPair.second->pushPoint(point); + active_tail_arbitrary::joinChains(point, tailabove, verticalPair.first, true, output); + (*iter).second = verticalPair.second; + verticalPair.first = 0; + verticalPair.second = 0; + } + } + //std::cout << "erasing\n"; + //erase all elements from the tree + for(typename std::vector::iterator iter = elementIters.begin(); + iter != elementIters.end(); ++iter) { + //std::cout << "erasing loop\n"; + polygon_arbitrary_formation::scanData_.erase(*iter); + } + //switch comparison tie breaking policy + polygon_arbitrary_formation::justBefore_ = false; + //add new elements into tree + //std::cout << "inserting\n"; + for(typename std::vector >::iterator iter = elements.begin(); + iter != elements.end(); ++iter) { + //std::cout << "inserting loop\n"; + polygon_arbitrary_formation::scanData_.insert(polygon_arbitrary_formation::scanData_.end(), *iter); + } + //std::cout << "end processEvent\n"; + return currentIter; + } + public: + template + static inline bool testTrapezoidArbitraryFormationRect(stream_type& stdcout) { + stdcout << "testing trapezoid formation\n"; + trapezoid_arbitrary_formation pf; + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + template + static inline bool testTrapezoidArbitraryFormationP1(stream_type& stdcout) { + stdcout << "testing trapezoid formation P1\n"; + trapezoid_arbitrary_formation pf; + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + template + static inline bool testTrapezoidArbitraryFormationP2(stream_type& stdcout) { + stdcout << "testing trapezoid formation P2\n"; + trapezoid_arbitrary_formation pf; + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(-3, 1), Point(2, -4), 1)); + data.push_back(vertex_half_edge(Point(-3, 1), Point(-2, 2), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(-2, 2), Point(-3, 1), 1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(-3, 1), -1)); + data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + + template + static inline bool testTrapezoidArbitraryFormationPolys(stream_type& stdcout) { + stdcout << "testing trapezoid formation polys\n"; + trapezoid_arbitrary_formation pf; + std::vector > polys; + //trapezoid_arbitrary_formation pf2(true); + //std::vector > polys2; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(100, 1), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(1, 100), -1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(0, 0), 1)); + data.push_back(vertex_half_edge(Point(1, 100), Point(101, 101), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(100, 1), Point(101, 101), 1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(100, 1), -1)); + data.push_back(vertex_half_edge(Point(101, 101), Point(1, 100), 1)); + + data.push_back(vertex_half_edge(Point(2, 2), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(2, 2), Point(2, 10), -1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(2, 10), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(2, 2), 1)); + data.push_back(vertex_half_edge(Point(10, 2), Point(10, 10), 1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(10, 2), -1)); + data.push_back(vertex_half_edge(Point(10, 10), Point(2, 10), -1)); + + data.push_back(vertex_half_edge(Point(2, 12), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(2, 12), Point(2, 22), -1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(2, 22), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(2, 12), 1)); + data.push_back(vertex_half_edge(Point(10, 12), Point(10, 22), 1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); + data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + //pf2.scan(polys2, data.begin(), data.end()); + //stdcout << "result size: " << polys2.size() << std::endl; + //for(std::size_t i = 0; i < polys2.size(); ++i) { + // stdcout << polys2[i] << std::endl; + //} + stdcout << "done testing trapezoid formation\n"; + return true; + } + + template + static inline bool testTrapezoidArbitraryFormationSelfTouch1(stream_type& stdcout) { + stdcout << "testing trapezoid formation self touch 1\n"; + trapezoid_arbitrary_formation pf; + std::vector > polys; + std::vector data; + data.push_back(vertex_half_edge(Point(0, 0), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(0, 0), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(0, 10), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(0, 10), Point(5, 10), -1)); + + data.push_back(vertex_half_edge(Point(10, 0), Point(0, 0), -1)); + data.push_back(vertex_half_edge(Point(10, 0), Point(10, 5), -1)); + + data.push_back(vertex_half_edge(Point(10, 5), Point(10, 0), 1)); + data.push_back(vertex_half_edge(Point(10, 5), Point(5, 5), 1)); + + data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); + data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); + + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); + + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); + data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); + + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); + + std::sort(data.begin(), data.end()); + pf.scan(polys, data.begin(), data.end()); + stdcout << "result size: " << polys.size() << std::endl; + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + stdcout << "done testing trapezoid formation\n"; + return true; + } + }; + + template + struct PolyLineArbitraryByConcept { typedef poly_line_arbitrary_polygon_data type; }; + template + struct PolyLineArbitraryByConcept { typedef poly_line_arbitrary_hole_data type; }; + + template + struct geometry_concept > { typedef polygon_45_with_holes_concept type; }; + template + struct geometry_concept > { typedef polygon_45_concept type; }; +} +} +#endif diff --git a/include/boost/polygon/detail/polygon_formation.hpp b/include/boost/polygon/detail/polygon_formation.hpp new file mode 100644 index 0000000..0129962 --- /dev/null +++ b/include/boost/polygon/detail/polygon_formation.hpp @@ -0,0 +1,1807 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_FORMATION_HPP +#define BOOST_POLYGON_POLYGON_FORMATION_HPP +namespace boost { namespace polygon{ + +namespace polygon_formation { + + /* + * End has two states, HEAD and TAIL as is represented by a bool + */ + typedef bool End; + + /* + * HEAD End is represented as false because it is the lesser state + */ + const End HEAD = false; + + /* + * TAIL End is represented by true because TAIL comes after head and 1 after 0 + */ + const End TAIL = true; + + /* + * 2D turning direction, left and right sides (is a boolean value since it has two states.) + */ + typedef bool Side; + + /* + * LEFT Side is 0 because we inuitively think left to right; left < right + */ + const Side LEFT = false; + + /* + * RIGHT Side is 1 so that right > left + */ + const Side RIGHT = true; + + /* + * The PolyLine class is data storage and services for building and representing partial polygons. + * As the polyline is added to it extends its storage to accomodate the data. + * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are + * part of the same polygon. + * PolyLines keep state information about what orientation their incomplete head and tail geometry have, + * which side of the polyline is solid and whether the polyline is joined head-to-head and tail-to-head. + * PolyLines have nothing whatsoever to do with holes. + * It may be valuable to collect a histogram of PolyLine lengths used by an algorithm on its typical data + * sets and tune the allocation of the initial vector of coordinate data to be greater than or equal to + * the mean, median, mode, or mean plus some number of standard deviation, or just generally large enough + * to prevent too much unnecesary reallocations, but not too big that it wastes a lot of memory and degrades cache + * performance. + */ + template + class PolyLine { + private: + //data + + /* + * ptdata_ a vector of coordiantes + * if VERTICAL_HEAD, first coordiante is an X + * else first coordinate is a Y + */ + std::vector ptdata_; + + /* + * head and tail points to other polylines before and after this in a chain + */ + PolyLine* headp_; + PolyLine* tailp_; + + /* + * state bitmask + * bit zero is orientation, 0 H, 1 V + * bit 1 is head connectivity, 0 for head, 1 for tail + * bit 2 is tail connectivity, 0 for head, 1 for tail + * bit 3 is solid to left of PolyLine when 1, right when 0 + */ + int state_; + + public: + /* + * default constructor (for preallocation) + */ + PolyLine(); + + /* + * constructor that takes the orientation, coordiante and side to which there is solid + */ + PolyLine(orientation_2d orient, Unit coord, Side side); + + //copy constructor + PolyLine(const PolyLine& pline); + + //destructor + ~PolyLine(); + + //assignment operator + PolyLine& operator=(const PolyLine& that); + + //equivalence operator + bool operator==(const PolyLine& b) const; + + /* + * valid PolyLine (only default constructed polylines are invalid.) + */ + bool isValid() const; + + /* + * Orientation of Head + */ + orientation_2d headOrient() const; + + /* + * returns true if first coordinate is an X value (first segment is vertical) + */ + bool verticalHead() const; + + /* + * returns the orientation_2d fo the tail + */ + orientation_2d tailOrient() const; + + /* + * returns true if last coordinate is an X value (last segment is vertical) + */ + bool verticalTail() const; + + /* + * retrun true if PolyLine has odd number of coordiantes + */ + bool oddLength() const; + + /* + * retrun the End of the other polyline that the specified end of this polyline is connected to + */ + End endConnectivity(End end) const; + + /* + * retrun true if the head of this polyline is connect to the tail of a polyline + */ + bool headToTail() const; + /* + * retrun true if the head of this polyline is connect to the head of a polyline + */ + bool headToHead() const; + + /* + * retrun true if the tail of this polyline is connect to the tail of a polyline + */ + bool tailToTail() const; + /* + * retrun true if the tail of this polyline is connect to the head of a polyline + */ + bool tailToHead() const; + + /* + * retrun the side on which there is solid for this polyline + */ + Side solidSide() const; + + /* + * retrun true if there is solid to the right of this polyline + */ + bool solidToRight() const; + + /* + * returns true if the polyline tail is not connected + */ + bool active() const; + + /* + * adds a coordinate value to the end of the polyline changing the tail orientation + */ + PolyLine& pushCoordinate(Unit coord); + + /* + * removes a coordinate value at the end of the polyline changing the tail orientation + */ + PolyLine& popCoordinate(); + + /* + * extends the tail of the polyline to include the point, changing orientation if needed + */ + PolyLine& pushPoint(const point_data& point); + + /* + * changes the last coordinate of the tail of the polyline by the amount of the delta + */ + PolyLine& extendTail(Unit delta); + + /* + * join thisEnd of this polyline to that polyline's end + */ + PolyLine& joinTo(End thisEnd, PolyLine& that, End end); + + /* + * join an end of this polyline to the tail of that polyline + */ + PolyLine& joinToTail(PolyLine& that, End end); + + /* + * join an end of this polyline to the head of that polyline + */ + PolyLine& joinToHead(PolyLine& that, End end); + + /* + * join the head of this polyline to the head of that polyline + */ + //join this to that in the given way + PolyLine& joinHeadToHead(PolyLine& that); + + /* + * join the head of this polyline to the tail of that polyline + */ + PolyLine& joinHeadToTail(PolyLine& that); + + /* + * join the tail of this polyline to the head of that polyline + */ + PolyLine& joinTailToHead(PolyLine& that); + + /* + * join the tail of this polyline to the tail of that polyline + */ + PolyLine& joinTailToTail(PolyLine& that); + + /* + * dissconnect the tail at the end of the polygon + */ + PolyLine& disconnectTails(); + + /* + * get the coordinate at one end of this polyline, by default the tail end + */ + Unit getEndCoord(End end = TAIL) const; + + /* + * get the point on the polyline at the given index (polylines have the same number of coordinates as points + */ + point_data getPoint(unsigned int index) const; + + /* + * get the point on one end of the polyline, by default the tail + */ + point_data getEndPoint(End end = TAIL) const; + + /* + * get the orientation of a segment by index + */ + orientation_2d segmentOrient(unsigned int index = 0) const; + + /* + * get a coordinate by index using the square bracket operator + */ + Unit operator[] (unsigned int index) const; + + /* + * get the number of segments/points/coordinates in the polyline + */ + unsigned int numSegments() const; + + /* + * get the pointer to the next polyline at one end of this + */ + PolyLine* next(End end) const; + + /* + * write out coordinates of this and all attached polylines to a single vector + */ + PolyLine* writeOut(std::vector& outVec, End startEnd = TAIL) const; + + private: + //methods + PolyLine& joinTo_(End thisEnd, PolyLine& that, End end); + }; + + //forward declaration + template + class PolyLinePolygonData; + + //forward declaration + template + class PolyLinePolygonWithHolesData; + + /* + * ActiveTail represents an edge of an incomplete polygon. + * + * An ActiveTail object is the active tail end of a polyline object, which may (should) be the attached to + * a chain of polyline objects through a pointer. The ActiveTail class provides an abstraction between + * and algorithm that builds polygons and the PolyLine data representation of incomplete polygons that are + * being built. It does this by providing an iterface to access the information about the last edge at the + * tail of the PolyLine it is associated with. To a polygon constructing algorithm, an ActiveTail is a floating + * edge of an incomplete polygon and has an orientation and coordinate value, as well as knowing which side of + * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails + * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails + * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon + * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete + * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. + * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In + * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, + * or reassociate the hole to another incomplete polygon in the case that it become a hole itself. Alternately, + * the active tail may add a filiment to stitch a hole into a shell and "fracture" the hole out of the interior + * of a polygon. The active tail maintains a static output buffer to temporarily write polygon data to when + * it outputs a figure so that outputting a polygon does not require the allocation of a temporary buffer. This + * static buffer should be destroyed whenever the program determines that it won't need it anymore and would prefer to + * release the memory it has allocated back to the system. + */ + template + class ActiveTail { + private: + //data + PolyLine* tailp_; + ActiveTail *otherTailp_; + std::list holesList_; + public: + + /* + * iterator over coordinates of the figure + */ + class iterator { + private: + const PolyLine* pLine_; + const PolyLine* pLineEnd_; + unsigned int index_; + unsigned int indexEnd_; + End startEnd_; + public: + inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} + inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : + pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { + //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal + //we want to use this active tail, otherwise we want to use the other active tail + startEnd_ = TAIL; + if(!isHole ^ (orient == HORIZONTAL)) { + //switch winding direction + at = at->getOtherActiveTail(); + } + //now we have the right winding direction + //if it is horizontal we need to skip the first element + pLine_ = at->getTail(); + index_ = at->getTail()->numSegments() - 1; + if((at->getOrient() == HORIZONTAL) ^ (orient == HORIZONTAL)) { + pLineEnd_ = at->getTail(); + indexEnd_ = pLineEnd_->numSegments() - 1; + if(index_ == 0) { + pLine_ = at->getTail()->next(HEAD); + if(at->getTail()->endConnectivity(HEAD) == TAIL) { + index_ = pLine_->numSegments() -1; + } else { + startEnd_ = HEAD; + index_ = 0; + } + } else { --index_; } + } else { + pLineEnd_ = at->getOtherActiveTail()->getTail(); + indexEnd_ = pLineEnd_->numSegments() - 1; + } + at->getTail()->joinTailToTail(*(at->getOtherActiveTail()->getTail())); + } + //use bitwise copy and assign provided by the compiler + inline iterator& operator++() { + if(pLine_ == pLineEnd_ && index_ == indexEnd_) { + pLine_ = 0; + index_ = 0; + return *this; + } + if(startEnd_ == HEAD) { + ++index_; + if(index_ == pLine_->numSegments()) { + End end = pLine_->endConnectivity(TAIL); + pLine_ = pLine_->next(TAIL); + if(end == TAIL) { + startEnd_ = TAIL; + index_ = pLine_->numSegments() -1; + } else { + index_ = 0; + } + } + } else { + if(index_ == 0) { + End end = pLine_->endConnectivity(HEAD); + pLine_ = pLine_->next(HEAD); + if(end == TAIL) { + index_ = pLine_->numSegments() -1; + } else { + startEnd_ = HEAD; + index_ = 0; + } + } else { + --index_; + } + } + return *this; + } + inline const iterator operator++(int) { + iterator tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator& that) const { + return pLine_ == that.pLine_ && index_ == that.index_; + } + inline bool operator!=(const iterator& that) const { + return pLine_ != that.pLine_ || index_ != that.index_; + } + inline Unit operator*() { return (*pLine_)[index_]; } + }; + + /* + * iterator over holes contained within the figure + */ + typedef typename std::list::const_iterator iteratorHoles; + + //default constructor + ActiveTail(); + + //constructor + ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp); + + //constructor + ActiveTail(PolyLine* active, ActiveTail* otherTailp); + + //copy constructor + ActiveTail(const ActiveTail& that); + + //destructor + ~ActiveTail(); + + //assignment operator + ActiveTail& operator=(const ActiveTail& that); + + //equivalence operator + bool operator==(const ActiveTail& b) const; + + /* + * comparison operators, ActiveTail objects are sortable by geometry + */ + bool operator<(const ActiveTail& b) const; + bool operator<=(const ActiveTail& b) const; + bool operator>(const ActiveTail& b) const; + bool operator>=(const ActiveTail& b) const; + + /* + * get the pointer to the polyline that this is an active tail of + */ + PolyLine* getTail() const; + + /* + * get the pointer to the polyline at the other end of the chain + */ + PolyLine* getOtherTail() const; + + /* + * get the pointer to the activetail at the other end of the chain + */ + ActiveTail* getOtherActiveTail() const; + + /* + * test if another active tail is the other end of the chain + */ + bool isOtherTail(const ActiveTail& b); + + /* + * update this end of chain pointer to new polyline + */ + ActiveTail& updateTail(PolyLine* newTail); + + /* + * associate a hole to this active tail by the specified policy + */ + ActiveTail* addHole(ActiveTail* hole, bool fractureHoles); + + /* + * get the list of holes + */ + const std::list& getHoles() const; + + /* + * copy holes from that to this + */ + void copyHoles(ActiveTail& that); + + /* + * find out if solid to right + */ + bool solidToRight() const; + + /* + * get coordinate (getCoord and getCoordinate are aliases for eachother) + */ + Unit getCoord() const; + Unit getCoordinate() const; + + /* + * get the tail orientation + */ + orientation_2d getOrient() const; + + /* + * add a coordinate to the polygon at this active tail end, properly handle degenerate edges by removing redundant coordinate + */ + void pushCoordinate(Unit coord); + + /* + * write the figure that this active tail points to out to the temp buffer + */ + void writeOutFigure(std::vector& outVec, bool isHole = false) const; + + /* + * write the figure that this active tail points to out through iterators + */ + void writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole = false, orientation_2d orient = VERTICAL) const; + iterator begin(bool isHole, orientation_2d orient) const; + iterator end() const; + + /* + * write the holes that this active tail points to out through iterators + */ + void writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const; + iteratorHoles beginHoles() const; + iteratorHoles endHoles() const; + + /* + * joins the two chains that the two active tail tails are ends of + * checks for closure of figure and writes out polygons appropriately + * returns a handle to a hole if one is closed + */ + static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp); + template + static ActiveTail* joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, typename std::vector& outBufferTmp); + + /* + * deallocate temp buffer + */ + static void destroyOutBuffer(); + + /* + * deallocate all polygon data this active tail points to (deep delete, call only from one of a pair of active tails) + */ + void destroyContents(); + }; + + /* allocate a polyline object */ + template + PolyLine* createPolyLine(orientation_2d orient, Unit coord, Side side); + + /* deallocate a polyline object */ + template + void destroyPolyLine(PolyLine* pLine); + + /* allocate an activetail object */ + template + ActiveTail* createActiveTail(); + + /* deallocate an activetail object */ + template + void destroyActiveTail(ActiveTail* aTail); + + template + class PolyLineHoleData { + private: + ActiveTail* p_; + public: + typedef Unit coordinate_type; + typedef typename ActiveTail::iterator compact_iterator_type; + typedef iterator_compact_to_points > iterator_type; + inline PolyLineHoleData() : p_(0) {} + inline PolyLineHoleData(ActiveTail* p) : p_(p) {} + //use default copy and assign + inline compact_iterator_type begin_compact() const { return p_->begin(true, (orientT ? VERTICAL : HORIZONTAL)); } + inline compact_iterator_type end_compact() const { return p_->end(); } + inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } + inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } + inline std::size_t size() const { return 0; } + inline ActiveTail* yield() { return p_; } + template + inline PolyLineHoleData& set(iT inputBegin, iT inputEnd) { + return *this; + } + template + inline PolyLineHoleData& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + + }; + + template + class PolyLinePolygonWithHolesData { + private: + ActiveTail* p_; + public: + typedef Unit coordinate_type; + typedef typename ActiveTail::iterator compact_iterator_type; + typedef iterator_compact_to_points > iterator_type; + typedef PolyLineHoleData hole_type; + typedef typename coordinate_traits::area_type area_type; + class iteratorHoles { + private: + typename ActiveTail::iteratorHoles itr_; + public: + inline iteratorHoles() : itr_() {} + inline iteratorHoles(typename ActiveTail::iteratorHoles itr) : itr_(itr) {} + //use bitwise copy and assign provided by the compiler + inline iteratorHoles& operator++() { + ++itr_; + return *this; + } + inline const iteratorHoles operator++(int) { + iteratorHoles tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iteratorHoles& that) const { + return itr_ == that.itr_; + } + inline bool operator!=(const iteratorHoles& that) const { + return itr_ != that.itr_; + } + inline PolyLineHoleData operator*() { return PolyLineHoleData(*itr_);} + }; + typedef iteratorHoles iterator_holes_type; + + inline PolyLinePolygonWithHolesData() : p_(0) {} + inline PolyLinePolygonWithHolesData(ActiveTail* p) : p_(p) {} + //use default copy and assign + inline compact_iterator_type begin_compact() const { return p_->begin(false, (orientT ? VERTICAL : HORIZONTAL)); } + inline compact_iterator_type end_compact() const { return p_->end(); } + inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } + inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } + inline iteratorHoles begin_holes() const { return iteratorHoles(p_->beginHoles()); } + inline iteratorHoles end_holes() const { return iteratorHoles(p_->endHoles()); } + inline ActiveTail* yield() { return p_; } + //stub out these four required functions that will not be used but are needed for the interface + inline std::size_t size_holes() const { return 0; } + inline std::size_t size() const { return 0; } + template + inline PolyLinePolygonWithHolesData& set(iT inputBegin, iT inputEnd) { + return *this; + } + template + inline PolyLinePolygonWithHolesData& set_compact(iT inputBegin, iT inputEnd) { + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline PolyLinePolygonWithHolesData& set_holes(iT inputBegin, iT inputEnd) { + return *this; + } + }; + + + template + struct PolyLineType { }; + template + struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; + template + struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; + template + struct PolyLineType { typedef PolyLinePolygonWithHolesData type; }; + template + struct PolyLineType { typedef PolyLineHoleData type; }; + template + struct PolyLineType { typedef PolyLineHoleData type; }; + template + struct PolyLineType { typedef PolyLineHoleData type; }; + + template + class ScanLineToPolygonItrs { + private: + std::map*> tailMap_; + typedef typename PolyLineType::type PolyLinePolygonData; + std::vector outputPolygons_; + bool fractureHoles_; + public: + typedef typename std::vector::iterator iterator; + inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} + /* construct a scanline with the proper offsets, protocol and options */ + inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} + + ~ScanLineToPolygonItrs() { clearOutput_(); } + + /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ + void processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, + std::vector >& rightEdges); + + private: + void clearOutput_(); + }; + + /* + * ScanLine does all the work of stitching together polygons from incoming vertical edges + */ +// template +// class ScanLineToPolygons { +// private: +// ScanLineToPolygonItrs scanline_; +// public: +// inline ScanLineToPolygons() : scanline_() {} +// /* construct a scanline with the proper offsets, protocol and options */ +// inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} + +// /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ +// inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, +// std::vector >& rightEdges) { +// typename ScanLineToPolygonItrs::iterator itr, endItr; +// scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); +// //copy data into outBufferTmp +// while(itr != endItr) { +// typename PolyLinePolygonData::iterator pditr; +// outBufferTmp.push_back(0); +// unsigned int sizeIndex = outBufferTmp.size() - 1; +// int count = 0; +// for(pditr = (*itr).begin(); pditr != (*itr).end(); ++pditr) { +// outBufferTmp.push_back(*pditr); +// ++count; +// } +// outBufferTmp[sizeIndex] = count; +// typename PolyLinePolygonData::iteratorHoles pdHoleItr; +// for(pdHoleItr = (*itr).beginHoles(); pdHoleItr != (*itr).endHoles(); ++pdHoleItr) { +// outBufferTmp.push_back(0); +// unsigned int sizeIndex2 = outBufferTmp.size() - 1; +// int count2 = 0; +// for(pditr = (*pdHoleItr).begin(); pditr != (*pdHoleItr).end(); ++pditr) { +// outBufferTmp.push_back(*pditr); +// ++count2; +// } +// outBufferTmp[sizeIndex2] = -count; +// } +// ++itr; +// } +// } +// }; + + const int VERTICAL_HEAD = 1, HEAD_TO_TAIL = 2, TAIL_TO_TAIL = 4, SOLID_TO_RIGHT = 8; + + //EVERY FUNCTION in this DEF file should be explicitly defined as inline + + //microsoft compiler improperly warns whenever you cast an integer to bool + //call this function on an integer to convert it to bool without a warning + template + inline bool to_bool(const T& val) { return val != 0; } + + //default constructor (for preallocation) + template + inline PolyLine::PolyLine() : ptdata_() ,headp_(0), tailp_(0), state_(-1) {} + + //constructor + template + inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : + ptdata_(1, coord), + headp_(0), + tailp_(0), + state_(orient.to_int() + + (side << 3)) {} + + //copy constructor + template + inline PolyLine::PolyLine(const PolyLine& pline) : ptdata_(pline.ptdata_), + headp_(pline.headp_), + tailp_(pline.tailp_), + state_(pline.state_) {} + + //destructor + template + inline PolyLine::~PolyLine() { + //clear out data just in case it is read later + headp_ = tailp_ = 0; + state_ = 0; + } + + template + inline PolyLine& PolyLine::operator=(const PolyLine& that) { + if(!(this == &that)) { + headp_ = that.headp_; + tailp_ = that.tailp_; + ptdata_ = that.ptdata_; + state_ = that.state_; + } + return *this; + } + + template + inline bool PolyLine::operator==(const PolyLine& b) const { + return this == &b || (state_ == b.state_ && + headp_ == b.headp_ && + tailp_ == b.tailp_); + } + + //valid PolyLine + template + inline bool PolyLine::isValid() const { + return state_ > -1; } + + //first coordinate is an X value + //first segment is vertical + template + inline bool PolyLine::verticalHead() const { + return state_ & VERTICAL_HEAD; + } + + //retrun true is PolyLine has odd number of coordiantes + template + inline bool PolyLine::oddLength() const { + return to_bool((ptdata_.size()-1) % 2); + } + + //last coordiante is an X value + //last segment is vertical + template + inline bool PolyLine::verticalTail() const { + return to_bool(verticalHead() ^ oddLength()); + } + + template + inline orientation_2d PolyLine::tailOrient() const { + return (verticalTail() ? VERTICAL : HORIZONTAL); + } + + template + inline orientation_2d PolyLine::headOrient() const { + return (verticalHead() ? VERTICAL : HORIZONTAL); + } + + template + inline End PolyLine::endConnectivity(End end) const { + //Tail should be defined as true + if(end) { return tailToTail(); } + return headToTail(); + } + + template + inline bool PolyLine::headToTail() const { + return to_bool(state_ & HEAD_TO_TAIL); + } + + template + inline bool PolyLine::headToHead() const { + return to_bool(!headToTail()); + } + + template + inline bool PolyLine::tailToHead() const { + return to_bool(!tailToTail()); + } + + template + inline bool PolyLine::tailToTail() const { + return to_bool(state_ & TAIL_TO_TAIL); + } + + template + inline Side PolyLine::solidSide() const { + return solidToRight(); } + + template + inline bool PolyLine::solidToRight() const { + return to_bool(state_ & SOLID_TO_RIGHT) != 0; + } + + template + inline bool PolyLine::active() const { + return !to_bool(tailp_); + } + + template + inline PolyLine& PolyLine::pushCoordinate(Unit coord) { + ptdata_.push_back(coord); + return *this; + } + + template + inline PolyLine& PolyLine::popCoordinate() { + ptdata_.pop_back(); + return *this; + } + + template + inline PolyLine& PolyLine::pushPoint(const point_data& point) { + point_data endPt = getEndPoint(); + //vertical is true, horizontal is false + if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { + //we were pushing a colinear segment + return popCoordinate(); + } + return pushCoordinate(tailOrient().to_int() ? point.get(VERTICAL) : point.get(HORIZONTAL)); + } + + template + inline PolyLine& PolyLine::extendTail(Unit delta) { + ptdata_.back() += delta; + return *this; + } + + //private member function that creates a link from this PolyLine to that + template + inline PolyLine& PolyLine::joinTo_(End thisEnd, PolyLine& that, End end) { + if(thisEnd){ + tailp_ = &that; + state_ &= ~TAIL_TO_TAIL; //clear any previous state_ of bit (for safety) + state_ |= (end << 2); //place bit into mask + } else { + headp_ = &that; + state_ &= ~HEAD_TO_TAIL; //clear any previous state_ of bit (for safety) + state_ |= (end << 1); //place bit into mask + } + return *this; + } + + //join two PolyLines (both ways of the association) + template + inline PolyLine& PolyLine::joinTo(End thisEnd, PolyLine& that, End end) { + joinTo_(thisEnd, that, end); + that.joinTo_(end, *this, thisEnd); + return *this; + } + + //convenience functions for joining PolyLines + template + inline PolyLine& PolyLine::joinToTail(PolyLine& that, End end) { + return joinTo(TAIL, that, end); + } + template + inline PolyLine& PolyLine::joinToHead(PolyLine& that, End end) { + return joinTo(HEAD, that, end); + } + template + inline PolyLine& PolyLine::joinHeadToHead(PolyLine& that) { + return joinToHead(that, HEAD); + } + template + inline PolyLine& PolyLine::joinHeadToTail(PolyLine& that) { + return joinToHead(that, TAIL); + } + template + inline PolyLine& PolyLine::joinTailToHead(PolyLine& that) { + return joinToTail(that, HEAD); + } + template + inline PolyLine& PolyLine::joinTailToTail(PolyLine& that) { + return joinToTail(that, TAIL); + } + + template + inline PolyLine& PolyLine::disconnectTails() { + next(TAIL)->state_ &= !TAIL_TO_TAIL; + next(TAIL)->tailp_ = 0; + state_ &= !TAIL_TO_TAIL; + tailp_ = 0; + return *this; + } + + template + inline Unit PolyLine::getEndCoord(End end) const { + if(end) + return ptdata_.back(); + return ptdata_.front(); + } + + template + inline orientation_2d PolyLine::segmentOrient(unsigned int index) const { + return (to_bool((unsigned int)verticalHead() ^ (index % 2)) ? VERTICAL : HORIZONTAL); + } + + template + inline point_data PolyLine::getPoint(unsigned int index) const { + //assert(isValid() && headp_->isValid()) ("PolyLine: headp_ must be valid"); + point_data pt; + pt.set(HORIZONTAL, ptdata_[index]); + pt.set(VERTICAL, ptdata_[index]); + Unit prevCoord; + if(index == 0) { + prevCoord = headp_->getEndCoord(headToTail()); + } else { + prevCoord = ptdata_[index-1]; + } + pt.set(segmentOrient(index), prevCoord); + return pt; + } + + template + inline point_data PolyLine::getEndPoint(End end) const { + return getPoint((end ? numSegments() - 1 : (unsigned int)0)); + } + + template + inline Unit PolyLine::operator[] (unsigned int index) const { + //assert(ptdata_.size() > index) ("PolyLine: out of bounds index"); + return ptdata_[index]; + } + + template + inline unsigned int PolyLine::numSegments() const { + return ptdata_.size(); + } + + template + inline PolyLine* PolyLine::next(End end) const { + return (end ? tailp_ : headp_); + } + + template + inline ActiveTail::ActiveTail() : tailp_(0), otherTailp_(0), holesList_() {} + + template + inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : + tailp_(0), otherTailp_(0), holesList_() { + tailp_ = createPolyLine(orient, coord, solidToRight); + otherTailp_ = otherTailp; + } + + template + inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : + tailp_(active), otherTailp_(otherTailp), holesList_() {} + + //copy constructor + template + inline ActiveTail::ActiveTail(const ActiveTail& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_() {} + + //destructor + template + inline ActiveTail::~ActiveTail() { + //clear them in case the memory is read later + tailp_ = 0; otherTailp_ = 0; + } + + template + inline ActiveTail& ActiveTail::operator=(const ActiveTail& that) { + //self assignment is safe in this case + tailp_ = that.tailp_; + otherTailp_ = that.otherTailp_; + return *this; + } + + template + inline bool ActiveTail::operator==(const ActiveTail& b) const { + return tailp_ == b.tailp_ && otherTailp_ == b.otherTailp_; + } + + template + inline bool ActiveTail::operator<(const ActiveTail& b) const { + return tailp_->getEndPoint().get(VERTICAL) < b.tailp_->getEndPoint().get(VERTICAL); + } + + template + inline bool ActiveTail::operator<=(const ActiveTail& b) const { + return !(*this > b); } + + template + inline bool ActiveTail::operator>(const ActiveTail& b) const { + return b < (*this); } + + template + inline bool ActiveTail::operator>=(const ActiveTail& b) const { + return !(*this < b); } + + template + inline PolyLine* ActiveTail::getTail() const { + return tailp_; } + + template + inline PolyLine* ActiveTail::getOtherTail() const { + return otherTailp_->tailp_; } + + template + inline ActiveTail* ActiveTail::getOtherActiveTail() const { + return otherTailp_; } + + template + inline bool ActiveTail::isOtherTail(const ActiveTail& b) { + // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || + // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) + // ("ActiveTail: Active tails out of sync"); + return otherTailp_ == &b; + } + + template + inline ActiveTail& ActiveTail::updateTail(PolyLine* newTail) { + tailp_ = newTail; + return *this; + } + + template + inline ActiveTail* ActiveTail::addHole(ActiveTail* hole, bool fractureHoles) { + if(!fractureHoles){ + holesList_.push_back(hole); + copyHoles(*hole); + copyHoles(*(hole->getOtherActiveTail())); + return this; + } + ActiveTail* h, *v; + ActiveTail* other = hole->getOtherActiveTail(); + if(other->getOrient() == VERTICAL) { + //assert that hole.getOrient() == HORIZONTAL + //this case should never happen + h = hole; + v = other; + } else { + //assert that hole.getOrient() == VERTICAL + h = other; + v = hole; + } + h->pushCoordinate(v->getCoordinate()); + //assert that h->getOrient() == VERTICAL + //v->pushCoordinate(getCoordinate()); + //assert that v->getOrient() == VERTICAL + //I can't close a figure by adding a hole, so pass zero for xMin and yMin + std::vector tmpVec; + ActiveTail::joinChains(this, h, false, tmpVec); + return v; + } + + template + inline const std::list*>& ActiveTail::getHoles() const { + return holesList_; + } + + template + inline void ActiveTail::copyHoles(ActiveTail& that) { + holesList_.splice(holesList_.end(), that.holesList_); //splice the two lists together + } + + template + inline bool ActiveTail::solidToRight() const { + return getTail()->solidToRight(); } + + template + inline Unit ActiveTail::getCoord() const { + return getTail()->getEndCoord(); } + + template + inline Unit ActiveTail::getCoordinate() const { + return getCoord(); } + + template + inline orientation_2d ActiveTail::getOrient() const { + return getTail()->tailOrient(); } + + template + inline void ActiveTail::pushCoordinate(Unit coord) { + //appropriately handle any co-linear polyline segments by calling push point internally + point_data p; + p.set(HORIZONTAL, coord); + p.set(VERTICAL, coord); + //if we are vertical assign the last coordinate (an X) to p.x, else to p.y + p.set(getOrient().get_perpendicular(), getCoordinate()); + tailp_->pushPoint(p); + } + + + //global utility functions + template + inline PolyLine* createPolyLine(orientation_2d orient, Unit coord, Side side) { + return new PolyLine(orient, coord, side); + } + + template + inline void destroyPolyLine(PolyLine* pLine) { + delete pLine; + } + + template + inline ActiveTail* createActiveTail() { + //consider replacing system allocator with ActiveTail memory pool + return new ActiveTail(); + } + + template + inline void destroyActiveTail(ActiveTail* aTail) { + delete aTail; + } + + + //no recursion, to prevent max recursion depth errors + template + inline void ActiveTail::destroyContents() { + tailp_->disconnectTails(); + PolyLine* nextPolyLinep = tailp_->next(HEAD); + End end = tailp_->endConnectivity(HEAD); + destroyPolyLine(tailp_); + while(nextPolyLinep) { + End nextEnd = nextPolyLinep->endConnectivity(!end); //get the direction of next polyLine + PolyLine* nextNextPolyLinep = nextPolyLinep->next(!end); //get the next polyline + destroyPolyLine(nextPolyLinep); //destroy the current polyline + end = nextEnd; + nextPolyLinep = nextNextPolyLinep; + } + } + + template + inline typename ActiveTail::iterator ActiveTail::begin(bool isHole, orientation_2d orient) const { + return iterator(this, isHole, orient); + } + + template + inline typename ActiveTail::iterator ActiveTail::end() const { + return iterator(); + } + + template + inline typename ActiveTail::iteratorHoles ActiveTail::beginHoles() const { + return holesList_.begin(); + } + + template + inline typename ActiveTail::iteratorHoles ActiveTail::endHoles() const { + return holesList_.end(); + } + + template + inline void ActiveTail::writeOutFigureItrs(iterator& beginOut, iterator& endOut, bool isHole, orientation_2d orient) const { + beginOut = begin(isHole, orient); + endOut = end(); + } + + template + inline void ActiveTail::writeOutFigureHoleItrs(iteratorHoles& beginOut, iteratorHoles& endOut) const { + beginOut = beginHoles(); + endOut = endHoles(); + } + + template + inline void ActiveTail::writeOutFigure(std::vector& outVec, bool isHole) const { + //we start writing out the polyLine that this active tail points to at its tail + std::size_t size = outVec.size(); + outVec.push_back(0); //place holder for size + PolyLine* nextPolyLinep = 0; + if(!isHole){ + nextPolyLinep = otherTailp_->tailp_->writeOut(outVec); + } else { + nextPolyLinep = tailp_->writeOut(outVec); + } + Unit firsty = outVec[size + 1]; + if((getOrient() == HORIZONTAL) ^ !isHole) { + //our first coordinate is a y value, so we need to rotate it to the end + typename std::vector::iterator tmpItr = outVec.begin(); + tmpItr += size; + outVec.erase(++tmpItr); //erase the 2nd element + } + End startEnd = tailp_->endConnectivity(HEAD); + if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); + while(nextPolyLinep) { + bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); + nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); + startEnd = nextStartEnd; + } + if((getOrient() == HORIZONTAL) ^ !isHole) { + //we want to push the y value onto the end since we ought to have ended with an x + outVec.push_back(firsty); //should never be executed because we want first value to be an x + } + //the vector contains the coordinates of the linked list of PolyLines in the correct order + //first element is supposed to be the size + outVec[size] = outVec.size() - 1 - size; //number of coordinates in vector + //assert outVec[size] % 2 == 0 //it should be even + //make the size negative for holes + outVec[size] *= (isHole ? -1 : 1); + } + + //no recursion to prevent max recursion depth errors + template + inline PolyLine* PolyLine::writeOut(std::vector& outVec, End startEnd) const { + if(startEnd == HEAD){ + //forward order + outVec.insert(outVec.end(), ptdata_.begin(), ptdata_.end()); + return tailp_; + }else{ + //reverse order + //do not reserve because we expect outVec to be large enough already + for(int i = ptdata_.size() - 1; i >= 0; --i){ + outVec.push_back(ptdata_[i]); + } + //NT didn't know about this version of the API.... + //outVec.insert(outVec.end(), ptdata_.rbegin(), ptdata_.rend()); + return headp_; + } + } + + //solid indicates if it was joined by a solit or a space + template + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) + { + //checks to see if we closed a figure + if(at1->isOtherTail(*at2)){ + //value of solid tells us if we closed solid or hole + //and output the solid or handle the hole appropriately + //if the hole needs to fracture across horizontal partition boundary we need to notify + //the calling context to do so + if(solid) { + //the chains are being joined because there is solid to the right + //this means that if the figure is closed at this point it must be a hole + //because otherwise it would have to have another vertex to the right of this one + //and would not be closed at this point + return at1; + } else { + //assert pG != 0 + //the figure that was closed is a shell + at1->writeOutFigure(outBufferTmp); + //process holes of the polygon + at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over + const std::list*>& holes = at1->getHoles(); + for(typename std::list*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { + (*litr)->writeOutFigure(outBufferTmp, true); + //delete the hole + (*litr)->destroyContents(); + destroyActiveTail((*litr)->getOtherActiveTail()); + destroyActiveTail((*litr)); + } + //delete the polygon + at1->destroyContents(); + //at2 contents are the same as at1, so it should not destroy them + destroyActiveTail(at1); + destroyActiveTail(at2); + } + return 0; + } + //join the two partial polygons into one large partial polygon + at1->getTail()->joinTailToTail(*(at2->getTail())); + *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); + *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); + at1->getOtherActiveTail()->copyHoles(*at1); + at1->getOtherActiveTail()->copyHoles(*at2); + destroyActiveTail(at1); + destroyActiveTail(at2); + return 0; + } + + //solid indicates if it was joined by a solit or a space + template + template + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, + std::vector& outBufferTmp) { + //checks to see if we closed a figure + if(at1->isOtherTail(*at2)){ + //value of solid tells us if we closed solid or hole + //and output the solid or handle the hole appropriately + //if the hole needs to fracture across horizontal partition boundary we need to notify + //the calling context to do so + if(solid) { + //the chains are being joined because there is solid to the right + //this means that if the figure is closed at this point it must be a hole + //because otherwise it would have to have another vertex to the right of this one + //and would not be closed at this point + return at1; + } else { + //assert pG != 0 + //the figure that was closed is a shell + outBufferTmp.push_back(at1); + at1->copyHoles(*at2); //there should not be holes on at2, but if there are, copy them over + } + return 0; + } + //join the two partial polygons into one large partial polygon + at1->getTail()->joinTailToTail(*(at2->getTail())); + *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); + *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); + at1->getOtherActiveTail()->copyHoles(*at1); + at1->getOtherActiveTail()->copyHoles(*at2); + destroyActiveTail(at1); + destroyActiveTail(at2); + return 0; + } + + template inline typename std::map::iterator findAtNext(std::map& theMap, + typename std::map::iterator pos, const TKey& key) + { + if(pos == theMap.end()) return theMap.find(key); + //if they match the mapItr is pointing to the correct position + if(pos->first < key) { + return theMap.find(key); + } + if(pos->first > key) { + return theMap.end(); + } + //else they are equal and no need to do anything to the iterator + return pos; + } + + // createActiveTailsAsPair is called in these two end cases of geometry + // 1. lower left concave corner + // ###| + // ###| + // ###|### + // ###|### + // 2. lower left convex corner + // |### + // |### + // | + // | + // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled + // the two active tails that form the filament fracture line edges can become the new active tail pair + // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails + // with add hole + template + inline std::pair*, ActiveTail*> createActiveTailsAsPair(Unit x, Unit y, bool solid, ActiveTail* phole, bool fractureHoles) { + ActiveTail* at1 = 0; + ActiveTail* at2 = 0; + if(!phole || !fractureHoles){ + at1 = createActiveTail(); + at2 = createActiveTail(); + (*at1) = ActiveTail(VERTICAL, x, solid, at2); + (*at2) = ActiveTail(HORIZONTAL, y, !solid, at1); + //provide a function through activeTail class to provide this + at1->getTail()->joinHeadToHead(*(at2->getTail())); + if(phole) + at1->addHole(phole, fractureHoles); //assert fractureHoles == false + return std::pair*, ActiveTail*>(at1, at2); + } + //assert phole is not null + //assert fractureHoles is true + if(phole->getOrient() == VERTICAL) { + at2 = phole; + } else { + at2 = phole->getOtherActiveTail(); //should never be executed since orientation is expected to be vertical + } + //assert solid == false, we should be creating a corner with solid below and to the left if there was a hole + at1 = at2->getOtherActiveTail(); + //assert at1 is horizontal + at1->pushCoordinate(x); + //assert at2 is vertical + at2->pushCoordinate(y); + return std::pair*, ActiveTail*>(at1, at2); + } + + //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member + //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. + // + //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique + //actions to take: + // 1. Solid on both sides of the vertical partition after the current position and space on both sides before + // ###|### + // ###|### + // | + // | + // This case does not need to be handled because there is no vertical edge at the current x coordinate. + // + // 2. Solid on both sides of the vertical partition before the current position and space on both sides after + // | + // | + // ###|### + // ###|### + // This case does not need to be handled because there is no vertical edge at the current x coordinate. + // + // 3. Solid on the left of the vertical partition after the current position and space elsewhere + // ###| + // ###| + // | + // | + // The horizontal edge from the left is found and turns upward because of the vertical right edge to become + // the currently active vertical edge. + // + // 4. Solid on the left of the vertical partion before the current position and space elsewhere + // | + // | + // ###| + // ###| + // The horizontal edge from the left is found and joined to the currently active vertical edge. + // + // 5. Solid to the right above and below and solid to the left above current position. + // ###|### + // ###|### + // |### + // |### + // The horizontal edge from the left is found and joined to the currently active vertical edge, + // potentially closing a hole. + // + // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below + // |### + // |### + // ###|### + // ###|### + // The horizontal edge from the left is found and turns upward because of the vertical right edge to become + // the currently active vertical edge. + // + // 7. Solid on the right of the vertical partition after the current position and space elsewhere + // |### + // |### + // | + // | + // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail + // + // 8. Solid on the right of the vertical partion before the current position and space elsewhere + // | + // | + // |### + // |### + // The currentTail vertical edge turns right and is added to the horizontal edges data + // + // 9. Solid to the right above and solid to the left above and below current position. + // ###|### + // ###|### + // ###| + // ###| + // The currentTail vertical edge turns right and is added to the horizontal edges data + // + // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below + // ###| + // ###| + // ###|### + // ###|### + // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail + // + // 11. Solid to the right above and solid to the left below current position. + // |### + // |### + // ###| + // ###| + // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) + // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail + // + // 12. Solid on the left of the vertical partion above the current position and solid to the right below + // ###| + // ###| + // |### + // |### + // The currentTail vertical edge turns right and is added to the horizontal edges data. + // The horizontal edge from the left turns upward and becomes the currentTail vertical edge + // + template + inline void ScanLineToPolygonItrs:: + processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, + std::vector >& rightEdges) { + clearOutput_(); + typename std::map*>::iterator nextMapItr = tailMap_.begin(); + //foreach edge + unsigned int leftIndex = 0; + unsigned int rightIndex = 0; + bool bottomAlreadyProcessed = false; + ActiveTail* currentTail = 0; + const Unit UnitMax = (std::numeric_limits::max)(); + while(leftIndex < leftEdges.size() || rightIndex < rightEdges.size()) { + interval_data edges[2] = {interval_data (UnitMax, UnitMax), interval_data (UnitMax, UnitMax)}; + bool haveNextEdge = true; + if(leftIndex < leftEdges.size()) + edges[0] = leftEdges[leftIndex]; + else + haveNextEdge = false; + if(rightIndex < rightEdges.size()) + edges[1] = rightEdges[rightIndex]; + else + haveNextEdge = false; + bool trailingEdge = edges[1].get(LOW) < edges[0].get(LOW); + interval_data & edge = edges[trailingEdge]; + interval_data & nextEdge = edges[!trailingEdge]; + //process this edge + if(!bottomAlreadyProcessed) { + //assert currentTail = 0 + + //process the bottom end of this edge + typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); + if(thisMapItr != tailMap_.end()) { + //there is an edge in the map at the low end of this edge + //it needs to turn upward and become the current tail + ActiveTail* tail = thisMapItr->second; + if(currentTail) { + //stitch currentTail into this tail + currentTail = tail->addHole(currentTail, fractureHoles_); + if(!fractureHoles_) + currentTail->pushCoordinate(currentX); + } else { + currentTail = tail; + currentTail->pushCoordinate(currentX); + } + //assert currentTail->getOrient() == VERTICAL + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + //remove thisMapItr from the map + tailMap_.erase(thisMapItr); + } else { + //there is no edge in the map at the low end of this edge + //we need to create one and another one to be the current vertical tail + //if this is a trailing edge then there is space to the right of the vertical edge + //so pass the inverse of trailingEdge to indicate solid to the right + std::pair*, ActiveTail*> tailPair = + createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); + currentTail = tailPair.first; + tailMap_.insert(nextMapItr, std::pair*>(edge.get(LOW), tailPair.second)); + // leave nextMapItr unchanged + } + + } + if(haveNextEdge && edge.get(HIGH) == nextEdge.get(LOW)) { + //the top of this edge is equal to the bottom of the next edge, process them both + bottomAlreadyProcessed = true; + typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); + if(thisMapItr == tailMap_.end()) //assert this should never happen + return; + if(trailingEdge) { + //geometry at this position + // |## + // |## + // ----- + // ##| + // ##| + //current tail should join thisMapItr tail + ActiveTail* tail = thisMapItr->second; + //pass false because they are being joined because space is to the right and it will close a solid figure + ActiveTail::joinChains(currentTail, tail, false, outputPolygons_); + //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail + //pass true becuase they are created at the lower left corner of some solid + //pass null because there is no hole pointer possible + std::pair*, ActiveTail*> tailPair = + createActiveTailsAsPair(currentX, edge.get(HIGH), true, 0, fractureHoles_); + currentTail = tailPair.first; + thisMapItr->second = tailPair.second; + } else { + //geometry at this position + // ##| + // ##| + // ----- + // |## + // |## + //current tail should turn right + currentTail->pushCoordinate(edge.get(HIGH)); + //thisMapItr tail should turn up + thisMapItr->second->pushCoordinate(currentX); + //thisMapItr tail becomes current tail and current tail becomes thisMapItr tail + std::swap(currentTail, thisMapItr->second); + } + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + } else { + //there is a gap between the top of this edge and the bottom of the next, process the top of this edge + bottomAlreadyProcessed = false; + //process the top of this edge + typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(HIGH)); + if(thisMapItr != tailMap_.end()) { + //thisMapItr is pointing to a horizontal edge in the map at the top of this vertical edge + //we need to join them and potentially close a figure + //assert currentTail != 0 + ActiveTail* tail = thisMapItr->second; + //pass the opositve of trailing edge to mean that they are joined because of solid to the right + currentTail = ActiveTail::joinChains(currentTail, tail, !trailingEdge, outputPolygons_); + nextMapItr = thisMapItr; //set nextMapItr to the next position after this one + ++nextMapItr; + if(currentTail) { + Unit nextItrY = UnitMax; + if(nextMapItr != tailMap_.end()) { + nextItrY = nextMapItr->first; + } + //for it to be a hole this must have been a left edge + Unit leftY = UnitMax; + if(leftIndex + 1 < leftEdges.size()) + leftY = leftEdges[leftIndex+1].get(LOW); + Unit rightY = nextEdge.get(LOW); + if(!haveNextEdge || (nextItrY < leftY && nextItrY < rightY)) { + //we need to add it to the next edge above it in the map + tail = nextMapItr->second; + tail = tail->addHole(currentTail, fractureHoles_); + if(fractureHoles_) { + //some small additional work stitching in the filament + tail->pushCoordinate(nextItrY); + nextMapItr->second = tail; + } + //set current tail to null + currentTail = 0; + } + } + //delete thisMapItr from the map + tailMap_.erase(thisMapItr); + } else { + //currentTail must turn right and be added into the map + currentTail->pushCoordinate(edge.get(HIGH)); + //assert currentTail->getOrient() == HORIZONTAL + tailMap_.insert(nextMapItr, std::pair*>(edge.get(HIGH), currentTail)); + //set currentTail to null + currentTail = 0; + //leave nextMapItr unchanged, it is still next + } + } + + //increment index + leftIndex += !trailingEdge; + rightIndex += trailingEdge; + } //end while + beginOutput = outputPolygons_.begin(); + endOutput = outputPolygons_.end(); + } //end function + + template + inline void ScanLineToPolygonItrs::clearOutput_() { + for(std::size_t i = 0; i < outputPolygons_.size(); ++i) { + ActiveTail* at1 = outputPolygons_[i].yield(); + const std::list*>& holes = at1->getHoles(); + for(typename std::list*>::const_iterator litr = holes.begin(); litr != holes.end(); ++litr) { + //delete the hole + (*litr)->destroyContents(); + destroyActiveTail((*litr)->getOtherActiveTail()); + destroyActiveTail((*litr)); + } + //delete the polygon + at1->destroyContents(); + //at2 contents are the same as at1, so it should not destroy them + destroyActiveTail((at1)->getOtherActiveTail()); + destroyActiveTail(at1); + } + outputPolygons_.clear(); + } + +} //polygon_formation namespace + + template + struct geometry_concept > { + typedef polygon_90_with_holes_concept type; + }; + + template + struct geometry_concept > { + typedef polygon_90_concept type; + }; + + //public API to access polygon formation algorithm + template + unsigned int get_polygons(output_container& container, iterator_type begin, iterator_type end, + orientation_2d orient, bool fracture_holes, concept_type ) { + typedef typename output_container::value_type polygon_type; + typedef typename std::iterator_traits::value_type::first_type coordinate_type; + polygon_type poly; + unsigned int countPolygons = 0; + typedef typename geometry_concept::type polygon_concept_type; + polygon_formation::ScanLineToPolygonItrs scanlineToPolygonItrsV(fracture_holes); + polygon_formation::ScanLineToPolygonItrs scanlineToPolygonItrsH(fracture_holes); + std::vector > leftEdges; + std::vector > rightEdges; + coordinate_type prevPos = (std::numeric_limits::max)(); + coordinate_type prevY = (std::numeric_limits::max)(); + int count = 0; + for(iterator_type itr = begin; + itr != end; ++ itr) { + coordinate_type pos = (*itr).first; + if(pos != prevPos) { + if(orient == VERTICAL) { + typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } else { + typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } + leftEdges.clear(); + rightEdges.clear(); + prevPos = pos; + prevY = (*itr).second.first; + count = (*itr).second.second; + continue; + } + coordinate_type y = (*itr).second.first; + if(count != 0 && y != prevY) { + std::pair, int> element(interval_data(prevY, y), count); + if(element.second == 1) { + if(leftEdges.size() && leftEdges.back().high() == element.first.low()) { + encompass(leftEdges.back(), element.first); + } else { + leftEdges.push_back(element.first); + } + } else { + if(rightEdges.size() && rightEdges.back().high() == element.first.low()) { + encompass(rightEdges.back(), element.first); + } else { + rightEdges.push_back(element.first); + } + } + + } + prevY = y; + count += (*itr).second.second; + } + if(orient == VERTICAL) { + typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } else { + typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { + ++countPolygons; + assign(poly, *itrPoly); + container.insert(container.end(), poly); + } + } + return countPolygons; + } + +} +} +#endif + diff --git a/include/boost/polygon/detail/polygon_set_view.hpp b/include/boost/polygon/detail/polygon_set_view.hpp new file mode 100644 index 0000000..7b159a8 --- /dev/null +++ b/include/boost/polygon/detail/polygon_set_view.hpp @@ -0,0 +1,207 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_SET_VIEW_HPP +#define BOOST_POLYGON_POLYGON_SET_VIEW_HPP +namespace boost { namespace polygon{ + + + template + inline void polygon_set_data::clean() const { + if(dirty_) { + polygon_45_set_data tmp; + if(downcast(tmp) ) { + tmp.clean(); + data_.clear(); + is_45_ = true; + polygon_set_data tmp2; + tmp2.insert(tmp); + data_.swap(tmp2.data_); + dirty_ = false; + sort(); + } else { + sort(); + arbitrary_boolean_op abo; + polygon_set_data tmp2; + abo.execute(tmp2, begin(), end(), end(), end(), 0); + data_.swap(tmp2.data_); + is_45_ = tmp2.is_45_; + dirty_ = false; + } + } + } + + template <> + inline void polygon_set_data::clean() const { + if(dirty_) { + sort(); + arbitrary_boolean_op abo; + polygon_set_data tmp2; + abo.execute(tmp2, begin(), end(), end(), end(), 0); + data_.swap(tmp2.data_); + is_45_ = tmp2.is_45_; + dirty_ = false; + } + } + + template + inline void insert_into_view_arg(value_type& dest, const arg_type& arg); + + template + class polygon_set_view; + + template + struct polygon_set_traits > { + typedef typename polygon_set_view::coordinate_type coordinate_type; + typedef typename polygon_set_view::iterator_type iterator_type; + typedef typename polygon_set_view::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_set_view& polygon_set); + static inline iterator_type end(const polygon_set_view& polygon_set); + + static inline bool clean(const polygon_set_view& polygon_set); + + static inline bool sort(const polygon_set_view& polygon_set); + }; + + //template + //void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_, + // double coord) { + // typedef geometry_type_1 ltype; + // typedef geometry_type_2 rtype; + // typedef typename polygon_set_traits::coordinate_type coordinate_type; + // value_type linput_; + // value_type rinput_; + // insert_into_view_arg(linput_, lvalue_); + // insert_into_view_arg(rinput_, rvalue_); + // arbitrary_boolean_op abo; + // abo.execute(output_, linput_.begin(), linput_.end(), + // rinput_.begin(), rinput_.end(), op_type); + //} + + template + void execute_boolean_op(value_type& output_, const geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_set_traits::coordinate_type coordinate_type; + value_type linput_; + value_type rinput_; + insert_into_view_arg(linput_, lvalue_); + insert_into_view_arg(rinput_, rvalue_); + polygon_45_set_data l45, r45, o45; + if(linput_.downcast(l45) && rinput_.downcast(r45)) { + //the op codes are screwed up between 45 and arbitrary +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type < 2) + l45.template applyAdaptiveBoolean_(o45, r45); + else if(op_type == 2) + l45.template applyAdaptiveBoolean_<3>(o45, r45); + else + l45.template applyAdaptiveBoolean_<2>(o45, r45); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + output_.insert(o45); + } else { + arbitrary_boolean_op abo; + abo.execute(output_, linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), op_type); + } + } + + template + class polygon_set_view { + public: + typedef typename polygon_set_traits::coordinate_type coordinate_type; + typedef polygon_set_data value_type; + typedef typename value_type::iterator_type iterator_type; + typedef polygon_set_view operator_arg_type; + private: + const ltype& lvalue_; + const rtype& rvalue_; + mutable value_type output_; + mutable bool evaluated_; + polygon_set_view& operator=(const polygon_set_view&); + public: + polygon_set_view(const ltype& lvalue, + const rtype& rvalue ) : + lvalue_(lvalue), rvalue_(rvalue), output_(), evaluated_(false) {} + + // get iterator to begin vertex data + public: + const value_type& value() const { + if(!evaluated_) { + evaluated_ = true; + execute_boolean_op(output_, lvalue_, rvalue_); + } + return output_; + } + public: + iterator_type begin() const { return value().begin(); } + iterator_type end() const { return value().end(); } + + bool dirty() const { return false; } //result of a boolean is clean + bool sorted() const { return true; } //result of a boolean is sorted + + void sort() const {} //is always sorted + }; + + template + typename polygon_set_traits >::iterator_type + polygon_set_traits >:: + begin(const polygon_set_view& polygon_set) { + return polygon_set.begin(); + } + template + typename polygon_set_traits >::iterator_type + polygon_set_traits >:: + end(const polygon_set_view& polygon_set) { + return polygon_set.end(); + } + template + bool polygon_set_traits >:: + clean(const polygon_set_view& ) { + return true; } + template + bool polygon_set_traits >:: + sort(const polygon_set_view& ) { + return true; } + + template + inline void insert_into_view_arg(value_type& dest, const arg_type& arg) { + typedef typename polygon_set_traits::iterator_type literator; + literator itr1, itr2; + itr1 = polygon_set_traits::begin(arg); + itr2 = polygon_set_traits::end(arg); + dest.insert(itr1, itr2); + } + + template + geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef typename polygon_set_traits::coordinate_type coordinate_type; + typedef polygon_set_data value_type; + value_type output_; + execute_boolean_op(output_, lvalue_, rvalue_); + polygon_set_mutable_traits::set(lvalue_, output_.begin(), output_.end()); + return lvalue_; + } + + // copy constructor + template + template + polygon_set_data::polygon_set_data(const polygon_set_view& that) : + data_(that.value().data_), dirty_(that.value().dirty_), unsorted_(that.value().unsorted_), is_45_(that.value().is_45_) {} + + template + struct geometry_concept > { typedef polygon_set_concept type; }; +} +} +#endif + diff --git a/include/boost/polygon/detail/property_merge.hpp b/include/boost/polygon/detail/property_merge.hpp new file mode 100644 index 0000000..586a927 --- /dev/null +++ b/include/boost/polygon/detail/property_merge.hpp @@ -0,0 +1,588 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_PROPERTY_MERGE_HPP +#define BOOST_POLYGON_PROPERTY_MERGE_HPP +namespace boost { namespace polygon{ + +template +class property_merge_point { +private: + coordinate_type x_, y_; +public: + inline property_merge_point() : x_(), y_() {} + inline property_merge_point(coordinate_type x, coordinate_type y) : x_(x), y_(y) {} + //use builtin assign and copy + inline bool operator==(const property_merge_point& that) const { return x_ == that.x_ && y_ == that.y_; } + inline bool operator!=(const property_merge_point& that) const { return !((*this) == that); } + inline bool operator<(const property_merge_point& that) const { + if(x_ < that.x_) return true; + if(x_ > that.x_) return false; + return y_ < that.y_; + } + inline coordinate_type x() const { return x_; } + inline coordinate_type y() const { return y_; } + inline void x(coordinate_type value) { x_ = value; } + inline void y(coordinate_type value) { y_ = value; } +}; + +template +class property_merge_interval { +private: + coordinate_type low_, high_; +public: + inline property_merge_interval() : low_(), high_() {} + inline property_merge_interval(coordinate_type low, coordinate_type high) : low_(low), high_(high) {} + //use builtin assign and copy + inline bool operator==(const property_merge_interval& that) const { return low_ == that.low_ && high_ == that.high_; } + inline bool operator!=(const property_merge_interval& that) const { return !((*this) == that); } + inline bool operator<(const property_merge_interval& that) const { + if(low_ < that.low_) return true; + if(low_ > that.low_) return false; + return high_ < that.high_; + } + inline coordinate_type low() const { return low_; } + inline coordinate_type high() const { return high_; } + inline void low(coordinate_type value) { low_ = value; } + inline void high(coordinate_type value) { high_ = value; } +}; + +template > +class merge_scanline { +public: + //definitions + + typedef keytype property_set; + typedef std::vector > property_map; + typedef std::pair, std::pair > vertex_property; + typedef std::pair, property_map> vertex_data; + typedef std::vector property_merge_data; + //typedef std::map Result; + typedef std::map scanline_type; + typedef typename scanline_type::iterator scanline_iterator; + typedef std::pair, std::pair > edge_property; + typedef std::vector edge_property_vector; + + //static public member functions + + template + static inline void + populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end, + const property_type& property, orientation_2d_type orient) { + for( ; input_begin != input_end; ++input_begin) { + std::pair, std::pair > element; + if(orient == HORIZONTAL) + element.first = property_merge_point((*input_begin).second.first, (*input_begin).first); + else + element.first = property_merge_point((*input_begin).first, (*input_begin).second.first); + element.second.first = property; + element.second.second = (*input_begin).second.second; + pmd.push_back(element); + } + } + + //public member functions + + merge_scanline() : output(), scanline(), currentVertex(), tmpVector(), previousY(), countFromBelow(), scanlinePosition() {} + merge_scanline(const merge_scanline& that) : + output(that.output), + scanline(that.scanline), + currentVertex(that.currentVertex), + tmpVector(that.tmpVector), + previousY(that.previousY), + countFromBelow(that.countFromBelow), + scanlinePosition(that.scanlinePosition) + {} + merge_scanline& operator=(const merge_scanline& that) { + output = that.output; + scanline = that.scanline; + currentVertex = that.currentVertex; + tmpVector = that.tmpVector; + previousY = that.previousY; + countFromBelow = that.countFromBelow; + scanlinePosition = that.scanlinePosition; + return *this; + } + + template + inline void perform_merge(result_type& result, property_merge_data& data) { + if(data.empty()) return; + //sort + std::sort(data.begin(), data.end(), less_vertex_data()); + //scanline + bool firstIteration = true; + scanlinePosition = scanline.end(); + for(std::size_t i = 0; i < data.size(); ++i) { + if(firstIteration) { + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + firstIteration = false; + } else { + if(data[i].first != currentVertex.first) { + if(data[i].first.x() != currentVertex.first.x()) { + processVertex(output); + //std::cout << scanline.size() << " "; + countFromBelow.clear(); //should already be clear + writeOutput(currentVertex.first.x(), result, output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + //std::cout << assertRedundant(scanline) << "/" << scanline.size() << " "; + } else { + processVertex(output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } + } else { + mergeProperty(currentVertex.second, data[i].second); + } + } + } + processVertex(output); + writeOutput(currentVertex.first.x(), result, output); + //std::cout << assertRedundant(scanline) << "/" << scanline.size() << "\n"; + //std::cout << scanline.size() << "\n"; + } + +private: + //private supporting types + + template + class less_vertex_data { + public: + less_vertex_data() {} + bool operator()(const T& lvalue, const T& rvalue) { + if(lvalue.first.x() < rvalue.first.x()) return true; + if(lvalue.first.x() > rvalue.first.x()) return false; + if(lvalue.first.y() < rvalue.first.y()) return true; + return false; + } + }; + + template + struct lessPropertyCount { + lessPropertyCount() {} + bool operator()(const T& a, const T& b) { + return a.first < b.first; + } + }; + + //private static member functions + + static inline void mergeProperty(property_map& lvalue, std::pair& rvalue) { + typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue, + lessPropertyCount >()); + if(itr == lvalue.end() || + (*itr).first != rvalue.first) { + lvalue.insert(itr, rvalue); + } else { + (*itr).second += rvalue.second; + if((*itr).second == 0) + lvalue.erase(itr); + } +// if(assertSorted(lvalue)) { +// std::cout << "in mergeProperty\n"; +// exit(0); +// } + } + +// static inline bool assertSorted(property_map& pset) { +// bool result = false; +// for(std::size_t i = 1; i < pset.size(); ++i) { +// if(pset[i] < pset[i-1]) { +// std::cout << "Out of Order Error "; +// result = true; +// } +// if(pset[i].first == pset[i-1].first) { +// std::cout << "Duplicate Property Error "; +// result = true; +// } +// if(pset[0].second == 0 || pset[1].second == 0) { +// std::cout << "Empty Property Error "; +// result = true; +// } +// } +// return result; +// } + + static inline void setProperty(property_set& pset, property_map& pmap) { + for(typename property_map::iterator itr = pmap.begin(); itr != pmap.end(); ++itr) { + if((*itr).second > 0) { + pset.insert(pset.end(), (*itr).first); + } + } + } + + //private data members + + edge_property_vector output; + scanline_type scanline; + vertex_data currentVertex; + property_map tmpVector; + coordinate_type previousY; + property_map countFromBelow; + scanline_iterator scanlinePosition; + + //private member functions + + inline void mergeCount(property_map& lvalue, property_map& rvalue) { + typename property_map::iterator litr = lvalue.begin(); + typename property_map::iterator ritr = rvalue.begin(); + tmpVector.clear(); + while(litr != lvalue.end() && ritr != rvalue.end()) { + if((*litr).first <= (*ritr).first) { + if(!tmpVector.empty() && + (*litr).first == tmpVector.back().first) { + tmpVector.back().second += (*litr).second; + } else { + tmpVector.push_back(*litr); + } + ++litr; + } else if((*ritr).first <= (*litr).first) { + if(!tmpVector.empty() && + (*ritr).first == tmpVector.back().first) { + tmpVector.back().second += (*ritr).second; + } else { + tmpVector.push_back(*ritr); + } + ++ritr; + } + } + while(litr != lvalue.end()) { + if(!tmpVector.empty() && + (*litr).first == tmpVector.back().first) { + tmpVector.back().second += (*litr).second; + } else { + tmpVector.push_back(*litr); + } + ++litr; + } + while(ritr != rvalue.end()) { + if(!tmpVector.empty() && + (*ritr).first == tmpVector.back().first) { + tmpVector.back().second += (*ritr).second; + } else { + tmpVector.push_back(*ritr); + } + ++ritr; + } + lvalue.clear(); + for(std::size_t i = 0; i < tmpVector.size(); ++i) { + if(tmpVector[i].second != 0) { + lvalue.push_back(tmpVector[i]); + } + } +// if(assertSorted(lvalue)) { +// std::cout << "in mergeCount\n"; +// exit(0); +// } + } + + inline void processVertex(edge_property_vector& output) { + if(!countFromBelow.empty()) { + //we are processing an interval of change in scanline state between + //previous vertex position and current vertex position where + //count from below represents the change on the interval + //foreach scanline element from previous to current we + //write the interval on the scanline that is changing + //the old value and the new value to output + property_merge_interval currentInterval(previousY, currentVertex.first.y()); + coordinate_type currentY = currentInterval.low(); + if(scanlinePosition == scanline.end() || + (*scanlinePosition).first != previousY) { + scanlinePosition = scanline.lower_bound(previousY); + } + scanline_iterator previousScanlinePosition = scanlinePosition; + ++scanlinePosition; + while(scanlinePosition != scanline.end()) { + coordinate_type elementY = (*scanlinePosition).first; + if(elementY <= currentInterval.high()) { + property_map& countOnLeft = (*previousScanlinePosition).second; + edge_property element; + output.push_back(element); + output.back().first = property_merge_interval((*previousScanlinePosition).first, elementY); + setProperty(output.back().second.first, countOnLeft); + mergeCount(countOnLeft, countFromBelow); + setProperty(output.back().second.second, countOnLeft); + if(output.back().second.first == output.back().second.second) { + output.pop_back(); //it was an internal vertical edge, not to be output + } + else if(output.size() > 1) { + edge_property& secondToLast = output[output.size()-2]; + if(secondToLast.first.high() == output.back().first.low() && + secondToLast.second.first == output.back().second.first && + secondToLast.second.second == output.back().second.second) { + //merge output onto previous output because properties are + //identical on both sides implying an internal horizontal edge + secondToLast.first.high(output.back().first.high()); + output.pop_back(); + } + } + if(previousScanlinePosition == scanline.begin()) { + if(countOnLeft.empty()) { + scanline.erase(previousScanlinePosition); + } + } else { + scanline_iterator tmpitr = previousScanlinePosition; + --tmpitr; + if((*tmpitr).second == (*previousScanlinePosition).second) + scanline.erase(previousScanlinePosition); + } + + } else if(currentY < currentInterval.high()){ + //elementY > currentInterval.high() + //split the interval between previous and current scanline elements + std::pair elementScan; + elementScan.first = currentInterval.high(); + elementScan.second = (*previousScanlinePosition).second; + scanlinePosition = scanline.insert(scanlinePosition, elementScan); + continue; + } else { + break; + } + previousScanlinePosition = scanlinePosition; + currentY = previousY = elementY; + ++scanlinePosition; + if(scanlinePosition == scanline.end() && + currentY < currentInterval.high()) { + //insert a new element for top of range + std::pair elementScan; + elementScan.first = currentInterval.high(); + scanlinePosition = scanline.insert(scanline.end(), elementScan); + } + } + if(scanlinePosition == scanline.end() && + currentY < currentInterval.high()) { + //handle case where we iterated to end of the scanline + //we need to insert an element into the scanline at currentY + //with property value coming from below + //and another one at currentInterval.high() with empty property value + mergeCount(scanline[currentY], countFromBelow); + std::pair elementScan; + elementScan.first = currentInterval.high(); + scanline.insert(scanline.end(), elementScan); + + edge_property element; + output.push_back(element); + output.back().first = property_merge_interval(currentY, currentInterval.high()); + setProperty(output.back().second.second, countFromBelow); + mergeCount(countFromBelow, currentVertex.second); + } else { + mergeCount(countFromBelow, currentVertex.second); + if(countFromBelow.empty()) { + if(previousScanlinePosition == scanline.begin()) { + if((*previousScanlinePosition).second.empty()) { + scanline.erase(previousScanlinePosition); + //previousScanlinePosition = scanline.end(); + //std::cout << "ERASE_A "; + } + } else { + scanline_iterator tmpitr = previousScanlinePosition; + --tmpitr; + if((*tmpitr).second == (*previousScanlinePosition).second) { + scanline.erase(previousScanlinePosition); + //previousScanlinePosition = scanline.end(); + //std::cout << "ERASE_B "; + } + } + } + } + } else { + //count from below is empty, we are starting a new interval of change + countFromBelow = currentVertex.second; + scanlinePosition = scanline.lower_bound(currentVertex.first.y()); + if(scanlinePosition != scanline.end()) { + if((*scanlinePosition).first != currentVertex.first.y()) { + if(scanlinePosition != scanline.begin()) { + //decrement to get the lower position of the first interval this vertex intersects + --scanlinePosition; + //insert a new element into the scanline for the incoming vertex + property_map& countOnLeft = (*scanlinePosition).second; + std::pair element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } else { + property_map countOnLeft; + std::pair element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } + } + } else { + property_map countOnLeft; + std::pair element(currentVertex.first.y(), countOnLeft); + scanlinePosition = scanline.insert(scanlinePosition, element); + } + } + previousY = currentVertex.first.y(); + } + + template + inline int assertRedundant(T& t) { + if(t.empty()) return 0; + int count = 0; + typename T::iterator itr = t.begin(); + if((*itr).second.empty()) + ++count; + typename T::iterator itr2 = itr; + ++itr2; + while(itr2 != t.end()) { + if((*itr).second == (*itr2).second) + ++count; + itr = itr2; + ++itr2; + } + return count; + } + + template + inline void performExtract(T& result, property_merge_data& data) { + if(data.empty()) return; + //sort + std::sort(data.begin(), data.end(), less_vertex_data()); + + //scanline + bool firstIteration = true; + scanlinePosition = scanline.end(); + for(std::size_t i = 0; i < data.size(); ++i) { + if(firstIteration) { + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + firstIteration = false; + } else { + if(data[i].first != currentVertex.first) { + if(data[i].first.x() != currentVertex.first.x()) { + processVertex(output); + //std::cout << scanline.size() << " "; + countFromBelow.clear(); //should already be clear + writeGraph(currentVertex.first.x(), result, output, scanline); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } else { + processVertex(output); + currentVertex.second.clear(); + mergeProperty(currentVertex.second, data[i].second); + currentVertex.first = data[i].first; + } + } else { + mergeProperty(currentVertex.second, data[i].second); + } + } + } + processVertex(output); + writeGraph(currentVertex.first.x(), result, output, scanline); + //std::cout << scanline.size() << "\n"; + } + + template + inline void insertEdges(T& graph, property_set& p1, property_set& p2) { + for(typename property_set::iterator itr = p1.begin(); itr != p1.end(); ++itr) { + for(typename property_set::iterator itr2 = p2.begin(); itr2 != p2.end(); ++itr2) { + if(*itr != *itr2) { + graph[*itr].insert(*itr2); + graph[*itr2].insert(*itr); + } + } + } + } + + template + inline void propertySetAbove(coordinate_type y, property_set& ps, T& scanline) { + ps.clear(); + typename T::iterator itr = scanline.find(y); + if(itr != scanline.end()) + setProperty(ps, (*itr).second); + } + + template + inline void propertySetBelow(coordinate_type y, property_set& ps, T& scanline) { + ps.clear(); + typename T::iterator itr = scanline.find(y); + if(itr != scanline.begin()) { + --itr; + setProperty(ps, (*itr).second); + } + } + + template + inline void writeGraph(coordinate_type x, T& graph, edge_property_vector& output, T2& scanline) { + if(output.empty()) return; + edge_property* previousEdgeP = &(output[0]); + bool firstIteration = true; + property_set ps; + for(std::size_t i = 0; i < output.size(); ++i) { + edge_property& previousEdge = *previousEdgeP; + edge_property& edge = output[i]; + if(previousEdge.first.high() == edge.first.low()) { + //horizontal edge + insertEdges(graph, edge.second.first, previousEdge.second.first); + //corner 1 + insertEdges(graph, edge.second.first, previousEdge.second.second); + //other horizontal edge + insertEdges(graph, edge.second.second, previousEdge.second.second); + //corner 2 + insertEdges(graph, edge.second.second, previousEdge.second.first); + } else { + if(!firstIteration){ + //look up regions above previous edge + propertySetAbove(previousEdge.first.high(), ps, scanline); + insertEdges(graph, ps, previousEdge.second.first); + insertEdges(graph, ps, previousEdge.second.second); + } + //look up regions below current edge in the scanline + propertySetBelow(edge.first.high(), ps, scanline); + insertEdges(graph, ps, edge.second.first); + insertEdges(graph, ps, edge.second.second); + } + firstIteration = false; + //vertical edge + insertEdges(graph, edge.second.second, edge.second.first); + //shared region to left + insertEdges(graph, edge.second.second, edge.second.second); + //shared region to right + insertEdges(graph, edge.second.first, edge.second.first); + previousEdgeP = &(output[i]); + } + edge_property& previousEdge = *previousEdgeP; + propertySetAbove(previousEdge.first.high(), ps, scanline); + insertEdges(graph, ps, previousEdge.second.first); + insertEdges(graph, ps, previousEdge.second.second); + output.clear(); + } + + template + inline void writeOutput(coordinate_type x, Result& result, edge_property_vector& output) { + for(std::size_t i = 0; i < output.size(); ++i) { + edge_property& edge = output[i]; + //edge.second.first is the property set on the left of the edge + if(!edge.second.first.empty()) { + typename Result::iterator itr = result.find(edge.second.first); + if(itr == result.end()) { + std::pair element(edge.second.first, polygon_set_type(VERTICAL)); + itr = result.insert(result.end(), element); + } + std::pair, int> element2(interval_data(edge.first.low(), edge.first.high()), -1); //right edge of figure + (*itr).second.insert(x, element2); + } + if(!edge.second.second.empty()) { + //edge.second.second is the property set on the right of the edge + typename Result::iterator itr = result.find(edge.second.second); + if(itr == result.end()) { + std::pair element(edge.second.second, polygon_set_type(VERTICAL)); + itr = result.insert(result.end(), element); + } + std::pair, int> element3(interval_data(edge.first.low(), edge.first.high()), 1); //left edge of figure + (*itr).second.insert(x, element3); + } + } + output.clear(); + } +}; + +} +} +#endif diff --git a/include/boost/polygon/detail/property_merge_45.hpp b/include/boost/polygon/detail/property_merge_45.hpp new file mode 100644 index 0000000..e919486 --- /dev/null +++ b/include/boost/polygon/detail/property_merge_45.hpp @@ -0,0 +1,160 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_PROPERTY_MERGE_45_HPP +#define BOOST_POLYGON_PROPERTY_MERGE_45_HPP +namespace boost { namespace polygon{ + + template + struct polygon_45_property_merge { + + typedef point_data Point; + typedef typename coordinate_traits::manhattan_area_type LongUnit; + + template + static inline void merge_property_maps(property_map& mp, const property_map& mp2, bool subtract = false) { + polygon_45_touch::merge_property_maps(mp, mp2, subtract); + } + + class CountMerge { + public: + inline CountMerge() : counts() {} + //inline CountMerge(int count) { counts[0] = counts[1] = count; } + //inline CountMerge(int count1, int count2) { counts[0] = count1; counts[1] = count2; } + inline CountMerge(const CountMerge& count) : counts(count.counts) {} + inline bool operator==(const CountMerge& count) const { return counts == count.counts; } + inline bool operator!=(const CountMerge& count) const { return !((*this) == count); } + //inline CountMerge& operator=(int count) { counts[0] = counts[1] = count; return *this; } + inline CountMerge& operator=(const CountMerge& count) { counts = count.counts; return *this; } + inline int& operator[](property_type index) { + std::vector >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); + if(itr != counts.end() && itr->first == index) { + return itr->second; + } + itr = counts.insert(itr, std::make_pair(index, int(0))); + return itr->second; + } +// inline int operator[](int index) const { +// std::vector >::const_iterator itr = counts.begin(); +// for( ; itr != counts.end() && itr->first <= index; ++itr) { +// if(itr->first == index) { +// return itr->second; +// } +// } +// return 0; +// } + inline CountMerge& operator+=(const CountMerge& count){ + merge_property_maps(counts, count.counts, false); + return *this; + } + inline CountMerge& operator-=(const CountMerge& count){ + merge_property_maps(counts, count.counts, true); + return *this; + } + inline CountMerge operator+(const CountMerge& count) const { + return CountMerge(*this)+=count; + } + inline CountMerge operator-(const CountMerge& count) const { + return CountMerge(*this)-=count; + } + inline CountMerge invert() const { + CountMerge retval; + retval -= *this; + return retval; + } + std::vector > counts; + }; + + //output is a std::map, polygon_45_set_data > + struct merge_45_output_functor { + template + void operator()(cT& output, const CountMerge& count1, const CountMerge& count2, + const Point& pt, int rise, direction_1d end) { + typedef typename cT::key_type keytype; + keytype left; + keytype right; + int edgeType = end == LOW ? -1 : 1; + for(typename std::vector >::const_iterator itr = count1.counts.begin(); + itr != count1.counts.end(); ++itr) { + left.insert(left.end(), (*itr).first); + } + for(typename std::vector >::const_iterator itr = count2.counts.begin(); + itr != count2.counts.end(); ++itr) { + right.insert(right.end(), (*itr).first); + } + if(left == right) return; + if(!left.empty()) { + //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << edgeType << std::endl; + output[left].insert_clean(typename boolean_op_45::Vertex45(pt, rise, -edgeType)); + } + if(!right.empty()) { + //std::cout << pt.x() << " " << pt.y() << " " << rise << " " << -edgeType << std::endl; + output[right].insert_clean(typename boolean_op_45::Vertex45(pt, rise, edgeType)); + } + } + }; + + typedef typename std::pair::template Scan45CountT > Vertex45Compact; + typedef std::vector MergeSetData; + + struct lessVertex45Compact { + bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { + return l.first < r.first; + } + }; + + template + static void performMerge(output_type& result, MergeSetData& tsd) { + + std::sort(tsd.begin(), tsd.end(), lessVertex45Compact()); + typedef std::vector::template Scan45CountT > > TSD; + TSD tsd_; + tsd_.reserve(tsd.size()); + for(typename MergeSetData::iterator itr = tsd.begin(); itr != tsd.end(); ) { + typename MergeSetData::iterator itr2 = itr; + ++itr2; + for(; itr2 != tsd.end() && itr2->first == itr->first; ++itr2) { + (itr->second) += (itr2->second); //accumulate + } + tsd_.push_back(std::make_pair(itr->first, itr->second)); + itr = itr2; + } + typename boolean_op_45::template Scan45 scanline; + for(typename TSD::iterator itr = tsd_.begin(); itr != tsd_.end(); ) { + typename TSD::iterator itr2 = itr; + ++itr2; + while(itr2 != tsd_.end() && itr2->first.x() == itr->first.x()) { + ++itr2; + } + scanline.scan(result, itr, itr2); + itr = itr2; + } + } + + template + static void populateMergeSetData(MergeSetData& tsd, iT begin, iT end, property_type property) { + for( ; begin != end; ++begin) { + Vertex45Compact vertex; + vertex.first = typename Vertex45Compact::first_type(begin->pt.x() * 2, begin->pt.y() * 2); + tsd.push_back(vertex); + for(unsigned int i = 0; i < 4; ++i) { + if(begin->count[i]) { + tsd.back().second[i][property] += begin->count[i]; + } + } + } + } + + }; + + + +} +} + +#endif diff --git a/include/boost/polygon/detail/rectangle_formation.hpp b/include/boost/polygon/detail/rectangle_formation.hpp new file mode 100644 index 0000000..d0ae180 --- /dev/null +++ b/include/boost/polygon/detail/rectangle_formation.hpp @@ -0,0 +1,267 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_RECTANGLE_FORMATION_HPP +#define BOOST_POLYGON_RECTANGLE_FORMATION_HPP +namespace boost { namespace polygon{ + +namespace rectangle_formation { + template + class ScanLineToRects { + public: + typedef T rectangle_type; + typedef typename rectangle_traits::coordinate_type coordinate_type; + typedef rectangle_data scan_rect_type; + private: + + typedef std::set > ScanData; + ScanData scanData_; + bool haveCurrentRect_; + scan_rect_type currentRect_; + orientation_2d orient_; + typename rectangle_traits::coordinate_type currentCoordinate_; + public: + inline ScanLineToRects() : scanData_(), haveCurrentRect_(), currentRect_(), orient_(), currentCoordinate_() {} + + inline ScanLineToRects(orientation_2d orient, rectangle_type model) : + scanData_(orientation_2d(orient.to_int() ? VERTICAL : HORIZONTAL)), + haveCurrentRect_(false), currentRect_(), orient_(orient), currentCoordinate_() { + assign(currentRect_, model); + currentCoordinate_ = (std::numeric_limits::max)(); + } + + template + inline ScanLineToRects& processEdge(CT& rectangles, const interval_data& edge); + + inline ScanLineToRects& nextMajorCoordinate(coordinate_type currentCoordinate) { + if(haveCurrentRect_) { + scanData_.insert(scanData_.end(), currentRect_); + haveCurrentRect_ = false; + } + currentCoordinate_ = currentCoordinate; + return *this; + } + + }; + + template inline CT& + processEdge_(CT& rectangles, ST& scanData, const interval_type& edge, + bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient) + { + typedef typename CT::value_type result_type; + bool edgeProcessed = false; + if(!scanData.empty()) { + + //process all rectangles in the scanData that touch the edge + typename ST::iterator dataIter = scanData.lower_bound(rectangle_type(edge, edge)); + //decrement beginIter until its low is less than edge's low + while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) && + dataIter != scanData.begin()) + { + --dataIter; + } + //process each rectangle until the low end of the rectangle + //is greater than the high end of the edge + while(dataIter != scanData.end() && + (*dataIter).get(orient).get(LOW) <= edge.get(HIGH)) + { + const rectangle_type& rect = *dataIter; + //if the rectangle data intersects the edge at all + if(rect.get(orient).get(HIGH) >= edge.get(LOW)) { + if(contains(rect.get(orient), edge, true)) { + //this is a closing edge + //we need to write out the intersecting rectangle and + //insert between 0 and 2 rectangles into the scanData + //write out rectangle + rectangle_type tmpRect = rect; + + if(rect.get(orient.get_perpendicular()).get(LOW) < currentCoordinate) { + //set the high coordinate perpedicular to slicing orientation + //to the current coordinate of the scan event + tmpRect.set(orient.get_perpendicular().get_direction(HIGH), + currentCoordinate); + result_type result; + assign(result, tmpRect); + rectangles.insert(rectangles.end(), result); + } + //erase the rectangle from the scan data + typename ST::iterator nextIter = dataIter; + ++nextIter; + scanData.erase(dataIter); + if(tmpRect.get(orient).get(LOW) < edge.get(LOW)) { + //insert a rectangle for the overhang of the bottom + //of the rectangle back into scan data + rectangle_type lowRect(tmpRect); + lowRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, + currentCoordinate)); + lowRect.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(nextIter, lowRect); + } + if(tmpRect.get(orient).get(HIGH) > edge.get(HIGH)) { + //insert a rectangle for the overhang of the top + //of the rectangle back into scan data + rectangle_type highRect(tmpRect); + highRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, + currentCoordinate)); + highRect.set(orient.get_direction(LOW), edge.get(HIGH)); + scanData.insert(nextIter, highRect); + } + //we are done with this edge + edgeProcessed = true; + break; + } else { + //it must be an opening edge + //assert that rect does not overlap the edge but only touches + //write out rectangle + rectangle_type tmpRect = rect; + //set the high coordinate perpedicular to slicing orientation + //to the current coordinate of the scan event + if(tmpRect.get(orient.get_perpendicular().get_direction(LOW)) < currentCoordinate) { + tmpRect.set(orient.get_perpendicular().get_direction(HIGH), + currentCoordinate); + result_type result; + assign(result, tmpRect); + rectangles.insert(rectangles.end(), result); + } + //erase the rectangle from the scan data + typename ST::iterator nextIter = dataIter; + ++nextIter; + scanData.erase(dataIter); + dataIter = nextIter; + if(haveCurrentRect) { + if(currentRect.get(orient).get(HIGH) >= edge.get(LOW)){ + if(!edgeProcessed && currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ + rectangle_type tmpRect2(currentRect); + tmpRect2.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(nextIter, tmpRect2); + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { + currentRect.set(orient, interval_data(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH)))); + } else { + haveCurrentRect = false; + } + } else { + //extend the top of current rect + currentRect.set(orient.get_direction(HIGH), + (std::max)(edge.get(HIGH), + tmpRect.get(orient.get_direction(HIGH)))); + } + } else { + //insert current rect into the scanData + scanData.insert(nextIter, currentRect); + //create a new current rect + currentRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, + currentCoordinate)); + currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), + edge.get(LOW)), + (std::max)(tmpRect.get(orient).get(HIGH), + edge.get(HIGH)))); + } + } else { + haveCurrentRect = true; + currentRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, + currentCoordinate)); + currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), + edge.get(LOW)), + (std::max)(tmpRect.get(orient).get(HIGH), + edge.get(HIGH)))); + } + //skip to nextIter position + edgeProcessed = true; + continue; + } + //edgeProcessed = true; + } + ++dataIter; + } //end while edge intersects rectangle data + + } + if(!edgeProcessed) { + if(haveCurrentRect) { + if(currentRect.get(orient.get_perpendicular().get_direction(HIGH)) + == currentCoordinate && + currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW)) + { + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ + rectangle_type tmpRect(currentRect); + tmpRect.set(orient.get_direction(HIGH), edge.get(LOW)); + scanData.insert(scanData.end(), tmpRect); + if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { + currentRect.set(orient, + interval_data(edge.get(HIGH), + currentRect.get(orient.get_direction(HIGH)))); + return rectangles; + } else { + haveCurrentRect = false; + return rectangles; + } + } + //extend current rect + currentRect.set(orient.get_direction(HIGH), edge.get(HIGH)); + return rectangles; + } + scanData.insert(scanData.end(), currentRect); + haveCurrentRect = false; + } + rectangle_type tmpRect(currentRect); + tmpRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, + currentCoordinate)); + tmpRect.set(orient, edge); + scanData.insert(tmpRect); + return rectangles; + } + return rectangles; + + } + + template + template + inline + ScanLineToRects& ScanLineToRects::processEdge(CT& rectangles, const interval_data& edge) + { + processEdge_(rectangles, scanData_, edge, haveCurrentRect_, currentRect_, currentCoordinate_, orient_); + return *this; + } + + +} //namespace rectangle_formation + + template + struct get_coordinate_type_for_rectangles { + typedef typename polygon_traits::coordinate_type type; + }; + template + struct get_coordinate_type_for_rectangles { + typedef typename rectangle_traits::coordinate_type type; + }; + + template + void form_rectangles(output_container& output, iterator_type begin, iterator_type end, + orientation_2d orient, rectangle_concept ) { + typedef typename output_container::value_type rectangle_type; + typedef typename get_coordinate_type_for_rectangles::type>::type Unit; + rectangle_data model; + Unit prevPos = (std::numeric_limits::max)(); + rectangle_formation::ScanLineToRects > scanlineToRects(orient, model); + for(iterator_type itr = begin; + itr != end; ++ itr) { + Unit pos = (*itr).first; + if(pos != prevPos) { + scanlineToRects.nextMajorCoordinate(pos); + prevPos = pos; + } + Unit lowy = (*itr).second.first; + iterator_type tmp_itr = itr; + ++itr; + Unit highy = (*itr).second.first; + scanlineToRects.processEdge(output, interval_data(lowy, highy)); + if(abs((*itr).second.second) > 1) itr = tmp_itr; //next edge begins from this vertex + } + } +} +} +#endif + diff --git a/include/boost/polygon/detail/scan_arbitrary.hpp b/include/boost/polygon/detail/scan_arbitrary.hpp new file mode 100644 index 0000000..7b0ecda --- /dev/null +++ b/include/boost/polygon/detail/scan_arbitrary.hpp @@ -0,0 +1,2852 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_SCAN_ARBITRARY_HPP +#define BOOST_POLYGON_SCAN_ARBITRARY_HPP +#ifdef BOOST_POLYGON_DEBUG_FILE +#include +#endif +namespace boost { namespace polygon{ + + template + class line_intersection : public scanline_base { + private: + typedef typename scanline_base::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair half_edge; + typedef typename scanline_base::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base::less_half_edge less_half_edge; + typedef typename scanline_base::less_point less_point; + + //when parallel half edges are encounterd the set of segments is expanded + //when a edge leaves the scanline it is removed from the set + //when the set is empty the element is removed from the map + typedef int segment_id; + typedef std::pair > scanline_element; + typedef std::map, less_half_edge> edge_scanline; + typedef typename edge_scanline::iterator iterator; + +// std::map > vertical_data_; +// edge_scanline edge_scanline_; +// Unit x_; +// int just_before_; +// segment_id segment_id_; +// std::vector > event_edges_; +// std::set intersection_queue_; + public: +// inline line_intersection() : vertical_data_(), edge_scanline_(), x_((std::numeric_limits::max)()), just_before_(0), segment_id_(0), event_edges_(), intersection_queue_() { +// less_half_edge lessElm(&x_, &just_before_); +// edge_scanline_ = edge_scanline(lessElm); +// } +// inline line_intersection(const line_intersection& that) : vertical_data_(), edge_scanline_(), x_(), just_before_(), segment_id_(), event_edges_(), intersection_queue_() { (*this) = that; } +// inline line_intersection& operator=(const line_intersection& that) { +// x_ = that.x_; +// just_before_ = that.just_before_; +// segment_id_ = that.segment_id_; + +// //I cannot simply copy that.edge_scanline_ to this edge_scanline_ becuase the functor store pointers to other members! +// less_half_edge lessElm(&x_, &just_before_); +// edge_scanline_ = edge_scanline(lessElm); + +// edge_scanline_.insert(that.edge_scanline_.begin(), that.edge_scanline_.end()); +// return *this; +// } + +// static inline void between(Point pt, Point pt1, Point pt2) { +// less_point lp; +// if(lp(pt1, pt2)) +// return lp(pt, pt2) && lp(pt1, pt); +// return lp(pt, pt1) && lp(pt2, pt); +// } + + template + static inline void compute_histogram_in_y(iT begin, iT end, std::size_t size, std::vector > >& histogram) { + std::vector > ends; + ends.reserve(size * 2); + for(iT itr = begin ; itr != end; ++itr) { + int count = (*itr).first.first.y() < (*itr).first.second.y() ? 1 : -1; + ends.push_back(std::make_pair((*itr).first.first.y(), count)); + ends.push_back(std::make_pair((*itr).first.second.y(), -count)); + } + std::sort(ends.begin(), ends.end()); + histogram.reserve(ends.size()); + histogram.push_back(std::make_pair(ends.front().first, std::make_pair(0, 0))); + for(typename std::vector >::iterator itr = ends.begin(); itr != ends.end(); ++itr) { + if((*itr).first != histogram.back().first) { + histogram.push_back(std::make_pair((*itr).first, histogram.back().second)); + } + if((*itr).second < 0) + histogram.back().second.second -= (*itr).second; + histogram.back().second.first += (*itr).second; + } + } + + template + static inline void compute_y_cuts(std::vector& y_cuts, iT begin, iT end, std::size_t size) { + if(begin == end) return; + if(size < 30) return; //30 is empirically chosen, but the algorithm is not sensitive to this constant + std::size_t min_cut = size; + iT cut = begin; + std::size_t position = 0; + std::size_t cut_size = 0; + std::size_t histogram_size = std::distance(begin, end); + for(iT itr = begin; itr != end; ++itr, ++position) { + if(position < histogram_size / 3) + continue; + if(histogram_size - position < histogram_size / 3) break; + if((*itr).second.first < min_cut) { + cut = itr; + min_cut = (*cut).second.first; + cut_size = position; + } + } + if(cut_size == 0 || (*cut).second.first > size / 9) //nine is empirically chosen + return; + compute_y_cuts(y_cuts, begin, cut, (*cut).second.first + (*cut).second.second); + y_cuts.push_back((*cut).first); + compute_y_cuts(y_cuts, cut, end, size - (*cut).second.second); + } + + template + static inline void validate_scan_divide_and_conquer(std::vector >& intersection_points, + iT begin, iT end) { + std::vector > > histogram; + compute_histogram_in_y(begin, end, std::distance(begin, end), histogram); + std::vector y_cuts; + compute_y_cuts(y_cuts, histogram.begin(), histogram.end(), std::distance(begin, end)); + std::map > > bins; + bins[histogram.front().first] = std::vector >(); + for(typename std::vector::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { + bins[*itr] = std::vector >(); + } + for(iT itr = begin; itr != end; ++itr) { + typename std::map > >::iterator lb = + bins.lower_bound((std::min)((*itr).first.first.y(), (*itr).first.second.y())); + if(lb != bins.begin()) + --lb; + typename std::map > >::iterator ub = + bins.upper_bound((std::max)((*itr).first.first.y(), (*itr).first.second.y())); + for( ; lb != ub; ++lb) { + (*lb).second.push_back(*itr); + } + } + validate_scan(intersection_points, bins[histogram.front().first].begin(), bins[histogram.front().first].end()); + for(typename std::vector::iterator itr = y_cuts.begin(); itr != y_cuts.end(); ++itr) { + validate_scan(intersection_points, bins[*itr].begin(), bins[*itr].end(), *itr); + } + } + + template + static inline void validate_scan(std::vector >& intersection_points, + iT begin, iT end) { + validate_scan(intersection_points, begin, end, (std::numeric_limits::min)()); + } + //quadratic algorithm to do same work as optimal scan for cross checking + template + static inline void validate_scan(std::vector >& intersection_points, + iT begin, iT end, Unit min_y) { + std::vector pts; + std::vector > data(begin, end); + for(std::size_t i = 0; i < data.size(); ++i) { + if(data[i].first.second < data[i].first.first) { + std::swap(data[i].first.first, data[i].first.second); + } + } + typename scanline_base::compute_intersection_pack pack_; + std::sort(data.begin(), data.end()); + //find all intersection points + for(typename std::vector >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + //its own end points + pts.push_back(he1.first); + pts.push_back(he1.second); + std::set& segmentpts = intersection_points[(*outer).second]; + for(typename std::set::iterator itr = segmentpts.begin(); itr != segmentpts.end(); ++itr) { + if((*itr).y() > min_y - 1) + pts.push_back(*itr); + } + bool have_first_y = he1.first.y() >= min_y && he1.second.y() >= min_y; + for(typename std::vector >::iterator inner = outer; + inner != data.end(); ++inner) { + const half_edge& he2 = (*inner).first; + if(have_first_y || (he2.first.y() >= min_y && he2.second.y() >= min_y)) { + //at least one segment has a low y value within the range + if(he1 == he2) continue; + if((std::min)(he2. first.get(HORIZONTAL), + he2.second.get(HORIZONTAL)) >= + (std::max)(he1.second.get(HORIZONTAL), + he1.first.get(HORIZONTAL))) + break; + if(he1.first == he2.first || he1.second == he2.second) + continue; + Point intersection; + if(pack_.compute_intersection(intersection, he1, he2)) { + //their intersection point + pts.push_back(intersection); + } + } + } + } + std::sort(pts.begin(), pts.end()); + typename std::vector::iterator newend = std::unique(pts.begin(), pts.end()); + typename std::vector::iterator lfinger = pts.begin(); + //find all segments that interact with intersection points + for(typename std::vector >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + segment_id id1 = (*outer).second; + typedef rectangle_data Rectangle; + //Rectangle rect1; + //set_points(rect1, he1.first, he1.second); + //typename std::vector::iterator itr = lower_bound(pts.begin(), newend, (std::min)(he1.first, he1.second)); + //typename std::vector::iterator itr2 = upper_bound(pts.begin(), newend, (std::max)(he1.first, he1.second)); + Point startpt = (std::min)(he1.first, he1.second); + Point stoppt = (std::max)(he1.first, he1.second); + //while(itr != newend && itr != pts.begin() && (*itr).get(HORIZONTAL) >= (std::min)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) --itr; + //while(itr2 != newend && (*itr2).get(HORIZONTAL) <= (std::max)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) ++itr2; + //itr = pts.begin(); + //itr2 = pts.end(); + while(lfinger != newend && (*lfinger).x() < startpt.x()) ++lfinger; + for(typename std::vector::iterator itr = lfinger ; itr != newend && (*itr).x() <= stoppt.x(); ++itr) { + if(scanline_base::intersects_grid(*itr, he1)) + intersection_points[id1].insert(*itr); + } + } + } + + template + static inline void validate_scan(std::vector > >& output_segments, + iT begin, iT end) { + std::vector > input_properties; + std::vector > input_segments, intermediate_segments; + int index = 0; + for( ; begin != end; ++begin) { + input_properties.push_back((*begin).second); + input_segments.push_back(std::make_pair((*begin).first, index++)); + } + validate_scan(intermediate_segments, input_segments.begin(), input_segments.end()); + for(std::size_t i = 0; i < intermediate_segments.size(); ++i) { + output_segments.push_back(std::make_pair(intermediate_segments[i].first, + input_properties[intermediate_segments[i].second])); + less_point lp; + if(lp(output_segments.back().first.first, output_segments.back().first.second) != + lp(input_segments[intermediate_segments[i].second].first.first, + input_segments[intermediate_segments[i].second].first.second)) { + //edge changed orientation, invert count on edge + output_segments.back().second.second *= -1; + } + if(!scanline_base::is_vertical(input_segments[intermediate_segments[i].second].first) && + scanline_base::is_vertical(output_segments.back().first)) { + output_segments.back().second.second *= -1; + } + if(lp(output_segments.back().first.second, output_segments.back().first.first)) { + std::swap(output_segments.back().first.first, output_segments.back().first.second); + } + } + } + + template + static inline void validate_scan(std::vector >& output_segments, + iT begin, iT end) { + std::vector > intersection_points(std::distance(begin, end)); + validate_scan_divide_and_conquer(intersection_points, begin, end); + //validate_scan(intersection_points, begin, end); + segment_intersections(output_segments, intersection_points, begin, end); +// std::pair offenders; +// if(!verify_scan(offenders, output_segments.begin(), output_segments.end())) { +// std::cout << "break here!\n"; +// for(typename std::set::iterator itr = intersection_points[offenders.first].begin(); +// itr != intersection_points[offenders.first].end(); ++itr) { +// std::cout << (*itr).x() << " " << (*itr).y() << " "; +// } std::cout << std::endl; +// for(typename std::set::iterator itr = intersection_points[offenders.second].begin(); +// itr != intersection_points[offenders.second].end(); ++itr) { +// std::cout << (*itr).x() << " " << (*itr).y() << " "; +// } std::cout << std::endl; +// exit(1); +// } + } + + //quadratic algorithm to find intersections + template + static inline bool verify_scan(std::pair& offenders, + iT begin, iT end) { + + std::vector > data(begin, end); + for(std::size_t i = 0; i < data.size(); ++i) { + if(data[i].first.second < data[i].first.first) { + std::swap(data[i].first.first, data[i].first.second); + } + } + std::sort(data.begin(), data.end()); + for(typename std::vector >::iterator outer = data.begin(); + outer != data.end(); ++outer) { + const half_edge& he1 = (*outer).first; + segment_id id1 = (*outer).second; + for(typename std::vector >::iterator inner = outer; + inner != data.end(); ++inner) { + const half_edge& he2 = (*inner).first; + if(he1 == he2) continue; + if((std::min)(he2. first.get(HORIZONTAL), + he2.second.get(HORIZONTAL)) > + (std::max)(he1.second.get(HORIZONTAL), + he1.first.get(HORIZONTAL))) + break; + segment_id id2 = (*inner).second; + if(scanline_base::intersects(he1, he2)) { + offenders.first = id1; + offenders.second = id2; + //std::cout << he1.first.x() << " " << he1.first.y() << " " << he1.second.x() << " " << he1.second.y() << " " << he2.first.x() << " " << he2.first.y() << " " << he2.second.x() << " " << he2.second.y() << std::endl; + return false; + } + } + } + return true; + } + + class less_point_down_slope : public std::binary_function { + public: + inline less_point_down_slope() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) > pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + template + static inline void segment_edge(std::vector >& output_segments, + const half_edge& , segment_id id, iT begin, iT end) { + iT current = begin; + iT next = begin; + ++next; + while(next != end) { + output_segments.push_back(std::make_pair(half_edge(*current, *next), id)); + current = next; + ++next; + } + } + + template + static inline void segment_intersections(std::vector >& output_segments, + std::vector >& intersection_points, + iT begin, iT end) { + for(iT iter = begin; iter != end; ++iter) { + //less_point lp; + const half_edge& he = (*iter).first; + //if(lp(he.first, he.second)) { + // //it is the begin event + segment_id id = (*iter).second; + const std::set& pts = intersection_points[id]; + Point hpt(he.first.get(HORIZONTAL)+1, he.first.get(VERTICAL)); + if(!scanline_base::is_vertical(he) && scanline_base::less_slope(he.first.get(HORIZONTAL), he.first.get(VERTICAL), + he.second, hpt)) { + //slope is below horizontal + std::vector tmpPts; + tmpPts.reserve(pts.size()); + tmpPts.insert(tmpPts.end(), pts.begin(), pts.end()); + less_point_down_slope lpds; + std::sort(tmpPts.begin(), tmpPts.end(), lpds); + segment_edge(output_segments, he, id, tmpPts.begin(), tmpPts.end()); + } else { + segment_edge(output_segments, he, id, pts.begin(), pts.end()); + } + //} + } + } + +// //iT iterator over unsorted pair representing line segments of input +// //output_segments is populated with fully intersected output line segment half +// //edges and the index of the input segment that they are assoicated with +// //duplicate output half edges with different ids will be generated in the case +// //that parallel input segments intersection +// //outputs are in sorted order and include both begin and end events for +// //each segment +// template +// inline void scan(std::vector >& output_segments, +// iT begin, iT end) { +// std::map > intersection_points; +// scan(intersection_points, begin, end); +// segment_intersections(output_segments, intersection_points, begin, end); +// } + +// //iT iterator over sorted sequence of half edge, segment id pairs representing segment begin and end points +// //intersection points provides a mapping from input segment id (vector index) to the set +// //of intersection points assocated with that input segment +// template +// inline void scan(std::map >& intersection_points, +// iT begin, iT end) { +// for(iT iter = begin; iter != end; ++iter) { +// const std::pair& elem = *iter; +// const half_edge& he = elem.first; +// Unit current_x = he.first.get(HORIZONTAL); +// if(current_x != x_) { +// process_scan_event(intersection_points); +// while(!intersection_queue_.empty() && +// (*(intersection_queue_.begin()).get(HORIZONTAL) < current_x)) { +// x_ = *(intersection_queue_.begin()).get(HORIZONTAL); +// process_intersections_at_scan_event(intersection_points); +// } +// x_ = current_x; +// } +// event_edges_.push_back(elem); +// } +// process_scan_event(intersection_points); +// } + +// inline iterator lookup(const half_edge& he) { +// return edge_scanline_.find(he); +// } + +// inline void insert_into_scanline(const half_edge& he, int id) { +// edge_scanline_[he].insert(id); +// } + +// inline void lookup_and_remove(const half_edge& he, int id) { +// iterator remove_iter = lookup(he); +// if(remove_iter == edge_scanline_.end()) { +// //std::cout << "failed to find removal segment in scanline\n"; +// return; +// } +// std::set& ids = (*remove_iter).second; +// std::set::iterator id_iter = ids.find(id); +// if(id_iter == ids.end()) { +// //std::cout << "failed to find removal segment id in scanline set\n"; +// return; +// } +// ids.erase(id_iter); +// if(ids.empty()) +// edge_scanline_.erase(remove_iter); +// } + +// static inline void update_segments(std::map >& intersection_points, +// const std::set& segments, Point pt) { +// for(std::set::const_iterator itr = segments.begin(); itr != segments.end(); ++itr) { +// intersection_points[*itr].insert(pt); +// } +// } + +// inline void process_intersections_at_scan_event(std::map >& intersection_points) { +// //there may be additional intersection points at this x location that haven't been +// //found yet if vertical or near vertical line segments intersect more than +// //once before the next x location +// just_before_ = true; +// std::set intersecting_elements; +// std::set intersection_locations; +// typedef typename std::set::iterator intersection_iterator; +// intersection_iterator iter; +// //first find all secondary intersection locations and all scanline iterators +// //that are intersecting +// for(iter = intersection_queue_.begin(); +// iter != intersection_queue_.end() && (*iter).get(HORIZONTAL) == x_; ++iter) { +// Point pt = *iter; +// Unit y = pt.get(VERTICAL); +// intersection_locations.insert(y); +// //if x_ is max there can be only end events and no sloping edges +// if(x_ != (std::numeric_limits::max)()) { +// //deal with edges that project to the right of scanline +// //first find the edges in the scanline adjacent to primary intersectin points +// //lookup segment in scanline at pt +// iterator itr = edge_scanline_.lower_bound(half_edge(pt, Point(x_+1, y))); +// //look above pt in scanline until reaching end or segment that doesn't intersect +// //1x1 grid upper right of pt +// //look below pt in scanline until reaching begin or segment that doesn't interset +// //1x1 grid upper right of pt + +// //second find edges in scanline on the y interval of each edge found in the previous +// //step for x_ to x_ + 1 + +// //third find overlaps in the y intervals of all found edges to find all +// //secondary intersection points + +// } +// } +// //erase the intersection points from the queue +// intersection_queue_.erase(intersection_queue_.begin(), iter); +// std::vector insertion_edges; +// insertion_edges.reserve(intersecting_elements.size()); +// std::vector > sloping_ends; +// //do all the work of updating the output of all intersecting +// for(typename std::set::iterator inter_iter = intersecting_elements.begin(); +// inter_iter != intersecting_elements.end(); ++inter_iter) { +// //if it is horizontal update it now and continue +// if(is_horizontal((*inter_iter).first)) { +// update_segments(intersection_points, (*inter_iter).second, Point(x_, (*inter_iter).first.get(VERTICAL))); +// } else { +// //if x_ is max there can be only end events and no sloping edges +// if(x_ != (std::numeric_limits::max)()) { +// //insert its end points into the vector of sloping ends +// const half_edge& he = (*inter_iter).first; +// Unit y = evalAtXforY(x_, he.first, he.second); +// Unit y2 = evalAtXforY(x_+1, he.first, he.second); +// if(y2 >= y) y2 +=1; //we round up, in exact case we don't worry about overbite of one +// else y += 1; //downward sloping round up +// sloping_ends.push_back(std::make_pair(y, inter_iter)); +// sloping_ends.push_back(std::make_pair(y2, inter_iter)); +// } +// } +// } + +// //merge sloping element data +// std::sort(sloping_ends.begin(), sloping_ends.end()); +// std::map > sloping_elements; +// std::set merge_elements; +// for(typename std::vector >::iterator slop_iter = sloping_ends.begin(); +// slop_iter == sloping_ends.end(); ++slop_iter) { +// //merge into sloping elements +// typename std::set::iterator merge_iterator = merge_elements.find((*slop_iter).second); +// if(merge_iterator == merge_elements.end()) { +// merge_elements.insert((*slop_iter).second); +// } else { +// merge_elements.erase(merge_iterator); +// } +// sloping_elements[(*slop_iter).first] = merge_elements; +// } + +// //scan intersection points +// typename std::map >::iterator vertical_iter = vertical_data_.begin(); +// typename std::map >::iterator sloping_iter = sloping_elements.begin(); +// for(typename std::set::iterator position_iter = intersection_locations.begin(); +// position_iter == intersection_locations.end(); ++position_iter) { +// //look for vertical segments that intersect this point and update them +// Unit y = *position_iter; +// Point pt(x_, y); +// //handle vertical segments +// if(vertical_iter != vertical_data_.end()) { +// typename std::map >::iterator next_vertical = vertical_iter; +// for(++next_vertical; next_vertical != vertical_data_.end() && +// (*next_vertical).first < y; ++next_vertical) { +// vertical_iter = next_vertical; +// } +// if((*vertical_iter).first < y && !(*vertical_iter).second.empty()) { +// update_segments(intersection_points, (*vertical_iter).second, pt); +// ++vertical_iter; +// if(vertical_iter != vertical_data_.end() && (*vertical_iter).first == y) +// update_segments(intersection_points, (*vertical_iter).second, pt); +// } +// } +// //handle sloping segments +// if(sloping_iter != sloping_elements.end()) { +// typename std::map >::iterator next_sloping = sloping_iter; +// for(++next_sloping; next_sloping != sloping_elements.end() && +// (*next_sloping).first < y; ++next_sloping) { +// sloping_iter = next_sloping; +// } +// if((*sloping_iter).first < y && !(*sloping_iter).second.empty()) { +// for(typename std::set::iterator element_iter = (*sloping_iter).second.begin(); +// element_iter != (*sloping_iter).second.end(); ++element_iter) { +// const half_edge& he = (*element_iter).first; +// if(intersects_grid(pt, he)) { +// update_segments(intersection_points, (*element_iter).second, pt); +// } +// } +// ++sloping_iter; +// if(sloping_iter != sloping_elements.end() && (*sloping_iter).first == y && +// !(*sloping_iter).second.empty()) { +// for(typename std::set::iterator element_iter = (*sloping_iter).second.begin(); +// element_iter != (*sloping_iter).second.end(); ++element_iter) { +// const half_edge& he = (*element_iter).first; +// if(intersects_grid(pt, he)) { +// update_segments(intersection_points, (*element_iter).second, pt); +// } +// } +// } +// } +// } +// } + +// //erase and reinsert edges into scanline with check for future intersection +// } + +// inline void process_scan_event(std::map >& intersection_points) { +// just_before_ = true; + +// //process end events by removing those segments from the scanline +// //and insert vertices of all events into intersection queue +// Point prev_point((std::numeric_limits::min)(), (std::numeric_limits::min)()); +// less_point lp; +// std::set vertical_ids; +// vertical_data_.clear(); +// for(std::size_t i = 0; i < event_edges_.size(); ++i) { +// segment_id id = event_edges_[i].second; +// const half_edge& he = event_edges_[i].first; +// //vertical half edges are handled during intersection processing because +// //they cannot be inserted into the scanline +// if(!is_vertical(he)) { +// if(lp(he.second, he.first)) { +// //half edge is end event +// lookup_and_remove(he, id); +// } else { +// //half edge is begin event +// insert_into_scanline(he, id); +// //note that they will be immediately removed and reinserted after +// //handling their intersection (vertex) +// //an optimization would allow them to be processed specially to avoid the redundant +// //removal and reinsertion +// } +// } else { +// //common case if you are lucky +// //update the map of y to set of segment id +// if(lp(he.second, he.first)) { +// //half edge is end event +// std::set::iterator itr = vertical_ids.find(id); +// if(itr == vertical_ids.end()) { +// //std::cout << "Failed to find end event id in vertical ids\n"; +// } else { +// vertical_ids.erase(itr); +// vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; +// } +// } else { +// //half edge is a begin event +// vertical_ids.insert(id); +// vertical_data_[he.first.get(HORIZONTAL)] = vertical_ids; +// } +// } +// //prevent repeated insertion of same vertex into intersection queue +// if(prev_point != he.first) +// intersection_queue_.insert(he.first); +// else +// prev_point = he.first; +// // process intersections at scan event +// process_intersections_at_scan_event(intersection_points); +// } +// event_edges_.clear(); +// } + + public: + template + static inline bool test_validate_scan(stream_type& stdcout) { + std::vector > input, edges; + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); + std::pair result; + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail1 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail3 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + input.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 " << result.first << " " << result.second << "\n"; + return false; + } + input.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), input.size())); + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail6 " << result.first << " " << result.second << "\n"; + return false; + } + input.pop_back(); + for(std::size_t i = 0; i < input.size(); ++i) { + std::swap(input[i].first.first, input[i].first.second); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 2 " << result.first << " " << result.second << "\n"; + return false; + } + for(std::size_t i = 0; i < input.size(); ++i) { + input[i].first.first = Point(input[i].first.first.get(HORIZONTAL) * -1, + input[i].first.first.get(VERTICAL) * -1); + input[i].first.second = Point(input[i].first.second.get(HORIZONTAL) * -1, + input[i].first.second.get(VERTICAL) * -1); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + stdcout << edges.size() << std::endl; + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail5 3 " << result.first << " " << result.second << "\n"; + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(5, 7), Point(7, 6)), 0)); + input.push_back(std::make_pair(half_edge(Point(2, 4), Point(6, 7)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 1 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(3, 2), Point(1, 7)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 6), Point(7, 4)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 2 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(6, 6), Point(1, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(3, 6), Point(2, 3)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 3 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(7, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(6, 0), Point(2, 0)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 4 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-17333131 - -17208131, -10316869 - -10191869), Point(0, 0)), 0)); + input.push_back(std::make_pair(half_edge(Point(-17291260 - -17208131, -10200000 - -10191869), Point(-17075000 - -17208131, -10200000 - -10191869)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-17333131, -10316869), Point(-17208131, -10191869)), 0)); + input.push_back(std::make_pair(half_edge(Point(-17291260, -10200000), Point(-17075000, -10200000)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 6 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-9850009+9853379, -286971+290340), Point(-12777869+9853379, -3214831+290340)), 0)); + input.push_back(std::make_pair(half_edge(Point(-5223510+9853379, -290340+290340), Point(-9858140+9853379, -290340+290340)), 1)); + validate_scan(edges, input.begin(), input.end()); + print(edges); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 7 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(-9850009, -286971), Point(-12777869, -3214831)), 0)); + input.push_back(std::make_pair(half_edge(Point(-5223510, -290340), Point(-9858140, -290340)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 8 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //3 3 2 2: 0; 4 2 0 6: 1; 0 3 6 3: 2; 4 1 5 5: 3; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(3, 3), Point(2, 2)), 0)); + input.push_back(std::make_pair(half_edge(Point(4, 2), Point(0, 6)), 1)); + input.push_back(std::make_pair(half_edge(Point(0, 3), Point(6, 3)), 2)); + input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 5)), 3)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 1 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //5 7 1 3: 0; 4 5 2 1: 1; 2 5 2 1: 2; 4 1 5 3: 3; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(5, 7), Point(1, 3)), 0)); + input.push_back(std::make_pair(half_edge(Point(4, 5), Point(2, 1)), 1)); + input.push_back(std::make_pair(half_edge(Point(2, 5), Point(2, 1)), 2)); + input.push_back(std::make_pair(half_edge(Point(4, 1), Point(5, 3)), 3)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail4 2 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + //1 0 -4 -1: 0; 0 0 2 -1: 1; + input.clear(); + edges.clear(); + input.push_back(std::make_pair(half_edge(Point(1, 0), Point(-4, -1)), 0)); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(2, -1)), 1)); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail2 5 " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + Unit min_c =0; + Unit max_c =0; + for(unsigned int outer = 0; outer < 1000; ++outer) { + input.clear(); + for(unsigned int i = 0; i < 4; ++i) { + Unit x1 = rand(); + Unit x2 = rand(); + Unit y1 = rand(); + Unit y2 = rand(); + int neg1 = rand() % 2; + if(neg1) x1 *= -1; + int neg2 = rand() % 2; + if(neg2) x2 *= -1; + int neg3 = rand() % 2; + if(neg3) y1 *= -1; + int neg4 = rand() % 2; + if(neg4) y2 *= -1; + if(x1 < min_c) min_c = x1; + if(x2 < min_c) min_c = x2; + if(y1 < min_c) min_c = y1; + if(y2 < min_c) min_c = y2; + if(x1 > max_c) max_c = x1; + if(x2 > max_c) max_c = x2; + if(y1 > max_c) max_c = y1; + if(y2 > max_c) max_c = y2; + Point pt1(x1, y1); + Point pt2(x2, y2); + if(pt1 != pt2) + input.push_back(std::make_pair(half_edge(pt1, pt2), i)); + } + edges.clear(); + validate_scan(edges, input.begin(), input.end()); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "s fail9 " << outer << ": " << result.first << " " << result.second << "\n"; + print(input); + print(edges); + return false; + } + } + return true; + } + + //static void print(const std::pair& segment) { + //std::cout << segment.first.first << " " << segment.first.second << ": " << segment.second << "; "; + //} + static void print(const std::vector >& vec) { + for(std::size_t i = 0; i < vec.size(); ++ i) { + // print(vec[i]); + } + //std::cout << std::endl; + } + + template + static inline bool test_verify_scan(stream_type& stdcout) { + std::vector > edges; + edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), 0)); + edges.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 10)), 1)); + std::pair result; + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail1\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(5, 5)), 2)); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail2\n"; + return false; + } + edges.pop_back(); + edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(11, 11)), (segment_id)edges.size())); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail3\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(1, 0), Point(10, 11)), (segment_id)edges.size())); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail4\n"; + return false; + } + edges.pop_back(); + edges.push_back(std::make_pair(half_edge(Point(1, 2), Point(11, 11)), (segment_id)edges.size())); + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 " << result.first << " " << result.second << "\n"; + return false; + } + edges.push_back(std::make_pair(half_edge(Point(0, 5), Point(0, 11)), (segment_id)edges.size())); + if(verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail6 " << result.first << " " << result.second << "\n"; + return false; + } + edges.pop_back(); + for(std::size_t i = 0; i < edges.size(); ++i) { + std::swap(edges[i].first.first, edges[i].first.second); + } + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 2 " << result.first << " " << result.second << "\n"; + return false; + } + for(std::size_t i = 0; i < edges.size(); ++i) { + edges[i].first.first = Point(edges[i].first.first.get(HORIZONTAL) * -1, + edges[i].first.first.get(VERTICAL) * -1); + edges[i].first.second = Point(edges[i].first.second.get(HORIZONTAL) * -1, + edges[i].first.second.get(VERTICAL) * -1); + } + if(!verify_scan(result, edges.begin(), edges.end())) { + stdcout << "fail5 3 " << result.first << " " << result.second << "\n"; + return false; + } + return true; + } + + }; + + //scanline consumes the "flattened" fully intersected line segments produced by + //a pass of line_intersection along with property and count information and performs a + //useful operation like booleans or property merge or connectivity extraction + template > + class scanline : public scanline_base { + public: + //definitions + typedef typename scanline_base::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair half_edge; + typedef typename scanline_base::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base::less_half_edge less_half_edge; + typedef typename scanline_base::less_point less_point; + + typedef keytype property_set; + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector > property_map; + //this data structure assocates a property and count to a half edge + typedef std::pair > vertex_property; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair vertex_data; + //this data type stores the combination of many half edges + typedef std::vector property_merge_data; + //this data structure stores end points of edges in the scanline + typedef std::set end_point_queue; + + //this is the output data type that is created by the scanline before it is post processed based on content of property sets + typedef std::pair > half_edge_property; + + //this is the scanline data structure + typedef std::map scanline_type; + typedef std::pair scanline_element; + typedef typename scanline_type::iterator iterator; + typedef typename scanline_type::const_iterator const_iterator; + + //data + scanline_type scan_data_; + std::vector removal_set_; //edges to be removed at the current scanline stop + std::vector insertion_set_; //edge to be inserted after current scanline stop + end_point_queue end_point_queue_; + Unit x_; + Unit y_; + int just_before_; + typename scanline_base::evalAtXforYPack evalAtXforYPack_; + public: + inline scanline() : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + x_((std::numeric_limits::max)()), y_((std::numeric_limits::max)()), just_before_(false), evalAtXforYPack_() { + less_half_edge lessElm(&x_, &just_before_, &evalAtXforYPack_); + scan_data_ = scanline_type(lessElm); + } + inline scanline(const scanline& that) : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + x_((std::numeric_limits::max)()), y_((std::numeric_limits::max)()), just_before_(false), evalAtXforYPack_() { + (*this) = that; } + inline scanline& operator=(const scanline& that) { + x_ = that.x_; + y_ = that.y_; + just_before_ = that.just_before_; + end_point_queue_ = that.end_point_queue_; + //I cannot simply copy that.scanline_type to this scanline_type becuase the functor store pointers to other members! + less_half_edge lessElm(&x_, &just_before_); + scan_data_ = scanline_type(lessElm); + + scan_data_.insert(that.scan_data_.begin(), that.scan_data_.end()); + return *this; + } + + template + void write_out(result_type& result, result_functor rf, const half_edge& he, + const property_map& pm_left, const property_map& pm_right) { + //std::cout << "write out "; + //std::cout << he.first << ", " << he.second << std::endl; + property_set ps_left, ps_right; + set_unique_property(ps_left, pm_left); + set_unique_property(ps_right, pm_right); + if(ps_left != ps_right) { + //std::cout << "!equivalent\n"; + rf(result, he, ps_left, ps_right); + } + } + + template + iT handle_input_events(result_type& result, result_functor rf, iT begin, iT end) { + typedef typename high_precision_type::type high_precision; + //for each event + property_map vertical_properties_above; + property_map vertical_properties_below; + half_edge vertical_edge_above; + half_edge vertical_edge_below; + std::vector insertion_elements; + //current_iter should increase monotonically toward end as we process scanline stop + iterator current_iter = scan_data_.begin(); + just_before_ = true; + Unit y = (std::numeric_limits::min)(); + bool first_iteration = true; + //we want to return from inside the loop when we hit end or new x +#ifdef BOOST_POLYGON_MSVC +#pragma warning( disable: 4127 ) +#endif + while(true) { + if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || + (*begin).first.first.get(HORIZONTAL) != x_))) { + //lookup iterator range in scanline for elements coming in from the left + //that end at this y + Point pt(x_, y); + //grab the properties coming in from below + property_map properties_below; + if(current_iter != scan_data_.end()) { + //make sure we are looking at element in scanline just below y + //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) != y) { + if(scanline_base::on_above_or_below(Point(x_, y), (*current_iter).first) != 0) { + Point e2(pt); + if(e2.get(VERTICAL) != (std::numeric_limits::max)()) + e2.set(VERTICAL, e2.get(VERTICAL) + 1); + else + e2.set(VERTICAL, e2.get(VERTICAL) - 1); + half_edge vhe(pt, e2); + current_iter = scan_data_.lower_bound(vhe); + } + if(current_iter != scan_data_.end()) { + //get the bottom iterator for elements at this point + //while(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y && + while(scanline_base::on_above_or_below(Point(x_, y), (*current_iter).first) != 1 && + current_iter != scan_data_.begin()) { + --current_iter; + } + //if(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y) { + if(scanline_base::on_above_or_below(Point(x_, y), (*current_iter).first) != 1) { + properties_below.clear(); + } else { + properties_below = (*current_iter).second; + //move back up to y or one past y + ++current_iter; + } + } + } + std::vector edges_from_left; + while(current_iter != scan_data_.end() && + //can only be true if y is integer + //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == y) { + scanline_base::on_above_or_below(Point(x_, y), (*current_iter).first) == 0) { + //removal_set_.push_back(current_iter); + ++current_iter; + } + //merge vertical count with count from below + if(!vertical_properties_below.empty()) { + merge_property_maps(vertical_properties_below, properties_below); + //write out vertical edge + write_out(result, rf, vertical_edge_below, properties_below, vertical_properties_below); + } else { + merge_property_maps(vertical_properties_below, properties_below); + } + //iteratively add intertion element counts to count from below + //and write them to insertion set + for(std::size_t i = 0; i < insertion_elements.size(); ++i) { + if(i == 0) { + merge_property_maps(insertion_elements[i].second, vertical_properties_below); + write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, vertical_properties_below); + } else { + merge_property_maps(insertion_elements[i].second, insertion_elements[i-1].second); + write_out(result, rf, insertion_elements[i].first, insertion_elements[i].second, insertion_elements[i-1].second); + } + insertion_set_.push_back(insertion_elements[i]); + } + if((begin == end || (*begin).first.first.get(HORIZONTAL) != x_)) { + if(vertical_properties_above.empty()) { + return begin; + } else { + y = vertical_edge_above.second.get(VERTICAL); + vertical_properties_below.clear(); + vertical_properties_above.swap(vertical_properties_below); + vertical_edge_below = vertical_edge_above; + insertion_elements.clear(); + continue; + } + } + vertical_properties_below.clear(); + vertical_properties_above.swap(vertical_properties_below); + vertical_edge_below = vertical_edge_above; + insertion_elements.clear(); + } + if(begin != end) { + const vertex_property& vp = *begin; + const half_edge& he = vp.first; + y = he.first.get(VERTICAL); + first_iteration = false; + if(! vertical_properties_below.empty() && + vertical_edge_below.second.get(VERTICAL) < y) { + y = vertical_edge_below.second.get(VERTICAL); + continue; + } + if(scanline_base::is_vertical(he)) { + update_property_map(vertical_properties_above, vp.second); + vertical_edge_above = he; + } else { + if(insertion_elements.empty() || + insertion_elements.back().first != he) { + insertion_elements.push_back(scanline_element(he, property_map())); + } + update_property_map(insertion_elements.back().second, vp.second); + } + ++begin; + } + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning( default: 4127 ) +#endif + + } + + inline void erase_end_events(typename end_point_queue::iterator epqi) { + end_point_queue_.erase(end_point_queue_.begin(), epqi); + for(typename std::vector::iterator retire_itr = removal_set_.begin(); + retire_itr != removal_set_.end(); ++retire_itr) { + scan_data_.erase(*retire_itr); + } + removal_set_.clear(); + } + + + inline void remove_retired_edges_from_scanline() { + just_before_ = true; + typename end_point_queue::iterator epqi = end_point_queue_.begin(); + Unit current_x = x_; + Unit previous_x = x_; + while(epqi != end_point_queue_.end() && + (*epqi).get(HORIZONTAL) <= current_x) { + x_ = (*epqi).get(HORIZONTAL); + if(x_ != previous_x) erase_end_events(epqi); + previous_x = x_; + //lookup elements + Point e2(*epqi); + if(e2.get(VERTICAL) != (std::numeric_limits::max)()) + e2.set(VERTICAL, e2.get(VERTICAL) + 1); + else + e2.set(VERTICAL, e2.get(VERTICAL) - 1); + half_edge vhe_e(*epqi, e2); + iterator current_iter = scan_data_.lower_bound(vhe_e); + while(current_iter != scan_data_.end() && (*current_iter).first.second == (*epqi)) { + //evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) == (*epqi).get(VERTICAL)) { + removal_set_.push_back(current_iter); + ++current_iter; + } + ++epqi; + } + x_ = current_x; + erase_end_events(epqi); + } + + inline void insert_new_edges_into_scanline() { + just_before_ = false; + for(typename std::vector::iterator insert_itr = insertion_set_.begin(); + insert_itr != insertion_set_.end(); ++insert_itr) { + scan_data_.insert(*insert_itr); + end_point_queue_.insert((*insert_itr).first.second); + } + insertion_set_.clear(); + } + + //iterator over range of vertex property elements and call result functor + //passing edge to be output, the merged data on both sides and the result + template + void scan(result_type& result, result_functor rf, iT begin, iT end) { + while(begin != end) { + x_ = (*begin).first.first.get(HORIZONTAL); //update scanline stop location + //print_scanline(); + --x_; + remove_retired_edges_from_scanline(); + ++x_; + begin = handle_input_events(result, rf, begin, end); + remove_retired_edges_from_scanline(); + //print_scanline(); + insert_new_edges_into_scanline(); + } + //print_scanline(); + x_ = (std::numeric_limits::max)(); + remove_retired_edges_from_scanline(); + } + + //inline void print_scanline() { + // std::cout << "scanline at " << x_ << ": "; + // for(iterator itr = scan_data_.begin(); itr != scan_data_.end(); ++itr) { + // const scanline_element& se = *itr; + // const half_edge& he = se.first; + // const property_map& mp = se.second; + // std::cout << he.first << ", " << he.second << " ( "; + // for(std::size_t i = 0; i < mp.size(); ++i) { + // std::cout << mp[i].first << ":" << mp[i].second << " "; + // } std::cout << ") "; + // } std::cout << std::endl; + //} + + static inline void merge_property_maps(property_map& mp, const property_map& mp2) { + property_map newmp; + newmp.reserve(mp.size() + mp2.size()); + unsigned int i = 0; + unsigned int j = 0; + while(i != mp.size() && j != mp2.size()) { + if(mp[i].first < mp2[j].first) { + newmp.push_back(mp[i]); + ++i; + } else if(mp[i].first > mp2[j].first) { + newmp.push_back(mp2[j]); + ++j; + } else { + int count = mp[i].second; + count += mp2[j].second; + if(count) { + newmp.push_back(mp[i]); + newmp.back().second = count; + } + ++i; + ++j; + } + } + while(i != mp.size()) { + newmp.push_back(mp[i]); + ++i; + } + while(j != mp2.size()) { + newmp.push_back(mp2[j]); + ++j; + } + mp.swap(newmp); + } + + static inline void update_property_map(property_map& mp, const std::pair& prop_data) { + property_map newmp; + newmp.reserve(mp.size() +1); + bool consumed = false; + for(std::size_t i = 0; i < mp.size(); ++i) { + if(!consumed && prop_data.first == mp[i].first) { + consumed = true; + int count = prop_data.second + mp[i].second; + if(count) + newmp.push_back(std::make_pair(prop_data.first, count)); + } else if(!consumed && prop_data.first < mp[i].first) { + consumed = true; + newmp.push_back(prop_data); + newmp.push_back(mp[i]); + } else { + newmp.push_back(mp[i]); + } + } + if(!consumed) newmp.push_back(prop_data); + mp.swap(newmp); + } + + static inline void set_unique_property(property_set& unqiue_property, const property_map& property) { + unqiue_property.clear(); + for(typename property_map::const_iterator itr = property.begin(); itr != property.end(); ++itr) { + if((*itr).second > 0) + unqiue_property.insert(unqiue_property.end(), (*itr).first); + } + } + + static inline bool common_vertex(const half_edge& he1, const half_edge& he2) { + return he1.first == he2.first || + he1.first == he2.second || + he1.second == he2.first || + he1.second == he2.second; + } + + typedef typename scanline_base::vertex_half_edge vertex_half_edge; + template + static inline void convert_segments_to_vertex_half_edges(std::vector& output, iT begin, iT end) { + for( ; begin != end; ++begin) { + const half_edge& he = (*begin).first; + int count = (*begin).second; + output.push_back(vertex_half_edge(he.first, he.second, count)); + output.push_back(vertex_half_edge(he.second, he.first, -count)); + } + std::sort(output.begin(), output.end()); + } + + class test_functor { + public: + inline test_functor() {} + inline void operator()(std::vector > >& result, + const half_edge& he, const property_set& ps_left, const property_set& ps_right) { + result.push_back(std::make_pair(he, std::make_pair(ps_left, ps_right))); + } + }; + template + static inline bool test_scanline(stream_type& stdcout) { + std::vector > > result; + std::vector > > input; + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl; + test_functor tf; + sl.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); + scanline sl2; + sl2.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl3; + sl3.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(8, 2)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(1, 1), Point(2, 8)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(2, 8), Point(9, 9)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(8, 2), Point(9, 9)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl4; + sl4.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl5; + sl5.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(10, 10)), std::make_pair(0, -1))); + scanline sl6; + sl6.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(9, 1)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(1, 9)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(10, 10)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(10, 20)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(9, 21)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(1, 29)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(0, 20), Point(0, 30)), std::make_pair(0, 1))); + input.push_back(std::make_pair(half_edge(Point(0, 30), Point(10, 30)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 9), Point(10, 10)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(1, 29), Point(10, 30)), std::make_pair(1, -1))); + input.push_back(std::make_pair(half_edge(Point(9, 1), Point(10, 10)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(9, 21), Point(10, 30)), std::make_pair(1, 1))); + input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); + input.push_back(std::make_pair(half_edge(Point(10, 20), Point(10, 30)), std::make_pair(0, -1))); + scanline sl7; + sl7.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + input.clear(); + result.clear(); + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); //a + input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(0, 10)), std::make_pair(0, -1))); //a + input.push_back(std::make_pair(half_edge(Point(0, 10), Point(11, 11)), std::make_pair(0, -1))); //a + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(20, 0)), std::make_pair(0, 1))); //b + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(10, 0), Point(11, 11)), std::make_pair(0, 1))); //a + input.push_back(std::make_pair(half_edge(Point(11, 11), Point(20, 10)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(30, 0)), std::make_pair(0, 1))); //c + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, -1))); //b + input.push_back(std::make_pair(half_edge(Point(20, 0), Point(20, 10)), std::make_pair(0, 1))); //c + input.push_back(std::make_pair(half_edge(Point(20, 10), Point(30, 10)), std::make_pair(0, -1))); //c + input.push_back(std::make_pair(half_edge(Point(30, 0), Point(30, 10)), std::make_pair(0, -1))); //c + scanline sl8; + sl8.scan(result, tf, input.begin(), input.end()); + stdcout << "scanned\n"; + for(std::size_t i = 0; i < result.size(); ++i) { + stdcout << result[i].first.first << ", " << result[i].first.second << "; "; + } stdcout << std::endl; + return true; + } + + }; + + template + class merge_output_functor { + public: + typedef typename scanline_base::half_edge half_edge; + merge_output_functor() {} + template + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + typename std::pair elem; + elem.first = edge; + elem.second = 1; + if(edge.second < edge.first) elem.second *= -1; + if(scanline_base::is_vertical(edge)) elem.second *= -1; + if(!left.empty()) + result[left].insert_clean(elem); + elem.second *= -1; + if(!right.empty()) + result[right].insert_clean(elem); + } + }; + + template , + typename output_functor_type = merge_output_functor > + class property_merge : public scanline_base { + protected: + typedef typename scanline_base::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair half_edge; + typedef typename scanline_base::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base::less_half_edge less_half_edge; + typedef typename scanline_base::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair vertex_data; + + property_merge_data pmd; + typename scanline_base::evalAtXforYPack evalAtXforYPack_; + + template + class less_vertex_data { + typename scanline_base::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + + inline void sort_property_merge_data() { + less_vertex_data lvd(&evalAtXforYPack_); + std::sort(pmd.begin(), pmd.end(), lvd); + } + public: + inline property_merge_data& get_property_merge_data() { return pmd; } + inline property_merge() : pmd(), evalAtXforYPack_() {} + inline property_merge(const property_merge& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline property_merge& operator=(const property_merge& pm) { pmd = pm.pmd; return *this; } + + template + void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole = false) { + insert(polygon_object, property_value, is_hole, typename geometry_concept::type()); + } + + //result type should be std::map, polygon_set_type> + //or std::map, polygon_set_type> + template + void merge(result_type& result) { + if(pmd.empty()) return; + //intersect data + property_merge_data tmp_pmd; + line_intersection::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline sl; + output_functor_type mof; + sl.scan(result, mof, pmd.begin(), pmd.end()); + } + + inline bool verify1() { + std::pair offenders; + std::vector > lines; + int count = 0; + for(std::size_t i = 0; i < pmd.size(); ++i) { + lines.push_back(std::make_pair(pmd[i].first, count++)); + } + if(!line_intersection::verify_scan(offenders, lines.begin(), lines.end())) { + //stdcout << "Intersection failed!\n"; + //stdcout << offenders.first << " " << offenders.second << std::endl; + return false; + } + std::vector pts; + for(std::size_t i = 0; i < lines.size(); ++i) { + pts.push_back(lines[i].first.first); + pts.push_back(lines[i].first.second); + } + std::sort(pts.begin(), pts.end()); + for(std::size_t i = 0; i < pts.size(); i+=2) { + if(pts[i] != pts[i+1]) { + //stdcout << "Non-closed figures after line intersection!\n"; + return false; + } + } + return true; + } + + void clear() {*this = property_merge();} + + protected: + template + void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole, + polygon_concept ) { + bool first_iteration = true; + bool second_iteration = true; + Point first_point; + Point second_point; + Point previous_previous_point; + Point previous_point; + Point current_point; + direction_1d winding_dir = winding(polygon_object); + for(typename polygon_traits::iterator_type itr = begin_points(polygon_object); + itr != end_points(polygon_object); ++itr) { + assign(current_point, *itr); + if(first_iteration) { + first_iteration = false; + first_point = previous_point = current_point; + } else if(second_iteration) { + if(previous_point != current_point) { + second_iteration = false; + previous_previous_point = previous_point; + second_point = previous_point = current_point; + } + } else { + if(previous_point != current_point) { + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + } + } + current_point = first_point; + if(!first_iteration && !second_iteration) { + if(previous_point != current_point) { + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + current_point = second_point; + create_vertex(pmd, previous_point, current_point, winding_dir, + is_hole, property_value); + previous_previous_point = previous_point; + previous_point = current_point; + } + } + + template + void insert(const polygon_with_holes_type& polygon_with_holes_object, const property_type& property_value, bool is_hole, + polygon_with_holes_concept tag) { + insert(polygon_with_holes_object, property_value, is_hole, polygon_concept()); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(polygon_with_holes_object); + itr != end_holes(polygon_with_holes_object); ++itr) { + insert(*itr, property_value, !is_hole, polygon_concept()); + } + } + + template + void insert(const rectangle_type& rectangle_object, const property_type& property_value, bool is_hole, + rectangle_concept ) { + polygon_90_data poly; + assign(poly, rectangle_object); + insert(poly, property_value, is_hole, polygon_concept()); + } + + public: //change to private when done testing + + static inline void create_vertex(property_merge_data& pmd, + const Point& current_point, + const Point& next_point, + direction_1d winding, + bool is_hole, const property_type& property) { + if(current_point == next_point) return; + vertex_property current_vertex; + current_vertex.first.first = current_point; + current_vertex.first.second = next_point; + current_vertex.second.first = property; + int multiplier = 1; + if(winding == CLOCKWISE) + multiplier = -1; + if(is_hole) + multiplier *= -1; + if(current_point < next_point) { + multiplier *= -1; + std::swap(current_vertex.first.first, current_vertex.first.second); + } + current_vertex.second.second = multiplier * (euclidean_distance(next_point, current_point, HORIZONTAL) == 0 ? -1: 1); + pmd.push_back(current_vertex); + //current_vertex.first.second = previous_point; + //current_vertex.second.second *= -1; + //pmd.push_back(current_vertex); + } + + static inline void sort_vertex_half_edges(vertex_data& vertex) { + less_half_edge_pair lessF(vertex.first); + std::sort(vertex.second.begin(), vertex.second.end(), lessF); + } + + class less_half_edge_pair { + private: + Point pt_; + public: + less_half_edge_pair(const Point& pt) : pt_(pt) {} + bool operator()(const half_edge& e1, const half_edge& e2) { + const Point& pt1 = e1.first; + const Point& pt2 = e2.first; + if(get(pt1, HORIZONTAL) == + get(pt_, HORIZONTAL)) { + //vertical edge is always largest + return false; + } + if(get(pt2, HORIZONTAL) == + get(pt_, HORIZONTAL)) { + //if half edge 1 is not vertical its slope is less than that of half edge 2 + return get(pt1, HORIZONTAL) != get(pt2, HORIZONTAL); + } + return scanline_base::less_slope(get(pt_, HORIZONTAL), + get(pt_, VERTICAL), pt1, pt2); + } + }; + + public: + //test functions + template + static stream_type& print (stream_type& o, const property_map& c) + { + o << "count: {"; + for(typename property_map::const_iterator itr = c.begin(); itr != c.end(); ++itr) { + o << ((*itr).first) << ":" << ((*itr).second) << " "; + } + return o << "} "; + } + + + template + static stream_type& print (stream_type& o, const half_edge& he) + { + o << "half edge: ("; + o << (he.first); + return o << ", " << (he.second) << ") "; + } + + template + static stream_type& print (stream_type& o, const vertex_property& c) + { + o << "vertex property: {"; + print(o, c.first); + o << ", " << c.second.first << ":" << c.second.second << " "; + return o; + } + + template + static stream_type& print (stream_type& o, const std::vector& hev) + { + o << "vertex properties: {"; + for(std::size_t i = 0; i < hev.size(); ++i) { + print(o, (hev[i])) << " "; + } + return o << "} "; + } + + template + static stream_type& print (stream_type& o, const std::vector& hev) + { + o << "half edges: {"; + for(std::size_t i = 0; i < hev.size(); ++i) { + print(o, (hev[i])) << " "; + } + return o << "} "; + } + + template + static stream_type& print (stream_type& o, const vertex_data& v) + { + return print(o << "vertex: <" << (v.first) << ", ", (v.second)) << "> "; + } + + template + static stream_type& print (stream_type& o, const std::vector& vv) + { + o << "vertices: {"; + for(std::size_t i = 0; i < vv.size(); ++i) { + print(o, (vv[i])) << " "; + } + return o << "} "; + } + + + + template + static inline bool test_insertion(stream_type& stdcout) { + property_merge si; + rectangle_data rect; + xl(rect, 0); + yl(rect, 1); + xh(rect, 10); + yh(rect, 11); + + si.insert(rect, 333); + print(stdcout, si.pmd) << std::endl; + + Point pts[4] = {Point(0, 0), Point(10,-3), Point(13, 8), Point(0, 0) }; + polygon_data poly; + property_merge si2; + poly.set(pts, pts+3); + si2.insert(poly, 444); + si2.sort_property_merge_data(); + print(stdcout, si2.pmd) << std::endl; + property_merge si3; + poly.set(pts, pts+4); + si3.insert(poly, 444); + si3.sort_property_merge_data(); + stdcout << (si2.pmd == si3.pmd) << std::endl; + std::reverse(pts, pts+4); + property_merge si4; + poly.set(pts, pts+4); + si4.insert(poly, 444); + si4.sort_property_merge_data(); + print(stdcout, si4.pmd) << std::endl; + stdcout << (si2.pmd == si4.pmd) << std::endl; + std::reverse(pts, pts+3); + property_merge si5; + poly.set(pts, pts+4); + si5.insert(poly, 444); + si5.sort_property_merge_data(); + stdcout << (si2.pmd == si5.pmd) << std::endl; + + return true; + } + + template + static inline bool test_merge(stream_type& stdcout) { + property_merge si; + rectangle_data rect; + xl(rect, 0); + yl(rect, 1); + xh(rect, 10); + yh(rect, 11); + + si.insert(rect, 333); + std::map, polygon_set_data > result; + si.merge(result); + print(stdcout, si.pmd) << std::endl; + polygon_set_data psd = (*(result.begin())).second; + std::vector > polys; + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 1\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + si.clear(); + std::vector pts; + pts.push_back(Point(0, 0)); + pts.push_back(Point(10, -10)); + pts.push_back(Point(10, 10)); + polygon_data poly; + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(5, 0)); + pts.push_back(Point(-5, -10)); + pts.push_back(Point(-5, 10)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 2\n"; + return false; + } + //Polygon { -4 -1, 3 3, -2 3 } + //Polygon { 0 -4, -4 -2, -2 1 } + si.clear(); + pts.clear(); + pts.push_back(Point(-4, -1)); + pts.push_back(Point(3, 3)); + pts.push_back(Point(-2, 3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(0, -4)); + pts.push_back(Point(-4, -2)); + pts.push_back(Point(-2, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 3\n"; + return false; + } + stdcout << "Polygon { -2 2, -2 2, 1 4 } \n"; + stdcout << "Polygon { 2 4, 2 -4, -3 1 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(-2, 2)); + pts.push_back(Point(-2, 2)); + pts.push_back(Point(1, 4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(2, 4)); + pts.push_back(Point(2, -4)); + pts.push_back(Point(-3, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 4\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + stdcout << "Polygon { -4 0, -2 -3, 3 -4 } \n"; + stdcout << "Polygon { -1 1, 1 -2, -4 -3 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(-4, 0)); + pts.push_back(Point(-2, -3)); + pts.push_back(Point(3, -4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-1, 1)); + pts.push_back(Point(1, -2)); + pts.push_back(Point(-4, -3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 5\n"; + return false; + } + stdcout << "Polygon { 2 2, -2 0, 0 1 } \n"; + stdcout << "Polygon { 4 -2, 3 -1, 2 3 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(2, 2)); + pts.push_back(Point(-2, 0)); + pts.push_back(Point(0, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(4, -2)); + pts.push_back(Point(3, -1)); + pts.push_back(Point(2, 3)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() != 1) { + stdcout << "fail merge 6\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + stdcout << "Polygon { 0 2, 3 -1, 4 1 } \n"; + stdcout << "Polygon { -4 3, 3 3, 4 2 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(0, 2)); + pts.push_back(Point(3, -1)); + pts.push_back(Point(4, 1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-4, 3)); + pts.push_back(Point(3, 3)); + pts.push_back(Point(4, 2)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 7\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } +stdcout << "Polygon { 1 -2, -1 4, 3 -2 } \n"; +stdcout << "Polygon { 0 -3, 3 1, -3 -4 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(1, -2)); + pts.push_back(Point(-1, 4)); + pts.push_back(Point(3, -2)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(0, -3)); + pts.push_back(Point(3, 1)); + pts.push_back(Point(-3, -4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 8\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } +stdcout << "Polygon { 2 2, 3 0, -3 4 } \n"; +stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; + si.clear(); + pts.clear(); + pts.push_back(Point(2, 2)); + pts.push_back(Point(3, 0)); + pts.push_back(Point(-3, 4)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + pts.clear(); + pts.push_back(Point(-2, -2)); + pts.push_back(Point(0, 0)); + pts.push_back(Point(-1, -1)); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 9\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + si.clear(); + pts.clear(); + //5624841,17616200,75000,9125000 + //pts.push_back(Point(5624841,75000)); + //pts.push_back(Point(5624841,9125000)); + //pts.push_back(Point(17616200,9125000)); + //pts.push_back(Point(17616200,75000)); +pts.push_back(Point(12262940, 6652520 )); pts.push_back(Point(12125750, 6652520 )); pts.push_back(Point(12121272, 6652961 )); pts.push_back(Point(12112981, 6656396 )); pts.push_back(Point(12106636, 6662741 )); pts.push_back(Point(12103201, 6671032 )); pts.push_back(Point(12103201, 6680007 )); pts.push_back(Point(12106636, 6688298 )); +pts.push_back(Point(12109500, 6691780 )); pts.push_back(Point(12748600, 7330890 )); pts.push_back(Point(15762600, 7330890 )); pts.push_back(Point(15904620, 7472900 )); pts.push_back(Point(15909200, 7473030 )); pts.push_back(Point(15935830, 7476006 )); pts.push_back(Point(15992796, 7499602 )); pts.push_back(Point(16036397, 7543203 )); +pts.push_back(Point(16059993, 7600169 )); pts.push_back(Point(16059993, 7661830 )); pts.push_back(Point(16036397, 7718796 )); pts.push_back(Point(15992796, 7762397 )); pts.push_back(Point(15935830, 7785993 )); pts.push_back(Point(15874169, 7785993 )); pts.push_back(Point(15817203, 7762397 )); pts.push_back(Point(15773602, 7718796 )); +pts.push_back(Point(15750006, 7661830 )); pts.push_back(Point(15747030, 7635200 )); pts.push_back(Point(15746900, 7630620 )); pts.push_back(Point(15670220, 7553930 )); pts.push_back(Point(14872950, 7553930 )); pts.push_back(Point(14872950, 7626170 )); +pts.push_back(Point(14869973, 7661280 )); pts.push_back(Point(14846377, 7718246 )); pts.push_back(Point(14802776, 7761847 )); pts.push_back(Point(14745810, 7785443 )); pts.push_back(Point(14684149, 7785443 )); pts.push_back(Point(14627183, 7761847 )); pts.push_back(Point(14583582, 7718246 )); +pts.push_back(Point(14559986, 7661280 )); pts.push_back(Point(14557070, 7636660 )); pts.push_back(Point(14556670, 7625570 )); pts.push_back(Point(13703330, 7625570 )); pts.push_back(Point(13702930, 7636660 )); pts.push_back(Point(13699993, 7661830 )); pts.push_back(Point(13676397, 7718796 )); +pts.push_back(Point(13632796, 7762397 )); pts.push_back(Point(13575830, 7785993 )); pts.push_back(Point(13514169, 7785993 )); pts.push_back(Point(13457203, 7762397 )); pts.push_back(Point(13436270, 7745670 )); pts.push_back(Point(13432940, 7742520 )); pts.push_back(Point(12963760, 7742520 )); +pts.push_back(Point(12959272, 7742961 )); pts.push_back(Point(12950981, 7746396 )); pts.push_back(Point(12944636, 7752741 )); pts.push_back(Point(12941201, 7761032 )); pts.push_back(Point(12941201, 7770007 )); pts.push_back(Point(12944636, 7778298 )); pts.push_back(Point(12947490, 7781780 )); +pts.push_back(Point(13425330, 8259620 )); pts.push_back(Point(15601330, 8259620 )); pts.push_back(Point(15904620, 8562900 )); pts.push_back(Point(15909200, 8563030 )); pts.push_back(Point(15935830, 8566006 )); pts.push_back(Point(15992796, 8589602 )); pts.push_back(Point(16036397, 8633203 )); +pts.push_back(Point(16059993, 8690169 )); pts.push_back(Point(16059993, 8751830 )); pts.push_back(Point(16036397, 8808796 )); pts.push_back(Point(15992796, 8852397 )); pts.push_back(Point(15935830, 8875993 )); pts.push_back(Point(15874169, 8875993 )); pts.push_back(Point(15817203, 8852397 )); pts.push_back(Point(15773602, 8808796 )); +pts.push_back(Point(15750006, 8751830 )); pts.push_back(Point(15747030, 8725200 )); pts.push_back(Point(15746900, 8720620 )); pts.push_back(Point(15508950, 8482660 )); pts.push_back(Point(14689890, 8482660 )); pts.push_back(Point(14685412, 8483101 )); pts.push_back(Point(14677121, 8486536 )); +pts.push_back(Point(14670776, 8492881 )); pts.push_back(Point(14667341, 8501172 )); pts.push_back(Point(14667341, 8510147 )); pts.push_back(Point(14670776, 8518438 )); pts.push_back(Point(14673630, 8521920 )); pts.push_back(Point(14714620, 8562900 )); pts.push_back(Point(14719200, 8563030 )); pts.push_back(Point(14745830, 8566006 )); +pts.push_back(Point(14802796, 8589602 )); pts.push_back(Point(14846397, 8633203 )); pts.push_back(Point(14869993, 8690169 )); pts.push_back(Point(14869993, 8751830 )); pts.push_back(Point(14846397, 8808796 )); pts.push_back(Point(14802796, 8852397 )); pts.push_back(Point(14745830, 8875993 )); pts.push_back(Point(14684169, 8875993 )); +pts.push_back(Point(14627203, 8852397 )); pts.push_back(Point(14583602, 8808796 )); pts.push_back(Point(14560006, 8751830 )); pts.push_back(Point(14557030, 8725200 )); pts.push_back(Point(14556900, 8720620 )); pts.push_back(Point(14408270, 8571980 )); pts.push_back(Point(13696320, 8571980 )); pts.push_back(Point(13696320, 8675520 )); +pts.push_back(Point(13699963, 8690161 )); pts.push_back(Point(13699963, 8751818 )); pts.push_back(Point(13676368, 8808781 )); pts.push_back(Point(13632771, 8852378 )); pts.push_back(Point(13575808, 8875973 )); pts.push_back(Point(13514151, 8875973 )); pts.push_back(Point(13457188, 8852378 )); pts.push_back(Point(13436270, 8835670 )); pts.push_back(Point(13432940, 8832520 )); +pts.push_back(Point(13281760, 8832520 )); pts.push_back(Point(13277272, 8832961 )); pts.push_back(Point(13268981, 8836396 )); pts.push_back(Point(13262636, 8842741 )); pts.push_back(Point(13259201, 8851032 )); pts.push_back(Point(13259201, 8860007 )); pts.push_back(Point(13262636, 8868298 )); pts.push_back(Point(13265500, 8871780 )); +pts.push_back(Point(13518710, 9125000 )); pts.push_back(Point(16270720, 9125000 )); pts.push_back(Point(16270720, 8939590 )); pts.push_back(Point(17120780, 8939590 )); pts.push_back(Point(17120780, 9125000 )); pts.push_back(Point(17616200, 9125000 )); pts.push_back(Point(17616200, 75000 )); pts.push_back(Point(16024790, 75000 )); +pts.push_back(Point(16021460, 80700 )); pts.push_back(Point(16016397, 88796 )); pts.push_back(Point(15972796, 132397 )); pts.push_back(Point(15915830, 155993 )); pts.push_back(Point(15908730, 157240 )); pts.push_back(Point(15905000, 157800 )); pts.push_back(Point(15516800, 546000 )); pts.push_back(Point(15905000, 934200 )); +pts.push_back(Point(15908730, 934760 )); pts.push_back(Point(15915830, 936006 )); pts.push_back(Point(15972796, 959602 )); pts.push_back(Point(16016397, 1003203 )); pts.push_back(Point(16039993, 1060169 )); pts.push_back(Point(16039993, 1121830 )); pts.push_back(Point(16016397, 1178796 )); pts.push_back(Point(15972796, 1222397 )); +pts.push_back(Point(15915830, 1245993 )); pts.push_back(Point(15854169, 1245993 )); pts.push_back(Point(15797203, 1222397 )); pts.push_back(Point(15753602, 1178796 )); pts.push_back(Point(15730006, 1121830 )); pts.push_back(Point(15728760, 1114730 )); pts.push_back(Point(15728200, 1111000 )); pts.push_back(Point(15363500, 746300 )); +pts.push_back(Point(14602620, 746300 )); pts.push_back(Point(14598142, 746741 )); pts.push_back(Point(14589851, 750176 )); pts.push_back(Point(14583506, 756521 )); pts.push_back(Point(14580071, 764812 )); pts.push_back(Point(14580071, 773787 )); pts.push_back(Point(14583506, 782078 )); pts.push_back(Point(14586360, 785560 )); +pts.push_back(Point(14586370, 785560 )); pts.push_back(Point(14735000, 934200 )); pts.push_back(Point(14738730, 934760 )); pts.push_back(Point(14745830, 936006 )); pts.push_back(Point(14802796, 959602 )); pts.push_back(Point(14846397, 1003203 )); pts.push_back(Point(14869993, 1060169 )); +pts.push_back(Point(14870450, 1062550 )); pts.push_back(Point(14872170, 1071980 )); pts.push_back(Point(14972780, 1071980 )); pts.push_back(Point(15925000, 2024200 )); pts.push_back(Point(15928730, 2024760 )); pts.push_back(Point(15935830, 2026006 )); pts.push_back(Point(15992796, 2049602 )); +pts.push_back(Point(16036397, 2093203 )); pts.push_back(Point(16059993, 2150169 )); pts.push_back(Point(16059993, 2211830 )); pts.push_back(Point(16036397, 2268796 )); pts.push_back(Point(15992796, 2312397 )); pts.push_back(Point(15935830, 2335993 )); pts.push_back(Point(15874169, 2335993 )); +pts.push_back(Point(15817203, 2312397 )); pts.push_back(Point(15773602, 2268796 )); pts.push_back(Point(15750006, 2211830 )); pts.push_back(Point(15748760, 2204730 )); pts.push_back(Point(15748200, 2201000 )); pts.push_back(Point(14869220, 1322020 )); pts.push_back(Point(14088350, 1322020 )); +pts.push_back(Point(14083862, 1322461 )); pts.push_back(Point(14075571, 1325896 )); pts.push_back(Point(14069226, 1332241 )); pts.push_back(Point(14065791, 1340532 )); pts.push_back(Point(14065791, 1349507 )); pts.push_back(Point(14069226, 1357798 )); pts.push_back(Point(14072080, 1361280 )); +pts.push_back(Point(14072090, 1361280 )); pts.push_back(Point(14735000, 2024200 )); pts.push_back(Point(14738730, 2024760 )); pts.push_back(Point(14745830, 2026006 )); pts.push_back(Point(14802796, 2049602 )); pts.push_back(Point(14846397, 2093203 )); pts.push_back(Point(14869993, 2150169 )); +pts.push_back(Point(14869993, 2211830 )); pts.push_back(Point(14846397, 2268796 )); pts.push_back(Point(14802796, 2312397 )); pts.push_back(Point(14745830, 2335993 )); pts.push_back(Point(14684169, 2335993 )); pts.push_back(Point(14627203, 2312397 )); pts.push_back(Point(14583602, 2268796 )); pts.push_back(Point(14560006, 2211830 )); +pts.push_back(Point(14558760, 2204730 )); pts.push_back(Point(14558200, 2201000 )); pts.push_back(Point(13752220, 1395020 )); pts.push_back(Point(12991340, 1395020 )); pts.push_back(Point(12986862, 1395461 )); pts.push_back(Point(12978571, 1398896 )); pts.push_back(Point(12972226, 1405241 )); +pts.push_back(Point(12968791, 1413532 )); pts.push_back(Point(12968791, 1422507 )); pts.push_back(Point(12972226, 1430798 )); pts.push_back(Point(12975080, 1434280 )); pts.push_back(Point(12975090, 1434280 )); pts.push_back(Point(13565000, 2024200 )); pts.push_back(Point(13568730, 2024760 )); pts.push_back(Point(13575830, 2026006 )); +pts.push_back(Point(13632796, 2049602 )); pts.push_back(Point(13676397, 2093203 )); pts.push_back(Point(13699993, 2150169 )); pts.push_back(Point(13699993, 2211830 )); pts.push_back(Point(13676397, 2268796 )); pts.push_back(Point(13632796, 2312397 )); pts.push_back(Point(13575830, 2335993 )); +pts.push_back(Point(13514169, 2335993 )); pts.push_back(Point(13457203, 2312397 )); pts.push_back(Point(13413602, 2268796 )); pts.push_back(Point(13390006, 2211830 )); pts.push_back(Point(13388760, 2204730 )); pts.push_back(Point(13388200, 2201000 )); pts.push_back(Point(12655220, 1468020 )); +pts.push_back(Point(11894340, 1468020 )); pts.push_back(Point(11889862, 1468461 )); pts.push_back(Point(11881571, 1471896 )); pts.push_back(Point(11875226, 1478241 )); pts.push_back(Point(11871791, 1486532 )); pts.push_back(Point(11871791, 1495507 )); +pts.push_back(Point(11875226, 1503798 )); pts.push_back(Point(11878090, 1507280 )); pts.push_back(Point(12395000, 2024200 )); pts.push_back(Point(12398730, 2024760 )); pts.push_back(Point(12405830, 2026006 )); pts.push_back(Point(12462796, 2049602 )); pts.push_back(Point(12506397, 2093203 )); +pts.push_back(Point(12529993, 2150169 )); pts.push_back(Point(12529993, 2211830 )); pts.push_back(Point(12506397, 2268796 )); pts.push_back(Point(12462796, 2312397 )); pts.push_back(Point(12405830, 2335993 )); pts.push_back(Point(12344169, 2335993 )); +pts.push_back(Point(12287203, 2312397 )); pts.push_back(Point(12243602, 2268796 )); pts.push_back(Point(12220006, 2211830 )); pts.push_back(Point(12218760, 2204730 )); pts.push_back(Point(12218200, 2201000 )); pts.push_back(Point(11558220, 1541020 )); +pts.push_back(Point(10797340, 1541020 )); pts.push_back(Point(10792862, 1541461 )); pts.push_back(Point(10784571, 1544896 )); pts.push_back(Point(10778226, 1551241 )); pts.push_back(Point(10774791, 1559532 )); pts.push_back(Point(10774791, 1568507 )); pts.push_back(Point(10778226, 1576798 )); pts.push_back(Point(10781080, 1580280 )); +pts.push_back(Point(10781090, 1580280 )); pts.push_back(Point(11225000, 2024200 )); pts.push_back(Point(11228730, 2024760 )); pts.push_back(Point(11235830, 2026006 )); pts.push_back(Point(11292796, 2049602 )); pts.push_back(Point(11336397, 2093203 )); pts.push_back(Point(11359993, 2150169 )); +pts.push_back(Point(11359993, 2211830 )); pts.push_back(Point(11336397, 2268796 )); pts.push_back(Point(11292796, 2312397 )); pts.push_back(Point(11235830, 2335993 )); pts.push_back(Point(11174169, 2335993 )); pts.push_back(Point(11117203, 2312397 )); pts.push_back(Point(11073602, 2268796 )); pts.push_back(Point(11050006, 2211830 )); +pts.push_back(Point(11048760, 2204730 )); pts.push_back(Point(11048200, 2201000 )); pts.push_back(Point(10461220, 1614020 )); pts.push_back(Point( 5647400, 1614020 )); pts.push_back(Point( 5642912, 1614461 )); +pts.push_back(Point( 5634621, 1617896 )); pts.push_back(Point( 5628276, 1624241 )); pts.push_back(Point( 5624841, 1632532 )); pts.push_back(Point( 5624841, 1641507 )); pts.push_back(Point( 5628276, 1649798 )); pts.push_back(Point( 5631130, 1653280 )); +pts.push_back(Point( 5688490, 1710640 )); pts.push_back(Point( 9722350, 1710640 )); pts.push_back(Point(10034620, 2022900 )); pts.push_back(Point(10039200, 2023030 )); pts.push_back(Point(10065830, 2026006 )); pts.push_back(Point(10122796, 2049602 )); +pts.push_back(Point(10166397, 2093203 )); pts.push_back(Point(10189993, 2150169 )); pts.push_back(Point(10189993, 2211830 )); pts.push_back(Point(10166397, 2268796 )); pts.push_back(Point(10158620, 2279450 )); pts.push_back(Point(10158620, 2404900 )); pts.push_back(Point(10548950, 2795240 )); +pts.push_back(Point(15586950, 2795240 )); pts.push_back(Point(15904620, 3112900 )); pts.push_back(Point(15909200, 3113030 )); pts.push_back(Point(15935830, 3116006 )); pts.push_back(Point(15992796, 3139602 )); pts.push_back(Point(16036397, 3183203 )); pts.push_back(Point(16059993, 3240169 )); pts.push_back(Point(16059993, 3301830 )); +pts.push_back(Point(16036397, 3358796 )); pts.push_back(Point(15992796, 3402397 )); pts.push_back(Point(15935830, 3425993 )); pts.push_back(Point(15874169, 3425993 )); pts.push_back(Point(15817203, 3402397 )); pts.push_back(Point(15773602, 3358796 )); pts.push_back(Point(15750006, 3301830 )); pts.push_back(Point(15747030, 3275200 )); +pts.push_back(Point(15746900, 3270620 )); pts.push_back(Point(15494570, 3018280 )); pts.push_back(Point(14675510, 3018280 )); pts.push_back(Point(14671032, 3018721 )); pts.push_back(Point(14662741, 3022156 )); pts.push_back(Point(14656396, 3028501 )); pts.push_back(Point(14652961, 3036792 )); +pts.push_back(Point(14652961, 3045767 )); pts.push_back(Point(14656396, 3054058 )); pts.push_back(Point(14659260, 3057540 )); pts.push_back(Point(14714620, 3112900 )); pts.push_back(Point(14719200, 3113030 )); pts.push_back(Point(14745830, 3116006 )); pts.push_back(Point(14802796, 3139602 )); +pts.push_back(Point(14846397, 3183203 )); pts.push_back(Point(14869993, 3240169 )); pts.push_back(Point(14869993, 3301830 )); pts.push_back(Point(14846397, 3358796 )); pts.push_back(Point(14802796, 3402397 )); pts.push_back(Point(14745830, 3425993 )); pts.push_back(Point(14684169, 3425993 )); pts.push_back(Point(14627203, 3402397 )); +pts.push_back(Point(14583602, 3358796 )); pts.push_back(Point(14560006, 3301830 )); pts.push_back(Point(14557030, 3275200 )); pts.push_back(Point(14556900, 3270620 )); pts.push_back(Point(14370700, 3084410 )); pts.push_back(Point(13702830, 3084410 )); pts.push_back(Point(13702830, 3263160 )); +pts.push_back(Point(13700003, 3302210 )); pts.push_back(Point(13676407, 3359176 )); pts.push_back(Point(13632806, 3402777 )); pts.push_back(Point(13575840, 3426373 )); pts.push_back(Point(13514179, 3426373 )); pts.push_back(Point(13457213, 3402777 )); pts.push_back(Point(13413612, 3359176 )); +pts.push_back(Point(13390016, 3302210 )); pts.push_back(Point(13387030, 3275200 )); pts.push_back(Point(13386900, 3270620 )); pts.push_back(Point(13266840, 3150550 )); pts.push_back(Point(12532920, 3150550 )); pts.push_back(Point(12532920, 3264990 )); pts.push_back(Point(12529993, 3301820 )); +pts.push_back(Point(12506397, 3358786 )); pts.push_back(Point(12462796, 3402387 )); pts.push_back(Point(12405830, 3425983 )); pts.push_back(Point(12344169, 3425983 )); pts.push_back(Point(12287203, 3402387 )); pts.push_back(Point(12243602, 3358786 )); pts.push_back(Point(12220006, 3301820 )); pts.push_back(Point(12217030, 3275200 )); +pts.push_back(Point(12216900, 3270620 )); pts.push_back(Point(12157460, 3211170 )); pts.push_back(Point(11362030, 3211170 )); pts.push_back(Point(11360250, 3220520 )); pts.push_back(Point(11359993, 3221830 )); pts.push_back(Point(11336397, 3278796 )); +pts.push_back(Point(11292796, 3322397 )); pts.push_back(Point(11235830, 3345993 )); pts.push_back(Point(11174169, 3345993 )); pts.push_back(Point(11117203, 3322397 )); pts.push_back(Point(11096270, 3305670 )); pts.push_back(Point(11092940, 3302520 )); pts.push_back(Point(10680760, 3302520 )); +pts.push_back(Point(10676272, 3302961 )); pts.push_back(Point(10667981, 3306396 )); pts.push_back(Point(10661636, 3312741 )); pts.push_back(Point(10658201, 3321032 )); pts.push_back(Point(10658201, 3330007 )); pts.push_back(Point(10661636, 3338298 )); pts.push_back(Point(10664500, 3341780 )); +pts.push_back(Point(11264260, 3941550 )); pts.push_back(Point(15643260, 3941550 )); pts.push_back(Point(15904620, 4202900 )); pts.push_back(Point(15909200, 4203030 )); pts.push_back(Point(15935830, 4206006 )); pts.push_back(Point(15992796, 4229602 )); +pts.push_back(Point(16036397, 4273203 )); pts.push_back(Point(16059993, 4330169 )); pts.push_back(Point(16059993, 4391830 )); pts.push_back(Point(16036397, 4448796 )); pts.push_back(Point(15992796, 4492397 )); +pts.push_back(Point(15935830, 4515993 )); pts.push_back(Point(15874169, 4515993 )); pts.push_back(Point(15817203, 4492397 )); pts.push_back(Point(15773602, 4448796 )); pts.push_back(Point(15750006, 4391830 )); pts.push_back(Point(15747030, 4365200 )); pts.push_back(Point(15746900, 4360620 )); +pts.push_back(Point(15550880, 4164590 )); pts.push_back(Point(14825070, 4164590 )); pts.push_back(Point(14825070, 4247610 )); pts.push_back(Point(14846397, 4273213 )); pts.push_back(Point(14869993, 4330179 )); pts.push_back(Point(14869993, 4391840 )); pts.push_back(Point(14846397, 4448806 )); +pts.push_back(Point(14802796, 4492407 )); pts.push_back(Point(14745830, 4516003 )); pts.push_back(Point(14684169, 4516003 )); pts.push_back(Point(14627203, 4492407 )); pts.push_back(Point(14583602, 4448806 )); pts.push_back(Point(14560006, 4391840 )); pts.push_back(Point(14557030, 4365200 )); +pts.push_back(Point(14556900, 4360620 )); pts.push_back(Point(14432520, 4236230 )); pts.push_back(Point(13702830, 4236230 )); pts.push_back(Point(13702830, 4352930 )); pts.push_back(Point(13699993, 4391750 )); pts.push_back(Point(13676397, 4448716 )); +pts.push_back(Point(13632796, 4492317 )); pts.push_back(Point(13575830, 4515913 )); pts.push_back(Point(13514169, 4515913 )); pts.push_back(Point(13457203, 4492317 )); pts.push_back(Point(13413602, 4448716 )); pts.push_back(Point(13390006, 4391750 )); pts.push_back(Point(13387030, 4365200 )); +pts.push_back(Point(13386900, 4360620 )); pts.push_back(Point(13334170, 4307880 )); pts.push_back(Point(12532990, 4307880 )); pts.push_back(Point(12532990, 4357550 )); pts.push_back(Point(12529993, 4391760 )); pts.push_back(Point(12506397, 4448726 )); pts.push_back(Point(12462796, 4492327 )); +pts.push_back(Point(12405830, 4515923 )); pts.push_back(Point(12344169, 4515923 )); pts.push_back(Point(12287203, 4492327 )); pts.push_back(Point(12243602, 4448726 )); pts.push_back(Point(12220006, 4391760 )); pts.push_back(Point(12217970, 4378710 )); pts.push_back(Point(12216810, 4368500 )); +pts.push_back(Point(11363190, 4368500 )); pts.push_back(Point(11362030, 4378710 )); pts.push_back(Point(11359983, 4391828 )); pts.push_back(Point(11336388, 4448791 )); pts.push_back(Point(11292791, 4492388 )); pts.push_back(Point(11235828, 4515983 )); pts.push_back(Point(11174171, 4515983 )); pts.push_back(Point(11117208, 4492388 )); +pts.push_back(Point(11096270, 4475670 )); pts.push_back(Point(11092940, 4472520 )); pts.push_back(Point(11057750, 4472520 )); pts.push_back(Point(11053272, 4472961 )); pts.push_back(Point(11044981, 4476396 )); pts.push_back(Point(11038636, 4482741 )); pts.push_back(Point(11035201, 4491032 )); +pts.push_back(Point(11035201, 4500007 )); pts.push_back(Point(11038636, 4508298 )); pts.push_back(Point(11041490, 4511780 )); pts.push_back(Point(11573490, 5043780 )); pts.push_back(Point(15655490, 5043780 )); pts.push_back(Point(15904620, 5292900 )); +pts.push_back(Point(15909200, 5293030 )); pts.push_back(Point(15935830, 5296006 )); pts.push_back(Point(15992796, 5319602 )); pts.push_back(Point(16036397, 5363203 )); pts.push_back(Point(16059993, 5420169 )); pts.push_back(Point(16059993, 5481830 )); pts.push_back(Point(16036397, 5538796 )); +pts.push_back(Point(15992796, 5582397 )); pts.push_back(Point(15935830, 5605993 )); pts.push_back(Point(15874169, 5605993 )); pts.push_back(Point(15817203, 5582397 )); pts.push_back(Point(15773602, 5538796 )); pts.push_back(Point(15750006, 5481830 )); pts.push_back(Point(15747030, 5455200 )); +pts.push_back(Point(15746900, 5450620 )); pts.push_back(Point(15563110, 5266820 )); pts.push_back(Point(14857380, 5266820 )); pts.push_back(Point(14857380, 5382430 )); pts.push_back(Point(14869993, 5420179 )); pts.push_back(Point(14869993, 5481840 )); pts.push_back(Point(14846397, 5538806 )); pts.push_back(Point(14802796, 5582407 )); +pts.push_back(Point(14745830, 5606003 )); pts.push_back(Point(14684169, 5606003 )); pts.push_back(Point(14627203, 5582407 )); pts.push_back(Point(14583602, 5538806 )); pts.push_back(Point(14560006, 5481840 )); pts.push_back(Point(14557030, 5455200 )); pts.push_back(Point(14556900, 5450620 )); pts.push_back(Point(14444750, 5338460 )); +pts.push_back(Point(13702890, 5338460 )); pts.push_back(Point(13702890, 5364400 )); pts.push_back(Point(13699993, 5401800 )); pts.push_back(Point(13676397, 5458766 )); pts.push_back(Point(13632796, 5502367 )); pts.push_back(Point(13575830, 5525963 )); pts.push_back(Point(13514169, 5525963 )); pts.push_back(Point(13457203, 5502367 )); +pts.push_back(Point(13413602, 5458766 )); pts.push_back(Point(13390006, 5401800 )); pts.push_back(Point(13389230, 5397620 )); pts.push_back(Point(13387590, 5388060 )); pts.push_back(Point(12532960, 5388060 )); pts.push_back(Point(12532960, 5446220 )); pts.push_back(Point(12529993, 5481820 )); +pts.push_back(Point(12506397, 5538786 )); pts.push_back(Point(12462796, 5582387 )); pts.push_back(Point(12405830, 5605983 )); pts.push_back(Point(12344169, 5605983 )); pts.push_back(Point(12287203, 5582387 )); pts.push_back(Point(12266270, 5565670 )); pts.push_back(Point(12262940, 5562520 )); pts.push_back(Point(11737750, 5562520 )); +pts.push_back(Point(11733272, 5562961 )); pts.push_back(Point(11724981, 5566396 )); pts.push_back(Point(11718636, 5572741 )); pts.push_back(Point(11715201, 5581032 )); pts.push_back(Point(11715201, 5590007 )); pts.push_back(Point(11718636, 5598298 )); pts.push_back(Point(11721500, 5601780 )); +pts.push_back(Point(12287760, 6168050 )); pts.push_back(Point(15689760, 6168050 )); pts.push_back(Point(15904620, 6382900 )); pts.push_back(Point(15909200, 6383030 )); pts.push_back(Point(15935830, 6386006 )); pts.push_back(Point(15992796, 6409602 )); +pts.push_back(Point(16036397, 6453203 )); pts.push_back(Point(16059993, 6510169 )); pts.push_back(Point(16059993, 6571830 )); pts.push_back(Point(16036397, 6628796 )); pts.push_back(Point(15992796, 6672397 )); pts.push_back(Point(15935830, 6695993 )); pts.push_back(Point(15874169, 6695993 )); +pts.push_back(Point(15817203, 6672397 )); pts.push_back(Point(15773602, 6628796 )); pts.push_back(Point(15750006, 6571830 )); pts.push_back(Point(15747030, 6545200 )); pts.push_back(Point(15746900, 6540620 )); pts.push_back(Point(15597380, 6391090 )); pts.push_back(Point(14858060, 6391090 )); +pts.push_back(Point(14858060, 6473860 )); pts.push_back(Point(14869993, 6510179 )); pts.push_back(Point(14869993, 6571840 )); pts.push_back(Point(14846397, 6628806 )); pts.push_back(Point(14802796, 6672407 )); pts.push_back(Point(14745830, 6696003 )); pts.push_back(Point(14684169, 6696003 )); +pts.push_back(Point(14627203, 6672407 )); pts.push_back(Point(14583602, 6628806 )); pts.push_back(Point(14560006, 6571840 )); pts.push_back(Point(14557030, 6545200 )); pts.push_back(Point(14556900, 6540620 )); pts.push_back(Point(14479020, 6462730 )); +pts.push_back(Point(13702990, 6462730 )); pts.push_back(Point(13702990, 6537170 )); pts.push_back(Point(13700003, 6571840 )); pts.push_back(Point(13676407, 6628806 )); pts.push_back(Point(13632806, 6672407 )); pts.push_back(Point(13575840, 6696003 )); +pts.push_back(Point(13514179, 6696003 )); pts.push_back(Point(13457213, 6672407 )); pts.push_back(Point(13413612, 6628806 )); pts.push_back(Point(13390016, 6571840 )); pts.push_back(Point(13387040, 6545550 )); pts.push_back(Point(13386710, 6534380 )); +pts.push_back(Point(12533290, 6534380 )); pts.push_back(Point(12532960, 6545550 )); pts.push_back(Point(12529983, 6571828 )); pts.push_back(Point(12506388, 6628791 )); pts.push_back(Point(12462791, 6672388 )); pts.push_back(Point(12405828, 6695983 )); +pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 )); pts.push_back(Point(12266270, 6655670 )); + poly.set(pts.begin(), pts.end()); + si.insert(poly, 444); + result.clear(); + si.merge(result); + si.verify1(); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + std::vector outpts; + for(typename polygon_set_data::iterator_type itr = psd.begin(); + itr != psd.end(); ++itr) { + outpts.push_back((*itr).first.first); + outpts.push_back((*itr).first.second); + } + std::sort(outpts.begin(), outpts.end()); + for(std::size_t i = 0; i < outpts.size(); i+=2) { + if(outpts[i] != outpts[i+1]) { + stdcout << "Polygon set not a closed figure\n"; + stdcout << i << std::endl; + stdcout << outpts[i] << " " << outpts[i+1] << std::endl; + return 0; + } + } + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + stdcout << "fail merge 10\n"; + return false; + } + stdcout << (polys[0]) << std::endl; + } + for(unsigned int i = 0; i < 10; ++i) { + stdcout << "random case # " << i << std::endl; + si.clear(); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data poly1; + poly1.set(pts.begin(), pts.end()); + stdcout << poly1 << std::endl; + si.insert(poly1, 444); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data poly2; + poly2.set(pts.begin(), pts.end()); + stdcout << poly2 << std::endl; + si.insert(poly2, 444); + result.clear(); + si.merge(result); + print(stdcout, si.pmd) << std::endl; + if(!result.empty()) { + psd = (*(result.begin())).second; + stdcout << psd << std::endl; + polys.clear(); + psd.get(polys); + if(polys.size() == 0) { + si.clear(); + si.insert(poly1, 333); + result.clear(); + si.merge(result); + psd = (*(result.begin())).second; + std::vector > polys1; + psd.get(polys1); + si.clear(); + si.insert(poly2, 333); + result.clear(); + si.merge(result); + psd = (*(result.begin())).second; + std::vector > polys2; + psd.get(polys2); + if(!polys1.empty() || !polys2.empty()) { + stdcout << "fail random merge " << i << std::endl; + return false; + } + } + } + if(!polys.empty()) + stdcout << polys.size() << ": " << (polys[0]) << std::endl; + } + return true; + } + + template + static inline bool check_rectangle_trio(rectangle_data rect1, rectangle_data rect2, rectangle_data rect3, stream_type& stdcout) { + property_merge si; + std::map, polygon_set_data > result; + std::vector > polys; + property_merge_90 si90; + std::map, polygon_90_set_data > result90; + std::vector > polys90; + si.insert(rect1, 111); + si90.insert(rect1, 111); + stdcout << rect1 << std::endl; + si.insert(rect2, 222); + si90.insert(rect2, 222); + stdcout << rect2 << std::endl; + si.insert(rect3, 333); + si90.insert(rect3, 333); + stdcout << rect3 << std::endl; + si.merge(result); + si90.merge(result90); + if(result.size() != result90.size()) { + stdcout << "merge failed with size mismatch\n"; + return 0; + } + typename std::map, polygon_90_set_data >::iterator itr90 = result90.begin(); + for(typename std::map, polygon_set_data >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + for(typename std::set::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data psd = (*itr).second; + polygon_90_set_data psd90 = (*itr90).second; + polys.clear(); + polys90.clear(); + psd.get(polys); + psd90.get(polys90); + if(polys.size() != polys90.size()) { + stdcout << "merge failed with polygon count mismatch\n"; + stdcout << psd << std::endl; + for(std::size_t j = 0; j < polys.size(); ++j) { + stdcout << polys[j] << std::endl; + } + stdcout << "reference\n"; + for(std::size_t j = 0; j < polys90.size(); ++j) { + stdcout << polys90[j] << std::endl; + } + return 0; + } + bool failed = false; + for(std::size_t j = 0; j < polys.size(); ++j) { + stdcout << polys[j] << std::endl; + stdcout << polys90[j] << std::endl; +#ifdef BOOST_POLYGON_ICC +#pragma warning (disable:1572) +#endif + if(area(polys[j]) != area(polys90[j])) { +#ifdef BOOST_POLYGON_ICC +#pragma warning (default:1572) +#endif + stdcout << "merge failed with area mismatch\n"; + failed = true; + } + } + if(failed) return 0; + ++itr90; + } + return true; + } + + template + static inline bool test_manhattan_intersection(stream_type& stdcout) { + rectangle_data rect1, rect2, rect3; + set_points(rect1, (Point(-1, 2)), (Point(1, 4))); + set_points(rect2, (Point(-1, 2)), (Point(2, 3))); + set_points(rect3, (Point(-3, 0)), (Point(4, 2))); + if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { + return false; + } + for(unsigned int i = 0; i < 100; ++i) { + property_merge si; + std::map, polygon_set_data > result; + std::vector > polys; + property_merge_90 si90; + std::map, polygon_90_set_data > result90; + std::vector > polys90; + stdcout << "random case # " << i << std::endl; + set_points(rect1, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + set_points(rect2, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + set_points(rect3, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); + if(!check_rectangle_trio(rect1, rect2, rect3, stdcout)) { + return false; + } + } + return true; + } + + template + static inline bool test_intersection(stream_type& stdcout) { + property_merge si; + rectangle_data rect; + xl(rect, 0); + yl(rect, 10); + xh(rect, 30); + yh(rect, 20); + si.insert(rect, 333); + xl(rect, 10); + yl(rect, 0); + xh(rect, 20); + yh(rect, 30); + si.insert(rect, 444); + xl(rect, 15); + yl(rect, 0); + xh(rect, 25); + yh(rect, 30); + si.insert(rect, 555); + std::map, polygon_set_data > result; + si.merge(result); + print(stdcout, si.pmd) << std::endl; + for(typename std::map, polygon_set_data >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + stdcout << "( "; + for(typename std::set::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data psd = (*itr).second; + stdcout << psd << std::endl; + std::vector > polys; + psd.get(polys); + for(std::size_t i = 0; i < polys.size(); ++i) { + stdcout << polys[i] << std::endl; + } + } + std::vector pts; + std::vector > polys; + for(unsigned int i = 0; i < 10; ++i) { + property_merge si2; + stdcout << "random case # " << i << std::endl; + si.clear(); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data poly1; + poly1.set(pts.begin(), pts.end()); + stdcout << poly1 << std::endl; + si.insert(poly1, 444); + si2.insert(poly1, 333); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data poly2; + poly2.set(pts.begin(), pts.end()); + stdcout << poly2 << std::endl; + si.insert(poly2, 444); + si2.insert(poly2, 444); + pts.clear(); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + pts.push_back(Point(rand()%9-4, rand()%9-4)); + polygon_data poly3; + poly3.set(pts.begin(), pts.end()); + stdcout << poly3 << std::endl; + si.insert(poly3, 444); + si2.insert(poly3, 555); + result.clear(); + std::map, polygon_set_data > result2; + si.merge(result); + si2.merge(result2); + stdcout << "merged result\n"; + for(typename std::map, polygon_set_data >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + stdcout << "( "; + for(typename std::set::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data psd = (*itr).second; + stdcout << psd << std::endl; + std::vector > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + stdcout << "intersected pmd\n"; + print(stdcout, si2.pmd) << std::endl; + stdcout << "intersected result\n"; + for(typename std::map, polygon_set_data >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + stdcout << "( "; + for(typename std::set::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data psd = (*itr).second; + stdcout << psd << std::endl; + std::vector > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + si.clear(); + for(typename std::map, polygon_set_data >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + polys.clear(); + (*itr).second.get(polys); + for(std::size_t j = 0; j < polys.size(); ++j) { + si.insert(polys[j], 444); + } + } + result2.clear(); + si.merge(result2); + stdcout << "remerged result\n"; + for(typename std::map, polygon_set_data >::iterator itr = result2.begin(); + itr != result2.end(); ++itr) { + stdcout << "( "; + for(typename std::set::const_iterator set_itr = (*itr).first.begin(); + set_itr != (*itr).first.end(); ++set_itr) { + stdcout << (*set_itr) << " "; + } stdcout << ") \n"; + polygon_set_data psd = (*itr).second; + stdcout << psd << std::endl; + std::vector > polys2; + psd.get(polys2); + for(std::size_t ii = 0; ii < polys2.size(); ++ii) { + stdcout << polys2[ii] << std::endl; + } + } + std::vector > polys2; + polys.clear(); + (*(result.begin())).second.get(polys); + (*(result2.begin())).second.get(polys2); + if(!(polys == polys2)) { + stdcout << "failed intersection check # " << i << std::endl; + return false; + } + } + return true; + } + }; + + template + class arbitrary_boolean_op : public scanline_base { + private: + + typedef int property_type; + typedef typename scanline_base::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair half_edge; + typedef typename scanline_base::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base::less_half_edge less_half_edge; + typedef typename scanline_base::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair vertex_data; + + property_merge_data pmd; + typename scanline_base::evalAtXforYPack evalAtXforYPack_; + + template + class less_vertex_data { + typename scanline_base::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + template + class boolean_output_functor { + public: + boolean_output_functor() {} + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + typename std::pair elem; + elem.first = edge; + elem.second = 1; + if(edge.second < edge.first) elem.second *= -1; + if(scanline_base::is_vertical(edge)) elem.second *= -1; +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op_type == 0) { //OR + if(!left.empty() && right.empty()) { + result.insert_clean(elem); + } else if(!right.empty() && left.empty()) { + elem.second *= -1; + result.insert_clean(elem); + } + } else if(op_type == 1) { //AND + if(left.size() == 2 && right.size() != 2) { + result.insert_clean(elem); + } else if(right.size() == 2 && left.size() != 2) { + elem.second *= -1; + result.insert_clean(elem); + } + } else if(op_type == 2) { //XOR + if(left.size() == 1 && right.size() != 1) { + result.insert_clean(elem); + } else if(right.size() == 1 && left.size() != 1) { + elem.second *= -1; + result.insert_clean(elem); + } + } else { //SUBTRACT + if(left.size() == 1) { + if((*(left.begin())) == 0) { + result.insert_clean(elem); + } + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + if(right.size() == 1) { + if((*(right.begin())) == 0) { + elem.second *= -1; + result.insert_clean(elem); + } + } + } + } + }; + + inline void sort_property_merge_data() { + less_vertex_data lvd(&evalAtXforYPack_); + std::sort(pmd.begin(), pmd.end(), lvd); + } + public: + inline arbitrary_boolean_op() : pmd(), evalAtXforYPack_() {} + inline arbitrary_boolean_op(const arbitrary_boolean_op& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline arbitrary_boolean_op& operator=(const arbitrary_boolean_op& pm) { pmd = pm.pmd; return *this; } + + enum BOOLEAN_OP_TYPE { + BOOLEAN_OR = 0, + BOOLEAN_AND = 1, + BOOLEAN_XOR = 2, + BOOLEAN_NOT = 3 + }; + template + inline void execute(result_type& result, iT1 b1, iT1 e1, iT2 b2, iT2 e2, int op) { + //intersect data + insert(b1, e1, 0); + insert(b2, e2, 1); + property_merge_data tmp_pmd; + //#define BOOST_POLYGON_DEBUG_FILE +#ifdef BOOST_POLYGON_DEBUG_FILE + std::fstream debug_file; + debug_file.open("gtl_debug.txt", std::ios::out); + property_merge >::print(debug_file, pmd); + debug_file.close(); +#endif + if(pmd.empty()) + return; + line_intersection::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline > sl; + if(op == BOOLEAN_OR) { + boolean_output_functor, 0> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_AND) { + boolean_output_functor, 1> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_XOR) { + boolean_output_functor, 2> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } else if(op == BOOLEAN_NOT) { + boolean_output_functor, 3> bof; + sl.scan(result, bof, pmd.begin(), pmd.end()); + } + } + + inline void clear() {*this = arbitrary_boolean_op();} + + private: + template + void insert(iT b, iT e, int id) { + for(; + b != e; ++b) { + pmd.push_back(vertex_property(half_edge((*b).first.first, (*b).first.second), + std::pair(id, (*b).second))); + } + } + + }; + + template + bool test_arbitrary_boolean_op(stream_type& stdcout) { + polygon_set_data psd; + rectangle_data rect; + set_points(rect, point_data(0, 0), point_data(10, 10)); + psd.insert(rect); + polygon_set_data psd2; + set_points(rect, point_data(5, 5), point_data(15, 15)); + psd2.insert(rect); + std::vector > pv; + pv.clear(); + arbitrary_boolean_op abo; + polygon_set_data psd3; + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_OR); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_AND); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_XOR); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + pv.clear(); + abo.clear(); + psd3.clear(); + abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_NOT); + psd3.get(pv); + for(std::size_t i = 0; i < pv.size(); ++i) { + stdcout << pv[i] << std::endl; + } + return true; + } + + + + + + + + + + + + + + + template + class arbitrary_connectivity_extraction : public scanline_base { + private: + + typedef typename scanline_base::Point Point; + + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex + //typedef std::pair half_edge; + typedef typename scanline_base::half_edge half_edge; + + //scanline comparator functor + typedef typename scanline_base::less_half_edge less_half_edge; + typedef typename scanline_base::less_point less_point; + + //this data structure assocates a property and count to a half edge + typedef std::pair > vertex_property; + //this data type stores the combination of many half edges + typedef std::vector property_merge_data; + + //this is the data type used internally to store the combination of property counts at a given location + typedef std::vector > property_map; + //this data type is used internally to store the combined property data for a given half edge + typedef std::pair vertex_data; + + property_merge_data pmd; + typename scanline_base::evalAtXforYPack evalAtXforYPack_; + + template + class less_vertex_data { + typename scanline_base::evalAtXforYPack* pack_; + public: + less_vertex_data() : pack_() {} + less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + less_point lp; + if(lp(lvalue.first.first, rvalue.first.first)) return true; + if(lp(rvalue.first.first, lvalue.first.first)) return false; + Unit x = lvalue.first.first.get(HORIZONTAL); + int just_before_ = 0; + less_half_edge lhe(&x, &just_before_, pack_); + return lhe(lvalue.first, rvalue.first); + } + }; + + + template + static void process_previous_x(cT& output) { + std::map, std::set >& y_prop_map = output.first.second; + if(y_prop_map.empty()) return; + Unit x = output.first.first; + for(typename std::map, std::set >::iterator itr = + y_prop_map.begin(); itr != y_prop_map.end(); ++itr) { + if((*itr).first.x() < x) { + y_prop_map.erase(y_prop_map.begin(), itr); + continue; + } + for(typename std::set::iterator inner_itr = itr->second.begin(); + inner_itr != itr->second.end(); ++inner_itr) { + std::set& output_edges = (*(output.second))[*inner_itr]; + typename std::set::iterator inner_inner_itr = inner_itr; + ++inner_inner_itr; + for( ; inner_inner_itr != itr->second.end(); ++inner_inner_itr) { + output_edges.insert(output_edges.end(), *inner_inner_itr); + std::set& output_edges_2 = (*(output.second))[*inner_inner_itr]; + output_edges_2.insert(output_edges_2.end(), *inner_itr); + } + } + } + } + + template + class connectivity_extraction_output_functor { + public: + connectivity_extraction_output_functor() {} + void operator()(result_type& result, const half_edge& edge, const key_type& left, const key_type& right) { + Unit& x = result.first.first; + std::map, std::set >& y_prop_map = result.first.second; + point_data pt = edge.first; + if(pt.x() != x) process_previous_x(result); + x = pt.x(); + std::set& output_set = y_prop_map[pt]; + { + for(typename key_type::const_iterator itr1 = + left.begin(); itr1 != left.end(); ++itr1) { + output_set.insert(output_set.end(), *itr1); + } + for(typename key_type::const_iterator itr2 = + right.begin(); itr2 != right.end(); ++itr2) { + output_set.insert(output_set.end(), *itr2); + } + } + std::set& output_set2 = y_prop_map[edge.second]; + for(typename key_type::const_iterator itr1 = + left.begin(); itr1 != left.end(); ++itr1) { + output_set2.insert(output_set2.end(), *itr1); + } + for(typename key_type::const_iterator itr2 = + right.begin(); itr2 != right.end(); ++itr2) { + output_set2.insert(output_set2.end(), *itr2); + } + } + }; + + inline void sort_property_merge_data() { + less_vertex_data lvd(&evalAtXforYPack_); + std::sort(pmd.begin(), pmd.end(), lvd); + } + public: + inline arbitrary_connectivity_extraction() : pmd(), evalAtXforYPack_() {} + inline arbitrary_connectivity_extraction + (const arbitrary_connectivity_extraction& pm) : pmd(pm.pmd), evalAtXforYPack_(pm.evalAtXforYPack_) {} + inline arbitrary_connectivity_extraction& operator= + (const arbitrary_connectivity_extraction& pm) { pmd = pm.pmd; return *this; } + + template + inline void execute(result_type& result) { + //intersect data + property_merge_data tmp_pmd; + line_intersection::validate_scan(tmp_pmd, pmd.begin(), pmd.end()); + pmd.swap(tmp_pmd); + sort_property_merge_data(); + scanline > sl; + std::pair, std::set > >, + result_type*> output + (std::make_pair(std::make_pair((std::numeric_limits::max)(), + std::map, + std::set >()), &result)); + connectivity_extraction_output_functor, std::set > >, result_type*>, + std::vector > ceof; + sl.scan(output, ceof, pmd.begin(), pmd.end()); + process_previous_x(output); + } + + inline void clear() {*this = arbitrary_connectivity_extraction();} + + template + void populateTouchSetData(iT begin, iT end, + property_type property) { + for( ; begin != end; ++begin) { + pmd.push_back(vertex_property(half_edge((*begin).first.first, (*begin).first.second), + std::pair(property, (*begin).second))); + } + } + + }; + +} +} +#endif + diff --git a/include/boost/polygon/detail/transform_detail.hpp b/include/boost/polygon/detail/transform_detail.hpp new file mode 100644 index 0000000..2cd3400 --- /dev/null +++ b/include/boost/polygon/detail/transform_detail.hpp @@ -0,0 +1,553 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_TRANSFORM_DETAIL_HPP +#define BOOST_POLYGON_TRANSFORM_DETAIL_HPP + +namespace boost { namespace polygon{ + // inline std::ostream& operator<< (std::ostream& o, const axis_transformation& r) { + // o << r.atr_; + // return o; + // } + + // inline std::istream& operator>> (std::istream& i, axis_transformation& r) { + // int tmp; + // i >> tmp; + // r = axis_transformation((axis_transformation::ATR)tmp); + // return i; + // } + + // template + // inline std::ostream& operator<< (std::ostream& o, const anisotropic_scale_factor& sc) { + // o << sc.scale_[0] << BOOST_POLYGON_SEP << sc.scale_[1] << GTL_SEP << sc.scale_[2]; + // return o; + // } + + // template + // inline std::istream& operator>> (std::istream& i, anisotropic_scale_factor& sc) { + // i >> sc.scale_[0] >> sc.scale_[1] >> sc.scale_[2]; + // return i; + // } + + // template + // inline std::ostream& operator<< (std::ostream& o, const transformation& tr) { + // o << tr.atr_ << BOOST_POLYGON_SEP << tr.p_; + // return o; + // } + + // template + // inline std::istream& operator>> (std::istream& i, transformation& tr) { + // i >> tr.atr_ >> tr.p_; + // return i; + // } + + + inline axis_transformation::axis_transformation(const orientation_3d& orient) : atr_(NULL_TRANSFORM) { + const ATR tmp[3] = { + UP_EAST_NORTH, //sort by x, then z, then y + EAST_UP_NORTH, //sort by y, then z, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[orient.to_int()]; + } + + inline axis_transformation::axis_transformation(const orientation_2d& orient) : atr_(NULL_TRANSFORM) { + const ATR tmp[3] = { + NORTH_EAST_UP, //sort by z, then x, then y + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[orient.to_int()]; + } + + inline axis_transformation::axis_transformation(const direction_3d& dir) : atr_(NULL_TRANSFORM) { + const ATR tmp[6] = { + DOWN_EAST_NORTH, //sort by -x, then z, then y + UP_EAST_NORTH, //sort by x, then z, then y + EAST_DOWN_NORTH, //sort by -y, then z, then x + EAST_UP_NORTH, //sort by y, then z, then x + EAST_NORTH_DOWN, //sort by -z, then y, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[dir.to_int()]; + } + + inline axis_transformation::axis_transformation(const direction_2d& dir) : atr_(NULL_TRANSFORM) { + const ATR tmp[4] = { + SOUTH_EAST_UP, //sort by z, then x, then y + NORTH_EAST_UP, //sort by z, then x, then y + EAST_SOUTH_UP, //sort by z, then y, then x + EAST_NORTH_UP //sort by z, then y, then x + }; + atr_ = tmp[dir.to_int()]; + } + + inline axis_transformation& axis_transformation::operator=(const axis_transformation& a) { + atr_ = a.atr_; + return *this; + } + + inline axis_transformation& axis_transformation::operator=(const ATR& atr) { + atr_ = atr; + return *this; + } + + inline bool axis_transformation::operator==(const axis_transformation& a) const { + return atr_ == a.atr_; + } + + inline bool axis_transformation::operator!=(const axis_transformation& a) const { + return !(*this == a); + } + + inline bool axis_transformation::operator<(const axis_transformation& a) const { + return atr_ < a.atr_; + } + + inline axis_transformation& axis_transformation::operator+=(const axis_transformation& a){ + bool abit5 = (a.atr_ & 32) != 0; + bool abit4 = (a.atr_ & 16) != 0; + bool abit3 = (a.atr_ & 8) != 0; + bool abit2 = (a.atr_ & 4) != 0; + bool abit1 = (a.atr_ & 2) != 0; + bool abit0 = (a.atr_ & 1) != 0; + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + int indexes[2][3] = { + { + ((int)((bit5 & bit2) | (bit4 & !bit2)) << 1) + + (int)(bit2 & !bit5), + ((int)((bit4 & bit2) | (bit5 & !bit2)) << 1) + + (int)(!bit5 & !bit2), + ((int)(!bit4 & !bit5) << 1) + + (int)(bit5) + }, + { + ((int)((abit5 & abit2) | (abit4 & !abit2)) << 1) + + (int)(abit2 & !abit5), + ((int)((abit4 & abit2) | (abit5 & !abit2)) << 1) + + (int)(!abit5 & !abit2), + ((int)(!abit4 & !abit5) << 1) + + (int)(abit5) + } + }; + int zero_bits[2][3] = { + {bit0, bit1, bit3}, + {abit0, abit1, abit3} + }; + int nbit3 = zero_bits[0][2] ^ zero_bits[1][indexes[0][2]]; + int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; + int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; + indexes[0][0] = indexes[1][indexes[0][0]]; + indexes[0][1] = indexes[1][indexes[0][1]]; + indexes[0][2] = indexes[1][indexes[0][2]]; + int nbit5 = (indexes[0][2] == 1); + int nbit4 = (indexes[0][2] == 0); + int nbit2 = (!(nbit5 | nbit4) & (bool)(indexes[0][0] & 1)) | //swap xy + (nbit5 & ((indexes[0][0] & 2) >> 1)) | //z->y x->z + (nbit4 & ((indexes[0][1] & 2) >> 1)); //z->x y->z + atr_ = (ATR)((nbit5 << 5) + + (nbit4 << 4) + + (nbit3 << 3) + + (nbit2 << 2) + + (nbit1 << 1) + nbit0); + return *this; + } + + inline axis_transformation axis_transformation::operator+(const axis_transformation& a) const { + axis_transformation retval(*this); + return retval+=a; + } + + // populate_axis_array writes the three INDIVIDUAL_AXIS values that the + // ATR enum value of 'this' represent into axis_array + inline void axis_transformation::populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + axis_array[2] = + (INDIVIDUAL_AXIS)((((int)(!bit4 & !bit5)) << 2) + + ((int)(bit5) << 1) + + bit3); + axis_array[1] = + (INDIVIDUAL_AXIS)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ + ((int)(!bit5 & !bit2) << 1) + + bit1); + axis_array[0] = + (INDIVIDUAL_AXIS)((((int)((bit5 & bit2) | (bit4 & !bit2))) << 2) + + ((int)(bit2 & !bit5) << 1) + + bit0); + } + + // combine_axis_arrays concatenates this_array and that_array overwriting + // the result into this_array + inline void + axis_transformation::combine_axis_arrays (INDIVIDUAL_AXIS this_array[], + const INDIVIDUAL_AXIS that_array[]){ + int indexes[3] = {this_array[0] >> 1, + this_array[1] >> 1, + this_array[2] >> 1}; + int zero_bits[2][3] = { + {this_array[0] & 1, this_array[1] & 1, this_array[2] & 1}, + {that_array[0] & 1, that_array[1] & 1, that_array[2] & 1} + }; + this_array[0] = that_array[indexes[0]]; + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] & (int)((int)PZ+(int)PY)); + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | + ((int)zero_bits[0][0] ^ + (int)zero_bits[1][indexes[0]])); + this_array[1] = that_array[indexes[1]]; + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] & (int)((int)PZ+(int)PY)); + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | + ((int)zero_bits[0][1] ^ + (int)zero_bits[1][indexes[1]])); + this_array[2] = that_array[indexes[2]]; + this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] & (int)((int)PZ+(int)PY)); + this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] | + ((int)zero_bits[0][2] ^ + (int)zero_bits[1][indexes[2]])); + } + + // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values + // to the ATR enum value and sets 'this' to that value + inline void axis_transformation::write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { + int bit5 = ((int)this_array[2] & 2) != 0; + int bit4 = !((((int)this_array[2] & 4) != 0) | (((int)this_array[2] & 2) != 0)); + int bit3 = ((int)this_array[2] & 1) != 0; + //bit 2 is the tricky bit + int bit2 = ((!(bit5 | bit4)) & (((int)this_array[0] & 2) != 0)) | //swap xy + (bit5 & (((int)this_array[0] & 4) >> 2)) | //z->y x->z + (bit4 & (((int)this_array[1] & 4) >> 2)); //z->x y->z + int bit1 = ((int)this_array[1] & 1); + int bit0 = ((int)this_array[0] & 1); + atr_ = ATR((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + } + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + inline axis_transformation& + axis_transformation::set_directions(const direction_2d& horizontalDir, + const direction_2d& verticalDir){ + int bit2 = (static_cast(horizontalDir).to_int()) != 0; + int bit1 = !(verticalDir.to_int() & 1); + int bit0 = !(horizontalDir.to_int() & 1); + atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); + return *this; + } + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + inline axis_transformation& axis_transformation::set_directions(const direction_3d& horizontalDir, + const direction_3d& verticalDir, + const direction_3d& proximalDir){ + int this_array[3] = {horizontalDir.to_int(), + verticalDir.to_int(), + proximalDir.to_int()}; + int bit5 = (this_array[2] & 2) != 0; + int bit4 = !(((this_array[2] & 4) != 0) | ((this_array[2] & 2) != 0)); + int bit3 = !((this_array[2] & 1) != 0); + //bit 2 is the tricky bit + int bit2 = (!(bit5 | bit4) & ((this_array[0] & 2) != 0 )) | //swap xy + (bit5 & ((this_array[0] & 4) >> 2)) | //z->y x->z + (bit4 & ((this_array[1] & 4) >> 2)); //z->x y->z + int bit1 = !(this_array[1] & 1); + int bit0 = !(this_array[0] & 1); + atr_ = ATR((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + return *this; + } + + template + inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y) const { + int bit2 = (atr_ & 4) != 0; + int bit1 = (atr_ & 2) != 0; + int bit0 = (atr_ & 1) != 0; + x *= -((bit0 << 1) - 1); + y *= -((bit1 << 1) - 1); + predicated_swap(bit2 != 0,x,y); + } + + template + inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { + int bit5 = (atr_ & 32) != 0; + int bit4 = (atr_ & 16) != 0; + int bit3 = (atr_ & 8) != 0; + int bit2 = (atr_ & 4) != 0; + int bit1 = (atr_ & 2) != 0; + int bit0 = (atr_ & 1) != 0; + x *= -((bit0 << 1) - 1); + y *= -((bit1 << 1) - 1); + z *= -((bit3 << 1) - 1); + predicated_swap(bit2 != 0, x, y); + predicated_swap(bit5 != 0, y, z); + predicated_swap(bit4 != 0, x, z); + } + + inline axis_transformation& axis_transformation::invert_2d() { + int bit2 = ((atr_ & 4) != 0); + int bit1 = ((atr_ & 2) != 0); + int bit0 = ((atr_ & 1) != 0); + //swap bit 0 and bit 1 if bit2 is 1 + predicated_swap(bit2 != 0, bit0, bit1); + bit1 = bit1 << 1; + atr_ = (ATR)(atr_ & (32+16+8+4)); //mask away bit0 and bit1 + atr_ = (ATR)(atr_ | bit0 | bit1); + return *this; + } + + inline axis_transformation axis_transformation::inverse_2d() const { + axis_transformation retval(*this); + return retval.invert_2d(); + } + + inline axis_transformation& axis_transformation::invert() { + int bit5 = ((atr_ & 32) != 0); + int bit4 = ((atr_ & 16) != 0); + int bit3 = ((atr_ & 8) != 0); + int bit2 = ((atr_ & 4) != 0); + int bit1 = ((atr_ & 2) != 0); + int bit0 = ((atr_ & 1) != 0); + predicated_swap(bit2 != 0, bit4, bit5); + predicated_swap(bit4 != 0, bit0, bit3); + predicated_swap(bit5 != 0, bit1, bit3); + predicated_swap(bit2 != 0, bit0, bit1); + atr_ = (ATR)((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + + (bit1 << 1) + bit0); + return *this; + } + + inline axis_transformation axis_transformation::inverse() const { + axis_transformation retval(*this); + return retval.invert(); + } + + template + inline scale_factor_type anisotropic_scale_factor::get(orientation_3d orient) const { + return scale_[orient.to_int()]; + } + + template + inline void anisotropic_scale_factor::set(orientation_3d orient, scale_factor_type value) { + scale_[orient.to_int()] = value; + } + + template + inline scale_factor_type anisotropic_scale_factor::x() const { return scale_[HORIZONTAL]; } + template + inline scale_factor_type anisotropic_scale_factor::y() const { return scale_[VERTICAL]; } + template + inline scale_factor_type anisotropic_scale_factor::z() const { return scale_[PROXIMAL]; } + template + inline void anisotropic_scale_factor::x(scale_factor_type value) { scale_[HORIZONTAL] = value; } + template + inline void anisotropic_scale_factor::y(scale_factor_type value) { scale_[VERTICAL] = value; } + template + inline void anisotropic_scale_factor::z(scale_factor_type value) { scale_[PROXIMAL] = value; } + + //concatenation operator (convolve scale factors) + template + inline anisotropic_scale_factor anisotropic_scale_factor::operator+(const anisotropic_scale_factor& s) const { + anisotropic_scale_factor retval(*this); + return retval+=s; + } + + //concatenate this with that + template + inline const anisotropic_scale_factor& anisotropic_scale_factor::operator+=(const anisotropic_scale_factor& s){ + scale_[0] *= s.scale_[0]; + scale_[1] *= s.scale_[1]; + scale_[2] *= s.scale_[2]; + return *this; + } + + //transform + template + inline anisotropic_scale_factor& anisotropic_scale_factor::transform(axis_transformation atr){ + direction_3d dirs[3]; + atr.get_directions(dirs[0],dirs[1],dirs[2]); + scale_factor_type tmp[3] = {scale_[0], scale_[1], scale_[2]}; + for(int i = 0; i < 3; ++i){ + scale_[orientation_3d(dirs[i]).to_int()] = tmp[i]; + } + return *this; + } + + template + template + inline void anisotropic_scale_factor::scale(coordinate_type_2& x, coordinate_type_2& y) const { + x = scaling_policy::round((scale_factor_type)x * get(HORIZONTAL)); + y = scaling_policy::round((scale_factor_type)y * get(HORIZONTAL)); + } + + template + template + inline void anisotropic_scale_factor::scale(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { + scale(x, y); + z = scaling_policy::round((scale_factor_type)z * get(HORIZONTAL)); + } + + template + inline anisotropic_scale_factor& anisotropic_scale_factor::invert() { + x(1/x()); + y(1/y()); + z(1/z()); + return *this; + } + + + template + inline transformation::transformation() : atr_(), p_(0, 0, 0) {;} + + template + inline transformation::transformation(axis_transformation atr) : atr_(atr), p_(0, 0, 0){;} + + template + inline transformation::transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0, 0){;} + + template + template + inline transformation::transformation(const point_type& p) : atr_(), p_(0, 0, 0) { + set_translation(p); + } + + template + template + inline transformation::transformation(axis_transformation atr, const point_type& p) : + atr_(atr), p_(0, 0, 0) { + set_translation(p); + } + + template + template + inline transformation::transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt) : atr_(), p_(0, 0, 0) { + transformation tmp(referencePt); + transformation rotRef(atr); + transformation tmpInverse = tmp.inverse(); + point_type decon(referencePt); + deconvolve(decon, destinationPt); + transformation displacement(decon); + tmp += rotRef; + tmp += tmpInverse; + tmp += displacement; + (*this) = tmp; + } + + template + inline transformation::transformation(const transformation& tr) : + atr_(tr.atr_), p_(tr.p_) {;} + + template + inline bool transformation::operator==(const transformation& tr) const { + return atr_ == tr.atr_ && p_ == tr.p_; + } + + template + inline bool transformation::operator!=(const transformation& tr) const { + return !(*this == tr); + } + + template + inline bool transformation::operator<(const transformation& tr) const { + return atr_ < tr.atr_ || atr_ == tr.atr_ && p_ < tr.p_; + } + + template + inline transformation transformation::operator+(const transformation& tr) const { + transformation retval(*this); + return retval+=tr; + } + + template + inline const transformation& transformation::operator+=(const transformation& tr){ + //apply the inverse transformation of this to the translation point of that + //and convolve it with this translation point + coordinate_type x, y, z; + transformation inv = inverse(); + inv.transform(x, y, z); + p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); + p_.set(VERTICAL, p_.get(VERTICAL) + y); + p_.set(PROXIMAL, p_.get(PROXIMAL) + z); + //concatenate axis transforms + atr_ += tr.atr_; + return *this; + } + + template + inline void transformation::set_axis_transformation(const axis_transformation& atr) { + atr_ = atr; + } + + template + template + inline void transformation::get_translation(point_type& p) const { + assign(p, p_); + } + + template + template + inline void transformation::set_translation(const point_type& p) { + assign(p_, p); + } + + template + inline void transformation::transform(coordinate_type& x, coordinate_type& y) const { + //subtract each component of new origin point + y -= p_.get(VERTICAL); + x -= p_.get(HORIZONTAL); + atr_.transform(x, y); + } + + template + inline void transformation::transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const { + //subtract each component of new origin point + z -= p_.get(PROXIMAL); + y -= p_.get(VERTICAL); + x -= p_.get(HORIZONTAL); + atr_.transform(x,y,z); + } + + // sets the axis_transform portion to its inverse + // transforms the tranlastion portion by that inverse axis_transform + // multiplies the translation portion by -1 to reverse it + template + inline transformation& transformation::invert() { + coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL), z = p_.get(PROXIMAL); + atr_.transform(x, y, z); + x *= -1; + y *= -1; + z *= -1; + p_ = point_3d_data(x, y, z); + atr_.invert(); + return *this; + } + + template + inline transformation transformation::inverse() const { + transformation retval(*this); + return retval.invert(); + } +} +} +#endif + + diff --git a/include/boost/polygon/gmp_override.hpp b/include/boost/polygon/gmp_override.hpp new file mode 100755 index 0000000..bfe3e3c --- /dev/null +++ b/include/boost/polygon/gmp_override.hpp @@ -0,0 +1,129 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_GMP_OVERRIDE_HPP +#define BOOST_POLYGON_GMP_OVERRIDE_HPP +#include +namespace boost { namespace polygon { + + class gmp_int { + private: + inline gmp_int(const mpq_class& input) : v_(input) {} + public: + inline gmp_int() {} + explicit inline gmp_int(long input) : v_(input) {} + inline gmp_int(const gmp_int& input) : v_(input.v_) {} + inline gmp_int& operator=(const gmp_int& that) { + v_ = that.v_; + return (*this); + } + inline gmp_int& operator=(long that) { + v_ = that; + return (*this); + } + inline operator int() const { + std::cout << "cast\n"; + mpz_class num = v_.get_num(); + mpz_class den = v_.get_den(); + num /= den; + return num.get_si(); + } + inline double get_d() const { + return v_.get_d(); + } + inline int get_num() const { + return v_.get_num().get_si(); + } + inline int get_den() const { + return v_.get_den().get_si(); + } + inline bool operator==(const gmp_int& that) const { + return v_ == that.v_; + } + inline bool operator!=(const gmp_int& that) const { + return v_ != that.v_; + } + inline bool operator<(const gmp_int& that) const { + bool retval = v_ < that.v_; + return retval; + } + inline bool operator<=(const gmp_int& that) const { + return v_ <= that.v_; + } + inline bool operator>(const gmp_int& that) const { + return v_ > that.v_; + } + inline bool operator>=(const gmp_int& that) const { + return v_ >= that.v_; + } + inline gmp_int operator+(const gmp_int& b) { + return gmp_int((*this).v_ + b.v_); + } + inline gmp_int operator-(const gmp_int& b) { + return gmp_int((*this).v_ - b.v_); + } + inline gmp_int operator*(const gmp_int& b) { + return gmp_int((*this).v_ * b.v_); + } + inline gmp_int operator/(const gmp_int& b) { + return gmp_int((*this).v_ / b.v_); + } + inline gmp_int& operator+=(const gmp_int& b) { + (*this).v_ += b.v_; + return (*this); + } + inline gmp_int& operator-=(const gmp_int& b) { + (*this).v_ -= b.v_; + return (*this); + } + inline gmp_int& operator*=(const gmp_int& b) { + (*this).v_ *= b.v_; + return (*this); + } + inline gmp_int& operator/=(const gmp_int& b) { + (*this).v_ /= b.v_; + return (*this); + } + inline gmp_int& operator++() { + ++v_; + return (*this); + } + inline gmp_int& operator--() { + --v_; + return (*this); + } + inline gmp_int operator++(int) { + gmp_int retval(*this); + ++(*this); + return retval; + } + inline gmp_int operator--(int) { + gmp_int retval(*this); + --(*this); + return retval; + } + private: + mpq_class v_; + }; + + template <> + struct high_precision_type { + typedef mpq_class type; + }; + + template <> + int convert_high_precision_type(const mpq_class& v) { + mpz_class num = v.get_num(); + mpz_class den = v.get_den(); + num /= den; + return num.get_si(); + }; + +} +} + +#endif diff --git a/include/boost/polygon/gtl.hpp b/include/boost/polygon/gtl.hpp new file mode 100755 index 0000000..cabbb63 --- /dev/null +++ b/include/boost/polygon/gtl.hpp @@ -0,0 +1,27 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef GTL_GTL_HPP +#define GTL_GTL_HPP + +#ifdef __ICC +#pragma warning (disable:1125) +#endif + +#ifdef WIN32 +#pragma warning( disable: 4996 ) +#pragma warning( disable: 4800 ) +#endif + +#define BOOST_POLYGON_NO_DEPS +#include "polygon.hpp" +namespace gtl = boost::polygon; +using namespace boost::polygon::operators; +#if __ICC +#pragma warning (default:1125) +#endif +#endif diff --git a/include/boost/polygon/interval_concept.hpp b/include/boost/polygon/interval_concept.hpp new file mode 100755 index 0000000..b3b1a46 --- /dev/null +++ b/include/boost/polygon/interval_concept.hpp @@ -0,0 +1,592 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_INTERVAL_CONCEPT_HPP +#define BOOST_POLYGON_INTERVAL_CONCEPT_HPP +#include "isotropy.hpp" +#include "interval_data.hpp" +#include "interval_traits.hpp" + +namespace boost { namespace polygon{ + struct interval_concept {}; + + template + struct is_interval_concept { typedef gtl_no type; }; + template <> + struct is_interval_concept { typedef gtl_yes type; }; + + template + struct is_mutable_interval_concept { typedef gtl_no type; }; + template <> + struct is_mutable_interval_concept { typedef gtl_yes type; }; + + template + struct interval_coordinate_type_by_concept { typedef void type; }; + template + struct interval_coordinate_type_by_concept { typedef typename interval_traits::coordinate_type type; }; + + template + struct interval_coordinate_type { + typedef typename interval_coordinate_type_by_concept< + T, typename is_interval_concept::type>::type>::type type; + }; + + template + struct interval_difference_type_by_concept { typedef void type; }; + template + struct interval_difference_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + + template + struct interval_difference_type { + typedef typename interval_difference_type_by_concept< + T, typename is_interval_concept::type>::type>::type type; + }; + + + template + typename interval_coordinate_type::type + get(const T& interval, direction_1d dir, + typename enable_if::type>::type>::type>::type * = 0 + ) { + return interval_traits::get(interval, dir); + } + + template + void + set(T& interval, direction_1d dir, coordinate_type value, + typename enable_if::type>::type>::type * = 0 + ) { + //this may need to be refined + interval_mutable_traits::set(interval, dir, value); + if(high(interval) < low(interval)) + interval_mutable_traits::set(interval, dir.backward(), value); + } + + template + T + construct(T2 low_value, T3 high_value, + typename enable_if::type>::type>::type * = 0 + ) { + if(low_value > high_value) std::swap(low_value, high_value); + return interval_mutable_traits::construct(low_value, high_value); + } + + template + T + copy_construct(const T2& interval, + typename enable_if< typename gtl_and::type>::type, + typename is_interval_concept::type>::type>::type>::type * = 0 + ) { + return construct + (get(interval, LOW ), + get(interval, HIGH)); + } + + template + T1 & + assign(T1& lvalue, const T2& rvalue, + typename enable_if< typename gtl_and< typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type>::type * = 0) { + lvalue = copy_construct(rvalue); + return lvalue; + } + + template + bool + equivalence(const T& interval1, const T2& interval2, + typename enable_if< typename gtl_and< typename is_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type>::type * = 0 + ) { + return get(interval1, LOW) == + get(interval2, LOW) && + get(interval1, HIGH) == + get(interval2, HIGH); + } + + struct y_i_contains : gtl_yes {}; + + template + typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept::type>::type >::type, bool>::type + contains(const interval_type& interval, + typename interval_traits::coordinate_type value, + bool consider_touch = true ) { + if(consider_touch) { + return value <= high(interval) && value >= low(interval); + } else { + return value < high(interval) && value > low(interval); + } + } + + template + bool + contains(const interval_type& interval, + const interval_type_2& value, bool consider_touch = true, + typename enable_if< typename gtl_and< typename is_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type>::type * = 0 + ) { + return contains(interval, get(value, LOW), consider_touch) && + contains(interval, get(value, HIGH), consider_touch); + } + + // get the low coordinate + template + typename interval_traits::coordinate_type + low(const interval_type& interval, + typename enable_if< typename is_interval_concept::type>::type>::type * = 0 + ) { return get(interval, LOW); } + + // get the high coordinate + template + typename interval_traits::coordinate_type + high(const interval_type& interval, + typename enable_if< typename is_interval_concept::type>::type>::type * = 0 + ) { return get(interval, HIGH); } + + // get the center coordinate + template + typename interval_traits::coordinate_type + center(const interval_type& interval, + typename enable_if< typename is_interval_concept::type>::type>::type * = 0 + ) { return (high(interval) + low(interval))/2; } + + + struct y_i_low : gtl_yes {}; + + // set the low coordinate to v + template + typename enable_if::type>::type>::type, void>::type + low(interval_type& interval, + typename interval_traits::coordinate_type v) { set(interval, LOW, v); } + + struct y_i_high : gtl_yes {}; + + // set the high coordinate to v + template + typename enable_if::type>::type>::type, void>::type + high(interval_type& interval, + typename interval_traits::coordinate_type v) { set(interval, HIGH, v); } + + // get the magnitude of the interval + template + typename interval_difference_type::type + delta(const interval_type& interval, + typename enable_if< typename is_interval_concept::type>::type>::type * = 0 + ) { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference diffT; + return (diffT)high(interval) - (diffT)low(interval); } + + struct y_i_flip : gtl_yes {}; + + // flip this about coordinate + template + typename enable_if::type>::type>::type, interval_type>::type & + flip(interval_type& interval, + typename interval_traits::coordinate_type axis = 0) { + typename interval_traits::coordinate_type newLow, newHigh; + newLow = 2 * axis - high(interval); + newHigh = 2 * axis - low(interval); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_scale_up : gtl_yes {}; + + // scale interval by factor + template + typename enable_if::type>::type>::type, interval_type>::type & + scale_up(interval_type& interval, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename interval_traits::coordinate_type Unit; + Unit newHigh = high(interval) * (Unit)factor; + low(interval, low(interval) * (Unit)factor); + high(interval, (newHigh)); + return interval; + } + + struct y_i_scale_down : gtl_yes {}; + + template + typename enable_if::type>::type>::type, interval_type>::type & + scale_down(interval_type& interval, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename interval_traits::coordinate_type Unit; + typedef typename coordinate_traits::coordinate_distance dt; + Unit newHigh = scaling_policy::round((dt)(high(interval)) / (dt)factor); + low(interval, scaling_policy::round((dt)(low(interval)) / (dt)factor)); + high(interval, (newHigh)); + return interval; + } + + struct y_i_scale : gtl_yes {}; + + template + typename enable_if::type>::type>::type, interval_type>::type & + scale(interval_type& interval, double factor) { + typedef typename interval_traits::coordinate_type Unit; + Unit newHigh = scaling_policy::round((double)(high(interval)) * factor); + low(interval, scaling_policy::round((double)low(interval)* factor)); + high(interval, (newHigh)); + return interval; + } + + // move interval by delta + template + interval_type& + move(interval_type& interval, + typename interval_difference_type::type displacement, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename interval_traits::coordinate_type ctype; + typedef typename coordinate_traits::coordinate_difference Unit; + Unit len = delta(interval); + low(interval, static_cast(static_cast(low(interval)) + displacement)); + high(interval, static_cast(static_cast(low(interval)) + len)); + return interval; + } + + struct y_i_convolve : gtl_yes {}; + + // convolve this with b + template + typename enable_if::type>::type>::type, interval_type>::type & + convolve(interval_type& interval, + typename interval_traits::coordinate_type b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) + b; + Unit newHigh = high(interval) + b; + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_deconvolve : gtl_yes {}; + + // deconvolve this with b + template + typename enable_if::type>::type>::type, interval_type>::type & + deconvolve(interval_type& interval, + typename interval_traits::coordinate_type b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) - b; + Unit newHigh = high(interval) - b; + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_convolve2 : gtl_yes {}; + + // convolve this with b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + interval_type>::type & + convolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) + low(b); + Unit newHigh = high(interval) + high(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_deconvolve2 : gtl_yes {}; + + // deconvolve this with b + template + typename enable_if< + typename gtl_and_3< y_i_deconvolve2, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + interval_type>::type & + deconvolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) - low(b); + Unit newHigh = high(interval) - high(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_reconvolve : gtl_yes {}; + + // reflected convolve this with b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + interval_type>::type & + reflected_convolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) - high(b); + Unit newHigh = high(interval) - low(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_redeconvolve : gtl_yes {}; + + // reflected deconvolve this with b + template + typename enable_if< + typename gtl_and_3< y_i_redeconvolve, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + interval_type>::type & + reflected_deconvolve(interval_type& interval, + const interval_type_2& b) { + typedef typename interval_traits::coordinate_type Unit; + Unit newLow = low(interval) + high(b); + Unit newHigh = high(interval) + low(b); + low(interval, newLow); + high(interval, newHigh); + return interval; + } + + struct y_i_e_dist1 : gtl_yes {}; + + // distance from a coordinate to an interval + template + typename enable_if< typename gtl_and::type>::type>::type, + typename interval_difference_type::type>::type + euclidean_distance(const interval_type& interval, + typename interval_traits::coordinate_type position) { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference Unit; + Unit dist[3] = {0, (Unit)low(interval) - (Unit)position, (Unit)position - (Unit)high(interval)}; + return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; + } + + struct y_i_e_dist2 : gtl_yes {}; + + // distance between two intervals + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + typename interval_difference_type::type>::type + euclidean_distance(const interval_type& interval, + const interval_type_2& b) { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference Unit; + Unit dist[3] = {0, (Unit)low(interval) - (Unit)high(b), (Unit)low(b) - (Unit)high(interval)}; + return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; + } + + struct y_i_e_intersects : gtl_yes {}; + + // check if Interval b intersects `this` Interval + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + intersects(const interval_type& interval, const interval_type_2& b, + bool consider_touch = true) { + return consider_touch ? + (low(interval) <= high(b)) & (high(interval) >= low(b)) : + (low(interval) < high(b)) & (high(interval) > low(b)); + } + + struct y_i_e_bintersect : gtl_yes {}; + + // check if Interval b partially overlaps `this` Interval + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + boundaries_intersect(const interval_type& interval, const interval_type_2& b, + bool consider_touch = true) { + return (contains(interval, low(b), consider_touch) || + contains(interval, high(b), consider_touch)) && + (contains(b, low(interval), consider_touch) || + contains(b, high(interval), consider_touch)); + } + + struct y_i_abuts1 : gtl_yes {}; + + // check if they are end to end + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + abuts(const interval_type& interval, const interval_type_2& b, direction_1d dir) { + return dir.to_int() ? low(b) == high(interval) : low(interval) == high(b); + } + + struct y_i_abuts2 : gtl_yes {}; + + // check if they are end to end + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + abuts(const interval_type& interval, const interval_type_2& b) { + return abuts(interval, b, HIGH) || abuts(interval, b, LOW); + } + + struct y_i_intersect : gtl_yes {}; + + // set 'this' interval to the intersection of 'this' and b + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + intersect(interval_type& interval, const interval_type_2& b, bool consider_touch = true) { + typedef typename interval_traits::coordinate_type Unit; + Unit lowVal = (std::max)(low(interval), low(b)); + Unit highVal = (std::min)(high(interval), high(b)); + bool valid = consider_touch ? + lowVal <= highVal : + lowVal < highVal; + if(valid) { + low(interval, lowVal); + high(interval, highVal); + } + return valid; + } + + struct y_i_g_intersect : gtl_yes {}; + + // set 'this' interval to the generalized intersection of 'this' and b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + interval_type>::type & + generalized_intersect(interval_type& interval, const interval_type_2& b) { + typedef typename interval_traits::coordinate_type Unit; + Unit coords[4] = {low(interval), high(interval), low(b), high(b)}; + //consider implementing faster sorting of small fixed length range + std::sort(coords, coords+4); + low(interval, coords[1]); + high(interval, coords[2]); + return interval; + } + + struct y_i_bloat : gtl_yes {}; + + // bloat the Interval + template + typename enable_if< typename gtl_and::type>::type>::type, + interval_type>::type & + bloat(interval_type& interval, typename interval_traits::coordinate_type bloating) { + low(interval, low(interval)-bloating); + high(interval, high(interval)+bloating); + return interval; + } + + struct y_i_bloat2 : gtl_yes {}; + + // bloat the specified side of `this` Interval + template + typename enable_if< typename gtl_and::type>::type>::type, + interval_type>::type & + bloat(interval_type& interval, direction_1d dir, typename interval_traits::coordinate_type bloating) { + set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); + return interval; + } + + struct y_i_shrink : gtl_yes {}; + + // shrink the Interval + template + typename enable_if< typename gtl_and::type>::type>::type, + interval_type>::type & + shrink(interval_type& interval, typename interval_traits::coordinate_type shrinking) { + return bloat(interval, -shrinking); + } + + struct y_i_shrink2 : gtl_yes {}; + + // shrink the specified side of `this` Interval + template + typename enable_if< typename gtl_and::type>::type>::type, + interval_type>::type & + shrink(interval_type& interval, direction_1d dir, typename interval_traits::coordinate_type shrinking) { + return bloat(interval, dir, -shrinking); + } + + // Enlarge `this` Interval to encompass the specified Interval + template + bool + encompass(interval_type& interval, const interval_type_2& b, + typename enable_if< + typename gtl_and< typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type>::type * = 0 + ) { + bool retval = !contains(interval, b, true); + low(interval, (std::min)(low(interval), low(b))); + high(interval, (std::max)(high(interval), high(b))); + return retval; + } + + struct y_i_encompass : gtl_yes {}; + + // Enlarge `this` Interval to encompass the specified Interval + template + typename enable_if< typename gtl_and::type>::type>::type, + bool>::type + encompass(interval_type& interval, typename interval_traits::coordinate_type b) { + bool retval = !contains(interval, b, true); + low(interval, (std::min)(low(interval), b)); + high(interval, (std::max)(high(interval), b)); + return retval; + } + + struct y_i_get_half : gtl_yes {}; + + // gets the half of the interval as an interval + template + typename enable_if::type>::type>::type, interval_type>::type + get_half(const interval_type& interval, direction_1d d1d) { + typedef typename interval_traits::coordinate_type Unit; + Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; + return construct((d1d == LOW) ? get(interval, LOW) : c, + (d1d == LOW) ? c : get(interval, HIGH)); + } + + struct y_i_join_with : gtl_yes {}; + + // returns true if the 2 intervals exactly touch at one value, like in l1 <= h1 == l2 <= h2 + // sets the argument to the joined interval + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + join_with(interval_type& interval, const interval_type_2& b) { + if(abuts(interval, b)) { + encompass(interval, b); + return true; + } + return false; + } + + template + template + interval_data& interval_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + struct geometry_concept > { + typedef interval_concept type; + }; +} +} +#endif diff --git a/include/boost/polygon/interval_data.hpp b/include/boost/polygon/interval_data.hpp new file mode 100755 index 0000000..cf2aabf --- /dev/null +++ b/include/boost/polygon/interval_data.hpp @@ -0,0 +1,67 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_INTERVAL_DATA_HPP +#define BOOST_POLYGON_INTERVAL_DATA_HPP +#include "isotropy.hpp" +namespace boost { namespace polygon{ + template + class interval_data { + public: + typedef T coordinate_type; + inline interval_data() +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + {} + inline interval_data(coordinate_type low, coordinate_type high) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[LOW] = low; coords_[HIGH] = high; + } + inline interval_data(const interval_data& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + (*this) = that; + } + inline interval_data& operator=(const interval_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + } + template + inline interval_data& operator=(const T2& rvalue); + inline coordinate_type get(direction_1d dir) const { + return coords_[dir.to_int()]; + } + inline coordinate_type low() const { return coords_[0]; } + inline coordinate_type high() const { return coords_[1]; } + inline bool operator==(const interval_data& that) const { + return low() == that.low() && high() == that.high(); } + inline bool operator!=(const interval_data& that) const { + return low() != that.low() || high() != that.high(); } + inline bool operator<(const interval_data& that) const { + if(coords_[0] < that.coords_[0]) return true; + if(coords_[0] > that.coords_[0]) return false; + if(coords_[1] < that.coords_[1]) return true; + return false; + } + inline bool operator<=(const interval_data& that) const { return !(that < *this); } + inline bool operator>(const interval_data& that) const { return that < *this; } + inline bool operator>=(const interval_data& that) const { return !((*this) < that); } + inline void set(direction_1d dir, coordinate_type value) { + coords_[dir.to_int()] = value; + } +private: + coordinate_type coords_[2]; +}; + +} +} +#endif diff --git a/include/boost/polygon/interval_traits.hpp b/include/boost/polygon/interval_traits.hpp new file mode 100755 index 0000000..a7d74ef --- /dev/null +++ b/include/boost/polygon/interval_traits.hpp @@ -0,0 +1,33 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_INTERVAL_TRAITS_HPP +#define BOOST_POLYGON_INTERVAL_TRAITS_HPP +namespace boost { namespace polygon{ + template + struct interval_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& interval, direction_1d dir) { + return interval.get(dir); + } + }; + + template + struct interval_mutable_traits { + static inline void set(T& interval, direction_1d dir, typename interval_traits::coordinate_type value) { + interval.set(dir, value); + } + static inline T construct(typename interval_traits::coordinate_type low_value, + typename interval_traits::coordinate_type high_value) { + return T(low_value, high_value); + } + }; +} +} +#endif + diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp new file mode 100755 index 0000000..1323cfd --- /dev/null +++ b/include/boost/polygon/isotropy.hpp @@ -0,0 +1,542 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ + +#ifndef BOOST_POLYGON_ISOTROPY_HPP +#define BOOST_POLYGON_ISOTROPY_HPP + +//external +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifndef BOOST_POLYGON_NO_DEPS + +#include +#ifdef BOOST_MSVC +#define BOOST_POLYGON_MSVC +#endif +#ifdef BOOST_INTEL +#define BOOST_POLYGON_ICC +#endif +#ifdef BOOST_HAS_LONG_LONG +#define BOOST_POLYGON_USE_LONG_LONG +typedef boost::long_long_type polygon_long_long_type; +typedef boost::ulong_long_type polygon_ulong_long_type; +//typedef long long polygon_long_long_type; +//typedef unsigned long long polygon_ulong_long_type; +#endif +#include +#include +#include +#include +#include +#include +#else + +#ifdef WIN32 +#define BOOST_POLYGON_MSVC +#endif +#ifdef __ICC +#define BOOST_POLYGON_ICC +#endif +#define BOOST_POLYGON_USE_LONG_LONG +typedef long long polygon_long_long_type; +typedef unsigned long long polygon_ulong_long_type; + + namespace boost { + template + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; + + template + struct lazy_enable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_enable_if_c {}; + + template + struct lazy_enable_if : public lazy_enable_if_c {}; + + + template + struct disable_if_c { + typedef T type; + }; + + template + struct disable_if_c {}; + + template + struct disable_if : public disable_if_c {}; + + template + struct lazy_disable_if_c { + typedef typename T::type type; + }; + + template + struct lazy_disable_if_c {}; + + template + struct lazy_disable_if : public lazy_disable_if_c {}; + } + +#endif + +namespace boost { namespace polygon{ + + enum GEOMETRY_CONCEPT_ID { + COORDINATE_CONCEPT, + INTERVAL_CONCEPT, + POINT_CONCEPT, + POINT_3D_CONCEPT, + RECTANGLE_CONCEPT, + POLYGON_90_CONCEPT, + POLYGON_90_WITH_HOLES_CONCEPT, + POLYGON_45_CONCEPT, + POLYGON_45_WITH_HOLES_CONCEPT, + POLYGON_CONCEPT, + POLYGON_WITH_HOLES_CONCEPT, + POLYGON_90_SET_CONCEPT, + POLYGON_45_SET_CONCEPT, + POLYGON_SET_CONCEPT + }; + + struct undefined_concept {}; + + template + struct geometry_concept { typedef undefined_concept type; }; + + template + struct view_of {}; + + template + view_of view_as(const T2& obj) { return view_of(obj); } + + template + struct coordinate_traits {}; + + template + struct high_precision_type { + typedef long double type; + }; + + template + T convert_high_precision_type(const typename high_precision_type::type& v) { + return T(v); + } + + template <> + struct coordinate_traits { + typedef int coordinate_type; + typedef long double area_type; +#ifdef BOOST_POLYGON_USE_LONG_LONG + typedef polygon_long_long_type manhattan_area_type; + typedef polygon_ulong_long_type unsigned_area_type; + typedef polygon_long_long_type coordinate_difference; +#else + typedef long manhattan_area_type; + typedef unsigned long unsigned_area_type; + typedef long coordinate_difference; +#endif + typedef long double coordinate_distance; + }; + +#ifdef BOOST_POLYGON_USE_LONG_LONG + template <> + struct coordinate_traits { + typedef polygon_long_long_type coordinate_type; + typedef long double area_type; + typedef polygon_long_long_type manhattan_area_type; + typedef polygon_ulong_long_type unsigned_area_type; + typedef polygon_long_long_type coordinate_difference; + typedef long double coordinate_distance; + }; +#endif + + template <> + struct coordinate_traits { + typedef float coordinate_type; + typedef float area_type; + typedef float manhattan_area_type; + typedef float unsigned_area_type; + typedef float coordinate_difference; + typedef float coordinate_distance; + }; + + template <> + struct coordinate_traits { + typedef double coordinate_type; + typedef double area_type; + typedef double manhattan_area_type; + typedef double unsigned_area_type; + typedef double coordinate_difference; + typedef double coordinate_distance; + }; + + template + struct scaling_policy { + template + static inline T round(T2 t2) { + return (T)std::floor(t2+0.5); + } + + static inline T round(T t2) { + return t2; + } + }; + + struct coordinate_concept {}; + + template <> + struct geometry_concept { typedef coordinate_concept type; }; +#ifdef BOOST_POLYGON_USE_LONG_LONG + template <> + struct geometry_concept { typedef coordinate_concept type; }; +#endif + template <> + struct geometry_concept { typedef coordinate_concept type; }; + template <> + struct geometry_concept { typedef coordinate_concept type; }; + +#ifndef BOOST_POLYGON_NO_DEPS + struct gtl_no : mpl::bool_ {}; + struct gtl_yes : mpl::bool_ {}; + template + struct gtl_and : mpl::and_ {}; + template + struct gtl_and_3 : mpl::and_ {}; + template + struct gtl_and_4 : mpl::and_ {}; +// template +// struct gtl_or : mpl::or_ {}; +// template +// struct gtl_or_3 : mpl::or_ {}; +// template +// struct gtl_or_4 : mpl::or_ {}; +#else + struct gtl_no { static const bool value = false; }; + struct gtl_yes { typedef gtl_yes type; + static const bool value = true; }; + + template + struct gtl_and_c { typedef gtl_no type; }; + template <> + struct gtl_and_c { typedef gtl_yes type; }; + + template + struct gtl_and : gtl_and_c {}; + template + struct gtl_and_3 { typedef typename gtl_and< + T, typename gtl_and::type>::type type; }; + + template + struct gtl_and_4 { typedef typename gtl_and_3< + T, T2, typename gtl_and::type>::type type; }; +#endif + template + struct gtl_or { typedef gtl_yes type; }; + template + struct gtl_or { typedef T type; }; + + template + struct gtl_or_3 { typedef typename gtl_or< + T, typename gtl_or::type>::type type; }; + + template + struct gtl_or_4 { typedef typename gtl_or< + T, typename gtl_or_3::type>::type type; }; + + template + struct gtl_not { typedef gtl_no type; }; + template <> + struct gtl_not { typedef gtl_yes type; }; + + template + struct gtl_if { +#ifdef WIN32 + typedef gtl_no type; +#endif + }; + template <> + struct gtl_if { typedef gtl_yes type; }; + + template + struct gtl_same_type { typedef gtl_no type; }; + template + struct gtl_same_type { typedef gtl_yes type; }; + template + struct gtl_different_type { typedef typename gtl_not::type>::type type; }; + + struct manhattan_domain {}; + struct forty_five_domain {}; + struct general_domain {}; + + template + struct geometry_domain { typedef general_domain type; }; + + template + struct area_type_by_domain { typedef typename coordinate_traits::area_type type; }; + template + struct area_type_by_domain { + typedef typename coordinate_traits::manhattan_area_type type; }; + + struct y_c_edist : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type, coordinate_concept>::type, + typename gtl_same_type::type, coordinate_concept>::type>::type, + typename coordinate_traits::coordinate_difference>::type + euclidean_distance(const coordinate_type_1& lvalue, const coordinate_type_2& rvalue) { + typedef typename coordinate_traits::coordinate_difference Unit; + return (lvalue < rvalue) ? (Unit)rvalue - (Unit)lvalue : (Unit)lvalue - (Unit)rvalue; + } + + + + // predicated_swap swaps a and b if pred is true + + // predicated_swap is guarenteed to behave the same as + // if(pred){ + // T tmp = a; + // a = b; + // b = tmp; + // } + // but will not generate a branch instruction. + // predicated_swap always creates a temp copy of a, but does not + // create more than one temp copy of an input. + // predicated_swap can be used to optimize away branch instructions in C++ + template + inline bool predicated_swap(const bool& pred, + T& a, + T& b) { + const T tmp = a; + const T* input[2] = {&b, &tmp}; + a = *input[!pred]; + b = *input[pred]; + return pred; + } + + enum direction_1d_enum { LOW = 0, HIGH = 1, + LEFT = 0, RIGHT = 1, + CLOCKWISE = 0, COUNTERCLOCKWISE = 1, + REVERSE = 0, FORWARD = 1, + NEGATIVE = 0, POSITIVE = 1 }; + enum orientation_2d_enum { HORIZONTAL = 0, VERTICAL = 1 }; + enum direction_2d_enum { WEST = 0, EAST = 1, SOUTH = 2, NORTH = 3 }; + enum orientation_3d_enum { PROXIMAL = 2 }; + enum direction_3d_enum { DOWN = 4, UP = 5 }; + enum winding_direction { + clockwise_winding = 0, + counterclockwise_winding = 1, + unknown_winding = 2 + }; + + class direction_2d; + class direction_3d; + class orientation_2d; + + class direction_1d { + private: + unsigned int val_; + explicit direction_1d(int d); + public: + inline direction_1d() : val_(LOW) {} + inline direction_1d(const direction_1d& that) : val_(that.val_) {} + inline direction_1d(const direction_1d_enum val) : val_(val) {} + explicit inline direction_1d(const direction_2d& that); + explicit inline direction_1d(const direction_3d& that); + inline direction_1d& operator = (const direction_1d& d) { + val_ = d.val_; return * this; } + inline bool operator==(direction_1d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_1d d) const { return !((*this) == d); } + inline unsigned int to_int(void) const { return val_; } + inline direction_1d& backward() { val_ ^= 1; return *this; } + inline int get_sign() const { return val_ * 2 - 1; } + }; + + class direction_2d; + + class orientation_2d { + private: + unsigned int val_; + explicit inline orientation_2d(int o); + public: + inline orientation_2d() : val_(HORIZONTAL) {} + inline orientation_2d(const orientation_2d& ori) : val_(ori.val_) {} + inline orientation_2d(const orientation_2d_enum val) : val_(val) {} + explicit inline orientation_2d(const direction_2d& that); + inline orientation_2d& operator=(const orientation_2d& ori) { + val_ = ori.val_; return * this; } + inline bool operator==(orientation_2d that) const { return (val_ == that.val_); } + inline bool operator!=(orientation_2d that) const { return (val_ != that.val_); } + inline unsigned int to_int() const { return (val_); } + inline void turn_90() { val_ = val_^ 1; } + inline orientation_2d get_perpendicular() const { + orientation_2d retval = *this; + retval.turn_90(); + return retval; + } + inline direction_2d get_direction(direction_1d dir) const; + }; + + class direction_2d { + private: + int val_; + + public: + + inline direction_2d() : val_(WEST) {} + + inline direction_2d(const direction_2d& that) : val_(that.val_) {} + + inline direction_2d(const direction_2d_enum val) : val_(val) {} + + inline direction_2d& operator=(const direction_2d& d) { + val_ = d.val_; + return * this; + } + + inline ~direction_2d() { } + + inline bool operator==(direction_2d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_2d d) const { return !((*this) == d); } + inline bool operator< (direction_2d d) const { return (val_ < d.val_); } + inline bool operator<=(direction_2d d) const { return (val_ <= d.val_); } + inline bool operator> (direction_2d d) const { return (val_ > d.val_); } + inline bool operator>=(direction_2d d) const { return (val_ >= d.val_); } + + // Casting to int + inline unsigned int to_int(void) const { return val_; } + + inline direction_2d backward() const { + // flip the LSB, toggles 0 - 1 and 2 - 3 + return direction_2d(direction_2d_enum(val_ ^ 1)); + } + + // Returns a direction 90 degree left (LOW) or right(HIGH) to this one + inline direction_2d turn(direction_1d t) const { + return direction_2d(direction_2d_enum(val_ ^ 3 ^ (val_ >> 1) ^ t.to_int())); + } + + // Returns a direction 90 degree left to this one + inline direction_2d left() const {return turn(HIGH);} + + // Returns a direction 90 degree right to this one + inline direction_2d right() const {return turn(LOW);} + + // N, E are positive, S, W are negative + inline bool is_positive() const {return (val_ & 1);} + inline bool is_negative() const {return !is_positive();} + inline int get_sign() const {return ((is_positive()) << 1) -1;} + + }; + + direction_1d::direction_1d(const direction_2d& that) : val_(that.to_int() & 1) {} + + orientation_2d::orientation_2d(const direction_2d& that) : val_(that.to_int() >> 1) {} + + direction_2d orientation_2d::get_direction(direction_1d dir) const { + return direction_2d(direction_2d_enum((val_ << 1) + dir.to_int())); + } + + class orientation_3d { + private: + unsigned int val_; + explicit inline orientation_3d(int o); + public: + inline orientation_3d() : val_((int)HORIZONTAL) {} + inline orientation_3d(const orientation_3d& ori) : val_(ori.val_) {} + inline orientation_3d(orientation_2d ori) : val_(ori.to_int()) {} + inline orientation_3d(const orientation_3d_enum val) : val_(val) {} + explicit inline orientation_3d(const direction_2d& that); + explicit inline orientation_3d(const direction_3d& that); + inline ~orientation_3d() { } + inline orientation_3d& operator=(const orientation_3d& ori) { + val_ = ori.val_; return * this; } + inline bool operator==(orientation_3d that) const { return (val_ == that.val_); } + inline bool operator!=(orientation_3d that) const { return (val_ != that.val_); } + inline unsigned int to_int() const { return (val_); } + inline direction_3d get_direction(direction_1d dir) const; + }; + + class direction_3d { + private: + int val_; + + public: + + inline direction_3d() : val_(WEST) {} + + inline direction_3d(direction_2d that) : val_(that.to_int()) {} + inline direction_3d(const direction_3d& that) : val_(that.val_) {} + + inline direction_3d(const direction_2d_enum val) : val_(val) {} + inline direction_3d(const direction_3d_enum val) : val_(val) {} + + inline direction_3d& operator=(direction_3d d) { + val_ = d.val_; + return * this; + } + + inline ~direction_3d() { } + + inline bool operator==(direction_3d d) const { return (val_ == d.val_); } + inline bool operator!=(direction_3d d) const { return !((*this) == d); } + inline bool operator< (direction_3d d) const { return (val_ < d.val_); } + inline bool operator<=(direction_3d d) const { return (val_ <= d.val_); } + inline bool operator> (direction_3d d) const { return (val_ > d.val_); } + inline bool operator>=(direction_3d d) const { return (val_ >= d.val_); } + + // Casting to int + inline unsigned int to_int(void) const { return val_; } + + inline direction_3d backward() const { + // flip the LSB, toggles 0 - 1 and 2 - 3 and 4 - 5 + return direction_2d(direction_2d_enum(val_ ^ 1)); + } + + // N, E, U are positive, S, W, D are negative + inline bool is_positive() const {return (val_ & 1);} + inline bool is_negative() const {return !is_positive();} + inline int get_sign() const {return ((is_positive()) << 1) -1;} + + }; + + direction_1d::direction_1d(const direction_3d& that) : val_(that.to_int() & 1) {} + orientation_3d::orientation_3d(const direction_3d& that) : val_(that.to_int() >> 1) {} + orientation_3d::orientation_3d(const direction_2d& that) : val_(that.to_int() >> 1) {} + + direction_3d orientation_3d::get_direction(direction_1d dir) const { + return direction_3d(direction_3d_enum((val_ << 1) + dir.to_int())); + } + +} +} +#endif + diff --git a/include/boost/polygon/point_3d_concept.hpp b/include/boost/polygon/point_3d_concept.hpp new file mode 100755 index 0000000..ab7afeb --- /dev/null +++ b/include/boost/polygon/point_3d_concept.hpp @@ -0,0 +1,270 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef GLT_POINT_3D_CONCEPT_HPP +#define GLT_POINT_3D_CONCEPT_HPP +#include "point_concept.hpp" +#include "point_3d_data.hpp" +#include "point_3d_traits.hpp" +namespace boost { namespace polygon{ + struct point_3d_concept {}; + + template + struct is_point_3d_concept { typedef gtl_no type; }; + template <> + struct is_point_3d_concept { typedef gtl_yes type; }; + //template <> + //struct is_point_concept { typedef void type; }; + + template + struct is_mutable_point_3d_concept { typedef gtl_no type; }; + template <> + struct is_mutable_point_3d_concept { typedef gtl_yes type; }; + + template + struct point_3d_coordinate_type_by_concept { typedef void type; }; + template + struct point_3d_coordinate_type_by_concept { typedef typename point_3d_traits::coordinate_type type; }; + + template + struct point_3d_coordinate_type { + typedef typename point_3d_coordinate_type_by_concept::type>::type>::type type; + }; + + template + struct point_3d_difference_type_by_concept { typedef void type; }; + template + struct point_3d_difference_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + + template + struct point_3d_difference_type { + typedef typename point_3d_difference_type_by_concept< + T, typename is_point_3d_concept::type>::type>::type type; + }; + + template + struct point_3d_distance_type_by_concept { typedef void type; }; + template + struct point_3d_distance_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + + template + struct point_3d_distance_type { + typedef typename point_3d_distance_type_by_concept< + T, typename is_point_3d_concept::type>::type>::type type; + }; + + struct y_p3d_get : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename point_3d_coordinate_type::type >::type + get(const T& point, orientation_3d orient) { return point_3d_traits::get(point, orient); } + + struct y_p3d_set : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, void>::type + set(T& point, orientation_3d orient, coordinate_type value) { point_3d_mutable_traits::set(point, orient, value); } + + struct y_p3d_set2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, void>::type + set(T& point, orientation_2d orient, coordinate_type value) { point_3d_mutable_traits::set(point, orient, value); } + + struct y_p3d_construct : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, T>::type + construct(coordinate_type1 x_value, coordinate_type2 y_value, coordinate_type3 z_value) { + return point_3d_mutable_traits::construct(x_value, y_value, z_value); } + + struct y_p3d_assign : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_point_3d_concept::type>::type>::type, + point_3d_type_1>::type & + assign(point_3d_type_1& lvalue, const point_3d_type_2& rvalue) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + set(lvalue, PROXIMAL, get(rvalue, PROXIMAL)); + return lvalue; + } + + struct y_p3d_z : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + typename point_3d_traits::coordinate_type >::type + z(const point_type& point) { return get(point, PROXIMAL); } + + struct y_p3d_x : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, void>::type + x(point_type& point, coordinate_type value) { set(point, HORIZONTAL, value); } + + struct y_p3d_y : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, void>::type + y(point_type& point, coordinate_type value) { set(point, VERTICAL, value); } + + struct y_p3d_z2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, void>::type + z(point_type& point, coordinate_type value) { set(point, PROXIMAL, value); } + + struct y_p3d_equiv : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename gtl_same_type::type>::type>::type, + bool>::type + equivalence(const T& point1, const T2& point2) { + return x(point1) == x(point2) && y(point1) == y(point2) && z(point1) == z(point2); + } + + struct y_p3d_dist : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_3d_concept::type>::type>::type, + typename point_3d_difference_type::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_3d orient) { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference return_type; + return_type return_value = + (return_type)get(point1, orient) - (return_type)get(point2, orient); + return return_value < 0 ? -return_value : return_value; + } + + struct y_p3d_man_dist : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type>::type>::type, + typename point_3d_difference_type::type>::type + manhattan_distance(const point_type_1& point1, const point_type_2& point2) { + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL) + + euclidean_distance(point1, point2, PROXIMAL); + } + + struct y_p3d_dist2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_p3d_dist2, + typename gtl_same_type::type>::type, + typename gtl_same_type::type>::type>::type, + typename point_3d_distance_type::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2) { + typedef typename coordinate_traits::coordinate_type>::coordinate_distance return_value; + return_value pdist = (return_value)euclidean_distance(point1, point2, PROXIMAL); + pdist *= pdist; + return sqrt((double)(distance_squared(point1, point2) + pdist)); + } + + struct y_p3d_convolve : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_p3d_convolve, + typename is_mutable_point_3d_concept::type>::type, + typename gtl_same_type::type>::type>::type, + point_type_1>::type & + convolve(point_type_1& lvalue, const point_type_2& rvalue) { + x(lvalue, x(lvalue) + x(rvalue)); + y(lvalue, y(lvalue) + y(rvalue)); + z(lvalue, z(lvalue) + z(rvalue)); + return lvalue; + } + + struct y_p3d_deconvolve : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename gtl_same_type::type>::type>::type, + point_type_1>::type & + deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { + x(lvalue, x(lvalue) - x(rvalue)); + y(lvalue, y(lvalue) - y(rvalue)); + z(lvalue, z(lvalue) - z(rvalue)); + return lvalue; + } + + struct y_p3d_scale_up : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale_up(point_type& point, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + x(point, x(point) * (typename point_3d_traits::coordinate_type)factor); + y(point, y(point) * (typename point_3d_traits::coordinate_type)factor); + z(point, z(point) * (typename point_3d_traits::coordinate_type)factor); + return point; + } + + struct y_p3d_scale_down : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale_down(point_type& point, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename point_3d_traits::coordinate_type Unit; + typedef typename coordinate_traits::coordinate_distance dt; + x(point, scaling_policy::round((dt)(x(point)) / (dt)factor)); + y(point, scaling_policy::round((dt)(y(point)) / (dt)factor)); + z(point, scaling_policy::round((dt)(z(point)) / (dt)factor)); + return point; + } + + struct y_p3d_scale : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale(point_type& point, + const scaling_type& scaling) { + typedef typename point_3d_traits::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)), z_(z(point)); + scaling.scale(x_, y_, z_); + x(point, x_); + y(point, y_); + z(point, z_); + return point; + } + + struct y_p3d_transform : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + transform(point_type& point, const transformation_type& transformation) { + typedef typename point_3d_traits::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)), z_(z(point)); + transformation.transform(x_, y_, z_); + x(point, x_); + y(point, y_); + z(point, z_); + return point; + } + + template + struct geometry_concept > { + typedef point_3d_concept type; + }; +} +} +#endif + diff --git a/include/boost/polygon/point_3d_data.hpp b/include/boost/polygon/point_3d_data.hpp new file mode 100755 index 0000000..c57097c --- /dev/null +++ b/include/boost/polygon/point_3d_data.hpp @@ -0,0 +1,51 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POINT_3D_DATA_HPP +#define BOOST_POLYGON_POINT_3D_DATA_HPP +namespace boost { namespace polygon{ + template + class point_3d_data { + public: + typedef T coordinate_type; + inline point_3d_data():coords_(){} + inline point_3d_data(coordinate_type x, coordinate_type y):coords_() { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = 0; } + inline point_3d_data(coordinate_type x, coordinate_type y, coordinate_type z) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = z; } + inline point_3d_data(const point_3d_data& that):coords_() { (*this) = that; } + inline point_3d_data& operator=(const point_3d_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; + coords_[2] = that.coords_[2]; return *this; } + template + inline point_3d_data& operator=(const T2& rvalue); + inline bool operator==(const point_3d_data& that) const { + return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1] && coords_[2] == that.coords_[2]; + } + inline bool operator!=(const point_3d_data& that) const { + return !((*this) == that); + } + inline coordinate_type get(orientation_2d orient) const { + return coords_[orient.to_int()]; } + inline coordinate_type get(orientation_3d orient) const { + return coords_[orient.to_int()]; } + inline void set(orientation_2d orient, coordinate_type value) { + coords_[orient.to_int()] = value; } + inline void set(orientation_3d orient, coordinate_type value) { + coords_[orient.to_int()] = value; } + private: + coordinate_type coords_[3]; + }; +} +} +#endif + + diff --git a/include/boost/polygon/point_3d_traits.hpp b/include/boost/polygon/point_3d_traits.hpp new file mode 100755 index 0000000..9f6eb9a --- /dev/null +++ b/include/boost/polygon/point_3d_traits.hpp @@ -0,0 +1,35 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POINT_3D_TRAITS_HPP +#define BOOST_POLYGON_POINT_3D_TRAITS_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + template + struct point_3d_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& point, orientation_3d orient) { + return point.get(orient); } + }; + + template + struct point_3d_mutable_traits { + static inline void set(T& point, orientation_3d orient, typename point_3d_traits::coordinate_type value) { + point.set(orient, value); } + + static inline T construct(typename point_3d_traits::coordinate_type x_value, + typename point_3d_traits::coordinate_type y_value, + typename point_3d_traits::coordinate_type z_value) { + return T(x_value, y_value, z_value); } + }; +} +} +#endif + diff --git a/include/boost/polygon/point_concept.hpp b/include/boost/polygon/point_concept.hpp new file mode 100755 index 0000000..6e2ce0a --- /dev/null +++ b/include/boost/polygon/point_concept.hpp @@ -0,0 +1,298 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POINT_CONCEPT_HPP +#define BOOST_POLYGON_POINT_CONCEPT_HPP +#include "isotropy.hpp" +#include "point_data.hpp" +#include "point_traits.hpp" + +namespace boost { namespace polygon{ + struct point_concept {}; + + template + struct is_point_concept { typedef gtl_no type; }; + template <> + struct is_point_concept { typedef gtl_yes type; }; + + struct point_3d_concept; + template <> + struct is_point_concept { typedef gtl_yes type; }; + + template + struct is_mutable_point_concept { typedef gtl_no type; }; + template <> + struct is_mutable_point_concept { typedef gtl_yes type; }; + + template + struct point_coordinate_type_by_concept { typedef void type; }; + template + struct point_coordinate_type_by_concept { typedef typename point_traits::coordinate_type type; }; + + template + struct point_coordinate_type { + typedef typename point_coordinate_type_by_concept::type>::type>::type type; + }; + + template + struct point_difference_type_by_concept { typedef void type; }; + template + struct point_difference_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + + template + struct point_difference_type { + typedef typename point_difference_type_by_concept< + T, typename is_point_concept::type>::type>::type type; + }; + + template + struct point_distance_type_by_concept { typedef void type; }; + template + struct point_distance_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + + template + struct point_distance_type { + typedef typename point_distance_type_by_concept< + T, typename is_point_concept::type>::type>::type type; + }; + + template + typename point_coordinate_type::type + get(const T& point, orientation_2d orient, + typename enable_if< typename gtl_if::type>::type>::type>::type * = 0 + ) { + return point_traits::get(point, orient); + } + + template + void + set(T& point, orientation_2d orient, coordinate_type value, + typename enable_if::type>::type>::type * = 0 + ) { + point_mutable_traits::set(point, orient, value); + } + + template + T + construct(coordinate_type1 x_value, coordinate_type2 y_value, + typename enable_if::type>::type>::type * = 0 + ) { + return point_mutable_traits::construct(x_value, y_value); + } + + template + T1& + assign(T1& lvalue, const T2& rvalue, + typename enable_if< typename gtl_and< typename is_mutable_point_concept::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + return lvalue; + } + + struct y_p_x : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + typename point_traits::coordinate_type >::type + x(const point_type& point) { + return get(point, HORIZONTAL); + } + + struct y_p_y : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + typename point_traits::coordinate_type >::type + y(const point_type& point) { + return get(point, VERTICAL); + } + + struct y_p_sx : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + void>::type + x(point_type& point, coordinate_type value) { + set(point, HORIZONTAL, value); + } + + struct y_p_sy : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + void>::type + y(point_type& point, coordinate_type value) { + set(point, VERTICAL, value); + } + + template + bool + equivalence(const T& point1, const T2& point2, + typename enable_if< typename gtl_and::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + typename point_traits::coordinate_type x1 = x(point1); + typename point_traits::coordinate_type x2 = get(point2, HORIZONTAL); + typename point_traits::coordinate_type y1 = get(point1, VERTICAL); + typename point_traits::coordinate_type y2 = y(point2); + return x1 == x2 && y1 == y2; + } + + template + typename point_difference_type::type + manhattan_distance(const point_type_1& point1, const point_type_2& point2, + typename enable_if< typename gtl_and::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0) { + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); + } + + struct y_i_ed1 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + typename point_difference_type::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_2d orient) { + typename coordinate_traits::coordinate_type>::coordinate_difference return_value = + get(point1, orient) - get(point2, orient); + return return_value < 0 ? (typename coordinate_traits::coordinate_type>::coordinate_difference)-return_value : return_value; + } + + struct y_i_ed2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type>::type>::type, + typename point_distance_type::type>::type + euclidean_distance(const point_type_1& point1, const point_type_2& point2) { + typedef typename point_traits::coordinate_type Unit; + return sqrt((double)(distance_squared(point1, point2))); + } + + template + typename point_difference_type::type + distance_squared(const point_type_1& point1, const point_type_2& point2, + typename enable_if< typename gtl_and::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + typename coordinate_traits::coordinate_difference dx = euclidean_distance(point1, point2, HORIZONTAL); + typename coordinate_traits::coordinate_difference dy = euclidean_distance(point1, point2, VERTICAL); + dx *= dx; + dy *= dy; + return dx + dy; + } + + template + point_type_1 & + convolve(point_type_1& lvalue, const point_type_2& rvalue, + typename enable_if< typename gtl_and::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + x(lvalue, x(lvalue) + x(rvalue)); + y(lvalue, y(lvalue) + y(rvalue)); + return lvalue; + } + + template + point_type_1 & + deconvolve(point_type_1& lvalue, const point_type_2& rvalue, + typename enable_if< typename gtl_and::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + x(lvalue, x(lvalue) - x(rvalue)); + y(lvalue, y(lvalue) - y(rvalue)); + return lvalue; + } + + template + point_type & + scale_up(point_type& point, coord_type factor, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + x(point, x(point) * (Unit)factor); + y(point, y(point) * (Unit)factor); + return point; + } + + template + point_type & + scale_down(point_type& point, coord_type factor, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + typedef typename coordinate_traits::coordinate_distance dt; + x(point, scaling_policy::round((dt)((dt)(x(point)) / (dt)factor))); + y(point, scaling_policy::round((dt)((dt)(y(point)) / (dt)factor))); + return point; + } + + template + point_type & + scale(point_type& point, + const scaling_type& scaling, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)); + scaling.scale(x_, y_); + x(point, x_); + y(point, y_); + return point; + } + + template + point_type & + transform(point_type& point, const transformation_type& transformation, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + Unit x_(x(point)), y_(y(point)); + transformation.transform(x_, y_); + x(point, x_); + y(point, y_); + return point; + } + + struct y_pt_move : gtl_yes {}; + + template + typename enable_if< + typename gtl_and< y_pt_move, + typename is_mutable_point_concept< + typename geometry_concept::type>::type>::type, + point_type>::type & + move(point_type& point, orientation_2d orient, + typename point_traits::coordinate_type displacement, + typename enable_if::type>::type>::type * = 0 + ) { + typedef typename point_traits::coordinate_type Unit; + Unit v(get(point, orient)); + set(point, orient, v + displacement); + return point; + } + + template + template + point_data& point_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + struct geometry_concept > { + typedef point_concept type; + }; +} +} +#endif + diff --git a/include/boost/polygon/point_data.hpp b/include/boost/polygon/point_data.hpp new file mode 100755 index 0000000..d181b03 --- /dev/null +++ b/include/boost/polygon/point_data.hpp @@ -0,0 +1,105 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef GTLPOINT_DATA_HPP +#define GTLPOINT_DATA_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + + template + class point_data { + public: + typedef T coordinate_type; + inline point_data() +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + {} + inline point_data(coordinate_type x, coordinate_type y) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; + } + inline point_data(const point_data& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { (*this) = that; } + template + point_data(const other& that) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { (*this) = that; } + inline point_data& operator=(const point_data& that) { + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + } + template + inline point_data(const T1& x, const T2& y) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = (coordinate_type)x; + coords_[VERTICAL] = (coordinate_type)y; + } + template + inline point_data(const point_data& rvalue) +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + { + coords_[HORIZONTAL] = (coordinate_type)(rvalue.x()); + coords_[VERTICAL] = (coordinate_type)(rvalue.y()); + } + template + inline point_data& operator=(const T2& rvalue); + inline bool operator==(const point_data& that) const { + return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1]; + } + inline bool operator!=(const point_data& that) const { + return !((*this) == that); + } + inline bool operator<(const point_data& that) const { + return coords_[0] < that.coords_[0] || + (coords_[0] == that.coords_[0] && coords_[1] < that.coords_[1]); + } + inline bool operator<=(const point_data& that) const { return !(that < *this); } + inline bool operator>(const point_data& that) const { return that < *this; } + inline bool operator>=(const point_data& that) const { return !((*this) < that); } + inline coordinate_type get(orientation_2d orient) const { + return coords_[orient.to_int()]; + } + inline void set(orientation_2d orient, coordinate_type value) { + coords_[orient.to_int()] = value; + } + inline coordinate_type x() const { + return coords_[HORIZONTAL]; + } + inline coordinate_type y() const { + return coords_[VERTICAL]; + } + inline point_data& x(coordinate_type value) { + coords_[HORIZONTAL] = value; + return *this; + } + inline point_data& y(coordinate_type value) { + coords_[VERTICAL] = value; + return *this; + } + private: + coordinate_type coords_[2]; + }; + +} +} +#endif + diff --git a/include/boost/polygon/point_traits.hpp b/include/boost/polygon/point_traits.hpp new file mode 100755 index 0000000..504fa35 --- /dev/null +++ b/include/boost/polygon/point_traits.hpp @@ -0,0 +1,35 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POINT_TRAITS_HPP +#define BOOST_POLYGON_POINT_TRAITS_HPP + +#include "isotropy.hpp" + +namespace boost { namespace polygon{ + template + struct point_traits { + typedef typename T::coordinate_type coordinate_type; + + static inline coordinate_type get(const T& point, orientation_2d orient) { + return point.get(orient); + } + }; + + template + struct point_mutable_traits { + static inline void set(T& point, orientation_2d orient, typename point_traits::coordinate_type value) { + point.set(orient, value); + } + static inline T construct(typename point_traits::coordinate_type x_value, typename point_traits::coordinate_type y_value) { + return T(x_value, y_value); + } + }; +} +} +#endif + diff --git a/include/boost/polygon/polygon.hpp b/include/boost/polygon/polygon.hpp new file mode 100755 index 0000000..0c1594f --- /dev/null +++ b/include/boost/polygon/polygon.hpp @@ -0,0 +1,90 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_HPP +#define BOOST_POLYGON_POLYGON_HPP + +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//point 3d +#include "point_3d_data.hpp" +#include "point_3d_traits.hpp" +#include "point_3d_concept.hpp" + +#include "transform.hpp" +#include "detail/transform_detail.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +//rectangle +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" +#include "rectangle_concept.hpp" + +//algorithms needed by polygon types +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" + +//polygons +#include "polygon_45_data.hpp" +#include "polygon_data.hpp" +#include "polygon_90_data.hpp" +#include "polygon_90_with_holes_data.hpp" +#include "polygon_45_with_holes_data.hpp" +#include "polygon_with_holes_data.hpp" +#include "polygon_traits.hpp" + +//manhattan boolean algorithms +#include "detail/boolean_op.hpp" +#include "detail/polygon_formation.hpp" +#include "detail/rectangle_formation.hpp" +#include "detail/max_cover.hpp" +#include "detail/property_merge.hpp" +#include "detail/polygon_90_touch.hpp" +#include "detail/iterator_geometry_to_set.hpp" + +//45 boolean op algorithms +#include "detail/boolean_op_45.hpp" +#include "detail/polygon_45_formation.hpp" + +//polygon set data types +#include "polygon_90_set_data.hpp" +//polygon set trait types +#include "polygon_90_set_traits.hpp" +//polygon set concepts +#include "polygon_90_set_concept.hpp" +//boolean operator syntax +#include "detail/polygon_90_set_view.hpp" + +//45 boolean op algorithms +#include "detail/polygon_45_touch.hpp" +#include "detail/property_merge_45.hpp" +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_traits.hpp" +#include "polygon_45_set_concept.hpp" +#include "detail/polygon_45_set_view.hpp" + +//arbitrary polygon algorithms +#include "detail/polygon_arbitrary_formation.hpp" +#include "polygon_set_data.hpp" + +//general scanline +#include "detail/scan_arbitrary.hpp" +#include "polygon_set_traits.hpp" +#include "detail/polygon_set_view.hpp" + +#include "polygon_set_concept.hpp" + +#endif diff --git a/include/boost/polygon/polygon_45_data.hpp b/include/boost/polygon/polygon_45_data.hpp new file mode 100755 index 0000000..86753ec --- /dev/null +++ b/include/boost/polygon/polygon_45_data.hpp @@ -0,0 +1,73 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_DATA_HPP +#include "isotropy.hpp" +namespace boost { namespace polygon{ +struct polygon_45_concept; +template class polygon_data; +template +class polygon_45_data { +public: + typedef polygon_45_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector >::const_iterator iterator_type; + typedef typename coordinate_traits::coordinate_distance area_type; + typedef point_data point_type; + + inline polygon_45_data() : coords_() {} //do nothing default constructor + + template + inline polygon_45_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} + + template + inline polygon_45_data& set(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + coords_.insert(coords_.end(), input_begin, input_end); + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_45_data(const polygon_45_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_45_data& operator=(const polygon_45_data& that) { + coords_ = that.coords_; + return *this; + } + + template + inline polygon_45_data& operator=(const T2& rvalue); + + inline bool operator==(const polygon_45_data& that) const { + if(coords_.size() != that.coords_.size()) return false; + for(std::size_t i = 0; i < coords_.size(); ++i) { + if(coords_[i] != that.coords_[i]) return false; + } + return true; + } + + inline bool operator!=(const polygon_45_data& that) const { return !((*this) == that); } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +public: + std::vector > coords_; +}; + + +} +} +#endif + diff --git a/include/boost/polygon/polygon_45_set_concept.hpp b/include/boost/polygon/polygon_45_set_concept.hpp new file mode 100755 index 0000000..f22910c --- /dev/null +++ b/include/boost/polygon/polygon_45_set_concept.hpp @@ -0,0 +1,441 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_45_SET_CONCEPT_HPP +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_traits.hpp" +#include "detail/polygon_45_touch.hpp" +namespace boost { namespace polygon{ + + template + struct is_either_polygon_45_set_type { + typedef typename gtl_or::type, typename is_polygon_45_set_type::type >::type type; + }; + + template + struct is_polygon_45_or_90_set_type { + typedef typename gtl_or::type, typename is_polygon_90_set_type::type >::type type; + }; + + template + typename enable_if< typename gtl_if::type>::type, + typename polygon_45_set_traits::iterator_type>::type + begin_45_set_data(const polygon_set_type& polygon_set) { + return polygon_45_set_traits::begin(polygon_set); + } + + template + typename enable_if< typename gtl_if::type>::type, + typename polygon_45_set_traits::iterator_type>::type + end_45_set_data(const polygon_set_type& polygon_set) { + return polygon_45_set_traits::end(polygon_set); + } + + template + typename enable_if< typename gtl_if::type>::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_45_set_traits::clean(polygon_set); + } + + //assign + template + typename enable_if< typename gtl_and< typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + polygon_45_set_mutable_traits::set(lvalue, begin_45_set_data(rvalue), end_45_set_data(rvalue)); + return lvalue; + } + + //get trapezoids + template + typename enable_if< typename gtl_if::type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_45_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output); + } + + //get trapezoids + template + typename enable_if< typename gtl_if::type>::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { + clean(polygon_set); + polygon_45_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output, slicing_orientation); + } + + //equivalence + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_45_set_data::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_45_set_data::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + //clear + template + typename enable_if< typename gtl_if::type>::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_45_set_data::coordinate_type> ps; + assign(polygon_set, ps); + } + + //empty + template + typename enable_if< typename gtl_if::type>::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_45_set_data(polygon_set) == end_45_set_data(polygon_set); + polygon_45_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template + typename enable_if< + typename gtl_and< typename gtl_if::type>::type, + typename is_mutable_rectangle_concept::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_45_set_data::coordinate_type> ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + typename coordinate_traits::coordinate_type>::area_type>::type + area(const polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + typedef polygon_45_with_holes_data p_type; + typedef typename coordinate_traits::area_type area_type; + std::vector polys; + assign(polys, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += area(polys[i]); + } + return retval; + } + + //interact + template + typename enable_if < + typename gtl_and< typename gtl_if::type>::type, + typename gtl_if::type>::type >::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + std::vector > polys; + assign(polys, polygon_set_1); + std::vector > graph(polys.size()+1, std::set()); + connectivity_extraction_45 ce; + ce.insert(polygon_set_2); + for(std::size_t i = 0; i < polys.size(); ++i){ + ce.insert(polys[i]); + } + ce.extract(graph); + clear(polygon_set_1); + polygon_45_set_data ps; + for(std::set::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ + ps.insert(polys[(*itr)-1]); + } + assign(polygon_set_1, ps); + return polygon_set_1; + } + +// //self_intersect +// template +// typename enable_if< typename is_mutable_polygon_45_set_type::type>::type, +// polygon_set_type>::type & +// self_intersect(polygon_set_type& polygon_set) { +// typedef typename polygon_45_set_traits::coordinate_type Unit; +// //TODO +// } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing, + RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.resize(resizing, rounding, corner); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + return resize(polygon_set, static_cast::coordinate_type>(bloating)); + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { + return resize(polygon_set, -(typename polygon_45_set_traits::coordinate_type)shrinking); + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + std::vector > polys; + assign(polys, polygon_set); + clear(polygon_set); + polygon_45_set_data ps; + for(std::size_t i = 0; i < polys.size(); ++i) { + polygon_45_set_data tmpPs; + tmpPs.insert(polys[i]); + bloat(tmpPs, bloating); + tmpPs.clean(); //apply implicit OR on tmp polygon set + ps.insert(tmpPs); + } + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + scale(polygon_set_type& polygon_set, double factor) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.scale(factor); + assign(polygon_set, ps); + return polygon_set; + } + + //self_intersect + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + self_intersect(polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + //self_xor + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + self_xor(polygon_set_type& polygon_set) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.self_xor(); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_45_set_data ps; + assign(ps, polygon_set); + ps.transform(transformation); + assign(polygon_set, ps); + return polygon_set; + } + + //keep + template + typename enable_if< typename is_mutable_polygon_45_set_type::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::area_type min_area, + typename coordinate_traits::coordinate_type>::area_type max_area, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + typedef typename coordinate_traits::unsigned_area_type uat; + std::list > polys; + assign(polys, polygon_set); + typename std::list >::iterator itr_nxt; + for(typename std::list >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + typename coordinate_traits::area_type parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + template + struct view_of { + typedef typename get_coordinate_type::type >::type coordinate_type; + T* tp; + std::vector > polys; + view_of(T& obj) : tp(&obj), polys() { + std::vector > gpolys; + assign(gpolys, obj); + for(typename std::vector >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_90_with_holes_data()); + assign(polys.back(), view_as(*itr)); + } + } + view_of(const T& obj) : tp(), polys() { + std::vector > gpolys; + assign(gpolys, obj); + for(typename std::vector >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_90_with_holes_data()); + assign(polys.back(), view_as(*itr)); + } + } + + typedef typename std::vector >::const_iterator iterator_type; + typedef view_of operator_arg_type; + + inline iterator_type begin() const { + return polys.begin(); + } + + inline iterator_type end() const { + return polys.end(); + } + + inline orientation_2d orient() const { return HORIZONTAL; } + + inline bool clean() const { return false; } + + inline bool sorted() const { return false; } + + inline T& get() { return *tp; } + + }; + + template + struct polygon_90_set_traits > { + typedef typename view_of::coordinate_type coordinate_type; + typedef typename view_of::iterator_type iterator_type; + typedef view_of operator_arg_type; + + static inline iterator_type begin(const view_of& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const view_of& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const view_of& polygon_set) { + return polygon_set.orient(); } + + static inline bool clean(const view_of& polygon_set) { + return polygon_set.clean(); } + + static inline bool sorted(const view_of& polygon_set) { + return polygon_set.sorted(); } + + }; + + template + struct geometry_concept > { + typedef polygon_90_set_concept type; + }; + + template + struct get_coordinate_type, polygon_90_set_concept> { + typedef typename view_of::coordinate_type type; + }; + template + struct get_iterator_type_2, polygon_90_set_concept> { + typedef typename view_of::iterator_type type; + static type begin(const view_of& t) { return t.begin(); } + static type end(const view_of& t) { return t.end(); } + }; + +} +} +#include "detail/polygon_45_set_view.hpp" +#endif diff --git a/include/boost/polygon/polygon_45_set_data.hpp b/include/boost/polygon/polygon_45_set_data.hpp new file mode 100755 index 0000000..b479cfd --- /dev/null +++ b/include/boost/polygon/polygon_45_set_data.hpp @@ -0,0 +1,1877 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_SET_DATA_HPP +#include "polygon_90_set_data.hpp" +#include "detail/boolean_op_45.hpp" +#include "detail/polygon_45_formation.hpp" +#include "detail/polygon_45_touch.hpp" +#include "detail/property_merge_45.hpp" +namespace boost { namespace polygon{ + + enum RoundingOption { CLOSEST = 0, OVERSIZE = 1, UNDERSIZE = 2, SQRT2 = 3, SQRT1OVER2 = 4 }; + enum CornerOption { INTERSECTION = 0, ORTHOGONAL = 1, UNFILLED = 2 }; + + template + class polygon_45_set_view; + + struct polygon_45_set_concept {}; + + template + class polygon_45_set_data { + public: + typedef typename polygon_45_formation::Vertex45Compact Vertex45Compact; + typedef std::vector Polygon45VertexData; + + typedef Unit coordinate_type; + typedef Polygon45VertexData value_type; + typedef typename value_type::const_iterator iterator_type; + typedef polygon_45_set_data operator_arg_type; + + // default constructor + inline polygon_45_set_data() : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {} + + // constructor from a geometry object + template + inline polygon_45_set_data(const geometry_type& that) : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { + insert(that); + } + + // copy constructor + inline polygon_45_set_data(const polygon_45_set_data& that) : + error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_), + unsorted_(that.unsorted_), is_manhattan_(that.is_manhattan_) {} + + template + inline polygon_45_set_data(const polygon_45_set_view& that) : + error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) { + (*this) = that.value(); + } + + // destructor + inline ~polygon_45_set_data() {} + + // assignement operator + inline polygon_45_set_data& operator=(const polygon_45_set_data& that) { + if(this == &that) return *this; + error_data_ = that.error_data_; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + is_manhattan_ = that.is_manhattan_; + return *this; + } + + template + inline polygon_45_set_data& operator=(const polygon_45_set_view& that) { + (*this) = that.value(); + return *this; + } + + template + inline polygon_45_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + // insert iterator range + template + inline void insert(iT input_begin, iT input_end, bool is_hole = false) { + if(input_begin == input_end) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + inline void insert(const polygon_45_set_data& polygon_set, bool is_hole = false); + template + inline void insert(const polygon_45_set_data& polygon_set, bool is_hole = false); + + template + inline void insert(const geometry_type& geometry_object, bool is_hole = false) { + insert_dispatch(geometry_object, is_hole, typename geometry_concept::type()); + } + + inline void insert_clean(const Vertex45Compact& vertex_45, bool is_hole = false) { + if(vertex_45.count.is_45()) is_manhattan_ = false; + data_.push_back(vertex_45); + if(is_hole) data_.back().count.invert(); + } + + inline void insert(const Vertex45Compact& vertex_45, bool is_hole = false) { + dirty_ = true; + unsorted_ = true; + insert_clean(vertex_45, is_hole); + } + + template + inline void insert(const polygon_90_set_data& polygon_set, bool is_hole = false) { + if(polygon_set.orient() == VERTICAL) { + for(typename polygon_90_set_data::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + Vertex45Compact vertex_45(point_data((*itr).first, (*itr).second.first), 2, (*itr).second.second); + vertex_45.count[1] = (*itr).second.second; + if(is_hole) vertex_45.count[1] *= - 1; + insert_clean(vertex_45, is_hole); + } + } else { + for(typename polygon_90_set_data::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + Vertex45Compact vertex_45(point_data((*itr).second.first, (*itr).first), 2, (*itr).second.second); + vertex_45.count[1] = (*itr).second.second; + if(is_hole) vertex_45.count[1] *= - 1; + insert_clean(vertex_45, is_hole); + } + } + dirty_ = true; + unsorted_ = true; + } + + template + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept::type()); + } + + inline bool has_error_data() const { return !error_data_.empty(); } + inline std::size_t error_count() const { return error_data_.size() / 4; } + inline void get_error_data(polygon_45_set_data& p) const { + p.data_.insert(p.data_.end(), error_data_.begin(), error_data_.end()); + } + + // equivalence operator + inline bool operator==(const polygon_45_set_data& p) const { + clean(); + p.clean(); + return data_ == p.data_; + } + + // inequivalence operator + inline bool operator!=(const polygon_45_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_45_set_data + inline void clear() { data_.clear(); error_data_.clear(); dirty_ = unsorted_ = false; is_manhattan_ = true; } + + // find out if Polygon set is empty + inline bool empty() const { return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + // find out if Polygon set is clean + inline bool is_manhattan() const { return is_manhattan_; } + + bool clean() const; + + void sort() const{ + if(unsorted_) { + std::sort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template + void set(input_iterator_type input_begin, input_iterator_type input_end) { + data_.clear(); + insert(input_begin, input_end); + dirty_ = true; + unsorted_ = true; + } + + void set_clean(const value_type& value) { + data_ = value; + dirty_ = false; + unsorted_ = false; + } + + void set(const value_type& value) { + data_ = value; + dirty_ = true; + unsorted_ = true; + } + + // append to the container cT with polygons (holes will be fractured vertically) + template + void get_polygons(cT& container) const { + get_dispatch(container, polygon_45_concept()); + } + + // append to the container cT with PolygonWithHoles objects + template + void get_polygons_with_holes(cT& container) const { + get_dispatch(container, polygon_45_with_holes_concept()); + } + + // append to the container cT with polygons of three or four verticies + // slicing orientation is vertical + template + void get_trapezoids(cT& container) const { + clean(); + typename polygon_45_formation::Polygon45Tiling pf; + //std::cout << "FORMING POLYGONS\n"; + pf.scan(container, data_.begin(), data_.end()); + //std::cout << "DONE FORMING POLYGONS\n"; + } + + // append to the container cT with polygons of three or four verticies + template + void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { + if(slicing_orientation == VERTICAL) { + get_trapezoids(container); + } else { + polygon_45_set_data ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + cT result; + ps.get_trapezoids(result); + for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + container.insert(container.end(), result.begin(), result.end()); + } + } + + // insert vertex sequence + template + void insert_vertex_sequence(iT begin_vertex, iT end_vertex, + direction_1d winding, bool is_hole = false); + + // get the external boundary rectangle + template + bool extents(rectangle_type& rect) const; + + // snap verticies of set to even,even or odd,odd coordinates + void snap() const; + + // |= &= += *= -= ^= binary operators + polygon_45_set_data& operator|=(const polygon_45_set_data& b); + polygon_45_set_data& operator&=(const polygon_45_set_data& b); + polygon_45_set_data& operator+=(const polygon_45_set_data& b); + polygon_45_set_data& operator*=(const polygon_45_set_data& b); + polygon_45_set_data& operator-=(const polygon_45_set_data& b); + polygon_45_set_data& operator^=(const polygon_45_set_data& b); + + // resizing operations + polygon_45_set_data& operator+=(Unit delta); + polygon_45_set_data& operator-=(Unit delta); + + // shrink the Polygon45Set by shrinking + polygon_45_set_data& resize(coordinate_type resizing, RoundingOption rounding = CLOSEST, + CornerOption corner = INTERSECTION); + + // transform set + template + polygon_45_set_data& transform(const transformation_type& tr); + + // scale set + polygon_45_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor); + polygon_45_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor); + polygon_45_set_data& scale(double scaling); + + // self_intersect + polygon_45_set_data& self_intersect() { + sort(); + applyAdaptiveUnary_<1>(); //1 = AND + dirty_ = false; + return *this; + } + + // self_xor + polygon_45_set_data& self_xor() { + sort(); + applyAdaptiveUnary_<3>(); //3 = XOR + dirty_ = false; + return *this; + } + + // accumulate the bloated polygon + template + polygon_45_set_data& insert_with_resize(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding = CLOSEST, + CornerOption corner = INTERSECTION, + bool hole = false) { + return insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, typename geometry_concept::type()); + } + + private: + mutable value_type error_data_; + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + mutable bool is_manhattan_; + + private: + //functions + template + void get_dispatch(output_container& output, polygon_45_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { + clean(); + typename polygon_45_formation::Polygon45Formation pf(fracture_holes); + //std::cout << "FORMING POLYGONS\n"; + pf.scan(container, data_.begin(), data_.end()); + } + + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, undefined_concept) { + insert(geometry_object.begin(), geometry_object.end(), is_hole); + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag); + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_with_holes_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(geometry_object); itr != end_holes(geometry_object); + ++itr) { + insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); + } + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_with_holes_concept ) { + insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(geometry_object); itr != end_holes(geometry_object); + ++itr) { + insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole); + } + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_set_concept ) { + polygon_45_set_data ps; + assign(ps, geometry_object); + insert(ps, is_hole); + } + template + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_set_concept ) { + std::list > pl; + assign(pl, geometry_object); + insert(pl.begin(), pl.end(), is_hole); + } + + void insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, + const point_data& pt3, direction_1d wdir); + + template + polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding, + CornerOption corner, bool hole, polygon_45_concept tag); + + // accumulate the bloated polygon with holes + template + polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, RoundingOption rounding, + CornerOption corner, bool hole, polygon_45_with_holes_concept tag); + + static void snap_vertex_45(Vertex45Compact& vertex); + + public: + template + void applyAdaptiveBoolean_(const polygon_45_set_data& rvalue) const; + template + void applyAdaptiveBoolean_(polygon_45_set_data& result, const polygon_45_set_data& rvalue) const; + template + void applyAdaptiveUnary_() const; + }; + + template + struct geometry_concept > { + typedef polygon_45_set_concept type; + }; + + template + void scale_up_vertex_45_compact_range(iT beginr, iT endr, T factor) { + for( ; beginr != endr; ++beginr) { + scale_up((*beginr).pt, factor); + } + } + template + void scale_down_vertex_45_compact_range_blindly(iT beginr, iT endr, T factor) { + for( ; beginr != endr; ++beginr) { + scale_down((*beginr).pt, factor); + } + } + + template + inline std::pair characterizeEdge45(const point_data& pt1, const point_data& pt2) { + std::pair retval(0, 1); + if(pt1.x() == pt2.x()) { + retval.first = 3; + retval.second = -1; + return retval; + } + //retval.second = pt1.x() < pt2.x() ? -1 : 1; + retval.second = 1; + if(pt1.y() == pt2.y()) { + retval.first = 1; + } else if(pt1.x() < pt2.x()) { + if(pt1.y() < pt2.y()) { + retval.first = 2; + } else { + retval.first = 0; + } + } else { + if(pt1.y() < pt2.y()) { + retval.first = 0; + } else { + retval.first = 2; + } + } + return retval; + } + + template + bool insert_vertex_half_edge_45_pair_into_vector(cT& output, + const pT& pt1, pT& pt2, + const pT& pt3, + direction_1d wdir) { + int multiplier = wdir == LOW ? -1 : 1; + typename cT::value_type vertex(pt2, 0, 0); + //std::cout << pt1 << " " << pt2 << " " << pt3 << std::endl; + std::pair check; + check = characterizeEdge45(pt1, pt2); + //std::cout << "index " << check.first << " " << check.second * -multiplier << std::endl; + vertex.count[check.first] += check.second * -multiplier; + check = characterizeEdge45(pt2, pt3); + //std::cout << "index " << check.first << " " << check.second * multiplier << std::endl; + vertex.count[check.first] += check.second * multiplier; + output.push_back(vertex); + return vertex.count.is_45(); + } + + template + inline void polygon_45_set_data::insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, + const point_data& pt3, + direction_1d wdir) { + if(insert_vertex_half_edge_45_pair_into_vector(data_, pt1, pt2, pt3, wdir)) is_manhattan_ = false; + } + + template + template + inline void polygon_45_set_data::insert_vertex_sequence(iT begin_vertex, iT end_vertex, + direction_1d winding, bool is_hole) { + if(begin_vertex == end_vertex) return; + if(is_hole) winding = winding.backward(); + iT itr = begin_vertex; + if(itr == end_vertex) return; + point_data firstPt = *itr; + ++itr; + point_data secondPt(firstPt); + //skip any duplicate points + do { + if(itr == end_vertex) return; + secondPt = *itr; + ++itr; + } while(secondPt == firstPt); + point_data prevPt = secondPt; + point_data prevPrevPt = firstPt; + while(itr != end_vertex) { + point_data pt = *itr; + //skip any duplicate points + if(pt == prevPt) { + ++itr; + continue; + } + //operate on the three points + insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, pt, winding); + prevPrevPt = prevPt; + prevPt = pt; + ++itr; + } + if(prevPt != firstPt) { + insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, firstPt, winding); + insert_vertex_half_edge_45_pair(prevPt, firstPt, secondPt, winding); + } else { + insert_vertex_half_edge_45_pair(prevPrevPt, firstPt, secondPt, winding); + } + dirty_ = true; + unsorted_ = true; + } + + // insert polygon set + template + inline void polygon_45_set_data::insert(const polygon_45_set_data& polygon_set, bool is_hole) { + std::size_t count = data_.size(); + data_.insert(data_.end(), polygon_set.data_.begin(), polygon_set.data_.end()); + error_data_.insert(error_data_.end(), polygon_set.error_data_.begin(), + polygon_set.error_data_.end()); + if(is_hole) { + for(std::size_t i = count; i < data_.size(); ++i) { + data_[i].count = data_[i].count.invert(); + } + } + dirty_ = true; + unsorted_ = true; + if(polygon_set.is_manhattan_ == false) is_manhattan_ = false; + return; + } + // insert polygon set + template + template + inline void polygon_45_set_data::insert(const polygon_45_set_data& polygon_set, bool is_hole) { + std::size_t count = data_.size(); + for(typename polygon_45_set_data::iterator_type itr = polygon_set.begin(); + itr != polygon_set.end(); ++itr) { + const typename polygon_45_set_data::Vertex45Compact& v = *itr; + typename polygon_45_set_data::Vertex45Compact v2; + v2.pt.x(static_cast(v.pt.x())); + v2.pt.y(static_cast(v.pt.y())); + v2.count = typename polygon_45_formation::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); + data_.push_back(v2); + } + polygon_45_set_data tmp; + polygon_set.get_error_data(tmp); + for(typename polygon_45_set_data::iterator_type itr = tmp.begin(); + itr != tmp.end(); ++itr) { + const typename polygon_45_set_data::Vertex45Compact& v = *itr; + typename polygon_45_set_data::Vertex45Compact v2; + v2.pt.x(static_cast(v.pt.x())); + v2.pt.y(static_cast(v.pt.y())); + v2.count = typename polygon_45_formation::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]); + error_data_.push_back(v2); + } + if(is_hole) { + for(std::size_t i = count; i < data_.size(); ++i) { + data_[i].count = data_[i].count.invert(); + } + } + dirty_ = true; + unsorted_ = true; + if(polygon_set.is_manhattan() == false) is_manhattan_ = false; + return; + } + + template + void insert_rectangle_into_vector_45(cT& output, const rT& rect, bool is_hole) { + point_data::coordinate_type> + llpt = ll(rect), lrpt = lr(rect), ulpt = ul(rect), urpt = ur(rect); + direction_1d dir = COUNTERCLOCKWISE; + if(is_hole) dir = CLOCKWISE; + insert_vertex_half_edge_45_pair_into_vector(output, llpt, lrpt, urpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, lrpt, urpt, ulpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, urpt, ulpt, llpt, dir); + insert_vertex_half_edge_45_pair_into_vector(output, ulpt, llpt, lrpt, dir); + } + + template + template + inline void polygon_45_set_data::insert_dispatch(const geometry_type& geometry_object, + bool is_hole, rectangle_concept ) { + dirty_ = true; + unsorted_ = true; + insert_rectangle_into_vector_45(data_, geometry_object, is_hole); + } + + // get the external boundary rectangle + template + template + inline bool polygon_45_set_data::extents(rectangle_type& rect) const{ + clean(); + if(empty()) { + return false; + } + Unit low = (std::numeric_limits::max)(); + Unit high = (std::numeric_limits::min)(); + interval_data xivl(low, high); + interval_data yivl(low, high); + for(typename value_type::const_iterator itr = data_.begin(); + itr != data_.end(); ++ itr) { + if((*itr).pt.x() > xivl.get(HIGH)) + xivl.set(HIGH, (*itr).pt.x()); + if((*itr).pt.x() < xivl.get(LOW)) + xivl.set(LOW, (*itr).pt.x()); + if((*itr).pt.y() > yivl.get(HIGH)) + yivl.set(HIGH, (*itr).pt.y()); + if((*itr).pt.y() < yivl.get(LOW)) + yivl.set(LOW, (*itr).pt.y()); + } + rect = construct(xivl, yivl); + return true; + } + + //this function snaps the vertex and two half edges + //to be both even or both odd coordinate values if one of the edges is 45 + //and throws an excpetion if an edge is non-manhattan, non-45. + template + inline void polygon_45_set_data::snap_vertex_45(typename polygon_45_set_data::Vertex45Compact& vertex) { + bool plus45 = vertex.count[2] != 0; + bool minus45 = vertex.count[0] != 0; + if(plus45 || minus45) { + if(abs(vertex.pt.x()) % 2 != abs(vertex.pt.y()) % 2) { + if(vertex.count[1] != 0 || + (plus45 && minus45)) { + //move right + vertex.pt.x(vertex.pt.x() + 1); + } else { + //assert that vertex.count[3] != 0 + Unit modifier = plus45 ? -1 : 1; + vertex.pt.y(vertex.pt.y() + modifier); + } + } + } + } + + template + inline void polygon_45_set_data::snap() const { + for(typename value_type::iterator itr = data_.begin(); + itr != data_.end(); ++itr) { + snap_vertex_45(*itr); + } + } + + // |= &= += *= -= ^= binary operators + template + inline polygon_45_set_data& polygon_45_set_data::operator|=(const polygon_45_set_data& b) { + insert(b); + return *this; + } + template + inline polygon_45_set_data& polygon_45_set_data::operator&=(const polygon_45_set_data& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<1>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + template + inline polygon_45_set_data& polygon_45_set_data::operator+=(const polygon_45_set_data& b) { + return (*this) |= b; + } + template + inline polygon_45_set_data& polygon_45_set_data::operator*=(const polygon_45_set_data& b) { + return (*this) &= b; + } + template + inline polygon_45_set_data& polygon_45_set_data::operator-=(const polygon_45_set_data& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<2>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + template + inline polygon_45_set_data& polygon_45_set_data::operator^=(const polygon_45_set_data& b) { + //b.sort(); + //sort(); + applyAdaptiveBoolean_<3>(b); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template + inline polygon_45_set_data& polygon_45_set_data::operator+=(Unit delta) { + return resize(delta); + } + template + inline polygon_45_set_data& polygon_45_set_data::operator-=(Unit delta) { + return (*this) += -delta; + } + + template + inline polygon_45_set_data& + polygon_45_set_data::resize(Unit resizing, RoundingOption rounding, CornerOption corner) { + if(resizing == 0) return *this; + std::list > pl; + get_polygons_with_holes(pl); + clear(); + for(typename std::list >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { + insert_with_resize(*itr, resizing, rounding, corner); + } + clean(); + //perterb 45 edges to prevent non-integer intersection errors upon boolean op + //snap(); + return *this; + } + + //distance is assumed to be positive + inline int roundClosest(double distance) { + int f = (int)distance; + if(distance - (double)f < 0.5) return f; + return f+1; + } + + //distance is assumed to be positive + template + inline Unit roundWithOptions(double distance, RoundingOption rounding) { + if(rounding == CLOSEST) { + return roundClosest(distance); + } else if(rounding == OVERSIZE) { + return (Unit)distance + 1; + } else { //UNDERSIZE + return (Unit)distance; + } + } + + // 0 is east, 1 is northeast, 2 is north, 3 is northwest, 4 is west, 5 is southwest, 6 is south + // 7 is southwest + template + inline point_data bloatVertexInDirWithOptions(const point_data& point, unsigned int dir, + Unit bloating, RoundingOption rounding) { + const double sqrt2 = 1.4142135623730950488016887242097; + if(dir & 1) { + Unit unitDistance = (Unit)bloating; + if(rounding != SQRT2) { + //45 degree bloating + double distance = (double)bloating; + distance /= sqrt2; // multiply by 1/sqrt2 + unitDistance = roundWithOptions(distance, rounding); + } + int xMultiplier = 1; + int yMultiplier = 1; + if(dir == 3 || dir == 5) xMultiplier = -1; + if(dir == 5 || dir == 7) yMultiplier = -1; + return point_data(point.x()+xMultiplier*unitDistance, + point.y()+yMultiplier*unitDistance); + } else { + if(dir == 0) + return point_data(point.x()+bloating, point.y()); + if(dir == 2) + return point_data(point.x(), point.y()+bloating); + if(dir == 4) + return point_data(point.x()-bloating, point.y()); + if(dir == 6) + return point_data(point.x(), point.y()-bloating); + return point_data(); + } + } + + template + inline unsigned int getEdge45Direction(const point_data& pt1, const point_data& pt2) { + if(pt1.x() == pt2.x()) { + if(pt1.y() < pt2.y()) return 2; + return 6; + } + if(pt1.y() == pt2.y()) { + if(pt1.x() < pt2.x()) return 0; + return 4; + } + if(pt2.y() > pt1.y()) { + if(pt2.x() > pt1.x()) return 1; + return 3; + } + if(pt2.x() > pt1.x()) return 7; + return 5; + } + + inline unsigned int getEdge45NormalDirection(unsigned int dir, int multiplier) { + if(multiplier < 0) + return (dir + 2) % 8; + return (dir + 4 + 2) % 8; + } + + template + inline point_data getIntersectionPoint(const point_data& pt1, unsigned int slope1, + const point_data& pt2, unsigned int slope2) { + //the intention here is to use all integer arithmetic without causing overflow + //turncation error or divide by zero error + //I don't use floating point arithmetic because its precision may not be high enough + //at the extremes of the integer range + typedef typename coordinate_traits::area_type LongUnit; + const Unit rises[8] = {0, 1, 1, 1, 0, -1, -1, -1}; + const Unit runs[8] = {1, 1, 0, -1, -1, -1, 0, 1}; + LongUnit rise1 = rises[slope1]; + LongUnit rise2 = rises[slope2]; + LongUnit run1 = runs[slope1]; + LongUnit run2 = runs[slope2]; + LongUnit x1 = (LongUnit)pt1.x(); + LongUnit x2 = (LongUnit)pt2.x(); + LongUnit y1 = (LongUnit)pt1.y(); + LongUnit y2 = (LongUnit)pt2.y(); + Unit x = 0; + Unit y = 0; + if(run1 == 0) { + x = pt1.x(); + y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y(); + } else if(run2 == 0) { + x = pt2.x(); + y = (Unit)(((x2 - x1) * rise1) / run1) + pt1.y(); + } else { + // y - y1 = (rise1/run1)(x - x1) + // y - y2 = (rise2/run2)(x - x2) + // y = (rise1/run1)(x - x1) + y1 = (rise2/run2)(x - x2) + y2 + // (rise1/run1 - rise2/run2)x = y2 - y1 + rise1/run1 x1 - rise2/run2 x2 + // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)/(rise1/run1 - rise2/run2) + // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)(rise1 run2 - rise2 run1)/(run1 run2) + x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) * + (run1 * run2) / (rise1 * run2 - rise2 * run1)); + if(rise1 == 0) { + y = pt1.y(); + } else if(rise2 == 0) { + y = pt2.y(); + } else { + // y - y1 = (rise1/run1)(x - x1) + // (run1/rise1)(y - y1) = x - x1 + // x = (run1/rise1)(y - y1) + x1 = (run2/rise2)(y - y2) + x2 + y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) * + (rise1 * rise2) / (run1 * rise2 - run2 * rise1)); + } + } + return point_data(x, y); + } + + template + inline + void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data& sizingSet, point_data first, + point_data second, Unit resizing, CornerOption corner) { + if(first.x() == second.x()) { + sizingSet.insert(rectangle_data(first.x() - resizing, first.y(), first.x() + resizing, second.y())); + return; + } + if(first.y() == second.y()) { + sizingSet.insert(rectangle_data(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); + return; + } + std::vector > pts; + Unit bloating = resizing < 0 ? -resizing : resizing; + if(corner == UNFILLED) { + //we have to round up + bloating = bloating / 2 + bloating % 2 ; //round up + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { //upward sloping + pts.push_back(point_data(first.x() + bloating, first.y() - bloating)); + pts.push_back(point_data(first.x() - bloating, first.y() + bloating)); + pts.push_back(point_data(second.x() - bloating, second.y() + bloating)); + pts.push_back(point_data(second.x() + bloating, second.y() - bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } else { //downward sloping + pts.push_back(point_data(first.x() + bloating, first.y() + bloating)); + pts.push_back(point_data(first.x() - bloating, first.y() - bloating)); + pts.push_back(point_data(second.x() - bloating, second.y() - bloating)); + pts.push_back(point_data(second.x() + bloating, second.y() + bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), COUNTERCLOCKWISE, false); + } + return; + } + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { //upward sloping + pts.push_back(point_data(first.x(), first.y() - bloating)); + pts.push_back(point_data(first.x() - bloating, first.y())); + pts.push_back(point_data(second.x(), second.y() + bloating)); + pts.push_back(point_data(second.x() + bloating, second.y())); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } else { //downward sloping + pts.push_back(point_data(first.x() - bloating, first.y())); + pts.push_back(point_data(first.x(), first.y() + bloating)); + pts.push_back(point_data(second.x() + bloating, second.y())); + pts.push_back(point_data(second.x(), second.y() - bloating)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false); + } + } + + + template + inline + void handleResizingEdge45(polygon_45_set_data& sizingSet, point_data first, + point_data second, Unit resizing, RoundingOption rounding) { + if(first.x() == second.x()) { + sizingSet.insert(rectangle_data(first.x() - resizing, first.y(), first.x() + resizing, second.y())); + return; + } + if(first.y() == second.y()) { + sizingSet.insert(rectangle_data(first.x(), first.y() - resizing, second.x(), first.y() + resizing)); + return; + } + //edge is 45 + std::vector > pts; + Unit bloating = resizing < 0 ? -resizing : resizing; + if(second.x() < first.x()) std::swap(first, second); + if(first.y() < second.y()) { + pts.push_back(bloatVertexInDirWithOptions(first, 3, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(first, 7, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 7, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 3, bloating, rounding)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); + } else { + pts.push_back(bloatVertexInDirWithOptions(first, 1, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(first, 5, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 5, bloating, rounding)); + pts.push_back(bloatVertexInDirWithOptions(second, 1, bloating, rounding)); + sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false); + } + } + + template + inline point_data bloatVertexInDirWithSQRT1OVER2(int edge1, int normal1, const point_data& second, Unit bloating, + bool first) { + orientation_2d orient = first ? HORIZONTAL : VERTICAL; + orientation_2d orientp = orient.get_perpendicular(); + int multiplier = first ? 1 : -1; + point_data pt1(second); + if(edge1 == 1) { + if(normal1 == 3) { + move(pt1, orient, -multiplier * bloating); + } else { + move(pt1, orientp, -multiplier * bloating); + } + } else if(edge1 == 3) { + if(normal1 == 1) { + move(pt1, orient, multiplier * bloating); + } else { + move(pt1, orientp, -multiplier * bloating); + } + } else if(edge1 == 5) { + if(normal1 == 3) { + move(pt1, orientp, multiplier * bloating); + } else { + move(pt1, orient, multiplier * bloating); + } + } else { + if(normal1 == 5) { + move(pt1, orient, -multiplier * bloating); + } else { + move(pt1, orientp, multiplier * bloating); + } + } + return pt1; + } + + template + inline + void handleResizingVertex45(polygon_45_set_data& sizingSet, const point_data& first, + const point_data& second, const point_data& third, Unit resizing, + RoundingOption rounding, CornerOption corner, + int multiplier) { + unsigned int edge1 = getEdge45Direction(first, second); + unsigned int edge2 = getEdge45Direction(second, third); + unsigned int diffAngle; + if(multiplier < 0) + diffAngle = (edge2 + 8 - edge1) % 8; + else + diffAngle = (edge1 + 8 - edge2) % 8; + if(diffAngle < 4) { + if(resizing > 0) return; //accute interior corner + else multiplier *= -1; //make it appear to be an accute exterior angle + } + Unit bloating = abs(resizing); + if(rounding == SQRT1OVER2) { + if(edge1 % 2 && edge2 % 2) return; + if(corner == ORTHOGONAL && edge1 % 2 == 0 && edge2 % 2 == 0) { + rectangle_data insertion_rect; + set_points(insertion_rect, second, second); + bloat(insertion_rect, bloating); + sizingSet.insert(insertion_rect); + } else if(corner != ORTHOGONAL) { + point_data pt1(0, 0); + point_data pt2(0, 0); + unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); + unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); + if(edge1 % 2) { + pt1 = bloatVertexInDirWithSQRT1OVER2(edge1, normal1, second, bloating, true); + } else { + pt1 = bloatVertexInDirWithOptions(second, normal1, bloating, UNDERSIZE); + } + if(edge2 % 2) { + pt2 = bloatVertexInDirWithSQRT1OVER2(edge2, normal2, second, bloating, false); + } else { + pt2 = bloatVertexInDirWithOptions(second, normal2, bloating, UNDERSIZE); + } + std::vector > pts; + pts.push_back(pt1); + pts.push_back(second); + pts.push_back(pt2); + pts.push_back(getIntersectionPoint(pt1, edge1, pt2, edge2)); + polygon_45_data poly(pts.begin(), pts.end()); + sizingSet.insert(poly); + } else { + //ORTHOGONAL of a 45 degree corner + int normal = 0; + if(edge1 % 2) { + normal = getEdge45NormalDirection(edge2, multiplier); + } else { + normal = getEdge45NormalDirection(edge1, multiplier); + } + rectangle_data insertion_rect; + point_data edgePoint = bloatVertexInDirWithOptions(second, normal, bloating, UNDERSIZE); + set_points(insertion_rect, second, edgePoint); + if(normal == 0 || normal == 4) + bloat(insertion_rect, VERTICAL, bloating); + else + bloat(insertion_rect, HORIZONTAL, bloating); + sizingSet.insert(insertion_rect); + } + return; + } + unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier); + unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier); + point_data edgePoint1 = bloatVertexInDirWithOptions(second, normal1, bloating, rounding); + point_data edgePoint2 = bloatVertexInDirWithOptions(second, normal2, bloating, rounding); + //if the change in angle is 135 degrees it is an accute exterior corner + if((edge1+ multiplier * 3) % 8 == edge2) { + if(corner == ORTHOGONAL) { + rectangle_data insertion_rect; + set_points(insertion_rect, edgePoint1, edgePoint2); + sizingSet.insert(insertion_rect); + return; + } + } + std::vector > pts; + pts.push_back(edgePoint1); + pts.push_back(second); + pts.push_back(edgePoint2); + pts.push_back(getIntersectionPoint(edgePoint1, edge1, edgePoint2, edge2)); + polygon_45_data poly(pts.begin(), pts.end()); + sizingSet.insert(poly); + } + + template + template + inline polygon_45_set_data& + polygon_45_set_data::insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, + RoundingOption rounding, + CornerOption corner, + bool hole, polygon_45_concept ) { + direction_1d wdir = winding(poly); + int multiplier = wdir == LOW ? -1 : 1; + if(hole) resizing *= -1; + typedef typename polygon_45_data::iterator_type piterator; + piterator first, second, third, end, real_end; + real_end = end_points(poly); + third = begin_points(poly); + first = third; + if(first == real_end) return *this; + ++third; + if(third == real_end) return *this; + second = end = third; + ++third; + if(third == real_end) return *this; + polygon_45_set_data sizingSet; + //insert minkofski shapes on edges and corners + do { + if(rounding != SQRT1OVER2) { + handleResizingEdge45(sizingSet, *first, *second, resizing, rounding); + } else { + handleResizingEdge45_SQRT1OVER2(sizingSet, *first, *second, resizing, corner); + } + if(corner != UNFILLED) + handleResizingVertex45(sizingSet, *first, *second, *third, resizing, rounding, corner, multiplier); + first = second; + second = third; + ++third; + if(third == real_end) { + third = begin_points(poly); + if(*second == *third) { + ++third; //skip first point if it is duplicate of last point + } + } + } while(second != end); + //sizingSet.snap(); + polygon_45_set_data tmp; + //insert original shape + tmp.insert_dispatch(poly, false, polygon_45_concept()); + if(resizing < 0) tmp -= sizingSet; + else tmp += sizingSet; + tmp.clean(); + insert(tmp, hole); + dirty_ = true; + unsorted_ = true; + return (*this); + } + + // accumulate the bloated polygon with holes + template + template + inline polygon_45_set_data& + polygon_45_set_data::insert_with_resize_dispatch(const geometry_type& poly, + coordinate_type resizing, + RoundingOption rounding, + CornerOption corner, + bool hole, polygon_45_with_holes_concept ) { + insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, polygon_45_concept()); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(poly); itr != end_holes(poly); + ++itr) { + insert_with_resize_dispatch(*itr, resizing, rounding, corner, !hole, polygon_45_concept()); + } + return *this; + } + + // transform set + template + template + inline polygon_45_set_data& polygon_45_set_data::transform(const transformation_type& tr){ + clean(); + std::vector > polys; + get(polys); + for(typename std::vector >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::transform(*itr, tr); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template + inline polygon_45_set_data& polygon_45_set_data::scale_up(typename coordinate_traits::unsigned_area_type factor) { + scale_up_vertex_45_compact_range(data_.begin(), data_.end(), factor); + return *this; + } + + template + inline polygon_45_set_data& polygon_45_set_data::scale_down(typename coordinate_traits::unsigned_area_type factor) { + clean(); + std::vector > polys; + get_polygons_with_holes(polys); + for(typename std::vector >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::scale_down(*itr, factor); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template + inline polygon_45_set_data& polygon_45_set_data::scale(double factor) { + clean(); + std::vector > polys; + get_polygons_with_holes(polys); + for(typename std::vector >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + ::boost::polygon::scale(*itr, factor); + } + clear(); + insert(polys.begin(), polys.end()); + dirty_ = true; + unsorted_ = true; + return *this; + } + + template + inline bool polygon_45_set_data::clean() const { + if(unsorted_) sort(); + if(dirty_) { + applyAdaptiveUnary_<0>(); + dirty_ = false; + } + return true; + } + + template + template + inline void polygon_45_set_data::applyAdaptiveBoolean_(const polygon_45_set_data& rvalue) const { + polygon_45_set_data tmp; + applyAdaptiveBoolean_(tmp, rvalue); + data_.swap(tmp.data_); //swapping vectors should be constant time operation + error_data_.swap(tmp.error_data_); + is_manhattan_ = tmp.is_manhattan_; + unsorted_ = false; + dirty_ = false; + } + + template + bool applyBoolean45OpOnVectors(std::vector::Vertex45Compact>& result_data, + std::vector::Vertex45Compact>& lvalue_data, + std::vector::Vertex45Compact>& rvalue_data + ) { + bool result_is_manhattan_ = true; + typename boolean_op_45::template Scan45::Count2, + typename boolean_op_45::template boolean_op_45_output_functor > scan45; + std::vector::Vertex45> eventOut; + typedef std::pair::Point, + typename boolean_op_45::template Scan45CountT::Count2> > Scan45Vertex; + std::vector eventIn; + typedef std::vector::Vertex45Compact> value_type; + typename value_type::const_iterator iter1 = lvalue_data.begin(); + typename value_type::const_iterator iter2 = rvalue_data.begin(); + typename value_type::const_iterator end1 = lvalue_data.end(); + typename value_type::const_iterator end2 = rvalue_data.end(); + const Unit2 UnitMax = (std::numeric_limits::max)(); + Unit2 x = UnitMax; + while(iter1 != end1 || iter2 != end2) { + Unit2 currentX = UnitMax; + if(iter1 != end1) currentX = iter1->pt.x(); + if(iter2 != end2) currentX = (std::min)(currentX, iter2->pt.x()); + if(currentX != x) { + //std::cout << "SCAN " << currentX << "\n"; + //scan event + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + std::sort(eventOut.begin(), eventOut.end()); + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + eventOut.clear(); + eventIn.clear(); + x = currentX; + } + //std::cout << "get next\n"; + if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() || + (iter2->pt.x() == iter1->pt.x() && + iter2->pt.y() < iter1->pt.y()) )) { + //std::cout << "case1 next\n"; + eventIn.push_back(Scan45Vertex + (iter2->pt, + typename polygon_45_formation:: + Scan45Count(typename polygon_45_formation::Count2(0, iter2->count[0]), + typename polygon_45_formation::Count2(0, iter2->count[1]), + typename polygon_45_formation::Count2(0, iter2->count[2]), + typename polygon_45_formation::Count2(0, iter2->count[3])))); + ++iter2; + } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() || + (iter1->pt.x() == iter2->pt.x() && + iter1->pt.y() < iter2->pt.y()) )) { + //std::cout << "case2 next\n"; + eventIn.push_back(Scan45Vertex + (iter1->pt, + typename polygon_45_formation:: + Scan45Count( + typename polygon_45_formation::Count2(iter1->count[0], 0), + typename polygon_45_formation::Count2(iter1->count[1], 0), + typename polygon_45_formation::Count2(iter1->count[2], 0), + typename polygon_45_formation::Count2(iter1->count[3], 0)))); + ++iter1; + } else { + //std::cout << "case3 next\n"; + eventIn.push_back(Scan45Vertex + (iter2->pt, + typename polygon_45_formation:: + Scan45Count(typename polygon_45_formation::Count2(iter1->count[0], + iter2->count[0]), + typename polygon_45_formation::Count2(iter1->count[1], + iter2->count[1]), + typename polygon_45_formation::Count2(iter1->count[2], + iter2->count[2]), + typename polygon_45_formation::Count2(iter1->count[3], + iter2->count[3])))); + ++iter1; + ++iter2; + } + } + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + std::sort(eventOut.begin(), eventOut.end()); + + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + if(!result_data.empty() && + result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + return result_is_manhattan_; + } + + template + bool applyUnary45OpOnVectors(std::vector::Vertex45Compact>& result_data, + std::vector::Vertex45Compact>& lvalue_data ) { + bool result_is_manhattan_ = true; + typename boolean_op_45::template Scan45::Count1, + typename boolean_op_45::template unary_op_45_output_functor > scan45; + std::vector::Vertex45> eventOut; + typedef typename boolean_op_45::template Scan45CountT::Count1> Scan45Count; + typedef std::pair::Point, Scan45Count> Scan45Vertex; + std::vector eventIn; + typedef std::vector::Vertex45Compact> value_type; + typename value_type::const_iterator iter1 = lvalue_data.begin(); + typename value_type::const_iterator end1 = lvalue_data.end(); + const Unit2 UnitMax = (std::numeric_limits::max)(); + Unit2 x = UnitMax; + while(iter1 != end1) { + Unit2 currentX = iter1->pt.x(); + if(currentX != x) { + //std::cout << "SCAN " << currentX << "\n"; + //scan event + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + std::sort(eventOut.begin(), eventOut.end()); + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + eventOut.clear(); + eventIn.clear(); + x = currentX; + } + //std::cout << "get next\n"; + eventIn.push_back(Scan45Vertex + (iter1->pt, + Scan45Count( typename boolean_op_45::Count1(iter1->count[0]), + typename boolean_op_45::Count1(iter1->count[1]), + typename boolean_op_45::Count1(iter1->count[2]), + typename boolean_op_45::Count1(iter1->count[3])))); + ++iter1; + } + scan45.scan(eventOut, eventIn.begin(), eventIn.end()); + std::sort(eventOut.begin(), eventOut.end()); + + std::size_t ptCount = 0; + for(std::size_t i = 0; i < eventOut.size(); ++i) { + if(!result_data.empty() && + result_data.back().pt == eventOut[i].pt) { + result_data.back().count += eventOut[i]; + ++ptCount; + } else { + if(!result_data.empty()) { + if(result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + } + result_data.push_back(eventOut[i]); + ptCount = 1; + } + } + if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation::Vertex45Count(0, 0, 0, 0))) { + result_data.pop_back(); + } + if(!result_data.empty() && + result_data.back().count.is_45()) { + result_is_manhattan_ = false; + } + return result_is_manhattan_; + } + + template + void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) { + typedef typename iT::value_type Point; + typedef typename point_traits::coordinate_type Unit; + typedef typename coordinate_traits::area_type area_type; + Point pt1, pt2, pt3; + bool i1 = true; + bool i2 = true; + bool not_done = beginr != endr; + bool next_to_last = false; + bool last = false; + Point first, second; + while(not_done) { + if(last) { + last = false; + not_done = false; + pt3 = second; + } else if(next_to_last) { + next_to_last = false; + last = true; + pt3 = first; + } else if(i1) { + const Point& pt = *beginr; + first = pt1 = pt; + i1 = false; + i2 = true; + ++beginr; + if(beginr == endr) return; //too few points + continue; + } else if (i2) { + const Point& pt = *beginr; + second = pt2 = pt; + i2 = false; + ++beginr; + if(beginr == endr) return; //too few points + continue; + } else { + const Point& pt = *beginr; + pt3 = pt; + ++beginr; + if(beginr == endr) { + next_to_last = true; + //skip last point equal to first + continue; + } + } + if(local_abs(x(pt2)) % 2) { //y % 2 should also be odd + //is corner concave or convex? + Point pts[] = {pt1, pt2, pt3}; + area_type ar = point_sequence_area(pts, pts+3); + direction_1d dir = ar < 0 ? COUNTERCLOCKWISE : CLOCKWISE; + //std::cout << pt1 << " " << pt2 << " " << pt3 << " " << ar << std::endl; + if(dir == CLOCKWISE) { + posE.push_back(rectangle_data + (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); + + } else { + negE.push_back(rectangle_data + (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); + } + } + pt1 = pt2; + pt2 = pt3; + } + } + + template + void get_error_rects(cT& posE, cT& negE, const pT& p) { + get_error_rects_shell(posE, negE, p.begin(), p.end()); + for(typename pT::iterator_holes_type iHb = p.begin_holes(); + iHb != p.end_holes(); ++iHb) { + get_error_rects_shell(posE, negE, iHb->begin(), iHb->end()); + } + } + + template + template + inline void polygon_45_set_data::applyAdaptiveBoolean_(polygon_45_set_data& result, + const polygon_45_set_data& rvalue) const { + result.clear(); + result.error_data_ = error_data_; + result.error_data_.insert(result.error_data_.end(), rvalue.error_data_.begin(), + rvalue.error_data_.end()); + if(is_manhattan() && rvalue.is_manhattan()) { + //convert each into polygon_90_set data and call boolean operations + polygon_90_set_data l90sd(VERTICAL), r90sd(VERTICAL), output(VERTICAL); + for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + for(typename value_type::const_iterator itr = rvalue.data_.begin(); itr != rvalue.data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + r90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + l90sd.sort(); + r90sd.sort(); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + } else if (op == 1) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + } else if (op == 2) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + } else if (op == 3) { + output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + result.data_.clear(); + result.insert(output); + result.is_manhattan_ = true; + result.dirty_ = false; + result.unsorted_ = false; + } else { + sort(); + rvalue.sort(); + try { + result.is_manhattan_ = applyBoolean45OpOnVectors(result.data_, data_, rvalue.data_); + } catch (std::string str) { + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + if(str == msg) { + result.clear(); + typedef typename coordinate_traits::manhattan_area_type Unit2; + typedef typename polygon_45_formation::Vertex45Compact Vertex45Compact2; + typedef std::vector Data2; + Data2 rvalue_data, lvalue_data, result_data; + rvalue_data.reserve(rvalue.data_.size()); + lvalue_data.reserve(data_.size()); + for(std::size_t i = 0 ; i < data_.size(); ++i) { + const Vertex45Compact& vi = data_[i]; + Vertex45Compact2 ci; + ci.pt = point_data(x(vi.pt), y(vi.pt)); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + lvalue_data.push_back(ci); + } + for(std::size_t i = 0 ; i < rvalue.data_.size(); ++i) { + const Vertex45Compact& vi = rvalue.data_[i]; + Vertex45Compact2 ci; + ci.pt = (point_data(x(vi.pt), y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + rvalue_data.push_back(ci); + } + scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); + scale_up_vertex_45_compact_range(rvalue_data.begin(), rvalue_data.end(), 2); + bool result_is_manhattan = applyBoolean45OpOnVectors(result_data, + lvalue_data, + rvalue_data ); + if(!result_is_manhattan) { + typename polygon_45_formation::Polygon45Formation pf(false); + //std::cout << "FORMING POLYGONS\n"; + std::vector > container; + pf.scan(container, result_data.begin(), result_data.end()); + Data2 error_data_out; + std::vector > pos_error_rects; + std::vector > neg_error_rects; + for(std::size_t i = 0; i < container.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, container[i]); + } + for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); + insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); + } + for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); + insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); + } + scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); + for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { + const Vertex45Compact2& vi = error_data_out[i]; + Vertex45Compact ci; + ci.pt.x(static_cast(x(vi.pt))); + ci.pt.y(static_cast(y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.error_data_.push_back(ci); + } + Data2 new_result_data; + std::sort(result_data.begin(), result_data.end()); + applyUnary45OpOnVectors(new_result_data, result_data); //OR operation + result_data.swap(new_result_data); + } + scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); + //result.data_.reserve(result_data.size()); + for(std::size_t i = 0 ; i < result_data.size(); ++i) { + const Vertex45Compact2& vi = result_data[i]; + Vertex45Compact ci; + ci.pt.x(static_cast(x(vi.pt))); + ci.pt.y(static_cast(y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.data_.push_back(ci); + } + result.is_manhattan_ = result_is_manhattan; + result.dirty_ = false; + result.unsorted_ = false; + } else { throw str; } + } + //std::cout << "DONE SCANNING\n"; + } + } + + template + template + inline void polygon_45_set_data::applyAdaptiveUnary_() const { + polygon_45_set_data result; + result.error_data_ = error_data_; + if(is_manhattan()) { + //convert each into polygon_90_set data and call boolean operations + polygon_90_set_data l90sd(VERTICAL); + for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) { + if((*itr).count[3] == 0) continue; //skip all non vertical edges + l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair((*itr).pt.y(), (*itr).count[3])), false, VERTICAL); + } + l90sd.sort(); +#ifdef BOOST_POLYGON_MSVC +#pragma warning (disable: 4127) +#endif + if(op == 0) { + l90sd.clean(); + } else if (op == 1) { + l90sd.self_intersect(); + } else if (op == 3) { + l90sd.self_xor(); + } +#ifdef BOOST_POLYGON_MSVC +#pragma warning (default: 4127) +#endif + result.data_.clear(); + result.insert(l90sd); + result.is_manhattan_ = true; + result.dirty_ = false; + result.unsorted_ = false; + } else { + sort(); + try { + result.is_manhattan_ = applyUnary45OpOnVectors(result.data_, data_); + } catch (std::string str) { + std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value."; + if(str == msg) { + result.clear(); + typedef typename coordinate_traits::manhattan_area_type Unit2; + typedef typename polygon_45_formation::Vertex45Compact Vertex45Compact2; + typedef std::vector Data2; + Data2 lvalue_data, result_data; + lvalue_data.reserve(data_.size()); + for(std::size_t i = 0 ; i < data_.size(); ++i) { + const Vertex45Compact& vi = data_[i]; + Vertex45Compact2 ci; + ci.pt.x(static_cast(x(vi.pt))); + ci.pt.y(static_cast(y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + lvalue_data.push_back(ci); + } + scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2); + bool result_is_manhattan = applyUnary45OpOnVectors(result_data, + lvalue_data ); + if(!result_is_manhattan) { + typename polygon_45_formation::Polygon45Formation pf(false); + //std::cout << "FORMING POLYGONS\n"; + std::vector > container; + pf.scan(container, result_data.begin(), result_data.end()); + Data2 error_data_out; + std::vector > pos_error_rects; + std::vector > neg_error_rects; + for(std::size_t i = 0; i < container.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, container[i]); + } + for(std::size_t i = 0; i < pos_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false); + insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false); + } + for(std::size_t i = 0; i < neg_error_rects.size(); ++i) { + insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true); + insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false); + } + scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2); + for(std::size_t i = 0 ; i < error_data_out.size(); ++i) { + const Vertex45Compact2& vi = error_data_out[i]; + Vertex45Compact ci; + ci.pt.x(static_cast(x(vi.pt))); + ci.pt.y(static_cast(y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.error_data_.push_back(ci); + } + Data2 new_result_data; + std::sort(result_data.begin(), result_data.end()); + applyUnary45OpOnVectors(new_result_data, result_data); //OR operation + result_data.swap(new_result_data); + } + scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2); + //result.data_.reserve(result_data.size()); + for(std::size_t i = 0 ; i < result_data.size(); ++i) { + const Vertex45Compact2& vi = result_data[i]; + Vertex45Compact ci; + ci.pt.x(static_cast(x(vi.pt))); + ci.pt.y(static_cast(y(vi.pt))); + ci.count = typename polygon_45_formation::Vertex45Count + ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); + result.data_.push_back(ci); + } + result.is_manhattan_ = result_is_manhattan; + result.dirty_ = false; + result.unsorted_ = false; + } else { throw str; } + } + //std::cout << "DONE SCANNING\n"; + } + data_.swap(result.data_); + error_data_.swap(result.error_data_); + dirty_ = result.dirty_; + unsorted_ = result.unsorted_; + is_manhattan_ = result.is_manhattan_; + } + + template + class property_merge_45 { + private: + typedef typename coordinate_traits::manhattan_area_type big_coord; + typedef typename polygon_45_property_merge::MergeSetData tsd; + tsd tsd_; + public: + inline property_merge_45() : tsd_() {} + inline property_merge_45(const property_merge_45& that) : tsd_(that.tsd_) {} + inline property_merge_45& operator=(const property_merge_45& that) { + tsd_ = that.tsd_; + return *this; + } + + inline void insert(const polygon_45_set_data& ps, property_type property) { + ps.clean(); + polygon_45_property_merge::populateMergeSetData(tsd_, ps.begin(), ps.end(), property); + } + template + inline void insert(const GeoObjT& geoObj, property_type property) { + polygon_45_set_data ps; + ps.insert(geoObj); + insert(ps, property); + } + + //merge properties of input geometries and store the resulting geometries of regions + //with unique sets of merged properties to polygons sets in a map keyed by sets of properties + // T = std::map, polygon_45_set_data > or + // T = std::map, polygon_45_set_data > + template + inline void merge(result_type& result) { + typedef typename result_type::key_type keytype; + typedef std::map > bigtype; + bigtype result_big; + polygon_45_property_merge::performMerge(result_big, tsd_); + std::vector > polys; + std::vector > pos_error_rects; + std::vector > neg_error_rects; + for(typename std::map >::iterator itr = result_big.begin(); + itr != result_big.end(); ++itr) { + polys.clear(); + (*itr).second.get(polys); + for(std::size_t i = 0; i < polys.size(); ++i) { + get_error_rects(pos_error_rects, neg_error_rects, polys[i]); + } + (*itr).second += pos_error_rects; + (*itr).second -= neg_error_rects; + (*itr).second.scale_down(2); + result[(*itr).first].insert((*itr).second); + } + } + }; + + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template + class connectivity_extraction_45 { + private: + typedef typename coordinate_traits::manhattan_area_type big_coord; + typedef typename polygon_45_touch::TouchSetData tsd; + tsd tsd_; + unsigned int nodeCount_; + public: + inline connectivity_extraction_45() : tsd_(), nodeCount_(0) {} + inline connectivity_extraction_45(const connectivity_extraction_45& that) : tsd_(that.tsd_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction_45& operator=(const connectivity_extraction_45& that) { + tsd_ = that.tsd_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_45_set_data& ps) { + ps.clean(); + polygon_45_touch::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_45_set_data ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template + inline void extract(GraphT& graph) { + polygon_45_touch::performTouch(graph, tsd_); + } + }; +} +} +#endif + diff --git a/include/boost/polygon/polygon_45_set_traits.hpp b/include/boost/polygon/polygon_45_set_traits.hpp new file mode 100755 index 0000000..cfc0f98 --- /dev/null +++ b/include/boost/polygon/polygon_45_set_traits.hpp @@ -0,0 +1,146 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_45_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + //default definition of polygon 45 set traits works for any model of polygon 45, polygon 45 with holes or any vector or list thereof + template + struct polygon_45_set_traits { + typedef typename get_coordinate_type::type >::type coordinate_type; + typedef typename get_iterator_type::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return get_iterator_type::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return get_iterator_type::end(polygon_set); + } + + static inline bool clean(const T& ) { return false; } + + static inline bool sorted(const T& ) { return false; } + }; + + template + struct is_45_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_45_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_45_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_45_polygonal_concept { typedef gtl_yes type; }; + + template + struct is_polygon_45_set_type { + typedef typename is_45_polygonal_concept::type>::type type; + }; + template + struct is_polygon_45_set_type > { + typedef typename gtl_or< + typename is_45_polygonal_concept >::type>::type, + typename is_45_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_polygon_45_set_type > { + typedef typename gtl_or< + typename is_45_polygonal_concept >::type>::type, + typename is_45_polygonal_concept::value_type>::type>::type>::type type; + }; + + template + struct is_mutable_polygon_45_set_type { + typedef typename gtl_same_type::type>::type type; + }; + template + struct is_mutable_polygon_45_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_45_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_mutable_polygon_45_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_45_polygonal_concept::value_type>::type>::type>::type type; + }; + + template + bool fracture_holes_45_by_concept() { return false; } + template <> + inline bool fracture_holes_45_by_concept() { return true; } + + template + void get_45_polygons_T(T& t, iT begin, iT end) { + typedef typename polygon_45_set_traits::coordinate_type Unit; + typedef typename geometry_concept::type CType; + typename polygon_45_formation::Polygon45Formation pf(fracture_holes_45_by_concept()); + //std::cout << "FORMING POLYGONS\n"; + pf.scan(t, begin, end); + } + + template + struct polygon_45_set_mutable_traits {}; + template + struct polygon_45_set_mutable_traits > { + template + static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_45_set_data >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.sort(); + ps.clean(); + get_45_polygons_T(polygon_set, ps.begin(), ps.end()); + } + }; + template + struct polygon_45_set_mutable_traits > { + template + static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_45_set_data >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.sort(); + ps.clean(); + get_45_polygons_T(polygon_set, ps.begin(), ps.end()); + } + }; + + template + struct polygon_45_set_mutable_traits > { + template + static inline void set(polygon_45_set_data& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.set(input_begin, input_end); + } + }; + template + struct polygon_45_set_traits > { + typedef typename polygon_45_set_data::coordinate_type coordinate_type; + typedef typename polygon_45_set_data::iterator_type iterator_type; + typedef typename polygon_45_set_data::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_45_set_data& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_45_set_data& polygon_set) { + return polygon_set.end(); + } + + static inline bool clean(const polygon_45_set_data& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_45_set_data& polygon_set) { polygon_set.sort(); return true; } + + }; +} +} +#endif + diff --git a/include/boost/polygon/polygon_45_with_holes_data.hpp b/include/boost/polygon/polygon_45_with_holes_data.hpp new file mode 100755 index 0000000..717bbd3 --- /dev/null +++ b/include/boost/polygon/polygon_45_with_holes_data.hpp @@ -0,0 +1,108 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_45_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_45_WITH_HOLES_DATA_HPP +#include "isotropy.hpp" +#include "polygon_45_data.hpp" +namespace boost { namespace polygon{ +struct polygon_45_with_holes_concept; +template +class polygon_45_with_holes_data { +public: + typedef polygon_45_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_45_data::iterator_type iterator_type; + typedef typename std::list >::const_iterator iterator_holes_type; + typedef polygon_45_data hole_type; + typedef typename coordinate_traits::coordinate_distance area_type; + typedef point_data point_type; + + // default constructor of point does not initialize x and y + inline polygon_45_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + template + inline polygon_45_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { + set(input_begin, input_end); + } + + template + inline polygon_45_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { + set(input_begin, input_end); + set_holes(holes_begin, holes_end); + } + + template + inline polygon_45_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_45_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set((*input_begin).begin(), (*input_begin).end()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_45_with_holes_data(const polygon_45_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_45_with_holes_data& operator=(const polygon_45_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template + inline polygon_45_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +public: + polygon_45_data self_; + std::list holes_; +}; + + +} +} +#endif + diff --git a/include/boost/polygon/polygon_90_data.hpp b/include/boost/polygon/polygon_90_data.hpp new file mode 100755 index 0000000..7e1d969 --- /dev/null +++ b/include/boost/polygon/polygon_90_data.hpp @@ -0,0 +1,80 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_DATA_HPP +namespace boost { namespace polygon{ +struct polygon_90_concept; +template +class polygon_90_data { +public: + typedef polygon_90_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector::const_iterator compact_iterator_type; + typedef iterator_compact_to_points > iterator_type; + typedef typename coordinate_traits::area_type area_type; + + inline polygon_90_data() : coords_() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_90_data& set(iT begin_point, iT end_point) { + return set_compact(iterator_points_to_compact::value_type>(begin_point, end_point), + iterator_points_to_compact::value_type>(end_point, end_point)); + } + + template + inline polygon_90_data& set_compact(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + while(input_begin != input_end) { + coords_.insert(coords_.end(), *input_begin); + ++input_begin; + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_90_data(const polygon_90_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_90_data& operator=(const polygon_90_data& that) { + coords_ = that.coords_; + return *this; + } + + template + inline polygon_90_data& operator=(const T2& rvalue); + + // assignment operator (since we have dynamic memory do a deep copy) + inline bool operator==(const polygon_90_data& that) const { + return coords_ == that.coords_; + } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return iterator_type(coords_.begin(), coords_.end()); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return iterator_type(coords_.end(), coords_.end()); } + + // get begin iterator, returns a pointer to a const Unit + inline compact_iterator_type begin_compact() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline compact_iterator_type end_compact() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +private: + std::vector coords_; +}; + + +} +} +#endif + diff --git a/include/boost/polygon/polygon_90_set_concept.hpp b/include/boost/polygon/polygon_90_set_concept.hpp new file mode 100755 index 0000000..09d5eee --- /dev/null +++ b/include/boost/polygon/polygon_90_set_concept.hpp @@ -0,0 +1,548 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_90_SET_CONCEPT_HPP +#include "polygon_90_set_data.hpp" +#include "polygon_90_set_traits.hpp" +namespace boost { namespace polygon{ + + template + typename enable_if< typename is_polygon_90_set_type::type, + typename polygon_90_set_traits::iterator_type>::type + begin_90_set_data(const polygon_set_type& polygon_set) { + return polygon_90_set_traits::begin(polygon_set); + } + + template + typename enable_if< typename is_polygon_90_set_type::type, + typename polygon_90_set_traits::iterator_type>::type + end_90_set_data(const polygon_set_type& polygon_set) { + return polygon_90_set_traits::end(polygon_set); + } + + template + typename enable_if< typename is_polygon_90_set_type::type, + orientation_2d>::type + scanline_orientation(const polygon_set_type& polygon_set) { + return polygon_90_set_traits::orient(polygon_set); + } + + template + typename enable_if< typename is_polygon_90_set_type::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_90_set_traits::clean(polygon_set); + } + + //assign + template + typename enable_if < + typename gtl_and< + typename is_mutable_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + polygon_90_set_mutable_traits::set(lvalue, begin_90_set_data(rvalue), end_90_set_data(rvalue), + scanline_orientation(rvalue)); + return lvalue; + } + + template + struct are_not_both_rectangle_concept { typedef gtl_yes type; }; + template <> + struct are_not_both_rectangle_concept { typedef gtl_no type; }; + + //equivalence + template + typename enable_if< typename gtl_and_3< + typename is_polygon_90_set_type::type, + typename is_polygon_90_set_type::type, + typename are_not_both_rectangle_concept::type, + typename geometry_concept::type>::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_90_set_data::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_90_set_data::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + + //get rectangle tiles (slicing orientation is vertical) + template + typename enable_if< typename gtl_if::type>::type, + void>::type + get_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_90_set_data::coordinate_type> ps(VERTICAL); + assign(ps, polygon_set); + ps.get_rectangles(output); + } + + //get rectangle tiles + template + typename enable_if< typename gtl_if::type>::type, + void>::type + get_rectangles(output_container_type& output, const polygon_set_type& polygon_set, orientation_2d slicing_orientation) { + clean(polygon_set); + polygon_90_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_rectangles(output, slicing_orientation); + } + + //get: min_rectangles max_rectangles + template + typename enable_if ::type, + typename gtl_same_type::value_type>::type>::type>::type, + void>::type + get_max_rectangles(output_container_type& output, const polygon_set_type& polygon_set) { + std::vector::coordinate_type> > rects; + assign(rects, polygon_set); + MaxCover::coordinate_type>::getMaxCover(output, rects, scanline_orientation(polygon_set)); + } + + //clear + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_90_set_data::coordinate_type> ps(scanline_orientation(polygon_set)); + assign(polygon_set, ps); + } + + //empty + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_90_set_data(polygon_set) == end_90_set_data(polygon_set); + polygon_90_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template + typename enable_if ::type, + typename is_mutable_rectangle_concept::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + typename coordinate_traits::coordinate_type>::manhattan_area_type>::type + area(const polygon_set_type& polygon_set) { + typedef rectangle_data::coordinate_type> rectangle_type; + typedef typename coordinate_traits::coordinate_type>::manhattan_area_type area_type; + std::vector rects; + assign(rects, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < rects.size(); ++i) { + retval += (area_type)area(rects[i]); + } + return retval; + } + + //interact + template + typename enable_if ::type, + typename is_mutable_polygon_90_set_type::type>::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps(scanline_orientation(polygon_set_2)); + polygon_90_set_data ps2(ps); + ps.insert(polygon_set_1); + ps2.insert(polygon_set_2); + ps.interact(ps2); + assign(polygon_set_1, ps); + return polygon_set_1; + } + + //self_intersect + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + self_intersect(polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.self_intersect(); + assign(polygon_set, ps); + return polygon_set; + } + + //self_xor + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + self_xor(polygon_set_type& polygon_set) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.self_xor(); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + return bloat(polygon_set, bloating, bloating, bloating, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return bloat(polygon_set, bloating, bloating, 0, 0); + return bloat(polygon_set, 0, 0, bloating, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type low_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type high_bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return bloat(polygon_set, low_bloating, high_bloating, 0, 0); + return bloat(polygon_set, 0, 0, low_bloating, high_bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + if(dir == direction_2d(EAST)) + return bloat(polygon_set, 0, bloating, 0, 0); + if(dir == direction_2d(WEST)) + return bloat(polygon_set, bloating, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return bloat(polygon_set, 0, 0, bloating, 0); + return bloat(polygon_set, 0, 0, 0, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type north_bloating) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.bloat(west_bloating, east_bloating, south_bloating, north_bloating); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { + return shrink(polygon_set, shrinking, shrinking, shrinking, shrinking); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { + if(orient == orientation_2d(HORIZONTAL)) + return shrink(polygon_set, shrinking, shrinking, 0, 0); + return shrink(polygon_set, 0, 0, shrinking, shrinking); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type low_shrinking, + typename coordinate_traits::coordinate_type>::unsigned_area_type high_shrinking) { + if(orient == orientation_2d(HORIZONTAL)) + return shrink(polygon_set, low_shrinking, high_shrinking, 0, 0); + return shrink(polygon_set, 0, 0, low_shrinking, high_shrinking); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { + if(dir == direction_2d(EAST)) + return shrink(polygon_set, 0, shrinking, 0, 0); + if(dir == direction_2d(WEST)) + return shrink(polygon_set, shrinking, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return shrink(polygon_set, 0, 0, shrinking, 0); + return shrink(polygon_set, 0, 0, 0, shrinking); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type west_shrinking, + typename coordinate_traits::coordinate_type>::unsigned_area_type east_shrinking, + typename coordinate_traits::coordinate_type>::unsigned_area_type south_shrinking, + typename coordinate_traits::coordinate_type>::unsigned_area_type north_shrinking) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.shrink(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + if(resizing > 0) { + return bloat(polygon_set, resizing); + } + if(resizing < 0) { + return shrink(polygon_set, -resizing); + } + return polygon_set; + } + + //positive or negative values allow for any and all directions of sizing + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type west, coord_type east, coord_type south, coord_type north) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.resize(west, east, south, north); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + return grow_and(polygon_set, bloating, bloating, bloating, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return grow_and(polygon_set, bloating, bloating, 0, 0); + return grow_and(polygon_set, 0, 0, bloating, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, orientation_2d orient, + typename coordinate_traits::coordinate_type>::unsigned_area_type low_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type high_bloating) { + if(orient == orientation_2d(HORIZONTAL)) + return grow_and(polygon_set, low_bloating, high_bloating, 0, 0); + return grow_and(polygon_set, 0, 0, low_bloating, high_bloating); + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, direction_2d dir, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + if(dir == direction_2d(EAST)) + return grow_and(polygon_set, 0, bloating, 0, 0); + if(dir == direction_2d(WEST)) + return grow_and(polygon_set, bloating, 0, 0, 0); + if(dir == direction_2d(SOUTH)) + return grow_and(polygon_set, 0, 0, bloating, 0); + return grow_and(polygon_set, 0, 0, 0, bloating); + } + + template + typename enable_if< typename gtl_if::type>::type, + polygon_set_type>::type & + grow_and(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type west_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type east_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type south_bloating, + typename coordinate_traits::coordinate_type>::unsigned_area_type north_bloating) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + std::vector > polys; + assign(polys, polygon_set); + clear(polygon_set); + polygon_90_set_data ps(scanline_orientation(polygon_set)); + for(std::size_t i = 0; i < polys.size(); ++i) { + polygon_90_set_data tmpPs(scanline_orientation(polygon_set)); + tmpPs.insert(polys[i]); + bloat(tmpPs, west_bloating, east_bloating, south_bloating, north_bloating); + tmpPs.clean(); //apply implicit OR on tmp polygon set + ps.insert(tmpPs); + } + self_intersect(ps); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type> + ::unsigned_area_type factor) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type> + ::unsigned_area_type factor) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + scale(polygon_set_type& polygon_set, + const scaling_type& scaling) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.scale(scaling); + assign(polygon_set, ps); + return polygon_set; + } + + //move + template + polygon_set_type& + move(polygon_set_type& polygon_set, + orientation_2d orient, typename polygon_90_set_traits::coordinate_type displacement, + typename enable_if< typename is_mutable_polygon_90_set_type::type>::type * = 0) { + if(orient == HORIZONTAL) + return move(polygon_set, displacement, 0); + else + return move(polygon_set, 0, displacement); + } + + template + polygon_set_type& + move(polygon_set_type& polygon_set, typename polygon_90_set_traits::coordinate_type x_displacement, + typename polygon_90_set_traits::coordinate_type y_displacement, + typename enable_if< typename is_mutable_polygon_90_set_type::type>::type * = 0 + ) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.move(x_displacement, y_displacement); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + polygon_90_set_data ps; + assign(ps, polygon_set); + ps.transform(transformation); + ps.clean(); + assign(polygon_set, ps); + return polygon_set; + typedef typename polygon_90_set_traits::coordinate_type Unit; + } + + //keep + template + typename enable_if< typename is_mutable_polygon_90_set_type::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_area, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_area, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_90_set_traits::coordinate_type Unit; + typedef typename coordinate_traits::unsigned_area_type uat; + std::list > polys; + assign(polys, polygon_set); + clear(polygon_set); + typename std::list >::iterator itr_nxt; + for(typename std::list >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + uat parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + +} +} +#include "detail/polygon_90_set_view.hpp" +#endif diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp new file mode 100755 index 0000000..7013ca5 --- /dev/null +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -0,0 +1,949 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_SET_DATA_HPP +#include "isotropy.hpp" +#include "point_concept.hpp" +#include "point_3d_concept.hpp" +#include "transform.hpp" +#include "interval_concept.hpp" +#include "rectangle_concept.hpp" +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" +#include "polygon_traits.hpp" + +//manhattan boolean algorithms +#include "detail/boolean_op.hpp" +#include "detail/polygon_formation.hpp" +#include "detail/rectangle_formation.hpp" +#include "detail/max_cover.hpp" +#include "detail/property_merge.hpp" +#include "detail/polygon_90_touch.hpp" +#include "detail/iterator_geometry_to_set.hpp" + +namespace boost { namespace polygon{ + template + class polygon_90_set_view; + + template + class polygon_90_set_data { + public: + typedef T coordinate_type; + typedef std::vector > > value_type; + typedef typename std::vector > >::const_iterator iterator_type; + typedef polygon_90_set_data operator_arg_type; + + // default constructor + inline polygon_90_set_data() : orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) {} + + // constructor + inline polygon_90_set_data(orientation_2d orient) : orient_(orient), data_(), dirty_(false), unsorted_(false) {} + + // constructor from an iterator pair over vertex data + template + inline polygon_90_set_data(orientation_2d orient, iT input_begin, iT input_end) : + orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) { + dirty_ = true; + unsorted_ = true; + for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } + } + + // copy constructor + inline polygon_90_set_data(const polygon_90_set_data& that) : + orient_(that.orient_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_) {} + + template + inline polygon_90_set_data(const polygon_90_set_view& that); + + // copy with orientation change constructor + inline polygon_90_set_data(orientation_2d orient, const polygon_90_set_data& that) : + orient_(orient), data_(), dirty_(false), unsorted_(false) { + insert(that, false, that.orient_); + } + + // destructor + inline ~polygon_90_set_data() {} + + // assignement operator + inline polygon_90_set_data& operator=(const polygon_90_set_data& that) { + if(this == &that) return *this; + orient_ = that.orient_; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + return *this; + } + + template + inline polygon_90_set_data& operator=(const polygon_90_set_view& that); + + template + inline polygon_90_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, orientation_2d orient = HORIZONTAL) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + if(orient == orient_) + data_.insert(data_.end(), input_begin, input_end); + else { + for( ; input_begin != input_end; ++input_begin) { + insert(*input_begin, false, orient); + } + } + } + + // insert iterator range + template + inline void insert(iT input_begin, iT input_end, orientation_2d orient = HORIZONTAL) { + if(input_begin == input_end) return; + dirty_ = true; + unsorted_ = true; + for( ; input_begin != input_end; ++input_begin) { + insert(*input_begin, false, orient); + } + } + + inline void insert(const polygon_90_set_data& polygon_set) { + insert(polygon_set.begin(), polygon_set.end(), polygon_set.orient()); + } + + inline void insert(const std::pair, point_data >, int>& edge, bool is_hole = false, + orientation_2d orient = HORIZONTAL) { + std::pair > vertex; + vertex.first = edge.first.first.x(); + vertex.second.first = edge.first.first.y(); + vertex.second.second = edge.second * (is_hole ? -1 : 1); + insert(vertex, false, VERTICAL); + vertex.first = edge.first.second.x(); + vertex.second.first = edge.first.second.y(); + vertex.second.second *= -1; + insert(vertex, false, VERTICAL); + } + + template + inline void insert(const geometry_type& geometry_object, bool is_hole = false, orientation_2d = HORIZONTAL) { + iterator_geometry_to_set::type, geometry_type> + begin_input(geometry_object, LOW, orient_, is_hole), end_input(geometry_object, HIGH, orient_, is_hole); + insert(begin_input, end_input, orient_); + } + + inline void insert(const std::pair >& vertex, bool is_hole = false, + orientation_2d orient = HORIZONTAL) { + data_.push_back(vertex); + if(orient != orient_) std::swap(data_.back().first, data_.back().second.first); + if(is_hole) data_.back().second.second *= -1; + dirty_ = true; + unsorted_ = true; + } + + inline void insert(coordinate_type major_coordinate, const std::pair, int>& edge) { + std::pair > vertex; + vertex.first = major_coordinate; + vertex.second.first = edge.first.get(LOW); + vertex.second.second = edge.second; + insert(vertex, false, orient_); + vertex.second.first = edge.first.get(HIGH); + vertex.second.second *= -1; + insert(vertex, false, orient_); + } + + template + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept::type()); + } + + template + inline void get_polygons(output_container& output) const { + get_dispatch(output, polygon_90_concept()); + } + + template + inline void get_rectangles(output_container& output) const { + clean(); + form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); + } + + template + inline void get_rectangles(output_container& output, orientation_2d slicing_orientation) const { + if(slicing_orientation == orient_) { + get_rectangles(output); + } else { + polygon_90_set_data ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + output_container result; + ps.get_rectangles(result); + for(typename output_container::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + output.insert(output.end(), result.begin(), result.end()); + } + } + + // equivalence operator + inline bool operator==(const polygon_90_set_data& p) const { + if(orient_ == p.orient()) { + clean(); + p.clean(); + return data_ == p.data_; + } else { + return false; + } + } + + // inequivalence operator + inline bool operator!=(const polygon_90_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_90_set_data + inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } + + // find out if Polygon set is empty + inline bool empty() const { clean(); return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + // get the scanline orientation of the polygon set + inline orientation_2d orient() const { return orient_; } + + polygon_90_set_data& operator-=(const polygon_90_set_data& that) { + sort(); + that.sort(); + value_type data; + std::swap(data, data_); + applyBooleanBinaryOp(data.begin(), data.end(), + that.begin(), that.end(), boolean_op::BinaryCount()); + return *this; + } + polygon_90_set_data& operator^=(const polygon_90_set_data& that) { + sort(); + that.sort(); + value_type data; + std::swap(data, data_); + applyBooleanBinaryOp(data.begin(), data.end(), + that.begin(), that.end(), boolean_op::BinaryCount()); + return *this; + } + polygon_90_set_data& operator&=(const polygon_90_set_data& that) { + sort(); + that.sort(); + value_type data; + std::swap(data, data_); + applyBooleanBinaryOp(data.begin(), data.end(), + that.begin(), that.end(), boolean_op::BinaryCount()); + return *this; + } + polygon_90_set_data& operator|=(const polygon_90_set_data& that) { + insert(that); + return *this; + } + + void clean() const { + sort(); + if(dirty_) { + boolean_op::default_arg_workaround::applyBooleanOr(data_); + dirty_ = false; + } + } + + void sort() const{ + if(unsorted_) { + std::sort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template + void set(input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + data_.clear(); + data_.insert(data_.end(), input_begin, input_end); + orient_ = orient; + dirty_ = true; + unsorted_ = true; + } + + void set(const value_type& value, orientation_2d orient) { + data_ = value; + orient_ = orient; + dirty_ = true; + unsorted_ = true; + } + + //extents + template + bool + extents(rectangle_type& extents_rectangle) const { + clean(); + if(data_.empty()) return false; + if(orient_ == HORIZONTAL) + set_points(extents_rectangle, point_data(data_[0].second.first, data_[0].first), + point_data(data_[data_.size() - 1].second.first, data_[data_.size() - 1].first)); + else + set_points(extents_rectangle, point_data(data_[0].first, data_[0].second.first), + point_data(data_[data_.size() - 1].first, data_[data_.size() - 1].second.first)); + for(std::size_t i = 1; i < data_.size() - 1; ++i) { + if(orient_ == HORIZONTAL) + encompass(extents_rectangle, point_data(data_[i].second.first, data_[i].first)); + else + encompass(extents_rectangle, point_data(data_[i].first, data_[i].second.first)); + } + return true; + } + + polygon_90_set_data& + bloat2(typename coordinate_traits::unsigned_area_type west_bloating, + typename coordinate_traits::unsigned_area_type east_bloating, + typename coordinate_traits::unsigned_area_type south_bloating, + typename coordinate_traits::unsigned_area_type north_bloating) { + std::vector > rects; + clean(); + rects.reserve(data_.size() / 2); + get(rects); + rectangle_data convolutionRectangle(interval_data(-((coordinate_type)west_bloating), + (coordinate_type)east_bloating), + interval_data(-((coordinate_type)south_bloating), + (coordinate_type)north_bloating)); + for(typename std::vector >::iterator itr = rects.begin(); + itr != rects.end(); ++itr) { + convolve(*itr, convolutionRectangle); + } + clear(); + insert(rects.begin(), rects.end()); + return *this; + } + + static void modify_pt(point_data& pt, const point_data& prev_pt, + const point_data& current_pt, const point_data& next_pt, + coordinate_type west_bloating, + coordinate_type east_bloating, + coordinate_type south_bloating, + coordinate_type north_bloating) { + bool pxl = prev_pt.x() < current_pt.x(); + bool pyl = prev_pt.y() < current_pt.y(); + bool nxl = next_pt.x() < current_pt.x(); + bool nyl = next_pt.y() < current_pt.y(); + bool pxg = prev_pt.x() > current_pt.x(); + bool pyg = prev_pt.y() > current_pt.y(); + bool nxg = next_pt.x() > current_pt.x(); + bool nyg = next_pt.y() > current_pt.y(); + //two of the four if statements will execute + if(pxl) + pt.y(current_pt.y() - south_bloating); + if(pxg) + pt.y(current_pt.y() + north_bloating); + if(nxl) + pt.y(current_pt.y() + north_bloating); + if(nxg) + pt.y(current_pt.y() - south_bloating); + if(pyl) + pt.x(current_pt.x() + east_bloating); + if(pyg) + pt.x(current_pt.x() - west_bloating); + if(nyl) + pt.x(current_pt.x() - west_bloating); + if(nyg) + pt.x(current_pt.x() + east_bloating); + } + static void resize_poly_up(std::vector >& poly, + coordinate_type west_bloating, + coordinate_type east_bloating, + coordinate_type south_bloating, + coordinate_type north_bloating) { + point_data first_pt = poly[0]; + point_data second_pt = poly[1]; + point_data prev_pt = poly[0]; + point_data current_pt = poly[1]; + for(std::size_t i = 2; i < poly.size(); ++i) { + point_data next_pt = poly[i]; + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + prev_pt = current_pt; + current_pt = next_pt; + } + point_data next_pt = first_pt; + modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); + remove_colinear_pts(poly); + } + static bool resize_poly_down(std::vector >& poly, + coordinate_type west_shrinking, + coordinate_type east_shrinking, + coordinate_type south_shrinking, + coordinate_type north_shrinking) { + rectangle_data extents_rectangle; + set_points(extents_rectangle, poly[0], poly[0]); + point_data first_pt = poly[0]; + point_data second_pt = poly[1]; + point_data prev_pt = poly[0]; + point_data current_pt = poly[1]; + encompass(extents_rectangle, current_pt); + for(int i = 2; i < poly.size(); ++i) { + point_data next_pt = poly[i]; + encompass(extents_rectangle, next_pt); + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + prev_pt = current_pt; + current_pt = next_pt; + } + if(delta(extents_rectangle, HORIZONTAL) < std::abs(west_shrinking + east_shrinking)) + return false; + if(delta(extents_rectangle, VERTICAL) < std::abs(north_shrinking + south_shrinking)) + return false; + point_data next_pt = first_pt; + modify_pt(poly.back(), prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); + return remove_colinear_pts(poly); + } + + static bool remove_colinear_pts(std::vector >& poly) { + bool found_colinear = true; + while(found_colinear) { + found_colinear = false; + typename std::vector >::iterator itr = poly.begin(); + itr += poly.size() - 1; //get last element position + typename std::vector >::iterator itr2 = poly.begin(); + typename std::vector >::iterator itr3 = itr2; + ++itr3; + std::size_t count = 0; + for( ; itr3 < poly.end(); ++itr3) { + if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || + ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { + ++count; + found_colinear = true; + } else { + itr = itr2; + ++itr2; + } + *itr2 = *itr3; + } + itr3 = poly.begin(); + if(((*itr).x() == (*itr2).x() && (*itr).x() == (*itr3).x()) || + ((*itr).y() == (*itr2).y() && (*itr).y() == (*itr3).y()) ) { + ++count; + found_colinear = true; + } + poly.erase(poly.end() - count, poly.end()); + } + return poly.size() >= 4; + } + + polygon_90_set_data& + bloat(typename coordinate_traits::unsigned_area_type west_bloating, + typename coordinate_traits::unsigned_area_type east_bloating, + typename coordinate_traits::unsigned_area_type south_bloating, + typename coordinate_traits::unsigned_area_type north_bloating) { + std::list > polys; + get(polys); + clear(); + for(typename std::list >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + //polygon_90_set_data psref; + //psref.insert(view_as((*itr).self_)); + //rectangle_data prerect; + //psref.extents(prerect); + resize_poly_up((*itr).self_.coords_, west_bloating, east_bloating, south_bloating, north_bloating); + iterator_geometry_to_set > > + begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); + insert(begin_input, end_input, orient_); + //polygon_90_set_data pstest; + //pstest.insert(view_as((*itr).self_)); + //psref.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); + //if(!equivalence(psref, pstest)) { + // std::cout << "test failed\n"; + //} + for(typename std::list >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + //rectangle_data rect; + //psref.extents(rect); + //polygon_90_set_data psrefhole; + //psrefhole.insert(prerect); + //psrefhole.insert(view_as(*itrh), true); + //polygon_45_data testpoly(*itrh); + if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { + iterator_geometry_to_set > > + begin_input(view_as(*itrh), LOW, orient_, true, true), + end_input(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input, end_input, orient_); + //polygon_90_set_data pstesthole; + //pstesthole.insert(rect); + //iterator_geometry_to_set > > + // begin_input2(view_as(*itrh), LOW, orient_, true, true); + //pstesthole.insert(begin_input2, end_input, orient_); + //psrefhole.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); + //if(!equivalence(psrefhole, pstesthole)) { + // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; + // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; + // polygon_90_set_data c(psrefhole); + // c.clean(); + // polygon_90_set_data a(pstesthole); + // polygon_90_set_data b(pstesthole); + // a.sort(); + // b.clean(); + // std::cout << "test hole failed\n"; + // //std::cout << testpoly << std::endl; + //} + } + } + } + return *this; + } + + polygon_90_set_data& + shrink(typename coordinate_traits::unsigned_area_type west_shrinking, + typename coordinate_traits::unsigned_area_type east_shrinking, + typename coordinate_traits::unsigned_area_type south_shrinking, + typename coordinate_traits::unsigned_area_type north_shrinking) { + std::list > polys; + get(polys); + clear(); + for(typename std::list >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + //polygon_90_set_data psref; + //psref.insert(view_as((*itr).self_)); + //rectangle_data prerect; + //psref.extents(prerect); + //polygon_45_data testpoly((*itr).self_); + if(resize_poly_down((*itr).self_.coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking)) { + iterator_geometry_to_set > > + begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); + insert(begin_input, end_input, orient_); + //iterator_geometry_to_set > > + // begin_input2(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); + //polygon_90_set_data pstest; + //pstest.insert(begin_input2, end_input, orient_); + //psref.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + //if(!equivalence(psref, pstest)) { + // std::cout << "test failed\n"; + //} + for(typename std::list >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + //rectangle_data rect; + //psref.extents(rect); + //polygon_90_set_data psrefhole; + //psrefhole.insert(prerect); + //psrefhole.insert(view_as(*itrh), true); + //polygon_45_data testpoly(*itrh); + resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); + iterator_geometry_to_set > > + begin_input(view_as(*itrh), LOW, orient_, true, true), + end_input(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input, end_input, orient_); + //polygon_90_set_data pstesthole; + //pstesthole.insert(rect); + //iterator_geometry_to_set > > + // begin_input2(view_as(*itrh), LOW, orient_, true, true); + //pstesthole.insert(begin_input2, end_input, orient_); + //psrefhole.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); + //if(!equivalence(psrefhole, pstesthole)) { + // std::cout << (winding(testpoly) == CLOCKWISE) << std::endl; + // std::cout << (winding(*itrh) == CLOCKWISE) << std::endl; + // polygon_90_set_data c(psrefhole); + // c.clean(); + // polygon_90_set_data a(pstesthole); + // polygon_90_set_data b(pstesthole); + // a.sort(); + // b.clean(); + // std::cout << "test hole failed\n"; + // //std::cout << testpoly << std::endl; + //} + } + } + } + return *this; + } + + polygon_90_set_data& + shrink2(typename coordinate_traits::unsigned_area_type west_shrinking, + typename coordinate_traits::unsigned_area_type east_shrinking, + typename coordinate_traits::unsigned_area_type south_shrinking, + typename coordinate_traits::unsigned_area_type north_shrinking) { + rectangle_data externalBoundary; + if(!extents(externalBoundary)) return *this; + ::boost::polygon::bloat(externalBoundary, 10); //bloat by diferential ammount + //insert a hole that encompasses the data + insert(externalBoundary, true); //note that the set is in a dirty state now + sort(); //does not apply implicit OR operation + std::vector > rects; + rects.reserve(data_.size() / 2); + //begin does not apply implicit or operation, this is a dirty range + form_rectangles(rects, data_.begin(), data_.end(), orient_, rectangle_concept()); + clear(); + rectangle_data convolutionRectangle(interval_data(-((coordinate_type)east_shrinking), + (coordinate_type)west_shrinking), + interval_data(-((coordinate_type)north_shrinking), + (coordinate_type)south_shrinking)); + for(typename std::vector >::iterator itr = rects.begin(); + itr != rects.end(); ++itr) { + rectangle_data& rect = *itr; + convolve(rect, convolutionRectangle); + //insert rectangle as a hole + insert(rect, true); + } + convolve(externalBoundary, convolutionRectangle); + //insert duplicate of external boundary as solid to cancel out the external hole boundaries + insert(externalBoundary); + clean(); //we have negative values in the set, so we need to apply an OR operation to make it valid input to a boolean + return *this; + } + + polygon_90_set_data& + shrink(direction_2d dir, typename coordinate_traits::unsigned_area_type shrinking) { + if(dir == WEST) + return shrink(shrinking, 0, 0, 0); + if(dir == EAST) + return shrink(0, shrinking, 0, 0); + if(dir == SOUTH) + return shrink(0, 0, shrinking, 0); + if(dir == NORTH) + return shrink(0, 0, 0, shrinking); + } + + polygon_90_set_data& + bloat(direction_2d dir, typename coordinate_traits::unsigned_area_type shrinking) { + if(dir == WEST) + return bloat(shrinking, 0, 0, 0); + if(dir == EAST) + return bloat(0, shrinking, 0, 0); + if(dir == SOUTH) + return bloat(0, 0, shrinking, 0); + if(dir == NORTH) + return bloat(0, 0, 0, shrinking); + } + + polygon_90_set_data& + resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north); + + polygon_90_set_data& move(coordinate_type x_delta, coordinate_type y_delta) { + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + (*itr).first += x_delta; + (*itr).second.first += y_delta; + } else { + (*itr).second.first += x_delta; + (*itr).first += y_delta; + } + } + return *this; + } + + // transform set + template + polygon_90_set_data& transform(const transformation_type& transformation) { + direction_2d dir1, dir2; + transformation.get_directions(dir1, dir2); + int sign = dir1.get_sign() * dir2.get_sign(); + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + transformation.transform((*itr).first, (*itr).second.first); + } else { + transformation.transform((*itr).second.first, (*itr).first); + } + (*itr).second.second *= sign; + } + if(dir1 != EAST || dir2 != NORTH) + unsorted_ = true; //some mirroring or rotation must have happened + return *this; + } + + // scale set + polygon_90_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor) { + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first *= (coordinate_type)factor; + (*itr).second.first *= (coordinate_type)factor; + } + return *this; + } + polygon_90_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor) { + typedef typename coordinate_traits::coordinate_distance dt; + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first = scaling_policy::round((dt)((*itr).first) / (dt)factor); + (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) / (dt)factor); + } + unsorted_ = true; //scaling down can make coordinates equal that were not previously equal + return *this; + } + template + polygon_90_set_data& scale(const anisotropic_scale_factor& scaling) { + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + scaling.scale((*itr).first, (*itr).second.first); + } else { + scaling.scale((*itr).second.first, (*itr).first); + } + } + unsorted_ = true; + return *this; + } + template + polygon_90_set_data& scale_with(const scaling_type& scaling) { + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + if(orient_ == orientation_2d(VERTICAL)) { + scaling.scale((*itr).first, (*itr).second.first); + } else { + scaling.scale((*itr).second.first, (*itr).first); + } + } + unsorted_ = true; + return *this; + } + polygon_90_set_data& scale(double factor) { + typedef typename coordinate_traits::coordinate_distance dt; + for(typename std::vector > >::iterator + itr = data_.begin(); itr != data_.end(); ++itr) { + (*itr).first = scaling_policy::round((dt)((*itr).first) * (dt)factor); + (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) * (dt)factor); + } + unsorted_ = true; //scaling make coordinates equal that were not previously equal + return *this; + } + + polygon_90_set_data& self_xor() { + sort(); + if(dirty_) { //if it is clean it is a no-op + boolean_op::default_arg_workaround::applyBooleanOr(data_); + dirty_ = false; + } + return *this; + } + + polygon_90_set_data& self_intersect() { + sort(); + if(dirty_) { //if it is clean it is a no-op + interval_data ivl((std::numeric_limits::min)(), (std::numeric_limits::max)()); + rectangle_data rect(ivl, ivl); + insert(rect, true); + clean(); + } + return *this; + } + + inline polygon_90_set_data& interact(const polygon_90_set_data& that) { + typedef coordinate_type Unit; + if(that.dirty_) that.clean(); + typename touch_90_operation::TouchSetData tsd; + touch_90_operation::populateTouchSetData(tsd, that.data_, 0); + std::vector > polys; + get(polys); + std::vector > graph(polys.size()+1, std::set()); + for(std::size_t i = 0; i < polys.size(); ++i){ + polygon_90_set_data psTmp(that.orient_); + psTmp.insert(polys[i]); + psTmp.clean(); + touch_90_operation::populateTouchSetData(tsd, psTmp.data_, i+1); + } + touch_90_operation::performTouch(graph, tsd); + clear(); + for(std::set::iterator itr = graph[0].begin(); itr != graph[0].end(); ++itr){ + insert(polys[(*itr)-1]); + } + dirty_ = false; + return *this; + } + + + template + void applyBooleanBinaryOp(iterator_type_1 itr1, iterator_type_1 itr1_end, + iterator_type_2 itr2, iterator_type_2 itr2_end, + T2 defaultCount) { + data_.clear(); + boolean_op::applyBooleanBinaryOp(data_, itr1, itr1_end, itr2, itr2_end, defaultCount); + } + + private: + orientation_2d orient_; + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + + private: + //functions + template + void get_dispatch(output_container& output, rectangle_concept ) const { + clean(); + form_rectangles(output, data_.begin(), data_.end(), orient_, rectangle_concept()); + } + template + void get_dispatch(output_container& output, polygon_90_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_90_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_dispatch(output_container& output, polygon_45_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_fracture(output_container& container, bool fracture_holes, concept_type tag) const { + clean(); + ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag); + } + }; + + template + polygon_90_set_data& + polygon_90_set_data::resize(coordinate_type west, + coordinate_type east, + coordinate_type south, + coordinate_type north) { + move(-west, -south); + coordinate_type e_total = west + east; + coordinate_type n_total = south + north; + if((e_total < 0) ^ (n_total < 0)) { + //different signs + if(e_total < 0) { + shrink(0, -e_total, 0, 0); + if(n_total != 0) + return bloat(0, 0, 0, n_total); + else + return (*this); + } else { + shrink(0, 0, 0, -n_total); //shrink first + if(e_total != 0) + return bloat(0, e_total, 0, 0); + else + return (*this); + } + } else { + if(e_total < 0) { + return shrink(0, -e_total, 0, -n_total); + } + return bloat(0, e_total, 0, n_total); + } + } + + template + class property_merge_90 { + private: + std::vector, std::pair > > pmd_; + public: + inline property_merge_90() : pmd_() {} + inline property_merge_90(const property_merge_90& that) : pmd_(that.pmd_) {} + inline property_merge_90& operator=(const property_merge_90& that) { pmd_ = that.pmd_; return *this; } + inline void insert(const polygon_90_set_data& ps, const property_type& property) { + merge_scanline >:: + populate_property_merge_data(pmd_, ps.begin(), ps.end(), property, ps.orient()); + } + template + inline void insert(const GeoObjT& geoObj, const property_type& property) { + polygon_90_set_data ps; + ps.insert(geoObj); + insert(ps, property); + } + //merge properties of input geometries and store the resulting geometries of regions + //with unique sets of merged properties to polygons sets in a map keyed by sets of properties + // T = std::map, polygon_90_set_data > or + // T = std::map, polygon_90_set_data > + template + inline void merge(ResultType& result) { + merge_scanline, typename ResultType::key_type> ms; + ms.perform_merge(result, pmd_); + } + }; + + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template + class connectivity_extraction_90 { + private: + typedef typename touch_90_operation::TouchSetData tsd; + tsd tsd_; + unsigned int nodeCount_; + public: + inline connectivity_extraction_90() : tsd_(), nodeCount_(0) {} + inline connectivity_extraction_90(const connectivity_extraction_90& that) : tsd_(that.tsd_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction_90& operator=(const connectivity_extraction_90& that) { + tsd_ = that.tsd_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_90_set_data& ps) { + ps.clean(); + touch_90_operation::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_90_set_data ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template + inline void extract(GraphT& graph) { + touch_90_operation::performTouch(graph, tsd_); + } + }; +} +} +#endif + diff --git a/include/boost/polygon/polygon_90_set_traits.hpp b/include/boost/polygon/polygon_90_set_traits.hpp new file mode 100755 index 0000000..18e6329 --- /dev/null +++ b/include/boost/polygon/polygon_90_set_traits.hpp @@ -0,0 +1,362 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_90_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + struct polygon_90_set_concept {}; + + template + struct traits_by_concept {}; + template + struct traits_by_concept { typedef coordinate_traits type; }; + template + struct traits_by_concept { typedef interval_traits type; }; + template + struct traits_by_concept { typedef point_traits type; }; + template + struct traits_by_concept { typedef point_3d_traits type; }; + template + struct traits_by_concept { typedef rectangle_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + template + struct traits_by_concept { typedef polygon_traits type; }; + + struct polygon_45_set_concept; + struct polygon_set_concept; + template + struct polygon_90_set_traits; + template + struct polygon_45_set_traits; + template + struct polygon_set_traits; + template + struct traits_by_concept { typedef polygon_90_set_traits type; }; + template + struct traits_by_concept { typedef polygon_45_set_traits type; }; + template + struct traits_by_concept { typedef polygon_set_traits type; }; + + template + struct get_coordinate_type { + typedef typename traits_by_concept::type traits_type; + typedef typename traits_type::coordinate_type type; + }; + //want to prevent recursive template definition syntax errors, so duplicate get_coordinate_type + template + struct get_coordinate_type_2 { + typedef typename traits_by_concept::type traits_type; + typedef typename traits_type::coordinate_type type; + }; + template + struct get_coordinate_type { + typedef typename get_coordinate_type_2::value_type, + typename geometry_concept::value_type>::type>::type type; }; + + template + struct get_iterator_type_2 { + typedef const T* type; + static type begin(const T& t) { return &t; } + static type end(const T& t) { const T* tp = &t; ++tp; return tp; } + }; + template + struct get_iterator_type { + typedef get_iterator_type_2::type> indirect_type; + typedef typename indirect_type::type type; + static type begin(const T& t) { return indirect_type::begin(t); } + static type end(const T& t) { return indirect_type::end(t); } + }; + template + struct get_iterator_type_2 { + typedef typename T::const_iterator type; + static type begin(const T& t) { return t.begin(); } + static type end(const T& t) { return t.end(); } + }; + +// //helpers for allowing polygon 45 and containers of polygon 45 to behave interchangably in polygon_45_set_traits +// template +// struct get_coordinate_type_45 {}; +// template +// struct get_coordinate_type_2_45 {}; +// template +// struct get_coordinate_type_45 { +// typedef typename get_coordinate_type_2_45< typename T::value_type, typename geometry_concept::type >::type type; }; +// template +// struct get_coordinate_type_45 { typedef typename polygon_traits::coordinate_type type; }; +// template +// struct get_coordinate_type_45 { typedef typename polygon_traits::coordinate_type type; }; +// template +// struct get_coordinate_type_2_45 { typedef typename polygon_traits::coordinate_type type; }; +// template +// struct get_coordinate_type_2_45 { typedef typename polygon_traits::coordinate_type type; }; +// template +// struct get_iterator_type_45 {}; +// template +// struct get_iterator_type_45 { +// typedef typename T::const_iterator type; +// static type begin(const T& t) { return t.begin(); } +// static type end(const T& t) { return t.end(); } +// }; +// template +// struct get_iterator_type_45 { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; +// template +// struct get_iterator_type_45 { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; +// template +// struct get_iterator_type_45 { +// typedef const T* type; +// static type begin(const T& t) { return &t; } +// static type end(const T& t) { const T* tp = &t; ++tp; return tp; } +// }; + + template + struct polygon_90_set_traits { + typedef typename get_coordinate_type::type >::type coordinate_type; + typedef get_iterator_type indirection_type; + typedef typename get_iterator_type::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return indirection_type::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return indirection_type::end(polygon_set); + } + + static inline orientation_2d orient(const T&) { return HORIZONTAL; } + + static inline bool clean(const T&) { return false; } + + static inline bool sorted(const T&) { return false; } + }; + + template + struct is_manhattan_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_manhattan_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_manhattan_polygonal_concept { typedef gtl_yes type; }; + + template + struct is_polygon_90_set_type { + typedef typename is_manhattan_polygonal_concept::type>::type type; + }; + template + struct is_polygon_90_set_type > { + typedef typename gtl_or< + typename is_manhattan_polygonal_concept >::type>::type, + typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_polygon_90_set_type > { + typedef typename gtl_or< + typename is_manhattan_polygonal_concept >::type>::type, + typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; + }; + + template + struct is_mutable_polygon_90_set_type { + typedef typename gtl_same_type::type>::type type; + }; + template + struct is_mutable_polygon_90_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_mutable_polygon_90_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; + }; + +// //specialization for rectangle, polygon_90 and polygon_90_with_holes types +// template +// struct polygon_90_set_traits +// typedef typename geometry_concept::type concept_type; +// typedef typename get_coordinate_type::type coordinate_type; +// typedef iterator_geometry_to_set iterator_type; +// typedef T operator_arg_type; + +// static inline iterator_type begin(const T& polygon_set) { +// return iterator_geometry_to_set(polygon_set, LOW, HORIZONTAL); +// } + +// static inline iterator_type end(const T& polygon_set) { +// return iterator_geometry_to_set(polygon_set, HIGH, HORIZONTAL); +// } + +// static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } + +// static inline bool clean(const T& polygon_set) { return false; } + +// static inline bool sorted(const T& polygon_set) { return false; } + +// }; + +// //specialization for containers of recangle, polygon_90, polygon_90_with_holes +// template +// struct polygon_90_set_traits::value_type>::type> { +// typedef typename std::iterator_traits::value_type geometry_type; +// typedef typename geometry_concept::type concept_type; +// typedef typename get_coordinate_type::type coordinate_type; +// typedef iterator_geometry_range_to_set iterator_type; +// typedef T operator_arg_type; + +// static inline iterator_type begin(const T& polygon_set) { +// return iterator_type(polygon_set.begin(), HORIZONTAL); +// } + +// static inline iterator_type end(const T& polygon_set) { +// return iterator_type(polygon_set.end(), HORIZONTAL); +// } + +// static inline orientation_2d orient(const T& polygon_set) { return HORIZONTAL; } + +// static inline bool clean(const T& polygon_set) { return false; } + +// static inline bool sorted(const T& polygon_set) { return false; } + +// }; + + //get dispatch functions + template + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, rectangle_concept ) { + form_rectangles(output, ps.begin(), ps.end(), orient, rectangle_concept()); + } + + template + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, polygon_90_concept tag) { + get_polygons(output, ps.begin(), ps.end(), orient, true, tag); + } + + template + void get_90_dispatch(output_container_type& output, const pst& ps, + orientation_2d orient, polygon_90_with_holes_concept tag) { + get_polygons(output, ps.begin(), ps.end(), orient, false, tag); + } + + //by default works with containers of rectangle, polygon or polygon with holes + //must be specialized to work with anything else + template + struct polygon_90_set_mutable_traits {}; + template + struct polygon_90_set_mutable_traits > { + typedef typename geometry_concept::type concept_type; + template + static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + polygon_set.clear(); + polygon_90_set_data >::coordinate_type> ps(orient); + ps.insert(input_begin, input_end, orient); + ps.clean(); + get_90_dispatch(polygon_set, ps, orient, concept_type()); + } + }; + template + struct polygon_90_set_mutable_traits > { + typedef typename geometry_concept::type concept_type; + template + static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { + polygon_set.clear(); + polygon_90_set_data >::coordinate_type> ps(orient); + ps.insert(input_begin, input_end, orient); + ps.clean(); + get_90_dispatch(polygon_set, ps, orient, concept_type()); + } + }; + + template + struct polygon_90_set_mutable_traits > { + + template + static inline void set(polygon_90_set_data& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end, + orientation_2d orient) { + polygon_set.clear(); + polygon_set.insert(input_begin, input_end, orient); + } + + }; + + template + struct polygon_90_set_traits > { + typedef typename polygon_90_set_data::coordinate_type coordinate_type; + typedef typename polygon_90_set_data::iterator_type iterator_type; + typedef typename polygon_90_set_data::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_90_set_data& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_90_set_data& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const polygon_90_set_data& polygon_set) { return polygon_set.orient(); } + + static inline bool clean(const polygon_90_set_data& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_90_set_data& polygon_set) { polygon_set.sort(); return true; } + + }; + + template + struct is_polygon_90_set_concept { }; + template <> + struct is_polygon_90_set_concept { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept { typedef gtl_yes type; }; + template <> + struct is_polygon_90_set_concept { typedef gtl_yes type; }; + + template + struct is_mutable_polygon_90_set_concept { typedef gtl_no type; }; + template <> + struct is_mutable_polygon_90_set_concept { typedef gtl_yes type; }; + + template + struct geometry_concept > { typedef polygon_90_set_concept type; }; + + //template + //typename enable_if::type, void>::type + //print_is_polygon_90_set_concept(const T& t) { std::cout << "is polygon 90 set concept\n"; } + //template + //typename enable_if::type, void>::type + //print_is_mutable_polygon_90_set_concept(const T& t) { std::cout << "is mutable polygon 90 set concept\n"; } +} +} +#endif + diff --git a/include/boost/polygon/polygon_90_with_holes_data.hpp b/include/boost/polygon/polygon_90_with_holes_data.hpp new file mode 100755 index 0000000..2fb6cdb --- /dev/null +++ b/include/boost/polygon/polygon_90_with_holes_data.hpp @@ -0,0 +1,116 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_90_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_90_WITH_HOLES_DATA_HPP +namespace boost { namespace polygon{ +#include "isotropy.hpp" +#include "polygon_90_data.hpp" +struct polygon_90_with_holes_concept; +template +class polygon_90_with_holes_data { +public: + typedef polygon_90_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_90_data::iterator_type iterator_type; + typedef typename polygon_90_data::compact_iterator_type compact_iterator_type; + typedef typename std::list >::const_iterator iterator_holes_type; + typedef polygon_90_data hole_type; + typedef typename coordinate_traits::area_type area_type; + typedef point_data point_type; + + // default constructor of point does not initialize x and y + inline polygon_90_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_90_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_90_with_holes_data& set_compact(iT input_begin, iT input_end) { + self_.set_compact(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_90_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set_compact((*input_begin).begin_compact(), (*input_begin).end_compact()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_90_with_holes_data(const polygon_90_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_90_with_holes_data& operator=(const polygon_90_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template + inline polygon_90_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + // get begin iterator, returns a pointer to a const coordinate_type + inline const compact_iterator_type begin_compact() const { + return self_.begin_compact(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const compact_iterator_type end_compact() const { + return self_.end_compact(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +private: + polygon_90_data self_; + std::list holes_; +}; +} +} +#endif + diff --git a/include/boost/polygon/polygon_data.hpp b/include/boost/polygon/polygon_data.hpp new file mode 100755 index 0000000..cd3b672 --- /dev/null +++ b/include/boost/polygon/polygon_data.hpp @@ -0,0 +1,70 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_DATA_HPP +#define BOOST_POLYGON_POLYGON_DATA_HPP +namespace boost { namespace polygon{ +struct polygon_concept; +template +class polygon_data { +public: + typedef polygon_concept geometry_type; + typedef T coordinate_type; + typedef typename std::vector >::const_iterator iterator_type; + typedef typename coordinate_traits::coordinate_distance area_type; + typedef point_data point_type; + + inline polygon_data() : coords_() {} //do nothing default constructor + + template + inline polygon_data(iT input_begin, iT input_end) : coords_(input_begin, input_end) {} + + template + inline polygon_data& set(iT input_begin, iT input_end) { + coords_.clear(); //just in case there was some old data there + coords_.insert(coords_.end(), input_begin, input_end); + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_data(const polygon_data& that) : coords_(that.coords_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_data& operator=(const polygon_data& that) { + coords_ = that.coords_; + return *this; + } + + template + inline polygon_data& operator=(const T2& rvalue); + + inline bool operator==(const polygon_data& that) const { + if(coords_.size() != that.coords_.size()) return false; + for(std::size_t i = 0; i < coords_.size(); ++i) { + if(coords_[i] != that.coords_[i]) return false; + } + return true; + } + + inline bool operator!=(const polygon_data& that) const { return !((*this) == that); } + + // get begin iterator, returns a pointer to a const Unit + inline iterator_type begin() const { return coords_.begin(); } + + // get end iterator, returns a pointer to a const Unit + inline iterator_type end() const { return coords_.end(); } + + inline std::size_t size() const { return coords_.size(); } + +public: + std::vector > coords_; +}; + +} +} +#endif + diff --git a/include/boost/polygon/polygon_set_concept.hpp b/include/boost/polygon/polygon_set_concept.hpp new file mode 100755 index 0000000..c6d015a --- /dev/null +++ b/include/boost/polygon/polygon_set_concept.hpp @@ -0,0 +1,557 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP +#define BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP +#include "polygon_set_data.hpp" +namespace boost { namespace polygon{ + + template + struct is_either_polygon_set_type { + typedef typename gtl_or::type, typename is_polygon_set_type::type >::type type; + }; + + template + struct is_any_polygon_set_type { + typedef typename gtl_or::type, typename is_polygon_set_type::type >::type type; + }; + + template + typename enable_if< typename is_any_polygon_set_type::type, + typename polygon_set_traits::iterator_type>::type + begin_polygon_set_data(const polygon_set_type& polygon_set) { + return polygon_set_traits::begin(polygon_set); + } + + template + typename enable_if< typename is_any_polygon_set_type::type, + typename polygon_set_traits::iterator_type>::type + end_polygon_set_data(const polygon_set_type& polygon_set) { + return polygon_set_traits::end(polygon_set); + } + + template + typename enable_if< typename is_polygon_set_type::type, + bool>::type + clean(const polygon_set_type& polygon_set) { + return polygon_set_traits::clean(polygon_set); + } + + //assign + template + typename enable_if< typename gtl_and< + typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + polygon_set_type_1>::type & + assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { + if(clean(rvalue)) + polygon_set_mutable_traits::set(lvalue, begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); + else { + polygon_set_data::coordinate_type> ps; + ps.insert(begin_polygon_set_data(rvalue), end_polygon_set_data(rvalue)); + ps.clean(); + polygon_set_mutable_traits::set(lvalue, ps.begin(), ps.end()); + } + return lvalue; + } + + //get trapezoids + template + typename enable_if< typename is_mutable_polygon_set_type::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set) { + polygon_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output); + } + + //get trapezoids + template + typename enable_if< typename is_mutable_polygon_set_type::type, + void>::type + get_trapezoids(output_container_type& output, const polygon_set_type& polygon_set, + orientation_2d orient) { + polygon_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.get_trapezoids(output, orient); + } + + //equivalence + template + typename enable_if< typename gtl_and_3 < + typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + bool>::type + equivalence(const polygon_set_type_1& lvalue, + const polygon_set_type_2& rvalue) { + polygon_set_data::coordinate_type> ps1; + assign(ps1, lvalue); + polygon_set_data::coordinate_type> ps2; + assign(ps2, rvalue); + return ps1 == ps2; + } + + //clear + template + typename enable_if< typename is_mutable_polygon_set_type::type, + void>::type + clear(polygon_set_type& polygon_set) { + polygon_set_data::coordinate_type> ps; + assign(polygon_set, ps); + } + + //empty + template + typename enable_if< typename is_mutable_polygon_set_type::type, + bool>::type + empty(const polygon_set_type& polygon_set) { + if(clean(polygon_set)) return begin_polygon_set_data(polygon_set) == end_polygon_set_data(polygon_set); + polygon_set_data::coordinate_type> ps; + assign(ps, polygon_set); + ps.clean(); + return ps.empty(); + } + + //extents + template + typename enable_if< typename gtl_and< + typename is_mutable_polygon_set_type::type, + typename is_mutable_rectangle_concept::type>::type>::type, + bool>::type + extents(rectangle_type& extents_rectangle, + const polygon_set_type& polygon_set) { + clean(polygon_set); + polygon_set_data::coordinate_type> ps; + assign(ps, polygon_set); + return ps.extents(extents_rectangle); + } + + //area + template + typename enable_if< typename is_mutable_polygon_set_type::type, + typename coordinate_traits::coordinate_type>::area_type>::type + area(const polygon_set_type& polygon_set) { + typedef typename polygon_set_traits::coordinate_type Unit; + typedef polygon_with_holes_data p_type; + typedef typename coordinate_traits::area_type area_type; + std::vector polys; + assign(polys, polygon_set); + area_type retval = (area_type)0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += area(polys[i]); + } + return retval; + } + + // TODO: Dafna add ngon parameter passing + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + resize(polygon_set_type& polygon_set, coord_type resizing, bool corner_fill_arcs = false, int ngon=0) { + typedef typename polygon_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_set_data ps; + assign(ps, polygon_set); + ps.resize(resizing, corner_fill_arcs,ngon); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + bloat(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { + return resize(polygon_set, bloating); + } + + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + shrink(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { + return resize(polygon_set, -(typename polygon_set_traits::coordinate_type)shrinking); + } + + //interact + template + typename enable_if< typename gtl_and_3 < + typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + polygon_set_type_1>::type& + interact(polygon_set_type_1& polygon_set_1, const polygon_set_type_2& polygon_set_2) { + polygon_set_data::coordinate_type> ps1; + assign(ps1, polygon_set_1); + polygon_set_data::coordinate_type> ps2; + assign(ps2, polygon_set_2); + ps1.interact(ps2); + assign(polygon_set_1, ps1); + return polygon_set_1; + } + + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + scale_up(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_set_data ps; + assign(ps, polygon_set); + ps.scale_up(factor); + assign(polygon_set, ps); + return polygon_set; + } + + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + scale_down(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_set_data ps; + assign(ps, polygon_set); + ps.scale_down(factor); + assign(polygon_set, ps); + return polygon_set; + } + + //transform + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + transform(polygon_set_type& polygon_set, + const transformation_type& transformation) { + typedef typename polygon_set_traits::coordinate_type Unit; + clean(polygon_set); + polygon_set_data ps; + assign(ps, polygon_set); + ps.transform(transformation); + assign(polygon_set, ps); + return polygon_set; + } + + //keep + template + typename enable_if< typename is_mutable_polygon_set_type::type, + polygon_set_type>::type & + keep(polygon_set_type& polygon_set, + typename coordinate_traits::coordinate_type>::area_type min_area, + typename coordinate_traits::coordinate_type>::area_type max_area, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_width, + typename coordinate_traits::coordinate_type>::unsigned_area_type min_height, + typename coordinate_traits::coordinate_type>::unsigned_area_type max_height) { + typedef typename polygon_set_traits::coordinate_type Unit; + typedef typename coordinate_traits::unsigned_area_type uat; + std::list > polys; + assign(polys, polygon_set); + typename std::list >::iterator itr_nxt; + for(typename std::list >::iterator itr = polys.begin(); itr != polys.end(); itr = itr_nxt){ + itr_nxt = itr; + ++itr_nxt; + rectangle_data bbox; + extents(bbox, *itr); + uat pwidth = delta(bbox, HORIZONTAL); + if(pwidth > min_width && pwidth <= max_width){ + uat pheight = delta(bbox, VERTICAL); + if(pheight > min_height && pheight <= max_height){ + typename coordinate_traits::area_type parea = area(*itr); + if(parea <= max_area && parea >= min_area) { + continue; + } + } + } + polys.erase(itr); + } + assign(polygon_set, polys); + return polygon_set; + } + + namespace operators { + + struct yes_ps_ob : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_ob, typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + polygon_set_view >::type + operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_op : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_op, + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type> + ::type, polygon_set_view >::type + operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_os : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_os, + typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + polygon_set_view >::type + operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_oa : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_oa, + typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + polygon_set_view >::type + operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_ox : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_ox, + typename is_any_polygon_set_type::type, + typename is_any_polygon_set_type::type, + typename is_either_polygon_set_type::type>::type, + polygon_set_view >::type + operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_om : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4 < yes_ps_om, + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type> + ::type, polygon_set_view >::type + operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return polygon_set_view + (lvalue, rvalue); + } + + struct yes_ps_ope : gtl_yes {}; + + template + typename enable_if< typename gtl_and_4< yes_ps_ope, gtl_yes, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct yes_ps_obe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< yes_ps_obe, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct yes_ps_ose : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< yes_ps_ose, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct yes_ps_oae : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3< yes_ps_oae, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct yes_ps_oxe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< yes_ps_oxe, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + struct yes_ps_ome : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3< yes_ps_ome, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { + return self_assignment_boolean_op(lvalue, rvalue); + } + + // TODO: Dafna, test these four resizing operators + struct y_ps_rpe : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< y_ps_rpe, typename is_mutable_polygon_set_type::type, + typename gtl_same_type::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, rvalue); + } + + struct y_ps_rme : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type>::type, + geometry_type_1>::type & + operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { + return resize(lvalue, -rvalue); + } + + struct y_ps_rp : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval += rvalue; + return retval; + } + + struct y_ps_rm : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, + coordinate_concept>::type> + ::type, geometry_type_1>::type + operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { + geometry_type_1 retval(lvalue); + retval -= rvalue; + return retval; + } + + + } //end operators namespace + + template + struct view_of { + typedef typename get_coordinate_type::type >::type coordinate_type; + T* tp; + std::vector > polys; + view_of(const T& obj) : tp(), polys() { + std::vector > gpolys; + assign(gpolys, obj); + for(typename std::vector >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_45_with_holes_data()); + assign(polys.back(), view_as(*itr)); + } + } + view_of(T& obj) : tp(&obj), polys() { + std::vector > gpolys; + assign(gpolys, obj); + for(typename std::vector >::iterator itr = gpolys.begin(); + itr != gpolys.end(); ++itr) { + polys.push_back(polygon_45_with_holes_data()); + assign(polys.back(), view_as(*itr)); + } + } + + typedef typename std::vector >::const_iterator iterator_type; + typedef view_of operator_arg_type; + + inline iterator_type begin() const { + return polys.begin(); + } + + inline iterator_type end() const { + return polys.end(); + } + + inline orientation_2d orient() const { return HORIZONTAL; } + + inline bool clean() const { return false; } + + inline bool sorted() const { return false; } + + inline T& get() { return *tp; } + }; + + template + struct polygon_45_set_traits > { + typedef typename view_of::coordinate_type coordinate_type; + typedef typename view_of::iterator_type iterator_type; + typedef view_of operator_arg_type; + + static inline iterator_type begin(const view_of& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const view_of& polygon_set) { + return polygon_set.end(); + } + + static inline orientation_2d orient(const view_of& polygon_set) { + return polygon_set.orient(); } + + static inline bool clean(const view_of& polygon_set) { + return polygon_set.clean(); } + + static inline bool sorted(const view_of& polygon_set) { + return polygon_set.sorted(); } + + }; + + template + struct geometry_concept > { + typedef polygon_45_set_concept type; + }; + + template + struct get_coordinate_type, polygon_45_set_concept> { + typedef typename view_of::coordinate_type type; + }; + template + struct get_iterator_type_2, polygon_45_set_concept> { + typedef typename view_of::iterator_type type; + static type begin(const view_of& t) { return t.begin(); } + static type end(const view_of& t) { return t.end(); } + }; +} +} +#endif diff --git a/include/boost/polygon/polygon_set_data.hpp b/include/boost/polygon/polygon_set_data.hpp new file mode 100755 index 0000000..4061ae2 --- /dev/null +++ b/include/boost/polygon/polygon_set_data.hpp @@ -0,0 +1,1000 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_SET_DATA_HPP +#define BOOST_POLYGON_POLYGON_SET_DATA_HPP +#include "polygon_45_set_data.hpp" +#include "polygon_45_set_concept.hpp" +#include "polygon_traits.hpp" +#include "detail/polygon_arbitrary_formation.hpp" +#include + +namespace boost { namespace polygon { + + + // utility function to round coordinate types down + // rounds down for both negative and positive numbers + // intended really for integer type T (does not make sense for float) + template + static inline T round_down(double val) { + T rounded_val = (T)(val); + if(val < (double)rounded_val) + --rounded_val; + return rounded_val; + } + template + static inline point_data round_down(point_data v) { + return point_data(round_down(v.x()),round_down(v.y())); + } + + + + //foward declare view + template class polygon_set_view; + + template + class polygon_set_data { + public: + typedef T coordinate_type; + typedef point_data point_type; + typedef std::pair edge_type; + typedef std::pair element_type; + typedef std::vector value_type; + typedef typename value_type::const_iterator iterator_type; + typedef polygon_set_data operator_arg_type; + + // default constructor + inline polygon_set_data() : data_(), dirty_(false), unsorted_(false), is_45_(true) {} + + // constructor from an iterator pair over edge data + template + inline polygon_set_data(iT input_begin, iT input_end) : data_(), dirty_(false), unsorted_(false), is_45_(true) { + for( ; input_begin != input_end; ++input_begin) { insert(*input_begin); } + } + + // copy constructor + inline polygon_set_data(const polygon_set_data& that) : + data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {} + + // copy constructor + template + inline polygon_set_data(const polygon_set_view& that); + + // destructor + inline ~polygon_set_data() {} + + // assignement operator + inline polygon_set_data& operator=(const polygon_set_data& that) { + if(this == &that) return *this; + data_ = that.data_; + dirty_ = that.dirty_; + unsorted_ = that.unsorted_; + is_45_ = that.is_45_; + return *this; + } + + template + inline polygon_set_data& operator=(const polygon_set_view& geometry) { + (*this) = geometry.value(); + dirty_ = false; + unsorted_ = false; + return *this; + } + + template + inline polygon_set_data& operator=(const geometry_object& geometry) { + data_.clear(); + insert(geometry); + return *this; + } + + + // insert iterator range + inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) { + if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return; + dirty_ = true; + unsorted_ = true; + while(input_begin != input_end) { + insert(*input_begin, is_hole); + ++input_begin; + } + } + + // insert iterator range + template + inline void insert(iT input_begin, iT input_end, bool is_hole = false) { + if(input_begin == input_end) return; + for(; input_begin != input_end; ++input_begin) { + insert(*input_begin, is_hole); + } + } + + template + inline void insert(const geometry_type& geometry_object, bool is_hole = false) { + insert(geometry_object, is_hole, typename geometry_concept::type()); + } + + template + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_concept ) { + insert_vertex_sequence(begin_points(polygon_object), end_points(polygon_object), winding(polygon_object), is_hole); + } + + inline void insert(const polygon_set_data& ps, bool is_hole = false) { + insert(ps.data_.begin(), ps.data_.end(), is_hole); + } + + template + inline void insert(const polygon_45_set_type& ps, bool is_hole, polygon_45_set_concept) { + std::vector::coordinate_type> > polys; + assign(polys, ps); + insert(polys.begin(), polys.end(), is_hole); + } + + template + inline void insert(const polygon_90_set_type& ps, bool is_hole, polygon_90_set_concept) { + std::vector::coordinate_type> > polys; + assign(polys, ps); + insert(polys.begin(), polys.end(), is_hole); + } + + template + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_45_concept ) { + insert(polygon_object, is_hole, polygon_concept()); } + + template + inline void insert(const polygon_type& polygon_object, bool is_hole, polygon_90_concept ) { + insert(polygon_object, is_hole, polygon_concept()); } + + template + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_concept()); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(polygon_with_holes_object); + itr != end_holes(polygon_with_holes_object); ++itr) { + insert(*itr, !is_hole, polygon_concept()); + } + } + + template + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_45_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } + + template + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + polygon_90_with_holes_concept ) { + insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } + + template + inline void insert(const rectangle_type& rectangle_object, bool is_hole, rectangle_concept ) { + polygon_90_data poly; + assign(poly, rectangle_object); + insert(poly, is_hole, polygon_concept()); + } + + inline void insert_clean(const element_type& edge, bool is_hole = false) { + if( ! scanline_base::is_45_degree(edge.first) && + ! scanline_base::is_horizontal(edge.first) && + ! scanline_base::is_vertical(edge.first) ) is_45_ = false; + data_.push_back(edge); + if(data_.back().first.second < data_.back().first.first) { + std::swap(data_.back().first.second, data_.back().first.first); + data_.back().second *= -1; + } + if(is_hole) + data_.back().second *= -1; + } + + inline void insert(const element_type& edge, bool is_hole = false) { + insert_clean(edge, is_hole); + dirty_ = true; + unsorted_ = true; + } + + template + inline void insert_vertex_sequence(iT begin_vertex, iT end_vertex, direction_1d winding, bool is_hole) { + bool first_iteration = true; + point_type first_point; + point_type previous_point; + point_type current_point; + direction_1d winding_dir = winding; + int multiplier = winding_dir == COUNTERCLOCKWISE ? 1 : -1; + if(is_hole) multiplier *= -1; + for( ; begin_vertex != end_vertex; ++begin_vertex) { + assign(current_point, *begin_vertex); + if(first_iteration) { + first_iteration = false; + first_point = previous_point = current_point; + } else { + if(previous_point != current_point) { + element_type elem(edge_type(previous_point, current_point), + ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); + insert_clean(elem); + } + } + previous_point = current_point; + } + current_point = first_point; + if(!first_iteration) { + if(previous_point != current_point) { + element_type elem(edge_type(previous_point, current_point), + ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); + insert_clean(elem); + } + dirty_ = true; + unsorted_ = true; + } + } + + template + inline void get(output_container& output) const { + get_dispatch(output, typename geometry_concept::type()); + } + + // append to the container cT with polygons of three or four verticies + // slicing orientation is vertical + template + void get_trapezoids(cT& container) const { + clean(); + trapezoid_arbitrary_formation pf; + typedef typename polygon_arbitrary_formation::vertex_half_edge vertex_half_edge; + std::vector data; + for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ + data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); + data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); + } + std::sort(data.begin(), data.end()); + pf.scan(container, data.begin(), data.end()); + //std::cout << "DONE FORMING POLYGONS\n"; + } + + // append to the container cT with polygons of three or four verticies + template + void get_trapezoids(cT& container, orientation_2d slicing_orientation) const { + if(slicing_orientation == VERTICAL) { + get_trapezoids(container); + } else { + polygon_set_data ps(*this); + ps.transform(axis_transformation(axis_transformation::SWAP_XY)); + cT result; + ps.get_trapezoids(result); + for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) { + ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY)); + } + container.insert(container.end(), result.begin(), result.end()); + } + } + + // equivalence operator + inline bool operator==(const polygon_set_data& p) const { + clean(); + p.clean(); + return data_ == p.data_; + } + + // inequivalence operator + inline bool operator!=(const polygon_set_data& p) const { + return !((*this) == p); + } + + // get iterator to begin vertex data + inline iterator_type begin() const { + return data_.begin(); + } + + // get iterator to end vertex data + inline iterator_type end() const { + return data_.end(); + } + + const value_type& value() const { + return data_; + } + + // clear the contents of the polygon_set_data + inline void clear() { data_.clear(); dirty_ = unsorted_ = false; } + + // find out if Polygon set is empty + inline bool empty() const { return data_.empty(); } + + // get the Polygon set size in vertices + inline std::size_t size() const { clean(); return data_.size(); } + + // get the current Polygon set capacity in vertices + inline std::size_t capacity() const { return data_.capacity(); } + + // reserve size of polygon set in vertices + inline void reserve(std::size_t size) { return data_.reserve(size); } + + // find out if Polygon set is sorted + inline bool sorted() const { return !unsorted_; } + + // find out if Polygon set is clean + inline bool dirty() const { return dirty_; } + + void clean() const; + + void sort() const{ + if(unsorted_) { + std::sort(data_.begin(), data_.end()); + unsorted_ = false; + } + } + + template + void set(input_iterator_type input_begin, input_iterator_type input_end) { + clear(); + insert(input_begin, input_end); + dirty_ = true; + unsorted_ = true; + } + + void set(const value_type& value) { + data_ = value; + dirty_ = true; + unsorted_ = true; + } + + template + bool extents(rectangle_type& rect) { + clean(); + if(empty()) return false; + bool first_iteration = true; + for(iterator_type itr = begin(); + itr != end(); ++itr) { + rectangle_type edge_box; + set_points(edge_box, (*itr).first.first, (*itr).first.second); + if(first_iteration) + rect = edge_box; + else + encompass(rect, edge_box); + first_iteration = false; + } + return true; + } + + inline polygon_set_data& + resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0) { + if(!corner_fill_arc) { + if(resizing < 0) + return shrink(-resizing); + if(resizing > 0) + return bloat(-resizing); + return *this; + } + if(resizing == 0) return *this; + std::list > pl; + get(pl); + clear(); + for(typename std::list >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { + insert_with_resize(*itr, resizing, corner_fill_arc, num_circle_segments); + } + clean(); + return *this; + } + + template + inline polygon_set_data& + transform(const transform_type& tr) { + std::vector > polys; + get(polys); + clear(); + for(std::size_t i = 0 ; i < polys.size(); ++i) { + ::boost::polygon::transform(polys[i], tr); + insert(polys[i]); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + inline polygon_set_data& + scale_up(typename coordinate_traits::unsigned_area_type factor) { + for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { + ::boost::polygon::scale_up((*itr).first.first, factor); + ::boost::polygon::scale_up((*itr).first.second, factor); + } + return *this; + } + + inline polygon_set_data& + scale_down(typename coordinate_traits::unsigned_area_type factor) { + for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { + ::boost::polygon::scale_down((*itr).first.first, factor); + ::boost::polygon::scale_down((*itr).first.second, factor); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + template + inline polygon_set_data& scale(polygon_set_data& polygon_set, + const scaling_type& scaling) { + for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { + ::boost::polygon::scale((*itr).first.first, scaling); + ::boost::polygon::scale((*itr).first.second, scaling); + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + static inline void compute_offset_edge(point_data& pt1, point_data& pt2, + const point_data& prev_pt, + const point_data& current_pt, + coordinate_type distance, int multiplier) { + coordinate_type dx = current_pt.x() - prev_pt.x(); + coordinate_type dy = current_pt.y() - prev_pt.y(); + double ddx = (double)dx; + double ddy = (double)dy; + double edge_length = std::sqrt(ddx*ddx + ddy*ddy); + double dnx = dy; + double dny = -dx; + dnx = dnx * (double)distance / edge_length; + dny = dny * (double)distance / edge_length; + dnx = std::floor(dnx+0.5); + dny = std::floor(dny+0.5); + pt1.x(prev_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); + pt2.x(current_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); + pt1.y(prev_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); + pt2.y(current_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); + } + + static inline void modify_pt(point_data& pt, const point_data& prev_pt, + const point_data& current_pt, const point_data& next_pt, + coordinate_type distance, coordinate_type multiplier) { + std::pair, point_data > he1(prev_pt, current_pt), he2(current_pt, next_pt); + compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); + compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); + typename scanline_base::compute_intersection_pack pack; + if(!pack.compute_lazy_intersection(pt, he1, he2, true, true)) { + pt = he1.second; //colinear offset edges use shared point + } + } + + static void resize_poly_up(std::vector >& poly, coordinate_type distance, coordinate_type multiplier) { + point_data first_pt = poly[0]; + point_data second_pt = poly[1]; + point_data prev_pt = poly[0]; + point_data current_pt = poly[1]; + for(std::size_t i = 2; i < poly.size()-1; ++i) { + point_data next_pt = poly[i]; + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + } + point_data next_pt = first_pt; + modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); + poly.back() = poly.front(); + } + static bool resize_poly_down(std::vector >& poly, coordinate_type distance, coordinate_type multiplier) { + std::vector > orig_poly(poly); + rectangle_data extents_rectangle; + set_points(extents_rectangle, poly[0], poly[0]); + point_data first_pt = poly[0]; + point_data second_pt = poly[1]; + point_data prev_pt = poly[0]; + point_data current_pt = poly[1]; + encompass(extents_rectangle, current_pt); + for(std::size_t i = 2; i < poly.size()-1; ++i) { + point_data next_pt = poly[i]; + encompass(extents_rectangle, next_pt); + modify_pt(poly[i-1], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + } + if(delta(extents_rectangle, HORIZONTAL) <= std::abs(2*distance)) + return false; + if(delta(extents_rectangle, VERTICAL) <= std::abs(2*distance)) + return false; + point_data next_pt = first_pt; + modify_pt(poly[poly.size()-2], prev_pt, current_pt, next_pt, distance, multiplier); + prev_pt = current_pt; + current_pt = next_pt; + next_pt = second_pt; + modify_pt(poly[0], prev_pt, current_pt, next_pt, distance, multiplier); + poly.back() = poly.front(); + //if the line segments formed between orignial and new points cross for an edge that edge inverts + //if all edges invert the polygon should be discarded + //if even one edge does not invert return true because the polygon is valid + bool non_inverting_edge = false; + for(std::size_t i = 1; i < poly.size(); ++i) { + std::pair, point_data > + he1(poly[i], orig_poly[i]), + he2(poly[i-1], orig_poly[i-1]); + if(!scanline_base::intersects(he1, he2)) { + non_inverting_edge = true; + break; + } + } + return non_inverting_edge; + } + + polygon_set_data& + bloat(typename coordinate_traits::unsigned_area_type distance) { + std::list > polys; + get(polys); + clear(); + for(typename std::list >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + resize_poly_up((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)1); + insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes + for(typename std::list >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + if(resize_poly_down((*itrh).coords_, (coordinate_type)distance, (coordinate_type)1)) { + insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); + } + } + } + return *this; + } + + polygon_set_data& + shrink(typename coordinate_traits::unsigned_area_type distance) { + std::list > polys; + get(polys); + clear(); + for(typename std::list >::iterator itr = polys.begin(); + itr != polys.end(); ++itr) { + if(resize_poly_down((*itr).self_.coords_, (coordinate_type)distance, (coordinate_type)-1)) { + insert_vertex_sequence((*itr).self_.begin(), (*itr).self_.end(), COUNTERCLOCKWISE, false); //inserts without holes + for(typename std::list >::iterator itrh = (*itr).holes_.begin(); + itrh != (*itr).holes_.end(); ++itrh) { + resize_poly_up((*itrh).coords_, (coordinate_type)distance, (coordinate_type)-1); + insert_vertex_sequence((*itrh).coords_.begin(), (*itrh).coords_.end(), CLOCKWISE, true); + } + } + } + return *this; + } + + // TODO:: should be private + template + inline polygon_set_data& + insert_with_resize(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc=false, unsigned int num_circle_segments=0, bool hole = false) { + return insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, typename geometry_concept::type()); + } + + template + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + polygon_with_holes_concept tag) { + insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept()); + for(typename polygon_with_holes_traits::iterator_holes_type itr = + begin_holes(poly); itr != end_holes(poly); + ++itr) { + insert_with_resize_dispatch(*itr, resizing, corner_fill_arc, num_circle_segments, !hole, polygon_concept()); + } + return *this; + } + + template + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + polygon_concept tag) { + + if (resizing==0) + return *this; + + + // one dimensional used to store CCW/CW flag + //direction_1d wdir = winding(poly); + // LOW==CLOCKWISE just faster to type + // so > 0 is CCW + //int multiplier = wdir == LOW ? -1 : 1; + //std::cout<<" multiplier : "<0?COUNTERCLOCKWISE:CLOCKWISE; + + typedef typename polygon_data::iterator_type piterator; + piterator first, second, third, end, real_end; + real_end = end_points(poly); + third = begin_points(poly); + first = third; + if(first == real_end) return *this; + ++third; + if(third == real_end) return *this; + second = end = third; + ++third; + if(third == real_end) return *this; + + // for 1st corner + std::vector > first_pts; + std::vector > all_pts; + direction_1d first_wdir = CLOCKWISE; + + // for all corners + polygon_set_data sizingSet; + bool sizing_sign = resizing>0; + bool prev_concave = true; + point_data prev_point; + //int iCtr=0; + + + //insert minkofski shapes on edges and corners + do { // REAL WORK IS HERE + + + //first, second and third point to points in correct CCW order + // check if convex or concave case + point_data normal1( second->y()-first->y(), first->x()-second->x()); + point_data normal2( third->y()-second->y(), second->x()-third->x()); + double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y(); + bool convex = direction>0; + + bool treat_as_concave = !convex; + if(sizing_sign) + treat_as_concave = convex; + point_data v; + assign(v, normal1); + double s2 = (v.x()*v.x()+v.y()*v.y()); + double s = sqrt(s2)/resizing; + v = point_data(v.x()/s,v.y()/s); + point_data curr_prev; + if (prev_concave) + //TODO missing round_down() + curr_prev = point_data(first->x()+v.x(),first->y()+v.y()); + else + curr_prev = prev_point; + + // around concave corners - insert rectangle + // if previous corner is concave it's point info may be ignored + if ( treat_as_concave) { + std::vector > pts; + + pts.push_back(point_data(second->x()+v.x(),second->y()+v.y())); + pts.push_back(*second); + pts.push_back(*first); + pts.push_back(point_data(curr_prev)); + if (first_pts.size()){ + sizingSet.insert_vertex_sequence(pts.begin(),pts.end(), resize_wdir,false); + }else { + first_pts=pts; + first_wdir = resize_wdir; + } + } else { + + // add either intersection_quad or pie_shape, based on corner_fill_arc option + // for convex corner (convexity depends on sign of resizing, whether we shrink or grow) + std::vector< std::vector > > pts; + direction_1d winding; + winding = convex?COUNTERCLOCKWISE:CLOCKWISE; + if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing + , num_circle_segments, corner_fill_arc)) + { + if (first_pts.size()) { + for (int i=0; i tmp; + + //insert original shape + tmp.insert(poly, false, polygon_concept()); + if((resizing < 0) ^ hole) tmp -= sizingSet; + else tmp += sizingSet; + //tmp.clean(); + insert(tmp, hole); + return (*this); + } + + + inline polygon_set_data& + interact(const polygon_set_data& that); + + inline bool downcast(polygon_45_set_data& result) const { + if(!is_45_) return false; + for(iterator_type itr = begin(); itr != end(); ++itr) { + const element_type& elem = *itr; + int count = elem.second; + int rise = 1; //up sloping 45 + if(scanline_base::is_horizontal(elem.first)) rise = 0; + else if(scanline_base::is_vertical(elem.first)) rise = 2; + else { + if(!scanline_base::is_45_degree(elem.first)) { + is_45_ = false; + return false; //consider throwing because is_45_ has be be wrong + } + if(elem.first.first.y() > elem.first.second.y()) rise = -1; //down sloping 45 + } + typename polygon_45_set_data::Vertex45Compact vertex(elem.first.first, rise, count); + result.insert(vertex); + typename polygon_45_set_data::Vertex45Compact vertex2(elem.first.second, rise, -count); + result.insert(vertex2); + } + return true; + } + + inline GEOMETRY_CONCEPT_ID concept_downcast() const { + typedef typename coordinate_traits::coordinate_difference delta_type; + bool is_45 = false; + for(iterator_type itr = begin(); itr != end(); ++itr) { + const element_type& elem = *itr; + delta_type h_delta = euclidean_distance(elem.first.first, elem.first.second, HORIZONTAL); + delta_type v_delta = euclidean_distance(elem.first.first, elem.first.second, VERTICAL); + if(h_delta != 0 || v_delta != 0) { + //neither delta is zero and the edge is not MANHATTAN + if(v_delta != h_delta && v_delta != -h_delta) return POLYGON_SET_CONCEPT; + else is_45 = true; + } + } + if(is_45) return POLYGON_45_SET_CONCEPT; + return POLYGON_90_SET_CONCEPT; + } + + private: + mutable value_type data_; + mutable bool dirty_; + mutable bool unsorted_; + mutable bool is_45_; + + private: + //functions + + template + void get_dispatch(output_container& output, polygon_concept tag) const { + get_fracture(output, true, tag); + } + template + void get_dispatch(output_container& output, polygon_with_holes_concept tag) const { + get_fracture(output, false, tag); + } + template + void get_fracture(output_container& container, bool fracture_holes, concept_type ) const { + clean(); + polygon_arbitrary_formation pf(fracture_holes); + typedef typename polygon_arbitrary_formation::vertex_half_edge vertex_half_edge; + std::vector data; + for(iterator_type itr = data_.begin(); itr != data_.end(); ++itr){ + data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); + data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); + } + std::sort(data.begin(), data.end()); + pf.scan(container, data.begin(), data.end()); + } + }; + + struct polygon_set_concept; + template + struct geometry_concept > { + typedef polygon_set_concept type; + }; + +// template +// inline double compute_area(point_data& a, point_data& b, point_data& c) { + +// return (double)(b.x()-a.x())*(double)(c.y()-a.y())- (double)(c.x()-a.x())*(double)(b.y()-a.y()); + + +// } + + template + inline int make_resizing_vertex_list(std::vector > >& return_points, + point_data& curr_prev, bool ignore_prev_point, + point_data< T> start, point_data middle, point_data< T> end, + double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) { + + // handle the case of adding an intersection point + point_data dn1( middle.y()-start.y(), start.x()-middle.x()); + double size = sizing_distance/sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y()); + dn1 = point_data( dn1.x()*size, dn1.y()* size); + point_data dn2( end.y()-middle.y(), middle.x()-end.x()); + size = sizing_distance/sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y()); + dn2 = point_data( dn2.x()*size, dn2.y()* size); + point_data start_offset((start.x()+dn1.x()),(start.y()+dn1.y())); + point_data mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y())); + point_data end_offset((end.x()+dn2.x()),(end.y()+dn2.y())); + point_data mid2_offset((middle.x()+dn2.x()),(middle.y()+dn2.y())); + if (ignore_prev_point) + curr_prev = round_down(start_offset); + + + if (corner_fill_arc) { + std::vector > return_points1; + return_points.push_back(return_points1); + std::vector >& return_points_back = return_points[return_points.size()-1]; + return_points_back.push_back(round_down(mid1_offset)); + return_points_back.push_back(middle); + return_points_back.push_back(start); + return_points_back.push_back(curr_prev); + point_data dmid(middle.x(),middle.y()); + return_points.push_back(return_points1); + int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); + curr_prev = round_down(mid2_offset); + return num; + + } + + std::pair,point_data > he1(start_offset,mid1_offset); + std::pair,point_data > he2(mid2_offset ,end_offset); + //typedef typename high_precision_type::type high_precision; + + point_data intersect; + typename scanline_base::compute_intersection_pack pack; + bool res = pack.compute_intersection(intersect,he1,he2,true); + if( res ) { + std::vector > return_points1; + return_points.push_back(return_points1); + std::vector >& return_points_back = return_points[return_points.size()-1]; + return_points_back.push_back(intersect); + return_points_back.push_back(middle); + return_points_back.push_back(start); + return_points_back.push_back(curr_prev); + + //double d1= compute_area(intersect,middle,start); + //double d2= compute_area(start,curr_prev,intersect); + + curr_prev = intersect; + + + return return_points.size(); + } + return 0; + + } + + // this routine should take in start and end point s.t. end point is CCW from start + // it sould make a pie slice polygon that is an intersection of that arc + // with an ngon segments approximation of the circle centered at center with radius r + // point start is gauaranteed to be on the segmentation + // returnPoints will start with the first point after start + // returnPoints vector may be empty + template + inline int make_arc(std::vector >& return_points, + point_data< double> start, point_data< double> end, + point_data< double> center, double r, unsigned int num_circle_segments) { + const double our_pi=3.1415926535897932384626433832795028841971; + + // derive start and end angles + double ps = atan2(start.y()-center.y(), start.x()-center.x()); + double pe = atan2(end.y()-center.y(), end.x()-center.x()); + if (ps < 0.0) + ps += 2.0 * our_pi; + if (pe <= 0.0) + pe += 2.0 * our_pi; + if (ps >= 2.0 * our_pi) + ps -= 2.0 * our_pi; + while (pe <= ps) + pe += 2.0 * our_pi; + double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; + if ( start==end) // full circle? + { + ps = delta_angle*0.5; + pe = ps + our_pi * 2.0; + double x,y; + x = center.x() + r * cos(ps); + y = center.y() + r * sin(ps); + start = point_data(x,y); + end = start; + } + return_points.push_back(round_down(center)); + return_points.push_back(round_down(start)); + int i=0; + double curr_angle = ps+delta_angle; + while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { + i++; + double x = center.x() + r * cos( curr_angle); + double y = center.y() + r * sin( curr_angle); + return_points.push_back( round_down((point_data(x,y)))); + curr_angle+=delta_angle; + } + return_points.push_back(round_down(end)); + return return_points.size(); + } + +}// close namespace +}// close name space + +#include "detail/scan_arbitrary.hpp" + +namespace boost { namespace polygon { + //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and + //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap + template + class connectivity_extraction{ + private: + typedef arbitrary_connectivity_extraction ce; + ce ce_; + unsigned int nodeCount_; + public: + inline connectivity_extraction() : ce_(), nodeCount_(0) {} + inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_), + nodeCount_(that.nodeCount_) {} + inline connectivity_extraction& operator=(const connectivity_extraction& that) { + ce_ = that.ce_; + nodeCount_ = that.nodeCount_; {} + return *this; + } + + //insert a polygon set graph node, the value returned is the id of the graph node + inline unsigned int insert(const polygon_set_data& ps) { + ps.clean(); + ce_.populateTouchSetData(ps.begin(), ps.end(), nodeCount_); + return nodeCount_++; + } + template + inline unsigned int insert(const GeoObjT& geoObj) { + polygon_set_data ps; + ps.insert(geoObj); + return insert(ps); + } + + //extract connectivity and store the edges in the graph + //graph must be indexable by graph node id and the indexed value must be a std::set of + //graph node id + template + inline void extract(GraphT& graph) { + ce_.execute(graph); + } + }; + + template + polygon_set_data& + polygon_set_data::interact(const polygon_set_data& that) { + connectivity_extraction ce; + std::vector > polys; + get(polys); + clear(); + for(std::size_t i = 0; i < polys.size(); ++i) { + ce.insert(polys[i]); + } + int id = ce.insert(that); + std::vector > graph(id+1); + ce.extract(graph); + for(std::set::iterator itr = graph[id].begin(); + itr != graph[id].end(); ++itr) { + insert(polys[*itr]); + } + return *this; + } +} +} + +#include "polygon_set_traits.hpp" +#include "detail/polygon_set_view.hpp" + +#include "polygon_set_concept.hpp" +#endif + diff --git a/include/boost/polygon/polygon_set_traits.hpp b/include/boost/polygon/polygon_set_traits.hpp new file mode 100755 index 0000000..93604c4 --- /dev/null +++ b/include/boost/polygon/polygon_set_traits.hpp @@ -0,0 +1,130 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_SET_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_SET_TRAITS_HPP +namespace boost { namespace polygon{ + + struct polygon_set_concept {}; + + //default definition of polygon set traits works for any model of polygon , polygon with holes or any vector or list thereof + template + struct polygon_set_traits { + typedef typename get_coordinate_type::type >::type coordinate_type; + typedef typename get_iterator_type::type iterator_type; + typedef T operator_arg_type; + + static inline iterator_type begin(const T& polygon_set) { + return get_iterator_type::begin(polygon_set); + } + + static inline iterator_type end(const T& polygon_set) { + return get_iterator_type::end(polygon_set); + } + + static inline bool clean(const T& ) { return false; } + + static inline bool sorted(const T& ) { return false; } + }; + + template + struct is_polygonal_concept { typedef gtl_no type; }; + template <> + struct is_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_polygonal_concept { typedef gtl_yes type; }; + template <> + struct is_polygonal_concept { typedef gtl_yes type; }; + + template + struct is_polygon_set_type { + typedef typename is_polygonal_concept::type>::type type; + }; + template + struct is_polygon_set_type > { + typedef typename gtl_or< + typename is_polygonal_concept >::type>::type, + typename is_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_polygon_set_type > { + typedef typename gtl_or< + typename is_polygonal_concept >::type>::type, + typename is_polygonal_concept::value_type>::type>::type>::type type; + }; + + template + struct is_mutable_polygon_set_type { + typedef typename gtl_same_type::type>::type type; + }; + template + struct is_mutable_polygon_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_polygonal_concept::value_type>::type>::type>::type type; + }; + template + struct is_mutable_polygon_set_type > { + typedef typename gtl_or< + typename gtl_same_type >::type>::type, + typename is_polygonal_concept::value_type>::type>::type>::type type; + }; + + template + struct polygon_set_mutable_traits {}; + template + struct polygon_set_mutable_traits > { + template + static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_set_data >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.get(polygon_set); + } + }; + template + struct polygon_set_mutable_traits > { + template + static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.clear(); + polygon_set_data >::coordinate_type> ps; + ps.insert(input_begin, input_end); + ps.get(polygon_set); + } + }; + + template + struct polygon_set_mutable_traits > { + template + static inline void set(polygon_set_data& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end) { + polygon_set.set(input_begin, input_end); + } + }; + template + struct polygon_set_traits > { + typedef typename polygon_set_data::coordinate_type coordinate_type; + typedef typename polygon_set_data::iterator_type iterator_type; + typedef typename polygon_set_data::operator_arg_type operator_arg_type; + + static inline iterator_type begin(const polygon_set_data& polygon_set) { + return polygon_set.begin(); + } + + static inline iterator_type end(const polygon_set_data& polygon_set) { + return polygon_set.end(); + } + + static inline bool clean(const polygon_set_data& polygon_set) { polygon_set.clean(); return true; } + + static inline bool sorted(const polygon_set_data& polygon_set) { polygon_set.sort(); return true; } + + }; +} +} +#endif + diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp new file mode 100755 index 0000000..caa1869 --- /dev/null +++ b/include/boost/polygon/polygon_traits.hpp @@ -0,0 +1,1848 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_TRAITS_HPP +#define BOOST_POLYGON_POLYGON_TRAITS_HPP +namespace boost { namespace polygon{ + + template + struct polygon_90_traits { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::compact_iterator_type compact_iterator_type; + + // Get the begin iterator + static inline compact_iterator_type begin_compact(const T& t) { + return t.begin_compact(); + } + + // Get the end iterator + static inline compact_iterator_type end_compact(const T& t) { + return t.end_compact(); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return t.size(); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T&) { + return unknown_winding; + } + }; + + template + struct polygon_traits_general { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::iterator_type iterator_type; + typedef typename T::point_type point_type; + + // Get the begin iterator + static inline iterator_type begin_points(const T& t) { + return t.begin(); + } + + // Get the end iterator + static inline iterator_type end_points(const T& t) { + return t.end(); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return t.size(); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T&) { + return unknown_winding; + } + }; + + template + struct polygon_traits_90 { + typedef typename polygon_90_traits::coordinate_type coordinate_type; + typedef iterator_compact_to_points::compact_iterator_type, point_data > iterator_type; + typedef point_data point_type; + + // Get the begin iterator + static inline iterator_type begin_points(const T& t) { + return iterator_type(polygon_90_traits::begin_compact(t), + polygon_90_traits::end_compact(t)); + } + + // Get the end iterator + static inline iterator_type end_points(const T& t) { + return iterator_type(polygon_90_traits::end_compact(t), + polygon_90_traits::end_compact(t)); + } + + // Get the number of sides of the polygon + static inline std::size_t size(const T& t) { + return polygon_90_traits::size(t); + } + + // Get the winding direction of the polygon + static inline winding_direction winding(const T& t) { + return polygon_90_traits::winding(t); + } + }; + +#ifndef BOOST_VERY_LITTLE_SFINAE + + template + struct polygon_traits {}; + + template + struct polygon_traits::type, polygon_concept>::type, + typename gtl_same_type::type, polygon_45_concept>::type, + typename gtl_same_type::type, polygon_with_holes_concept>::type, + typename gtl_same_type::type, polygon_45_with_holes_concept>::type + >::type> : public polygon_traits_general {}; + + template + struct polygon_traits< T, + typename gtl_or< + typename gtl_same_type::type, polygon_90_concept>::type, + typename gtl_same_type::type, polygon_90_with_holes_concept>::type + >::type > : public polygon_traits_90 {}; + +#else + + template + struct gtl_ifelse {}; + template + struct gtl_ifelse { + typedef T_ELSE type; + }; + template + struct gtl_ifelse { + typedef T_IF type; + }; + + template + struct polygon_traits {}; + + template + struct polygon_traits::type, polygon_concept>::type, + typename gtl_same_type::type, polygon_45_concept>::type, + typename gtl_same_type::type, polygon_with_holes_concept>::type, + typename gtl_same_type::type, polygon_45_with_holes_concept>::type + >::type, typename gtl_or< + typename gtl_same_type::type, polygon_90_concept>::type, + typename gtl_same_type::type, polygon_90_with_holes_concept>::type + >::type>::type > : public gtl_ifelse::type, polygon_90_concept>::type, + typename gtl_same_type::type, polygon_90_with_holes_concept>::type >::type, + polygon_traits_90, + polygon_traits_general >::type { + }; + +#endif + + template + struct polygon_with_holes_traits { + typedef typename T::iterator_holes_type iterator_holes_type; + typedef typename T::hole_type hole_type; + + // Get the begin iterator + static inline iterator_holes_type begin_holes(const T& t) { + return t.begin_holes(); + } + + // Get the end iterator + static inline iterator_holes_type end_holes(const T& t) { + return t.end_holes(); + } + + // Get the number of holes + static inline std::size_t size_holes(const T& t) { + return t.size_holes(); + } + }; + + template + struct polygon_90_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template + static inline T& set_compact(T& t, iT input_begin, iT input_end) { + t.set_compact(input_begin, input_end); + return t; + } + + }; + + template + struct polygon_90_mutable_traits::type>::type> { + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template + static inline T& set_compact(T& t, iT input_begin, iT input_end) { + typedef iterator_points_to_compact::point_type> iTp; + t.set_points(iTp(polygon_traits::begin_points(t)), iTp(polygon_traits::end_points(t))); + return t; + } + }; + + template + struct polygon_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template + static inline T& set_points(T& t, iT input_begin, iT input_end) { + t.set(input_begin, input_end); + return t; + } + + }; + + template + struct polygon_with_holes_mutable_traits { + + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x + template + static inline T& set_holes(T& t, iT inputBegin, iT inputEnd) { + t.set_holes(inputBegin, inputEnd); + return t; + } + + }; +} +} +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +//rectangle +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" +#include "rectangle_concept.hpp" + +//algorithms needed by polygon types +#include "detail/iterator_points_to_compact.hpp" +#include "detail/iterator_compact_to_points.hpp" + +//polygons +#include "polygon_45_data.hpp" +#include "polygon_data.hpp" +#include "polygon_90_data.hpp" +#include "polygon_90_with_holes_data.hpp" +#include "polygon_45_with_holes_data.hpp" +#include "polygon_with_holes_data.hpp" + +namespace boost { namespace polygon{ + struct polygon_concept {}; + struct polygon_with_holes_concept {}; + struct polygon_45_concept {}; + struct polygon_45_with_holes_concept {}; + struct polygon_90_concept {}; + struct polygon_90_with_holes_concept {}; + + + template + struct is_polygon_90_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_polygon_45_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_or::type, + typename gtl_same_type::type>::type type; + }; + + template + struct is_polygon_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_or::type, + typename gtl_same_type::type>::type type; + }; + + template + struct is_polygon_90_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_or::type, + typename gtl_same_type::type>::type type; + }; + + template + struct is_polygon_45_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_or_3::type, + typename is_polygon_45_type::type, + typename gtl_same_type::type>::type type; + }; + + template + struct is_polygon_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_or_3::type, + typename is_polygon_type::type, + typename gtl_same_type::type>::type type; + }; + + template + struct is_mutable_polygon_90_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_mutable_polygon_45_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_mutable_polygon_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_mutable_polygon_90_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_mutable_polygon_45_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_mutable_polygon_with_holes_type { + typedef typename geometry_concept::type GC; + typedef typename gtl_same_type::type type; + }; + + template + struct is_any_mutable_polygon_with_holes_type { + typedef typename gtl_or_3::type, + typename is_mutable_polygon_45_with_holes_type::type, + typename is_mutable_polygon_with_holes_type::type>::type type; + }; + template + struct is_any_mutable_polygon_without_holes_type { + typedef typename gtl_or_3< + typename is_mutable_polygon_90_type::type, + typename is_mutable_polygon_45_type::type, + typename is_mutable_polygon_type::type>::type type; }; + + template + struct is_any_mutable_polygon_type { + typedef typename gtl_or::type, + typename is_any_mutable_polygon_without_holes_type::type>::type type; + }; + + template + struct polygon_from_polygon_with_holes_type {}; + template <> + struct polygon_from_polygon_with_holes_type { typedef polygon_concept type; }; + template <> + struct polygon_from_polygon_with_holes_type { typedef polygon_45_concept type; }; + template <> + struct polygon_from_polygon_with_holes_type { typedef polygon_90_concept type; }; + + template <> + struct geometry_domain { typedef forty_five_domain type; }; + template <> + struct geometry_domain { typedef forty_five_domain type; }; + template <> + struct geometry_domain { typedef manhattan_domain type; }; + template <> + struct geometry_domain { typedef manhattan_domain type; }; + + template + struct distance_type_by_domain { typedef typename coordinate_traits::coordinate_distance type; }; + template + struct distance_type_by_domain { + typedef typename coordinate_traits::coordinate_difference type; }; + + // \brief Sets the boundary of the polygon to the points in the iterator range + // \tparam T A type that models polygon_concept + // \tparam iT Iterator type over objects that model point_concept + // \param t The polygon to set + // \param begin_points The start of the range of points + // \param end_points The end of the range of points + + /// \relatesalso polygon_concept + template + typename enable_if ::type, T>::type & + set_points(T& t, iT begin_points, iT end_points) { + polygon_mutable_traits::set_points(t, begin_points, end_points); + return t; + } + + // \brief Sets the boundary of the polygon to the non-redundant coordinates in the iterator range + // \tparam T A type that models polygon_90_concept + // \tparam iT Iterator type over objects that model coordinate_concept + // \param t The polygon to set + // \param begin_compact_coordinates The start of the range of coordinates + // \param end_compact_coordinates The end of the range of coordinates + +/// \relatesalso polygon_90_concept + template + typename enable_if ::type, + typename is_mutable_polygon_90_with_holes_type::type>::type, T>::type & + set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { + polygon_90_mutable_traits::set_compact(t, begin_compact_coordinates, end_compact_coordinates); + return t; + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if< typename gtl_and < + typename is_any_mutable_polygon_with_holes_type::type, + typename gtl_different_type::type>::type, + manhattan_domain>::type>::type, + T>::type & + set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { + iterator_compact_to_points::coordinate_type> > + itrb(begin_compact_coordinates, end_compact_coordinates), + itre(end_compact_coordinates, end_compact_coordinates); + return set_points(t, itrb, itre); + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if ::type, T>::type & + set_holes(T& t, iT begin_holes, iT end_holes) { + polygon_with_holes_mutable_traits::set_holes(t, begin_holes, end_holes); + return t; + } + +/// \relatesalso polygon_90_concept + template + typename polygon_90_traits::compact_iterator_type + begin_compact(const T& polygon, + typename enable_if< + typename gtl_and ::type, + typename gtl_same_type::type>::type, + manhattan_domain>::type>::type>::type * = 0 + ) { + return polygon_90_traits::begin_compact(polygon); + } + +/// \relatesalso polygon_90_concept + template + typename polygon_90_traits::compact_iterator_type + end_compact(const T& polygon, + typename enable_if< + typename gtl_and ::type, + typename gtl_same_type::type>::type, + manhattan_domain>::type>::type>::type * = 0 + ) { + return polygon_90_traits::end_compact(polygon); + } + + /// \relatesalso polygon_concept + template + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type::type>::type, + typename polygon_traits::iterator_type>::type + begin_points(const T& polygon) { + return polygon_traits::begin_points(polygon); + } + + /// \relatesalso polygon_concept + template + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type::type>::type, + typename polygon_traits::iterator_type>::type + end_points(const T& polygon) { + return polygon_traits::end_points(polygon); + } + + /// \relatesalso polygon_concept + template + typename enable_if ::type, + std::size_t>::type + size(const T& polygon) { + return polygon_traits::size(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type::type>::type, + typename polygon_with_holes_traits::iterator_holes_type>::type + begin_holes(const T& polygon) { + return polygon_with_holes_traits::begin_holes(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if < typename gtl_if< + typename is_polygon_with_holes_type::type>::type, + typename polygon_with_holes_traits::iterator_holes_type>::type + end_holes(const T& polygon) { + return polygon_with_holes_traits::end_holes(polygon); + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if ::type, + std::size_t>::type + size_holes(const T& polygon) { + return polygon_with_holes_traits::size_holes(polygon); + } + + // \relatesalso polygon_concept + template + typename enable_if< + typename gtl_and< typename is_mutable_polygon_type::type, + typename is_polygon_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits::set_points(lvalue, polygon_traits::begin_points(rvalue), + polygon_traits::end_points(rvalue)); + return lvalue; + } + +// \relatesalso polygon_with_holes_concept + template + typename enable_if< + typename gtl_and< typename is_mutable_polygon_with_holes_type::type, + typename is_polygon_with_holes_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits::set_points(lvalue, polygon_traits::begin_points(rvalue), + polygon_traits::end_points(rvalue)); + polygon_with_holes_mutable_traits::set_holes(lvalue, polygon_with_holes_traits::begin_holes(rvalue), + polygon_with_holes_traits::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_45_concept + template + typename enable_if< typename gtl_and< typename is_mutable_polygon_45_type::type, typename is_polygon_45_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits::set_points(lvalue, polygon_traits::begin_points(rvalue), + polygon_traits::end_points(rvalue)); + return lvalue; + } + +// \relatesalso polygon_45_with_holes_concept + template + typename enable_if< + typename gtl_and< typename is_mutable_polygon_45_with_holes_type::type, + typename is_polygon_45_with_holes_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_mutable_traits::set_points(lvalue, polygon_traits::begin_points(rvalue), + polygon_traits::end_points(rvalue)); + polygon_with_holes_mutable_traits::set_holes(lvalue, polygon_with_holes_traits::begin_holes(rvalue), + polygon_with_holes_traits::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_90_concept + template + typename enable_if< + typename gtl_and< typename is_mutable_polygon_90_type::type, + typename is_polygon_90_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_90_mutable_traits::set_compact(lvalue, polygon_90_traits::begin_compact(rvalue), + polygon_90_traits::end_compact(rvalue)); + return lvalue; + } + +// \relatesalso polygon_90_with_holes_concept + template + typename enable_if< + typename gtl_and< typename is_mutable_polygon_90_with_holes_type::type, + typename is_polygon_90_with_holes_type::type>::type, T1>::type & + assign(T1& lvalue, const T2& rvalue) { + polygon_90_mutable_traits::set_compact(lvalue, polygon_90_traits::begin_compact(rvalue), + polygon_90_traits::end_compact(rvalue)); + polygon_with_holes_mutable_traits::set_holes(lvalue, polygon_with_holes_traits::begin_holes(rvalue), + polygon_with_holes_traits::end_holes(rvalue)); + return lvalue; + } + + // \relatesalso polygon_90_concept + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_type::type, + typename is_rectangle_concept::type>::type>::type, T1>::type & + assign(T1& polygon, const T2& rect) { + typedef point_data::coordinate_type> PT; + PT points[4] = {PT(xl(rect), yl(rect)), PT(xh(rect), yl(rect)), PT(xh(rect), yh(rect)), PT(xl(rect), yh(rect))}; + set_points(polygon, points, points+4); + return polygon; + } + +/// \relatesalso polygon_90_concept + template + typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type::type, + typename is_point_concept::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + std::vector::coordinate_type> coords; + coords.reserve(size(polygon)); + bool pingpong = true; + for(typename polygon_90_traits::compact_iterator_type iter = begin_compact(polygon); + iter != end_compact(polygon); ++iter) { + coords.push_back((*iter) + (pingpong ? x(point) : y(point))); + pingpong = !pingpong; + } + polygon_90_mutable_traits::set_compact(polygon, coords.begin(), coords.end()); + return polygon; + } + +/// \relatesalso polygon_concept + template + typename enable_if< typename gtl_and< typename gtl_or< + typename is_mutable_polygon_45_type::type, + typename is_mutable_polygon_type::type>::type, + typename is_point_concept::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + convolve(points.back(), point); + } + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, + typename is_point_concept::type>::type>::type, + polygon_type>::type & + convolve(polygon_type& polygon, const point_type& point) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + convolve(h, point); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + convolve(holes.back(), point); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + +/// \relatesalso polygon_concept + template + typename enable_if< typename is_any_mutable_polygon_type::type, T>::type & + move(T& polygon, orientation_2d orient, typename polygon_traits::coordinate_type displacement) { + typedef typename polygon_traits::coordinate_type Unit; + if(orient == HORIZONTAL) return convolve(polygon, point_data(displacement, Unit(0))); + return convolve(polygon, point_data(Unit(0), displacement)); + } + +/// \relatesalso polygon_concept +/// \brief Applies a transformation to the polygon. +/// \tparam polygon_type A type that models polygon_concept +/// \tparam transform_type A type that may be either axis_transformation or transformation or that overloads point_concept::transform +/// \param polygon The polygon to transform +/// \param tr The transformation to apply + template + typename enable_if< typename is_any_mutable_polygon_without_holes_type::type, polygon_type>::type & + transform(polygon_type& polygon, const transform_type& tr) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + transform(points.back(), tr); + } + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + +/// \relatesalso polygon_with_holes_concept + template + typename enable_if< typename is_any_mutable_polygon_with_holes_type::type, T>::type & + transform(T& polygon, const transform_type& tr) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + transform(h, tr); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + transform(holes.back(), tr); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + template + typename enable_if< typename is_any_mutable_polygon_without_holes_type::type, polygon_type>::type & + scale_up(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_up(points.back(), factor); + } + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template + typename enable_if< typename is_any_mutable_polygon_with_holes_type::type, T>::type & + scale_up(T& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale_up(h, factor); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale_up(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale non-45 down + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_not::type>::type>::type>::type>::type, + polygon_type>::type & + scale_down(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_down(points.back(), factor); + } + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template + Unit local_abs(Unit value) { return value < 0 ? (Unit)-value : value; } + + template + void snap_point_vector_to_45(std::vector >& pts) { + typedef point_data Point; + if(pts.size() < 3) { pts.clear(); return; } + Point firstPt = pts.front(); + Point prevPt = firstPt; + std::unique(pts.begin(), pts.end()); + if(pts.back() == pts[0]) pts.pop_back(); + //iterate over point triplets + int numPts = pts.size(); + bool wrap_around = false; + for(int i = 0; i < numPts; ++i) { + Point& pt1 = pts[i]; + Point& pt2 = pts[(i + 1) % numPts]; + Point& pt3 = pts[(i + 2) % numPts]; + //check if non-45 edge + Unit deltax = x(pt2) - x(pt1); + Unit deltay = y(pt2) - y(pt1); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) { + //adjust the middle point + Unit ndx = x(pt3) - x(pt2); + Unit ndy = y(pt3) - y(pt2); + if(ndx && ndy) { + Unit diff = local_abs(local_abs(deltax) - local_abs(deltay)); + Unit halfdiff = diff/2; + if((deltax > 0 && deltay > 0) || + (deltax < 0 && deltay < 0)) { + //previous edge is rising slope + if(local_abs(deltax + halfdiff + (diff % 2)) == + local_abs(deltay - halfdiff)) { + x(pt2, x(pt2) + halfdiff + (diff % 2)); + y(pt2, y(pt2) - halfdiff); + } else if(local_abs(deltax - halfdiff - (diff % 2)) == + local_abs(deltay + halfdiff)) { + x(pt2, x(pt2) - halfdiff - (diff % 2)); + y(pt2, y(pt2) + halfdiff); + } else{ + //std::cout << "fail1\n"; + } + } else { + //previous edge is falling slope + if(local_abs(deltax + halfdiff + (diff % 2)) == + local_abs(deltay + halfdiff)) { + x(pt2, x(pt2) + halfdiff + (diff % 2)); + y(pt2, y(pt2) + halfdiff); + } else if(local_abs(deltax - halfdiff - (diff % 2)) == + local_abs(deltay - halfdiff)) { + x(pt2, x(pt2) - halfdiff - (diff % 2)); + y(pt2, y(pt2) - halfdiff); + } else { + //std::cout << "fail2\n"; + } + } + if(i == numPts - 1 && (diff % 2)) { + //we have a wrap around effect + if(!wrap_around) { + wrap_around = true; + i = -1; + } + } + } else if(ndx) { + //next edge is horizontal + //find the x value for pt1 that would make the abs(deltax) == abs(deltay) + Unit newDeltaX = local_abs(deltay); + if(deltax < 0) newDeltaX *= -1; + x(pt2, x(pt1) + newDeltaX); + } else { //ndy + //next edge is vertical + //find the y value for pt1 that would make the abs(deltax) == abs(deltay) + Unit newDeltaY = local_abs(deltax); + if(deltay < 0) newDeltaY *= -1; + y(pt2, y(pt1) + newDeltaY); + } + } + } + } + + template + typename enable_if< typename is_any_mutable_polygon_without_holes_type::type, polygon_type>::type & + snap_to_45(polygon_type& polygon) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + } + snap_point_vector_to_45(points); + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template + typename enable_if< typename is_any_mutable_polygon_with_holes_type::type, polygon_type>::type & + snap_to_45(polygon_type& polygon) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + snap_to_45(h); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + snap_to_45(holes.back()); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale specifically 45 down + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_same_type + < forty_five_domain, + typename geometry_domain::type>::type>::type>::type, + polygon_type>::type & + scale_down(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale_down(points.back(), factor); + } + snap_point_vector_to_45(points); + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template + typename enable_if< typename is_any_mutable_polygon_with_holes_type::type, T>::type & + scale_down(T& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale_down(h, factor); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale_down(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + //scale non-45 + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_not::type>::type>::type>::type>::type, + polygon_type>::type & + scale(polygon_type& polygon, double factor) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale(points.back(), anisotropic_scale_factor(factor, factor)); + } + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + //scale specifically 45 + template + polygon_type& + scale(polygon_type& polygon, double factor, + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_same_type + < forty_five_domain, + typename geometry_domain::type>::type>::type>::type>::type * = 0 + ) { + std::vector::iterator_type>::value_type> points; + points.reserve(size(polygon)); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); + iter != end_points(polygon); ++iter) { + points.push_back(*iter); + scale(points.back(), anisotropic_scale_factor(factor, factor)); + } + snap_point_vector_to_45(points); + polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); + return polygon; + } + + template + T& + scale(T& polygon, double factor, + typename enable_if< typename is_any_mutable_polygon_with_holes_type::type>::type * = 0 + ) { + typedef typename polygon_with_holes_traits::hole_type hole_type; + hole_type h; + set_points(h, begin_points(polygon), end_points(polygon)); + scale(h, factor); + std::vector holes; + holes.reserve(size_holes(polygon)); + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon); + itr != end_holes(polygon); ++itr) { + holes.push_back(*itr); + scale(holes.back(), factor); + } + assign(polygon, h); + set_holes(polygon, holes.begin(), holes.end()); + return polygon; + } + + template + static area_type + point_sequence_area(iterator_type begin_range, iterator_type end_range) { + typedef typename std::iterator_traits::value_type point_type; + typedef typename point_traits::coordinate_type Unit; + if(begin_range == end_range) return area_type(0); + point_type first = *begin_range; + point_type previous = first; + ++begin_range; + // Initialize trapezoid base line + area_type y_base = (area_type)y(first); + // Initialize area accumulator + + area_type area(0); + while (begin_range != end_range) { + area_type x1 = (area_type)x(previous); + area_type x2 = (area_type)x(*begin_range); +#ifdef BOOST_POLYGON_ICC +#pragma warning (disable:1572) +#endif + if(x1 != x2) { +#ifdef BOOST_POLYGON_ICC +#pragma warning (default:1572) +#endif + // do trapezoid area accumulation + area += (x2 - x1) * (((area_type)y(*begin_range) - y_base) + + ((area_type)y(previous) - y_base)) / 2; + } + previous = *begin_range; + // go to next point + ++begin_range; + } + //wrap around to evaluate the edge between first and last if not closed + if(!equivalence(first, previous)) { + area_type x1 = (area_type)x(previous); + area_type x2 = (area_type)x(first); + area += (x2 - x1) * (((area_type)y(first) - y_base) + + ((area_type)y(previous) - y_base)) / 2; + } + return area; + } + + template + typename enable_if< + typename is_polygon_with_holes_type::type, + typename area_type_by_domain< typename geometry_domain::type>::type, + typename polygon_traits::coordinate_type>::type>::type + area(const T& polygon) { + typedef typename area_type_by_domain< typename geometry_domain::type>::type, + typename polygon_traits::coordinate_type>::type area_type; + area_type retval = point_sequence_area::iterator_type, area_type> + (begin_points(polygon), end_points(polygon)); + if(retval < 0) retval *= -1; + for(typename polygon_with_holes_traits::iterator_holes_type itr = + polygon_with_holes_traits::begin_holes(polygon); + itr != polygon_with_holes_traits::end_holes(polygon); ++itr) { + area_type tmp_area = point_sequence_area + ::hole_type>::iterator_type, area_type> + (begin_points(*itr), end_points(*itr)); + if(tmp_area < 0) tmp_area *= -1; + retval -= tmp_area; + } + return retval; + } + + template + bool point_sequence_is_45(iT itr, iT itr_end) { + typedef typename iT::value_type Point; + typedef typename point_traits::coordinate_type Unit; + if(itr == itr_end) return true; + Point firstPt = *itr; + Point prevPt = firstPt; + ++itr; + while(itr != itr_end) { + Point pt = *itr; + Unit deltax = x(pt) - x(prevPt); + Unit deltay = y(pt) - y(prevPt); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) + return false; + prevPt = pt; + ++itr; + } + Unit deltax = x(firstPt) - x(prevPt); + Unit deltay = y(firstPt) - y(prevPt); + if(deltax && deltay && + local_abs(deltax) != local_abs(deltay)) + return false; + return true; + } + + template + typename enable_if< typename is_polygon_with_holes_type::type, bool>::type + is_45(const polygon_type& polygon) { + typename polygon_traits::iterator_type itr = begin_points(polygon), itr_end = end_points(polygon); + if(!point_sequence_is_45(itr, itr_end)) return false; + typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygon), itrh_end = end_holes(polygon); + typedef typename polygon_with_holes_traits::hole_type hole_type; + for(; itrh != itrh_end; ++ itrh) { + typename polygon_traits::iterator_type itr1 = begin_points(polygon), itr1_end = end_points(polygon); + if(!point_sequence_is_45(itr1, itr1_end)) return false; + } + return true; + } + + template + distance_type point_sequence_distance(iterator_type itr, iterator_type itr_end) { + typedef distance_type Unit; + typedef iterator_type iterator; + typedef typename std::iterator_traits::value_type point_type; + Unit return_value = Unit(0); + point_type previous_point, first_point; + if(itr == itr_end) return return_value; + previous_point = first_point = *itr; + ++itr; + for( ; itr != itr_end; ++itr) { + point_type current_point = *itr; + return_value += (Unit)euclidean_distance(current_point, previous_point); + previous_point = current_point; + } + return_value += (Unit)euclidean_distance(previous_point, first_point); + return return_value; + } + + template + typename distance_type_by_domain + ::type>::type, typename polygon_traits::coordinate_type>::type + perimeter(const T& polygon, + typename enable_if< + typename is_polygon_with_holes_type::type>::type * = 0 + ) { + typedef typename distance_type_by_domain + ::type>::type, typename polygon_traits::coordinate_type>::type Unit; + typedef typename polygon_traits::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itr_end = end_points(polygon); + Unit return_value = point_sequence_distance(itr, itr_end); + for(typename polygon_with_holes_traits::iterator_holes_type itr_holes = begin_holes(polygon); + itr_holes != end_holes(polygon); ++itr_holes) { + typedef typename polygon_traits::hole_type>::iterator_type hitertype; + return_value += point_sequence_distance(begin_points(*itr_holes), end_points(*itr_holes)); + } + return return_value; + } + + template + typename enable_if ::type, + direction_1d>::type + winding(const T& polygon) { + winding_direction wd = polygon_traits::winding(polygon); + if(wd != unknown_winding) { + return wd == clockwise_winding ? CLOCKWISE: COUNTERCLOCKWISE; + } + typedef typename area_type_by_domain< typename geometry_domain::type>::type, + typename polygon_traits::coordinate_type>::type area_type; + return point_sequence_area::iterator_type, area_type>(begin_points(polygon), end_points(polygon)) < 0 ? + COUNTERCLOCKWISE : CLOCKWISE; + } + + template + typename enable_if< + typename gtl_and< typename is_polygon_90_type::type, + typename gtl_same_type::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef T polygon_type; + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator; + typedef typename std::iterator_traits::value_type point_type; + iterator iter, iter_end; + iter_end = end_points(polygon); + iter = begin_points(polygon); + point_type prev_pt = *iter; + std::size_t num = size(polygon); + std::size_t counts[2] = {0, 0}; + for(std::size_t i = 0; i < num; ++i) { + if(i == num-1) iter = begin_points(polygon); + else ++iter; + point_type current_pt = *iter; + if(x(current_pt) == + x(prev_pt)) { + unsigned int index = x(current_pt) > + x(point); + std::size_t increment = 0; + interval_data ivl(y(current_pt), + y(prev_pt)); + if(contains(ivl, y(point), true)) { + if(x(current_pt) == + x(point)) return consider_touch; + ++increment; + if(y(current_pt) != + y(point) && + y(prev_pt) != + y(point)) { + ++increment; + } + counts[index] += increment; + } + } + prev_pt = current_pt; + } + //odd count implies boundary condition + if(counts[0] % 2 || counts[1] % 2) return consider_touch; + //an odd number of edges to the left implies interior pt + return counts[0] % 4 != 0; + } + + //TODO: refactor to expose as user APIs + template + struct edge_utils { + typedef point_data Point; + typedef std::pair half_edge; + + class less_point : public std::binary_function { + public: + inline less_point() {} + inline bool operator () (const Point& pt1, const Point& pt2) const { + if(pt1.get(HORIZONTAL) < pt2.get(HORIZONTAL)) return true; + if(pt1.get(HORIZONTAL) == pt2.get(HORIZONTAL)) { + if(pt1.get(VERTICAL) < pt2.get(VERTICAL)) return true; + } + return false; + } + }; + + static inline bool between(Point pt, Point pt1, Point pt2) { + less_point lp; + if(lp(pt1, pt2)) + return lp(pt, pt2) && lp(pt1, pt); + return lp(pt, pt1) && lp(pt2, pt); + } + + template + static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + return cross_1 == cross_2 && (cross_1_sign == cross_2_sign || cross_1 == 0); + } + + static inline bool equal_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + typedef typename coordinate_traits::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return equal_slope(dx1, dy1, dx2, dy2); + } + + template + static inline bool less_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { + //reflext x and y slopes to right hand side half plane + if(dx1 < 0) { + dy1 *= -1; + dx1 *= -1; + } else if(dx1 == 0) { + //if the first slope is vertical the first cannot be less + return false; + } + if(dx2 < 0) { + dy2 *= -1; + dx2 *= -1; + } else if(dx2 == 0) { + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + return dx1 != 0; + } + typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; + unsigned_product_type cross_1 = (unsigned_product_type)(dx2 < 0 ? -dx2 :dx2) * (unsigned_product_type)(dy1 < 0 ? -dy1 : dy1); + unsigned_product_type cross_2 = (unsigned_product_type)(dx1 < 0 ? -dx1 :dx1) * (unsigned_product_type)(dy2 < 0 ? -dy2 : dy2); + int dx1_sign = dx1 < 0 ? -1 : 1; + int dx2_sign = dx2 < 0 ? -1 : 1; + int dy1_sign = dy1 < 0 ? -1 : 1; + int dy2_sign = dy2 < 0 ? -1 : 1; + int cross_1_sign = dx2_sign * dy1_sign; + int cross_2_sign = dx1_sign * dy2_sign; + if(cross_1_sign < cross_2_sign) return true; + if(cross_2_sign < cross_1_sign) return false; + if(cross_1_sign == -1) return cross_2 < cross_1; + return cross_1 < cross_2; + } + + static inline bool less_slope(const Unit& x, const Unit& y, + const Point& pt1, const Point& pt2) { + const Point* pts[2] = {&pt1, &pt2}; + //compute y value on edge from pt_ to pts[1] at the x value of pts[0] + typedef typename coordinate_traits::manhattan_area_type at; + at dy2 = (at)pts[1]->get(VERTICAL) - (at)y; + at dy1 = (at)pts[0]->get(VERTICAL) - (at)y; + at dx2 = (at)pts[1]->get(HORIZONTAL) - (at)x; + at dx1 = (at)pts[0]->get(HORIZONTAL) - (at)x; + return less_slope(dx1, dy1, dx2, dy2); + } + + //return -1 below, 0 on and 1 above line + //assumes point is on x interval of segment + static inline int on_above_or_below(Point pt, const half_edge& he) { + if(pt == he.first || pt == he.second) return 0; + if(equal_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second)) return 0; + bool less_result = less_slope(pt.get(HORIZONTAL), pt.get(VERTICAL), he.first, he.second); + int retval = less_result ? -1 : 1; + less_point lp; + if(lp(he.second, he.first)) retval *= -1; + if(!between(pt, he.first, he.second)) retval *= -1; + return retval; + } + }; + + template + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, + typename gtl_same_type::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename polygon_with_holes_traits::iterator_holes_type holes_iterator; + bool isInside = contains( view_as< typename polygon_from_polygon_with_holes_type< + typename geometry_concept::type>::type>( polygon ), point, consider_touch ); + if(!isInside) return false; //no need to check holes + holes_iterator itH = begin_holes( polygon ); + while( itH != end_holes( polygon ) ) { + if( contains( *itH, point, !consider_touch ) ) { + isInside = false; + break; + } + ++itH; + } + return isInside; + } + + template + typename enable_if< + typename gtl_and_3< + typename is_polygon_type::type, + typename gtl_different_type::type>::type, manhattan_domain>::type, + typename gtl_same_type::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename point_traits::coordinate_type Unit; + typedef point_data Point; + typedef std::pair half_edge; + typedef typename polygon_traits::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itrEnd = end_points(polygon); + half_edge he; + if(itr == itrEnd) return false; + assign(he.first, *itr); + Point firstPt; + assign(firstPt, *itr); + ++itr; + if(itr == itrEnd) return false; + bool done = false; + int above = 0; + while(!done) { + Point currentPt; + if(itr == itrEnd) { + done = true; + currentPt = firstPt; + } else { + assign(currentPt, *itr); + ++itr; + } + if(currentPt == he.first) { + continue; + } else { + he.second = currentPt; + if(equivalence(point, currentPt)) return consider_touch; + Unit xmin = (std::min)(x(he.first), x(he.second)); + Unit xmax = (std::max)(x(he.first), x(he.second)); + if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax + Point tmppt; + assign(tmppt, point); + int oabedge = edge_utils::on_above_or_below(tmppt, he); + if(oabedge == 0) return consider_touch; + if(oabedge == 1) ++above; + } else if(x(point) == xmax) { + Point tmppt; + assign(tmppt, point); + if( edge_utils::on_above_or_below(tmppt, he) == 0 ) { + return consider_touch; + } + } + } + he.first = he.second; + } + return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon + } + + /* + template + typename enable_if< + typename gtl_and_3< + typename is_polygon_with_holes_type::type, + typename gtl_different_type::type>::type, manhattan_domain>::type, + typename gtl_same_type::type, point_concept>::type>::type, + bool>::type + contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { + typedef typename point_traits::coordinate_type Unit; + typedef point_data Point; + typedef std::pair half_edge; + typedef typename polygon_traits::iterator_type iterator; + iterator itr = begin_points(polygon); + iterator itrEnd = end_points(polygon); + half_edge he; + if(itr == itrEnd) return false; + assign(he.first, *itr); + Point firstPt; + assign(firstPt, *itr); + ++itr; + if(itr == itrEnd) return false; + bool done = false; + int above = 0; + while(!done) { + Point currentPt; + if(itr == itrEnd) { + done = true; + currentPt = firstPt; + } else { + assign(currentPt, *itr); + ++itr; + } + if(currentPt == he.first) { + continue; + } else { + he.second = currentPt; + if(equivalence(point, currentPt)) return consider_touch; + Unit xmin = (std::min)(x(he.first), x(he.second)); + Unit xmax = (std::max)(x(he.first), x(he.second)); + if(x(point) >= xmin && x(point) < xmax) { //double counts if <= xmax + Point tmppt; + assign(tmppt, point); + int oabedge = edge_utils::on_above_or_below(tmppt, he); + if(oabedge == 0) return consider_touch; + if(oabedge == 1) ++above; + } + } + he.first = he.second; + } + return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon + } + */ + + template + typename enable_if< + typename gtl_and< typename is_mutable_point_concept::type>::type, + typename is_polygon_with_holes_type::type>::type, + bool>::type + center(T1& center_point, const T2& polygon) { + typedef typename polygon_traits::coordinate_type coordinate_type; + rectangle_data bbox; + extents(bbox, polygon); + return center(center_point, bbox); + } + + template + typename enable_if< + typename gtl_and< typename is_mutable_rectangle_concept::type>::type, + typename is_polygon_with_holes_type::type>::type, + bool>::type + extents(T1& bounding_box, const T2& polygon) { + typedef typename polygon_traits::iterator_type iterator; + bool first_iteration = true; + iterator itr_end = end_points(polygon); + for(iterator itr = begin_points(polygon); itr != itr_end; ++itr) { + if(first_iteration) { + set_points(bounding_box, *itr, *itr); + first_iteration = false; + } else { + encompass(bounding_box, *itr); + } + } + if(first_iteration) return false; + return true; + } + + template + template + polygon_90_data& polygon_90_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + polygon_45_data& polygon_45_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + polygon_data& polygon_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + polygon_90_with_holes_data& polygon_90_with_holes_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + polygon_45_with_holes_data& polygon_45_with_holes_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + polygon_with_holes_data& polygon_with_holes_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + struct geometry_concept > { + typedef polygon_concept type; + }; + template + struct geometry_concept > { + typedef polygon_45_concept type; + }; + template + struct geometry_concept > { + typedef polygon_90_concept type; + }; + template + struct geometry_concept > { + typedef polygon_with_holes_concept type; + }; + template + struct geometry_concept > { + typedef polygon_45_with_holes_concept type; + }; + template + struct geometry_concept > { + typedef polygon_90_with_holes_concept type; + }; + +// template struct polygon_with_holes_traits > { +// typedef polygon_90_data hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; +// template struct polygon_with_holes_traits > { +// typedef polygon_45_data hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; +// template struct polygon_with_holes_traits > { +// typedef polygon_data hole_type; +// typedef const hole_type* iterator_holes_type; +// static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } +// static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } +// static inline std::size_t size_holes(const hole_type& t) { return 0; } +// }; + template struct get_void {}; + template <> struct get_void { typedef void type; }; + + template struct polygon_with_holes_traits< + T, typename get_void::type>::type > { + typedef T hole_type; + typedef const hole_type* iterator_holes_type; + static inline iterator_holes_type begin_holes(const hole_type& t) { return &t; } + static inline iterator_holes_type end_holes(const hole_type& t) { return &t; } + static inline std::size_t size_holes(const hole_type& t) { return 0; } + }; + + template + struct view_of { + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef interval_data interval_type; + rectangle_data rect; + view_of(const T& obj) : rect() { + point_data pts[2]; + typename polygon_traits::iterator_type itr = + begin_points(obj), itre = end_points(obj); + if(itr == itre) return; + assign(pts[0], *itr); + ++itr; + if(itr == itre) return; + ++itr; + if(itr == itre) return; + assign(pts[1], *itr); + set_points(rect, pts[0], pts[1]); + } + inline interval_type get(orientation_2d orient) const { + return rect.get(orient); } + }; + + template + struct geometry_concept > { + typedef rectangle_concept type; + }; + + template + struct view_of { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator_type; + typedef typename polygon_traits::point_type point_type; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits::winding(*t); + } + }; + + template + struct geometry_concept > { + typedef polygon_45_concept type; + }; + + template + struct view_of { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator_type; + typedef typename polygon_traits::point_type point_type; + typedef iterator_points_to_compact compact_iterator_type; + + /// Get the begin iterator + inline compact_iterator_type begin_compact() const { + return compact_iterator_type(polygon_traits::begin_points(*t), + polygon_traits::end_points(*t)); + } + + /// Get the end iterator + inline compact_iterator_type end_compact() const { + return compact_iterator_type(polygon_traits::end_points(*t), + polygon_traits::end_points(*t)); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits::winding(*t); + } + }; + + template + struct geometry_concept > { + typedef polygon_90_concept type; + }; + + template + struct view_of { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator_type; + typedef typename polygon_traits::point_type point_type; + typedef view_of::hole_type> hole_type; + struct iterator_holes_type { + typedef std::forward_iterator_tag iterator_category; + typedef hole_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const hole_type* pointer; //immutable + typedef const hole_type& reference; //immutable + typedef typename polygon_with_holes_traits::iterator_holes_type iht; + iht internal_itr; + iterator_holes_type() : internal_itr() {} + iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} + inline iterator_holes_type& operator++() { + ++internal_itr; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_holes_type& that) const { + return (internal_itr == that.internal_itr); + } + inline bool operator!=(const iterator_holes_type& that) const { + return (internal_itr != that.internal_itr); + } + inline value_type operator*() const { + return view_as(*internal_itr); + } + }; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits::winding(*t); + } + + /// Get the begin iterator + inline iterator_holes_type begin_holes() const { + return polygon_with_holes_traits::begin_holes(*t); + } + + /// Get the end iterator + inline iterator_holes_type end_holes() const { + return polygon_with_holes_traits::end_holes(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size_holes() const { + return polygon_with_holes_traits::size_holes(*t); + } + + }; + + template + struct geometry_concept > { + typedef polygon_45_with_holes_concept type; + }; + + template + struct view_of { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator_type; + typedef typename polygon_traits::point_type point_type; + typedef iterator_points_to_compact compact_iterator_type; + typedef view_of::hole_type> hole_type; + struct iterator_holes_type { + typedef std::forward_iterator_tag iterator_category; + typedef hole_type value_type; + typedef std::ptrdiff_t difference_type; + typedef const hole_type* pointer; //immutable + typedef const hole_type& reference; //immutable + typedef typename polygon_with_holes_traits::iterator_holes_type iht; + iht internal_itr; + iterator_holes_type() : internal_itr() {} + iterator_holes_type(iht iht_in) : internal_itr(iht_in) {} + inline iterator_holes_type& operator++() { + ++internal_itr; + return *this; + } + inline const iterator_holes_type operator++(int) { + iterator_holes_type tmp(*this); + ++(*this); + return tmp; + } + inline bool operator==(const iterator_holes_type& that) const { + return (internal_itr == that.internal_itr); + } + inline bool operator!=(const iterator_holes_type& that) const { + return (internal_itr != that.internal_itr); + } + inline value_type operator*() const { + return view_as(*internal_itr); + } + }; + + /// Get the begin iterator + inline compact_iterator_type begin_compact() const { + return compact_iterator_type(polygon_traits::begin_points(*t), + polygon_traits::end_points(*t)); + } + + /// Get the end iterator + inline compact_iterator_type end_compact() const { + return compact_iterator_type(polygon_traits::end_points(*t), + polygon_traits::end_points(*t)); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits::winding(*t); + } + + /// Get the begin iterator + inline iterator_holes_type begin_holes() const { + return polygon_with_holes_traits::begin_holes(*t); + } + + /// Get the end iterator + inline iterator_holes_type end_holes() const { + return polygon_with_holes_traits::end_holes(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size_holes() const { + return polygon_with_holes_traits::size_holes(*t); + } + + }; + + template + struct geometry_concept > { + typedef polygon_90_with_holes_concept type; + }; + + template + struct view_of { + const T* t; + view_of(const T& obj) : t(&obj) {} + typedef typename polygon_traits::coordinate_type coordinate_type; + typedef typename polygon_traits::iterator_type iterator_type; + typedef typename polygon_traits::point_type point_type; + + /// Get the begin iterator + inline iterator_type begin() const { + return polygon_traits::begin_points(*t); + } + + /// Get the end iterator + inline iterator_type end() const { + return polygon_traits::end_points(*t); + } + + /// Get the number of sides of the polygon + inline std::size_t size() const { + return polygon_traits::size(*t); + } + + /// Get the winding direction of the polygon + inline winding_direction winding() const { + return polygon_traits::winding(*t); + } + }; + + template + struct geometry_concept > { + typedef polygon_concept type; + }; +} +} + +#endif + diff --git a/include/boost/polygon/polygon_with_holes_data.hpp b/include/boost/polygon/polygon_with_holes_data.hpp new file mode 100755 index 0000000..e5a975b --- /dev/null +++ b/include/boost/polygon/polygon_with_holes_data.hpp @@ -0,0 +1,108 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_POLYGON_WITH_HOLES_DATA_HPP +#define BOOST_POLYGON_POLYGON_WITH_HOLES_DATA_HPP +#include "isotropy.hpp" +#include "polygon_data.hpp" +namespace boost { namespace polygon{ + struct polygon_with_holes_concept; + template + class polygon_with_holes_data { +public: + typedef polygon_with_holes_concept geometry_type; + typedef T coordinate_type; + typedef typename polygon_data::iterator_type iterator_type; + typedef typename std::list >::const_iterator iterator_holes_type; + typedef polygon_data hole_type; + typedef typename coordinate_traits::coordinate_distance area_type; + typedef point_data point_type; + + // default constructor of point does not initialize x and y + inline polygon_with_holes_data() : self_(), holes_() {} //do nothing default constructor + + template + inline polygon_with_holes_data(iT input_begin, iT input_end) : self_(), holes_() { + set(input_begin, input_end); + } + + template + inline polygon_with_holes_data(iT input_begin, iT input_end, hiT holes_begin, hiT holes_end) : self_(), holes_() { + set(input_begin, input_end); + set_holes(holes_begin, holes_end); + } + + template + inline polygon_with_holes_data& set(iT input_begin, iT input_end) { + self_.set(input_begin, input_end); + return *this; + } + + // initialize a polygon from x,y values, it is assumed that the first is an x + // and that the input is a well behaved polygon + template + inline polygon_with_holes_data& set_holes(iT input_begin, iT input_end) { + holes_.clear(); //just in case there was some old data there + for( ; input_begin != input_end; ++ input_begin) { + holes_.push_back(hole_type()); + holes_.back().set((*input_begin).begin(), (*input_begin).end()); + } + return *this; + } + + // copy constructor (since we have dynamic memory) + inline polygon_with_holes_data(const polygon_with_holes_data& that) : self_(that.self_), + holes_(that.holes_) {} + + // assignment operator (since we have dynamic memory do a deep copy) + inline polygon_with_holes_data& operator=(const polygon_with_holes_data& that) { + self_ = that.self_; + holes_ = that.holes_; + return *this; + } + + template + inline polygon_with_holes_data& operator=(const T2& rvalue); + + // get begin iterator, returns a pointer to a const coordinate_type + inline const iterator_type begin() const { + return self_.begin(); + } + + // get end iterator, returns a pointer to a const coordinate_type + inline const iterator_type end() const { + return self_.end(); + } + + inline std::size_t size() const { + return self_.size(); + } + + // get begin iterator, returns a pointer to a const polygon + inline const iterator_holes_type begin_holes() const { + return holes_.begin(); + } + + // get end iterator, returns a pointer to a const polygon + inline const iterator_holes_type end_holes() const { + return holes_.end(); + } + + inline std::size_t size_holes() const { + return holes_.size(); + } + +public: + polygon_data self_; + std::list holes_; + }; + + +} +} +#endif + diff --git a/include/boost/polygon/rectangle_concept.hpp b/include/boost/polygon/rectangle_concept.hpp new file mode 100755 index 0000000..e302b99 --- /dev/null +++ b/include/boost/polygon/rectangle_concept.hpp @@ -0,0 +1,1080 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_RECTANGLE_CONCEPT_HPP +#define BOOST_POLYGON_RECTANGLE_CONCEPT_HPP + +#include "isotropy.hpp" + +//point +#include "point_data.hpp" +#include "point_traits.hpp" +#include "point_concept.hpp" + +//interval +#include "interval_data.hpp" +#include "interval_traits.hpp" +#include "interval_concept.hpp" + +#include "rectangle_data.hpp" +#include "rectangle_traits.hpp" + +namespace boost { namespace polygon{ + struct rectangle_concept {}; + + template + struct is_rectangle_concept { typedef gtl_no type; }; + template <> + struct is_rectangle_concept { typedef gtl_yes type; }; + + template + struct is_mutable_rectangle_concept { typedef gtl_no type; }; + template <> + struct is_mutable_rectangle_concept { typedef gtl_yes type; }; + + template <> + struct geometry_domain { typedef manhattan_domain type; }; + + template + struct rectangle_interval_type_by_concept { typedef void type; }; + template + struct rectangle_interval_type_by_concept { typedef typename rectangle_traits::interval_type type; }; + + template + struct rectangle_interval_type { + typedef typename rectangle_interval_type_by_concept::type>::type>::type type; + }; + + template + struct rectangle_coordinate_type_by_concept { typedef void type; }; + template + struct rectangle_coordinate_type_by_concept { typedef typename rectangle_traits::coordinate_type type; }; + + template + struct rectangle_coordinate_type { + typedef typename rectangle_coordinate_type_by_concept::type>::type>::type type; + }; + + template + struct rectangle_difference_type_by_concept { typedef void type; }; + template + struct rectangle_difference_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + + template + struct rectangle_difference_type { + typedef typename rectangle_difference_type_by_concept< + T, typename is_rectangle_concept::type>::type>::type type; + }; + + template + struct rectangle_distance_type_by_concept { typedef void type; }; + template + struct rectangle_distance_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + + template + struct rectangle_distance_type { + typedef typename rectangle_distance_type_by_concept< + T, typename is_rectangle_concept::type>::type>::type type; + }; + + template + typename rectangle_interval_type::type + get(const T& rectangle, orientation_2d orient, + typename enable_if< typename gtl_if::type>::type>::type>::type * = 0 + ) { + return rectangle_traits::get(rectangle, orient); + } + + struct y_r_h : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_traits::interval_type>::type + horizontal(const T& rectangle) { + return rectangle_traits::get(rectangle, HORIZONTAL); + } + + struct y_r_v : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_traits::interval_type>::type + vertical(const T& rectangle) { + return rectangle_traits::get(rectangle, VERTICAL); + } + + struct y_r_set : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + void>::type + set(T& rectangle, const T2& interval) { + rectangle_mutable_traits::set(rectangle, orient, interval); + } + + struct y_r_set2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + void>::type + set(T& rectangle, orientation_2d orient, const T2& interval) { + rectangle_mutable_traits::set(rectangle, orient, interval); + } + + struct y_r_h2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + void>::type + horizontal(T& rectangle, const T2& interval) { + rectangle_mutable_traits::set(rectangle, HORIZONTAL, interval); + } + + struct y_r_v2 : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, void>::type + vertical(T& rectangle, const T2& interval) { + rectangle_mutable_traits::set(rectangle, VERTICAL, interval); + } + + struct y_r_construct : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + T>::type + construct(const T2& interval_horizontal, + const T3& interval_vertical) { + return rectangle_mutable_traits::construct(interval_horizontal, interval_vertical); } + + struct y_r_construct2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type, + T>::type + construct(coord_type xl, coord_type yl, coord_type xh, coord_type yh) { + return rectangle_mutable_traits::construct(interval_data(xl, xh), + interval_data(yl, yh)); + } + + struct y_r_cconstruct : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + T>::type + copy_construct(const T2& rectangle) { + return construct (get(rectangle, HORIZONTAL), get(rectangle, VERTICAL)); + } + + struct y_r_assign : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3< y_r_assign, + typename is_mutable_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + assign(rectangle_type_1& lvalue, const rectangle_type_2& rvalue) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + return lvalue; + } + + struct y_r_equiv : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3< y_r_equiv, + typename is_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + equivalence(const T& rect1, const T2& rect2) { + return equivalence(get(rect1, HORIZONTAL), get(rect2, HORIZONTAL)) && + equivalence(get(rect1, VERTICAL), get(rect2, VERTICAL)); + } + + struct y_r_get : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_coordinate_type::type>::type + get(const rectangle_type& rectangle, orientation_2d orient, direction_1d dir) { + return get(rectangle_traits::get(rectangle, orient), dir); + } + + struct y_r_set3 : gtl_yes {}; + + template + typename enable_if::type>::type>::type, void>::type + set(rectangle_type& rectangle, orientation_2d orient, direction_1d dir, + typename rectangle_traits::coordinate_type value) { + typename rectangle_traits::interval_type ivl = get(rectangle, orient); + set(ivl, dir, value); + set(rectangle, orient, ivl); + } + + struct y_r_xl : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_coordinate_type::type>::type + xl(const rectangle_type& rectangle) { + return get(rectangle, HORIZONTAL, LOW); + } + + struct y_r_xl2 : gtl_yes {}; + + template + typename enable_if::type>::type>::type, void>::type + xl(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + return set(rectangle, HORIZONTAL, LOW, value); + } + + struct y_r_xh : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_coordinate_type::type>::type + xh(const rectangle_type& rectangle) { + return get(rectangle, HORIZONTAL, HIGH); + } + + struct y_r_xh2 : gtl_yes {}; + + template + typename enable_if::type>::type>::type, void>::type + xh(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + return set(rectangle, HORIZONTAL, HIGH, value); + } + + struct y_r_yl : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_coordinate_type::type>::type + yl(const rectangle_type& rectangle) { + return get(rectangle, VERTICAL, LOW); + } + + struct y_r_yl2 : gtl_yes {}; + + template + typename enable_if::type>::type>::type, void>::type + yl(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + return set(rectangle, VERTICAL, LOW, value); + } + + struct y_r_yh : gtl_yes {}; + + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_coordinate_type::type>::type + yh(const rectangle_type& rectangle) { + return get(rectangle, VERTICAL, HIGH); + } + + struct y_r_yh2 : gtl_yes {}; + + template + typename enable_if::type>::type>::type, void>::type + yh(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + return set(rectangle, VERTICAL, HIGH, value); + } + + struct y_r_ll : gtl_yes {}; + + template + typename enable_if::type>::type>::type>::type, + point_data::coordinate_type> >::type + ll(const rectangle_type& rectangle) { + return point_data::coordinate_type> (xl(rectangle), yl(rectangle)); + } + + struct y_r_lr : gtl_yes {}; + + template + typename enable_if::type>::type>::type>::type, + point_data::coordinate_type> >::type + lr(const rectangle_type& rectangle) { + return point_data::coordinate_type> (xh(rectangle), yl(rectangle)); + } + + struct y_r_ul : gtl_yes {}; + + template + typename enable_if::type>::type>::type>::type, + point_data::coordinate_type> >::type + ul(const rectangle_type& rectangle) { + return point_data::coordinate_type> (xl(rectangle), yh(rectangle)); + } + + struct y_r_ur : gtl_yes {}; + + template + typename enable_if::type>::type>::type>::type, + point_data::coordinate_type> >::type + ur(const rectangle_type& rectangle) { + return point_data::coordinate_type> (xh(rectangle), yh(rectangle)); + } + + struct y_r_contains : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + contains(const rectangle_type& rectangle, const rectangle_type_2 rectangle_contained, + bool consider_touch = true) { + return contains(horizontal(rectangle), horizontal(rectangle_contained), consider_touch) && + contains(vertical(rectangle), vertical(rectangle_contained), consider_touch); + } + + struct y_r_contains2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, bool>::type + contains(const rectangle_type& rectangle, const point_type point_contained, + bool consider_touch = true) { + return contains(horizontal(rectangle), x(point_contained), consider_touch) && + contains(vertical(rectangle), y(point_contained), consider_touch); + } + + struct y_r_set_points : gtl_yes {}; + + // set all four coordinates based upon two points + template + typename enable_if< typename gtl_and_4< y_r_set_points, + typename is_mutable_rectangle_concept::type>::type, + typename is_point_concept::type>::type, + typename is_point_concept::type>::type>::type, + rectangle_type>::type & + set_points(rectangle_type& rectangle, const point_type_1& p1, + const point_type_2& p2) { + typedef typename rectangle_traits::coordinate_type Unit; + Unit x1(x(p1)); + Unit x2(x(p2)); + Unit y1(y(p1)); + Unit y2(y(p2)); + horizontal(rectangle, construct::interval_type>(x1, x2)); + vertical(rectangle, construct::interval_type>(y1, y2)); + return rectangle; + } + + // move rectangle by delta in orient + template + rectangle_type& + move(rectangle_type& rectangle, orientation_2d orient, + typename coordinate_traits::coordinate_type>::coordinate_difference delta, + typename enable_if::type>::type>::type * = 0 + ) { + typename rectangle_traits::interval_type ivl = get(rectangle, orient); + move(ivl, delta); + set(rectangle, orient, ivl); + return rectangle; + } + + struct y_r_convolve : gtl_yes {}; + + // convolve this with b + template + typename enable_if< + typename gtl_and_3< y_r_convolve, + typename is_mutable_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + convolve(rectangle_type_1& rectangle, + const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, convolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, convolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_deconvolve : gtl_yes {}; + + // deconvolve this with b + template + typename enable_if< typename gtl_and_3< y_r_deconvolve, + typename is_mutable_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, deconvolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, deconvolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_reconvolve : gtl_yes {}; + + // reflectedConvolve this with b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + reflected_convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, reflected_convolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, reflected_convolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_redeconvolve : gtl_yes {}; + + // reflectedDeconvolve this with b + // deconvolve this with b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + reflected_deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, reflected_deconvolve(ivl, horizontal(convolution_rectangle))); + ivl = vertical(rectangle); + vertical(rectangle, reflected_deconvolve(ivl, vertical(convolution_rectangle))); + return rectangle; + } + + struct y_r_convolve2 : gtl_yes {}; + + // convolve with point + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + rectangle_type>::type & + convolve(rectangle_type& rectangle, const point_type& convolution_point) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, convolve(ivl, x(convolution_point))); + ivl = vertical(rectangle); + vertical(rectangle, convolve(ivl, y(convolution_point))); + return rectangle; + } + + struct y_r_deconvolve2 : gtl_yes {}; + + // deconvolve with point + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, rectangle_type>::type & + deconvolve(rectangle_type& rectangle, const point_type& convolution_point) { + typename rectangle_traits::interval_type ivl = horizontal(rectangle); + horizontal(rectangle, deconvolve(ivl, x(convolution_point))); + ivl = vertical(rectangle); + vertical(rectangle, deconvolve(ivl, y(convolution_point))); + return rectangle; + } + + struct y_r_delta : gtl_yes {}; + + // get the magnitude of the interval range depending on orient + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_difference_type::type>::type + delta(const rectangle_type& rectangle, orientation_2d orient) { + return delta(get(rectangle, orient)); + } + + struct y_r_area : gtl_yes {}; + + // get the area of the rectangle + template + typename enable_if< typename gtl_and::type>::type>::type, + typename coordinate_traits::coordinate_type>::manhattan_area_type>::type + area(const rectangle_type& rectangle) { + typedef typename coordinate_traits::coordinate_type>::manhattan_area_type area_type; + return (area_type)delta(rectangle, HORIZONTAL) * (area_type)delta(rectangle, VERTICAL); + } + + struct y_r_go : gtl_yes {}; + + // returns the orientation of the longest side + template + typename enable_if::type>::type>::type, + orientation_2d>::type + guess_orientation(const rectangle_type& rectangle) { + return delta(rectangle, HORIZONTAL) >= delta(rectangle, VERTICAL) ? + HORIZONTAL : VERTICAL; + } + + struct y_r_half_p : gtl_yes {}; + + // get the half perimeter of the rectangle + template + typename enable_if< typename gtl_and::type>::type>::type>::type, + typename rectangle_difference_type::type>::type + half_perimeter(const rectangle_type& rectangle) { + return delta(rectangle, HORIZONTAL) + delta(rectangle, VERTICAL); + } + + // get the perimeter of the rectangle + template + typename rectangle_difference_type::type + perimeter(const rectangle_type& rectangle, + typename enable_if< typename is_rectangle_concept::type>::type>::type * = 0 + ) { + return 2 * half_perimeter(rectangle); + } + + struct y_r_intersects : gtl_yes {}; + + // check if Rectangle b intersects `this` Rectangle + // [in] b Rectangle that will be checked + // [in] considerTouch If true, return true even if b touches the boundary + // [ret] . true if `t` intersects b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + intersects(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { + return intersects(horizontal(rectangle), horizontal(b), consider_touch) && + intersects(vertical(rectangle), vertical(b), consider_touch); + } + + struct y_r_b_intersect : gtl_yes {}; + + // Check if boundaries of Rectangle b and `this` Rectangle intersect + // [in] b Rectangle that will be checked + // [in] considerTouch If true, return true even if p is on the foundary + // [ret] . true if `t` contains p + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + boundaries_intersect(const rectangle_type_1& rectangle, const rectangle_type_2& b, + bool consider_touch = true) { + return (intersects(rectangle, b, consider_touch) && + !(contains(rectangle, b, !consider_touch)) && + !(contains(b, rectangle, !consider_touch))); + } + + struct y_r_b_abuts : gtl_yes {}; + + // check if b is touching 'this' on the end specified by dir + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, + direction_2d dir) { + return + abuts(get(rectangle, orientation_2d(dir)), + get(b, orientation_2d(dir)), + direction_1d(dir)) && + intersects(get(rectangle, orientation_2d(dir).get_perpendicular()), + get(b, orientation_2d(dir).get_perpendicular()), true); + } + + struct y_r_b_abuts2 : gtl_yes {}; + + // check if they are touching in the given orientation + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, + orientation_2d orient) { + return + abuts(get(rectangle, orient), get(b, orient)) && + intersects(get(rectangle, orient.get_perpendicular()), + get(b, orient.get_perpendicular()), true); + } + + struct y_r_b_abuts3 : gtl_yes {}; + + // check if they are touching but not overlapping + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b) { + return abuts(rectangle, b, HORIZONTAL) || abuts(rectangle, b, VERTICAL); + } + + struct y_r_b_intersect2 : gtl_yes {}; + + // intersect rectangle with interval on orient + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + intersect(rectangle_type& rectangle, const interval_type& b, + orientation_2d orient, bool consider_touch = true) { + typename rectangle_traits::interval_type ivl = get(rectangle, orient); + if(intersect(ivl, b, consider_touch)) { + set(rectangle, orient, ivl); + return true; + } + return false; + } + + struct y_r_b_intersect3 : gtl_yes {}; + + // clip rectangle to b + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + intersect(rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { + if(intersects(rectangle, b)) { + intersect(rectangle, horizontal(b), HORIZONTAL, consider_touch); + intersect(rectangle, vertical(b), VERTICAL, consider_touch); + return true; + } + return false; + } + + struct y_r_g_intersect : gtl_yes {}; + + // Sets this to the generalized intersection of this and the given rectangle + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + rectangle_type_1>::type & + generalized_intersect(rectangle_type_1& rectangle, const rectangle_type_2& b) { + typename rectangle_traits::interval_type ivl = get(rectangle, HORIZONTAL); + generalized_intersect(ivl, horizontal(b)); + horizontal(rectangle, ivl); + ivl = vertical(rectangle); + generalized_intersect(ivl, vertical(b)); + vertical(rectangle, ivl); + return rectangle; + } + + struct y_r_bloat : gtl_yes {}; + + // bloat the interval specified by orient by bloating + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_traits::coordinate_type bloating) { + typename rectangle_traits::interval_type ivl = get(rectangle, orient); + bloat(ivl, bloating); + set(rectangle, orient, ivl); + return rectangle; + } + + struct y_r_bloat2 : gtl_yes {}; + + // bloat the Rectangle by bloating + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, + typename rectangle_traits::coordinate_type bloating) { + bloat(rectangle, HORIZONTAL, bloating); + return bloat(rectangle, VERTICAL, bloating); + } + + struct y_r_bloat3 : gtl_yes {}; + + // bloat the interval cooresponding to orient by bloating in dir direction + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + bloat(rectangle_type& rectangle, direction_2d dir, + typename rectangle_traits::coordinate_type bloating) { + typename rectangle_traits::interval_type ivl = get(rectangle, orientation_2d(dir)); + bloat(ivl, direction_1d(dir), bloating); + set(rectangle, orientation_2d(dir), ivl); + return rectangle; + } + + struct y_r_shrink : gtl_yes {}; + + // shrink the interval specified by orient by bloating + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_traits::coordinate_type shrinking) { + return bloat(rectangle, orient, -shrinking); + } + + struct y_r_shrink2 : gtl_yes {}; + + // shrink the Rectangle by bloating + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, + typename rectangle_traits::coordinate_type shrinking) { + return bloat(rectangle, -shrinking); + } + + struct y_r_shrink3 : gtl_yes {}; + + // shrink the interval cooresponding to orient by bloating in dir direction + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + shrink(rectangle_type& rectangle, direction_2d dir, + typename rectangle_traits::coordinate_type shrinking) { + return bloat(rectangle, dir, -shrinking); + } + + struct y_r_encompass : gtl_yes {}; + + // encompass interval on orient + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + encompass(rectangle_type& rectangle, const interval_type& b, + orientation_2d orient) { + typename rectangle_traits::interval_type ivl = get(rectangle, orient); + if(encompass(ivl, b)) { + set(rectangle, orient, ivl); + return true; + } + return false; + } + + struct y_r_encompass2 : gtl_yes {}; + + // enlarge rectangle to encompass the Rectangle b + template + bool + encompass(rectangle_type_1& rectangle, const rectangle_type_2& b, + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type >::type>::type * = 0 + ) { + //note that operator | is intentional because both should be called regardless + return encompass(rectangle, horizontal(b), HORIZONTAL) | + encompass(rectangle, vertical(b), VERTICAL); + } + + struct y_r_encompass3 : gtl_yes {}; + + // enlarge rectangle to encompass the point b + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + bool>::type + encompass(rectangle_type_1& rectangle, const point_type& b, + typename enable_if< + typename gtl_and< typename is_mutable_rectangle_concept::type>::type, + typename is_point_concept::type>::type>::type>::type * = 0 + ) { + typename rectangle_traits::interval_type hivl, vivl; + hivl = horizontal(rectangle); + vivl = vertical(rectangle); + //note that operator | is intentional because both should be called regardless + bool retval = encompass(hivl, x(b)) | encompass(vivl, y(b)); + if(retval) { + horizontal(rectangle, hivl); + vertical(rectangle, vivl); + } + return retval; + } + + struct y_r_center : gtl_yes {}; + + // returns the center of the rectangle + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + center(point_type& center_point, const rectangle_type& rectangle) { + center_point = construct(center(horizontal(rectangle)), + center(vertical(rectangle))); + return true; + } + + struct y_r_get_corner : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + get_corner(point_type& corner_point, const rectangle_type& rectangle, direction_2d direction_facing, direction_1d direction_turning) { + typedef typename rectangle_traits::coordinate_type Unit; + Unit u1 = get(rectangle, direction_facing); + Unit u2 = get(rectangle, direction_facing.turn(direction_turning)); + if(orientation_2d(direction_facing).to_int()) std::swap(u1, u2); + corner_point = construct(u1, u2); + return true; + } + + struct y_r_get_half : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + rectangle_type>::type + get_half(const rectangle_type& rectangle, direction_2d dir) { + rectangle_type retval(rectangle); + set(retval, orientation_2d(dir), get_half(get(rectangle, orientation_2d(dir)), direction_1d(dir))); + return retval; + } + + struct y_r_join_with : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + join_with(rectangle_type_1& rectangle, const rectangle_type_2& b) { + typedef typename rectangle_traits::interval_type Interval1; + typedef typename rectangle_traits::interval_type Interval2; + Interval1 hi1 = get(rectangle, HORIZONTAL); + Interval1 vi1 = get(rectangle, VERTICAL); + Interval2 hi2 = get(b, HORIZONTAL), vi2 = get(b, VERTICAL); + Interval1 temp; + if (equivalence(hi1, hi2) && join_with(vi1, vi2)) { + vertical(rectangle, vi1); + return true; + } + if (equivalence(vi1, vi2) && join_with(hi1, hi2)) { + horizontal(rectangle, hi1); + return true; + } + return false; + } + + struct y_r_eda2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + typename rectangle_difference_type::type>::type + euclidean_distance(const rectangle_type& lvalue, const point_type& rvalue, orientation_2d orient) { + return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); + } + + struct y_r_eda : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + typename rectangle_difference_type::type>::type + euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue, orientation_2d orient) { + return euclidean_distance(get(lvalue, orient), get(rvalue, orient)); + } + + struct y_r_sed : gtl_yes {}; + + template + typename enable_if< typename gtl_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type>::type, + typename rectangle_difference_type::type>::type + square_euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { + typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return (xdist * xdist) + (ydist * ydist); + } + + struct y_r_sed2 : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept< typename geometry_concept::type>::type>::type, + typename rectangle_difference_type::type>::type + square_euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return (xdist * xdist) + (ydist * ydist); + } + + struct y_r_edist : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + typename rectangle_distance_type::type>::type + euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { + return sqrt((double) + (square_euclidean_distance(lvalue, rvalue))); + } + + struct y_r_edist2 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + typename rectangle_distance_type::type>::type + euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + double val = (int)square_euclidean_distance(lvalue, rvalue); + return sqrt(val); + } + + struct y_r_mdist : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_point_concept::type>::type>::type, + typename rectangle_difference_type::type>::type + manhattan_distance(rectangle_type& lvalue, const point_type& rvalue) { + typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return xdist + ydist; + } + + struct y_r_mdist2 : gtl_yes {}; + + template + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept::type>::type>::type, + typename rectangle_difference_type::type>::type + manhattan_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { + typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); + ydist = euclidean_distance(lvalue, rvalue, VERTICAL); + return xdist + ydist; + } + + struct y_r_scale_up : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + scale_up(rectangle_type& rectangle, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + horizontal(rectangle, scale_up(horizontal(rectangle), factor)); + vertical(rectangle, scale_up(vertical(rectangle), factor)); + return rectangle; + } + + struct y_r_scale_down : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + scale_down(rectangle_type& rectangle, + typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + horizontal(rectangle, scale_down(horizontal(rectangle), factor)); + vertical(rectangle, scale_down(vertical(rectangle), factor)); + return rectangle; + } + + struct y_r_scale : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + scale(rectangle_type& rectangle, const scaling_type& scaling) { + point_data::coordinate_type> llp(xl(rectangle), yl(rectangle)); + point_data::coordinate_type> urp(xl(rectangle), yl(rectangle)); + scale(llp, scaling); + scale(urp, scaling); + set_points(rectangle, llp, urp); + return rectangle; + } + + struct y_r_transform : gtl_yes {}; + + template + typename enable_if::type>::type>::type, + rectangle_type>::type & + transform(rectangle_type& rectangle, const transformation_type& transformation) { + point_data::coordinate_type> llp(xl(rectangle), yl(rectangle)); + point_data::coordinate_type> urp(xh(rectangle), yh(rectangle)); + transform(llp, transformation); + transform(urp, transformation); + set_points(rectangle, llp, urp); + return rectangle; + } + + template + class less_rectangle_concept { + private: + orientation_2d orient_; + public: + inline less_rectangle_concept(orientation_2d orient = VERTICAL) : orient_(orient) {} + typename enable_if< + typename gtl_and< typename is_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, + bool>::type + operator () (const rectangle_type_1& a, + const rectangle_type_2& b) const { + typedef typename rectangle_traits::coordinate_type Unit; + Unit vl1 = get(get(a, orient_), LOW); + Unit vl2 = get(get(b, orient_), LOW); + if(vl1 > vl2) return false; + if(vl1 == vl2) { + orientation_2d perp = orient_.get_perpendicular(); + Unit hl1 = get(get(a, perp), LOW); + Unit hl2 = get(get(b, perp), LOW); + if(hl1 > hl2) return false; + if(hl1 == hl2) { + Unit vh1 = get(get(a, orient_), HIGH); + Unit vh2 = get(get(b, orient_), HIGH); + if(vh1 > vh2) return false; + if(vh1 == vh2) { + Unit hh1 = get(get(a, perp), HIGH); + Unit hh2 = get(get(b, perp), HIGH); + return hh1 < hh2; + } + } + } + return true; + } + + }; + + template + template + inline void rectangle_data::set(orientation_2d orient, const interval_type_1& interval) { + assign(ranges_[orient.to_int()], interval); + } + + template + template + rectangle_data& rectangle_data::operator=(const T2& rvalue) { + assign(*this, rvalue); + return *this; + } + + template + template + bool rectangle_data::operator==(const T2& rvalue) const { + return equivalence(*this, rvalue); + } + + template + struct geometry_concept > { + typedef rectangle_concept type; + }; +} +} +#endif + diff --git a/include/boost/polygon/rectangle_data.hpp b/include/boost/polygon/rectangle_data.hpp new file mode 100755 index 0000000..2bcbb46 --- /dev/null +++ b/include/boost/polygon/rectangle_data.hpp @@ -0,0 +1,64 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_RECTANGLE_DATA_HPP +#define BOOST_POLYGON_RECTANGLE_DATA_HPP + +#include "isotropy.hpp" +//interval +#include "interval_data.hpp" + +namespace boost { namespace polygon{ + +template +class rectangle_data { +public: + typedef T coordinate_type; + typedef interval_data interval_type; + inline rectangle_data():ranges_() {} + inline rectangle_data(T xl, T yl, T xh, T yh):ranges_() { + if(xl > xh) std::swap(xl, xh); + if(yl > yh) std::swap(yl, yh); + ranges_[HORIZONTAL] = interval_data(xl, xh); + ranges_[VERTICAL] = interval_data(yl, yh); + } + template + inline rectangle_data(const interval_type_1& hrange, + const interval_type_2& vrange):ranges_() { + set(HORIZONTAL, hrange); set(VERTICAL, vrange); } + + inline rectangle_data(const rectangle_data& that):ranges_() { (*this) = that; } + inline rectangle_data& operator=(const rectangle_data& that) { + ranges_[0] = that.ranges_[0]; ranges_[1] = that.ranges_[1]; return *this; + } + template + inline rectangle_data& operator=(const T2& rvalue); + + template + inline bool operator==(const T2& rvalue) const; + template + inline bool operator!=(const T2& rvalue) const { return !((*this) == rvalue); } + + inline interval_data get(orientation_2d orient) const { + return ranges_[orient.to_int()]; } + inline coordinate_type get(direction_2d dir) const { + return ranges_[orientation_2d(dir).to_int()].get(direction_1d(dir)); + } + inline void set(direction_2d dir, coordinate_type value) { + return ranges_[orientation_2d(dir).to_int()].set(direction_1d(dir), value); + } + template + inline void set(orientation_2d orient, const interval_type_1& interval); +private: + interval_data ranges_[2]; +}; + + +} +} +#endif + diff --git a/include/boost/polygon/rectangle_traits.hpp b/include/boost/polygon/rectangle_traits.hpp new file mode 100755 index 0000000..fe777a4 --- /dev/null +++ b/include/boost/polygon/rectangle_traits.hpp @@ -0,0 +1,38 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_RECTANGLE_TRAITS_HPP +#define BOOST_POLYGON_RECTANGLE_TRAITS_HPP +namespace boost { namespace polygon{ + + template + struct rectangle_traits {}; + template + struct rectangle_traits {}; + + template + struct rectangle_traits::type> { + typedef typename T::coordinate_type coordinate_type; + typedef typename T::interval_type interval_type; + static inline interval_type get(const T& rectangle, orientation_2d orient) { + return rectangle.get(orient); } + }; + + template + struct rectangle_mutable_traits { + template + static inline void set(T& rectangle, orientation_2d orient, const T2& interval) { + rectangle.set(orient, interval); } + template + static inline T construct(const T2& interval_horizontal, + const T3& interval_vertical) { + return T(interval_horizontal, interval_vertical); } + }; +} +} +#endif + diff --git a/include/boost/polygon/transform.hpp b/include/boost/polygon/transform.hpp new file mode 100755 index 0000000..16b566d --- /dev/null +++ b/include/boost/polygon/transform.hpp @@ -0,0 +1,501 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_TRANSFORM_HPP +#define BOOST_POLYGON_TRANSFORM_HPP +#include "isotropy.hpp" +#include "point_3d_concept.hpp" +namespace boost { namespace polygon{ +// Transformation of Coordinate Systems +// Enum meaning: +// Select which direction_3d to change the positive direction of each +// axis in the old coordinate system to map it to the new coordiante system. +// The first direction_3d listed for each enum is the direction to map the +// positive horizontal direction to. +// The second direction_3d listed for each enum is the direction to map the +// positive vertical direction to. +// The third direction_3d listed for each enum is the direction to map the +// positive proximal direction to. +// The zero position bit (LSB) indicates whether the horizontal axis flips +// when transformed. +// The 1st postion bit indicates whether the vertical axis flips when +// transformed. +// The 2nd position bit indicates whether the horizontal and vertical axis +// swap positions when transformed. +// Note that the first eight values are the complete set of 2D transforms. +// The 3rd position bit indicates whether the proximal axis flips when +// transformed. +// The 4th position bit indicates whether the proximal and horizontal axis are +// swapped when transformed. It changes the meaning of the 2nd position bit +// to mean that the horizontal and vertical axis are swapped in their new +// positions, naturally. +// The 5th position bit (MSB) indicates whether the proximal and vertical axis +// are swapped when transformed. It is mutually exclusive with the 4th postion +// bit, making the maximum legal value 48 (decimal). It similarly changes the +// meaning of the 2nd position bit to mean that the horizontal and vertical are +// swapped in their new positions. +// Enum Values: +// 000000 EAST NORTH UP +// 000001 WEST NORTH UP +// 000010 EAST SOUTH UP +// 000011 WEST SOUTH UP +// 000100 NORTH EAST UP +// 000101 SOUTH EAST UP +// 000110 NORTH WEST UP +// 000111 SOUTH WEST UP +// 001000 EAST NORTH DOWN +// 001001 WEST NORTH DOWN +// 001010 EAST SOUTH DOWN +// 001011 WEST SOUTH DOWN +// 001100 NORTH EAST DOWN +// 001101 SOUTH EAST DOWN +// 001110 NORTH WEST DOWN +// 001111 SOUTH WEST DOWN +// 010000 UP NORTH EAST +// 010001 DOWN NORTH EAST +// 010010 UP SOUTH EAST +// 010011 DOWN SOUTH EAST +// 010100 NORTH UP EAST +// 010101 SOUTH UP EAST +// 010110 NORTH DOWN EAST +// 010111 SOUTH DOWN EAST +// 011000 UP NORTH WEST +// 011001 DOWN NORTH WEST +// 011010 UP SOUTH WEST +// 011011 DOWN SOUTH WEST +// 011100 NORTH UP WEST +// 011101 SOUTH UP WEST +// 011110 NORTH DOWN WEST +// 011111 SOUTH DOWN WEST +// 100000 EAST UP NORTH +// 100001 WEST UP NORTH +// 100010 EAST DOWN NORTH +// 100011 WEST DOWN NORTH +// 100100 UP EAST NORTH +// 100101 DOWN EAST NORTH +// 100110 UP WEST NORTH +// 100111 DOWN WEST NORTH +// 101000 EAST UP SOUTH +// 101001 WEST UP SOUTH +// 101010 EAST DOWN SOUTH +// 101011 WEST DOWN SOUTH +// 101100 UP EAST SOUTH +// 101101 DOWN EAST SOUTH +// 101110 UP WEST SOUTH +// 101111 DOWN WEST SOUTH +class axis_transformation { +public: + // Enum Names and values + // NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, + // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + // WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, + // ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, + // NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, + // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, + // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, + // END_2D_TRANSFORM = 7, + // END = 8, EAST_NORTH_DOWN = 8, + // WND = 9, WEST_NORTH_DOWN = 9, + // ESD = 10, EAST_SOUTH_DOWN = 10, + // WSD = 11, WEST_SOUTH_DOWN = 11, + // NED = 12, NORTH_EAST_DOWN = 12, + // SED = 13, SOUTH_EAST_DOWN = 13, + // NWD = 14, NORTH_WEST_DOWN = 14, + // SWD = 15, SOUTH_WEST_DOWN = 15, + // UNE = 16, UP_NORTH_EAST = 16, + // DNE = 17, DOWN_NORTH_EAST = 17, + // USE = 18, UP_SOUTH_EAST = 18, + // DSE = 19, DOWN_SOUTH_EAST = 19, + // NUE = 20, NORTH_UP_EAST = 20, + // SUE = 21, SOUTH_UP_EAST = 21, + // NDE = 22, NORTH_DOWN_EAST = 22, + // SDE = 23, SOUTH_DOWN_EAST = 23, + // UNW = 24, UP_NORTH_WEST = 24, + // DNW = 25, DOWN_NORTH_WEST = 25, + // USW = 26, UP_SOUTH_WEST = 26, + // DSW = 27, DOWN_SOUTH_WEST = 27, + // NUW = 28, NORTH_UP_WEST = 28, + // SUW = 29, SOUTH_UP_WEST = 29, + // NDW = 30, NORTH_DOWN_WEST = 30, + // SDW = 31, SOUTH_DOWN_WEST = 31, + // EUN = 32, EAST_UP_NORTH = 32, + // WUN = 33, WEST_UP_NORTH = 33, + // EDN = 34, EAST_DOWN_NORTH = 34, + // WDN = 35, WEST_DOWN_NORTH = 35, + // UEN = 36, UP_EAST_NORTH = 36, + // DEN = 37, DOWN_EAST_NORTH = 37, + // UWN = 38, UP_WEST_NORTH = 38, + // DWN = 39, DOWN_WEST_NORTH = 39, + // EUS = 40, EAST_UP_SOUTH = 40, + // WUS = 41, WEST_UP_SOUTH = 41, + // EDS = 42, EAST_DOWN_SOUTH = 42, + // WDS = 43, WEST_DOWN_SOUTH = 43, + // UES = 44, UP_EAST_SOUTH = 44, + // DES = 45, DOWN_EAST_SOUTH = 45, + // UWS = 46, UP_WEST_SOUTH = 46, + // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + enum ATR { + NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, + ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, + ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, + NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, + NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, + SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_2D_TRANSFORM = 7, + END = 8, EAST_NORTH_DOWN = 8, FLIP_Z = 8, + WND = 9, WEST_NORTH_DOWN = 9, + ESD = 10, EAST_SOUTH_DOWN = 10, + WSD = 11, WEST_SOUTH_DOWN = 11, + NED = 12, NORTH_EAST_DOWN = 12, + SED = 13, SOUTH_EAST_DOWN = 13, + NWD = 14, NORTH_WEST_DOWN = 14, + SWD = 15, SOUTH_WEST_DOWN = 15, + UNE = 16, UP_NORTH_EAST = 16, + DNE = 17, DOWN_NORTH_EAST = 17, + USE = 18, UP_SOUTH_EAST = 18, + DSE = 19, DOWN_SOUTH_EAST = 19, + NUE = 20, NORTH_UP_EAST = 20, + SUE = 21, SOUTH_UP_EAST = 21, + NDE = 22, NORTH_DOWN_EAST = 22, + SDE = 23, SOUTH_DOWN_EAST = 23, + UNW = 24, UP_NORTH_WEST = 24, + DNW = 25, DOWN_NORTH_WEST = 25, + USW = 26, UP_SOUTH_WEST = 26, + DSW = 27, DOWN_SOUTH_WEST = 27, + NUW = 28, NORTH_UP_WEST = 28, + SUW = 29, SOUTH_UP_WEST = 29, + NDW = 30, NORTH_DOWN_WEST = 30, + SDW = 31, SOUTH_DOWN_WEST = 31, + EUN = 32, EAST_UP_NORTH = 32, + WUN = 33, WEST_UP_NORTH = 33, + EDN = 34, EAST_DOWN_NORTH = 34, + WDN = 35, WEST_DOWN_NORTH = 35, + UEN = 36, UP_EAST_NORTH = 36, + DEN = 37, DOWN_EAST_NORTH = 37, + UWN = 38, UP_WEST_NORTH = 38, + DWN = 39, DOWN_WEST_NORTH = 39, + EUS = 40, EAST_UP_SOUTH = 40, + WUS = 41, WEST_UP_SOUTH = 41, + EDS = 42, EAST_DOWN_SOUTH = 42, + WDS = 43, WEST_DOWN_SOUTH = 43, + UES = 44, UP_EAST_SOUTH = 44, + DES = 45, DOWN_EAST_SOUTH = 45, + UWS = 46, UP_WEST_SOUTH = 46, + DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + }; + + // Individual axis enum values indicate which axis an implicit individual + // axis will be mapped to. + // The value of the enum paired with an axis provides the information + // about what the axis will transform to. + // Three individual axis values, one for each axis, are equivalent to one + // ATR enum value, but easier to work with because they are independent. + // Converting to and from the individual axis values from the ATR value + // is a convenient way to implement tranformation related functionality. + // Enum meanings: + // PX: map to positive x axis + // NX: map to negative x axis + // PY: map to positive y axis + // NY: map to negative y axis + // PZ: map to positive z axis + // NZ: map to negative z axis + enum INDIVIDUAL_AXIS { + PX = 0, + NX = 1, + PY = 2, + NY = 3, + PZ = 4, + NZ = 5 + }; + + inline axis_transformation() : atr_(NULL_TRANSFORM) {} + inline axis_transformation(ATR atr) : atr_(atr) {} + inline axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} + explicit axis_transformation(const orientation_3d& orient); + explicit axis_transformation(const direction_3d& dir); + explicit axis_transformation(const orientation_2d& orient); + explicit axis_transformation(const direction_2d& dir); + + // assignment operator + axis_transformation& operator=(const axis_transformation& a); + + // assignment operator + axis_transformation& operator=(const ATR& atr); + + // equivalence operator + bool operator==(const axis_transformation& a) const; + + // inequivalence operator + bool operator!=(const axis_transformation& a) const; + + // ordering + bool operator<(const axis_transformation& a) const; + + // concatenation operator + axis_transformation operator+(const axis_transformation& a) const; + + // concatenate this with that + axis_transformation& operator+=(const axis_transformation& a); + + // populate_axis_array writes the three INDIVIDUAL_AXIS values that the + // ATR enum value of 'this' represent into axis_array + void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const; + + // it is recommended that the directions stored in an array + // in the caller code for easier isotropic access by orientation value + inline void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1)); + horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); + } + + // it is recommended that the directions stored in an array + // in the caller code for easier isotropic access by orientation value + inline void get_directions(direction_3d& horizontal_dir, + direction_3d& vertical_dir, + direction_3d& proximal_dir) const { + bool bit5 = (atr_ & 32) != 0; + bool bit4 = (atr_ & 16) != 0; + bool bit3 = (atr_ & 8) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + proximal_dir = direction_3d((direction_2d_enum)((((int)(!bit4 & !bit5)) << 2) + + ((int)(bit5) << 1) + + !bit3)); + vertical_dir = direction_3d((direction_2d_enum)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ + ((int)(!bit5 & !bit2) << 1) + + !bit1)); + horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) | + (bit4 & !bit2))) << 2) + + ((int)(bit2 & !bit5) << 1) + + !bit0)); + } + + // combine_axis_arrays concatenates this_array and that_array overwriting + // the result into this_array + static void combine_axis_arrays (INDIVIDUAL_AXIS this_array[], + const INDIVIDUAL_AXIS that_array[]); + + // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values + // to the ATR enum value and sets 'this' to that value + void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]); + + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + axis_transformation& set_directions(const direction_2d& horizontal_dir, + const direction_2d& vertical_dir); + // behavior is deterministic but undefined in the case where illegal + // combinations of directions are passed in. + axis_transformation& set_directions(const direction_3d& horizontal_dir, + const direction_3d& vertical_dir, + const direction_3d& proximal_dir); + + // transform the two coordinates by reference using the 2D portion of this + template + void transform(coordinate_type& x, coordinate_type& y) const; + + // transform the three coordinates by reference + template + void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert the 2D portion of this + axis_transformation& invert_2d(); + + // get the inverse of the 2D portion of this + axis_transformation inverse_2d() const; + + // invert this axis_transformation + axis_transformation& invert(); + + // get the inverse axis_transformation of this + axis_transformation inverse() const; + + //friend std::ostream& operator<< (std::ostream& o, const axis_transformation& r); + //friend std::istream& operator>> (std::istream& i, axis_transformation& r); + +private: + ATR atr_; +}; + + +// Scaling object to be used to store the scale factor for each axis + +// For use by the transformation object, in that context the scale factor +// is the amount that each axis scales by when transformed. +// If the horizontal value of the Scale is 10 that means the horizontal +// axis of the input is multiplied by 10 when the transformation is applied. +template +class anisotropic_scale_factor { +public: + inline anisotropic_scale_factor() +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = 1; + scale_[1] = 1; + scale_[2] = 1; + } + inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale) +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = xscale; + scale_[1] = yscale; + scale_[2] = 1; + } + inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale) +#ifndef BOOST_POLYGON_MSVC + : scale_() +#endif + { + scale_[0] = xscale; + scale_[1] = yscale; + scale_[2] = zscale; + } + + // get a component of the anisotropic_scale_factor by orientation + scale_factor_type get(orientation_3d orient) const; + scale_factor_type get(orientation_2d orient) const { return get(orientation_3d(orient)); } + + // set a component of the anisotropic_scale_factor by orientation + void set(orientation_3d orient, scale_factor_type value); + void set(orientation_2d orient, scale_factor_type value) { set(orientation_3d(orient), value); } + + scale_factor_type x() const; + scale_factor_type y() const; + scale_factor_type z() const; + void x(scale_factor_type value); + void y(scale_factor_type value); + void z(scale_factor_type value); + + // concatination operator (convolve scale factors) + anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const; + + // concatinate this with that + const anisotropic_scale_factor& operator+=(const anisotropic_scale_factor& s); + + // transform this scale with an axis_transform + anisotropic_scale_factor& transform(axis_transformation atr); + + // scale the two coordinates + template + void scale(coordinate_type& x, coordinate_type& y) const; + + // scale the three coordinates + template + void scale(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert this scale factor to give the reverse scale factor + anisotropic_scale_factor& invert(); + +private: + scale_factor_type scale_[3]; + + //friend std::ostream& operator<< (std::ostream& o, const Scale& r); + //friend std::istream& operator>> (std::istream& i, Scale& r); +}; + +// Transformation object, stores and provides services for transformations + +// Transformation object stores an axistransformation, a scale factor and a translation. +// The tranlation is the position of the origin of the new system of coordinates in the old system. +// The scale scales the coordinates before they are transformed. +template +class transformation { +public: + transformation(); + transformation(axis_transformation atr); + transformation(axis_transformation::ATR atr); + template + transformation(const point_type& p); + template + transformation(axis_transformation atr, const point_type& p); + template + transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt); + transformation(const transformation& tr); + + // equivalence operator + bool operator==(const transformation& tr) const; + + // inequivalence operator + bool operator!=(const transformation& tr) const; + + // ordering + bool operator<(const transformation& tr) const; + + // concatenation operator + transformation operator+(const transformation& tr) const; + + // concatenate this with that + const transformation& operator+=(const transformation& tr); + + // get the axis_transformation portion of this + inline axis_transformation get_axis_transformation() const {return atr_;} + + // set the axis_transformation portion of this + void set_axis_transformation(const axis_transformation& atr); + + // get the translation portion of this as a point3d + template + void get_translation(point_type& translation) const; + + // set the translation portion of this with a point3d + template + void set_translation(const point_type& p); + + // apply the 2D portion of this transformation to the two coordinates given + void transform(coordinate_type& x, coordinate_type& y) const; + + // apply this transformation to the three coordinates given + void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + + // invert this transformation + transformation& invert(); + + // get the inverse of this transformation + transformation inverse() const; + + inline void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { + return atr_.get_directions(horizontal_dir, vertical_dir); } + + inline void get_directions(direction_3d& horizontal_dir, + direction_3d& vertical_dir, + direction_3d& proximal_dir) const { + return atr_.get_directions(horizontal_dir, vertical_dir, proximal_dir); } + +private: + axis_transformation atr_; + point_3d_data p_; + + template + void construct_dispatch(axis_transformation atr, point_type p, point_concept tag); + template + void construct_dispatch(axis_transformation atr, point_type p, point_3d_concept tag); + template + void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_concept tag); + template + void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_3d_concept tag); + + //friend std::ostream& operator<< (std::ostream& o, const transformation& tr); + //friend std::istream& operator>> (std::istream& i, transformation& tr); +}; +} +} +#include "detail/transform_detail.hpp" +#endif + diff --git a/index.html b/index.html new file mode 100644 index 0000000..3e6e42f --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ + + + + + Boost.Polygon Documentation + + + + + + Automatic redirection failed, please go to doc/index.htm + +
+Copyright (C) 2010 Intel Corporation
+
+Distributed under the Boost Software License, Version 1.0. (See +accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.tx +t)
+ + + diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 new file mode 100644 index 0000000..1462d79 --- /dev/null +++ b/test/Jamfile.v2 @@ -0,0 +1,22 @@ +# test/Jamfile.v2 controls building of Polygon Library unit tests +# +# Copyright (c) 2010 Intel Corporation +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import testing ; + +project polygon-test + : + requirements + . + msvc:on + ; + +test-suite polygon-unit + : + [ run gtl_boost_unit_test.cpp ] + ; + diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp new file mode 100644 index 0000000..6625bb9 --- /dev/null +++ b/test/gtl_boost_unit_test.cpp @@ -0,0 +1,3452 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#include +#include +namespace gtl = boost::polygon; +using namespace boost::polygon::operators; +#include +#include + +namespace boost { namespace polygon{ + + template + std::ostream& operator << (std::ostream& o, const interval_data& i) + { + return o << i.get(LOW) << ' ' << i.get(HIGH); + } + template + std::ostream& operator << (std::ostream& o, const point_data& r) + { + return o << r.get(HORIZONTAL) << ' ' << r.get(VERTICAL); + } + template + std::ostream& operator<<(std::ostream& o, const polygon_45_data& poly) { + o << "Polygon { "; + for(typename polygon_45_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } + o << " } "; + return o; + } + template + inline std::ostream& operator<< (std::ostream& o, const polygon_45_set_data& p) { + o << "Polygon45Set "; + o << " " << !p.sorted() << " " << p.dirty() << " { "; + for(typename polygon_45_set_data::iterator_type itr = p.begin(); + itr != p.end(); ++itr) { + o << (*itr).pt << ":"; + for(unsigned int i = 0; i < 4; ++i) { + o << (*itr).count[i] << ","; + } o << " "; + //o << (*itr).first << ":" << (*itr).second << "; "; + } + o << "} "; + return o; + } + + template + inline std::istream& operator>> (std::istream& i, polygon_45_set_data& p) { + //TODO + return i; + } + template + std::ostream& operator << (std::ostream& o, const polygon_90_data& r) + { + o << "Polygon { "; + for(typename polygon_90_data::iterator_type itr = r.begin(); itr != r.end(); ++itr) { + o << *itr << ", "; + } + return o << "} "; + } + + template + std::istream& operator >> (std::istream& i, polygon_90_data& r) + { + std::size_t size; + i >> size; + std::vector vec; + vec.reserve(size); + for(std::size_t ii = 0; ii < size; ++ii) { + T coord; + i >> coord; + vec.push_back(coord); + } + r.set_compact(vec.begin(), vec.end()); + return i; + } + + template + std::ostream& operator << (std::ostream& o, const std::vector >& r) { + o << r.size() << ' '; + for(std::size_t ii = 0; ii < r.size(); ++ii) { + o << (r[ii]); + } + return o; + } + template + std::istream& operator >> (std::istream& i, std::vector >& r) { + std::size_t size; + i >> size; + r.clear(); + r.reserve(size); + for(std::size_t ii = 0; ii < size; ++ii) { + polygon_90_data tmp; + i >> tmp; + r.push_back(tmp); + } + return i; + } + template + std::ostream& operator<<(std::ostream& o, const polygon_data& poly) { + o << "Polygon { "; + for(typename polygon_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } + o << " } "; + return o; + } + template + std::ostream& operator << (std::ostream& o, const polygon_set_data& r) + { + o << "Polygon Set Data { "; + for(typename polygon_set_data::iterator_type itr = r.begin(); itr != r.end(); ++itr) { + o << "<" << (*itr).first.first << ", " << (*itr).first.second << ">:" << (*itr).second << " "; + } + o << "} "; + return o; + } + template + std::ostream& operator<<(std::ostream& o, const polygon_90_with_holes_data& poly) { + o << "Polygon With Holes { "; + for(typename polygon_90_with_holes_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } o << " { "; + for(typename polygon_90_with_holes_data::iterator_holes_type itr = poly.begin_holes(); + itr != poly.end_holes(); ++itr) { + o << (*itr); + } + o << " } } "; + return o; + } + template + std::ostream& operator<<(std::ostream& o, const polygon_45_with_holes_data& poly) { + o << "Polygon With Holes { "; + for(typename polygon_45_with_holes_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } o << " { "; + for(typename polygon_45_with_holes_data::iterator_holes_type itr = poly.begin_holes(); + itr != poly.end_holes(); ++itr) { + o << (*itr); + } + o << " } } "; + return o; + } + template + std::ostream& operator<<(std::ostream& o, const polygon_with_holes_data& poly) { + o << "Polygon With Holes { "; + for(typename polygon_with_holes_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } o << " { "; + for(typename polygon_with_holes_data::iterator_holes_type itr = poly.begin_holes(); + itr != poly.end_holes(); ++itr) { + o << (*itr); + } + o << " } } "; + return o; + } + template + std::ostream& operator << (std::ostream& o, const rectangle_data& r) + { + return o << r.get(HORIZONTAL) << ' ' << r.get(VERTICAL); + } + + + template + typename enable_if::type, void>::type + print_is_polygon_90_set_concept(const T& ) { std::cout << "is polygon 90 set concept\n"; } + template + typename enable_if::type, void>::type + print_is_mutable_polygon_90_set_concept(const T& ) { std::cout << "is mutable polygon 90 set concept\n"; } + namespace boolean_op { + //self contained unit test for BooleanOr algorithm + template + inline bool testBooleanOr() { + BooleanOp booleanOr; + //test one rectangle + std::vector, int> > container; + booleanOr.processInterval(container, interval_data(0, 10), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(0, 10), -1); + if(container.size() != 2) { + std::cout << "Test one rectangle, wrong output size\n"; + return false; + } + if(container[0] != std::pair, int>(interval_data(0, 10), 1)) { + std::cout << "Test one rectangle, first output wrong: Interval(" << + container[0].first << "), " << container[0].second << std::endl; + } + if(container[1] != std::pair, int>(interval_data(0, 10), -1)) { + std::cout << "Test one rectangle, second output wrong: Interval(" << + container[1].first << "), " << container[1].second << std::endl; + } + + //test two rectangles + container.clear(); + booleanOr = BooleanOp(); + booleanOr.processInterval(container, interval_data(0, 10), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(5, 15), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(0, 10), -1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(5, 15), -1); + if(container.size() != 4) { + std::cout << "Test two rectangles, wrong output size\n"; + for(std::size_t i = 0; i < container.size(); ++i){ + std::cout << container[i].first << "), " << container[i].second << std::endl; + } + return false; + } + if(container[0] != std::pair, int>(interval_data(0, 10), 1)) { + std::cout << "Test two rectangles, first output wrong: Interval(" << + container[0].first << "), " << container[0].second << std::endl; + } + if(container[1] != std::pair, int>(interval_data(10, 15), 1)) { + std::cout << "Test two rectangles, second output wrong: Interval(" << + container[1].first << "), " << container[1].second << std::endl; + } + if(container[2] != std::pair, int>(interval_data(0, 5), -1)) { + std::cout << "Test two rectangles, third output wrong: Interval(" << + container[2].first << "), " << container[2].second << std::endl; + } + if(container[3] != std::pair, int>(interval_data(5, 15), -1)) { + std::cout << "Test two rectangles, fourth output wrong: Interval(" << + container[3].first << "), " << container[3].second << std::endl; + } + + //test two rectangles + container.clear(); + booleanOr = BooleanOp(); + booleanOr.processInterval(container, interval_data(5, 15), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(0, 10), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(5, 15), -1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(0, 10), -1); + if(container.size() != 4) { + std::cout << "Test other two rectangles, wrong output size\n"; + for(std::size_t i = 0; i < container.size(); ++i){ + std::cout << container[i].first << "), " << container[i].second << std::endl; + } + return false; + } + if(container[0] != std::pair, int>(interval_data(5, 15), 1)) { + std::cout << "Test other two rectangles, first output wrong: Interval(" << + container[0].first << "), " << container[0].second << std::endl; + } + if(container[1] != std::pair, int>(interval_data(0, 5), 1)) { + std::cout << "Test other two rectangles, second output wrong: Interval(" << + container[1].first << "), " << container[1].second << std::endl; + } + if(container[2] != std::pair, int>(interval_data(10, 15), -1)) { + std::cout << "Test other two rectangles, third output wrong: Interval(" << + container[2].first << "), " << container[2].second << std::endl; + } + if(container[3] != std::pair, int>(interval_data(0, 10), -1)) { + std::cout << "Test other two rectangles, fourth output wrong: Interval(" << + container[3].first << "), " << container[3].second << std::endl; + } + + //test two nonoverlapping rectangles + container.clear(); + booleanOr = BooleanOp(); + booleanOr.processInterval(container, interval_data(0, 10), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(15, 25), 1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(0, 10), -1); + booleanOr.advanceScan(); + booleanOr.processInterval(container, interval_data(15, 25), -1); + if(container.size() != 4) { + std::cout << "Test two nonoverlapping rectangles, wrong output size\n"; + return false; + } + if(container[0] != std::pair, int>(interval_data(0, 10), 1)) { + std::cout << "Test two nonoverlapping rectangles, first output wrong: Interval(" << + container[0].first << "), " << container[0].second << std::endl; + } + if(container[1] != std::pair, int>(interval_data(15, 25), 1)) { + std::cout << "Test two nonoverlapping rectangles, second output wrong: Interval(" << + container[1].first << "), " << container[1].second << std::endl; + } + if(container[2] != std::pair, int>(interval_data(0, 10), -1)) { + std::cout << "Test two nonoverlapping rectangles, third output wrong: Interval(" << + container[2].first << "), " << container[2].second << std::endl; + } + if(container[3] != std::pair, int>(interval_data(15, 25), -1)) { + std::cout << "Test two nonoverlapping rectangles, fourth output wrong: Interval(" << + container[3].first << "), " << container[3].second << std::endl; + } + return true; + } + } + + void test_assign() { + using namespace gtl; + std::vector > ps; + polygon_90_set_data ps90; + assign(ps, ps90); + } + + //this is a compile time test, if it compiles it passes + void test_view_as() { + using namespace gtl; + polygon_data p; + polygon_45_data p45; + polygon_90_data p90; + polygon_with_holes_data pwh; + polygon_45_with_holes_data p45wh; + polygon_90_with_holes_data p90wh; + rectangle_data rect(0, 1, 10, 11); + polygon_90_set_data ps90; + polygon_45_set_data ps45; + polygon_set_data ps; + + assign(p, rect); + assign(p90, view_as(p)); + if(!equivalence(p90, rect)) + std::cout << "fail 1\n"; + assign(p45, view_as(p)); + if(!equivalence(p45, rect)) + std::cout << "fail 2\n"; + assign(p90, view_as(p45)); + if(!equivalence(p90, rect)) + std::cout << "fail 3\n"; + if(!equivalence(rect, view_as(p))) + std::cout << "fail 4\n"; + if(!equivalence(rect, view_as(p45))) + std::cout << "fail 5\n"; + if(!equivalence(rect, view_as(p90))) + std::cout << "fail 6\n"; + assign(pwh, rect); + assign(p90wh, rect); + assign(p45wh, rect); + if(!equivalence(rect, view_as(pwh))) + std::cout << "fail 7\n"; + if(!equivalence(rect, view_as(p45wh))) + std::cout << "fail 8\n"; + if(!equivalence(rect, view_as(p90wh))) + std::cout << "fail 9\n"; + assign(p90wh, view_as(pwh)); + if(!equivalence(p90wh, rect)) + std::cout << "fail 10\n"; + assign(p45wh, view_as(pwh)); + if(!equivalence(p45wh, rect)) + std::cout << "fail 11\n"; + assign(p90wh, view_as(p45wh)); + if(!equivalence(p90wh, rect)) + std::cout << "fail 12\n"; + assign(p90, view_as(pwh)); + if(!equivalence(p90, rect)) + std::cout << "fail 13\n"; + assign(p45, view_as(pwh)); + if(!equivalence(p45, rect)) + std::cout << "fail 14\n"; + assign(p90, view_as(p45wh)); + if(!equivalence(p90, rect)) + std::cout << "fail 15\n"; + assign(ps, rect); + assign(ps90, view_as(ps)); + if(!equivalence(ps90, rect)) + std::cout << "fail 16\n"; + assign(ps45, view_as(ps)); + if(!equivalence(ps45, rect)) + std::cout << "fail 17\n"; + assign(ps90, view_as(ps45)); + if(!equivalence(ps90, rect)) + std::cout << "fail 18\n"; + } + + inline bool testPolygon45SetRect() { + std::vector > points; + points.push_back(point_data(0,0)); + points.push_back(point_data(0,10)); + points.push_back(point_data(10,10)); + points.push_back(point_data(10,0)); + polygon_45_data poly; + poly.set(points.begin(), points.end()); + polygon_45_set_data ps; + ps.insert(poly); + std::vector > polys; + ps.get_polygons(polys); + std::cout << polys.size() << std::endl; + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + return true; + } + + inline bool testPolygon45Set() { + polygon_45_formation::Polygon45Formation pf(true); + typedef boolean_op_45::Vertex45 Vertex45; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(point_data(0, 8), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(point_data(0, 8), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(point_data(4, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(point_data(4, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(point_data(4, 4), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(point_data(4, 4), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(point_data(4, 12), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(point_data(4, 12), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(point_data(4, 16), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(point_data(4, 16), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(point_data(6, 2), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(point_data(6, 14), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(point_data(6, 2), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(point_data(6, 14), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(point_data(8, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(point_data(8, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(point_data(8, 4), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(point_data(8, 4), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(point_data(8, 12), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(point_data(8, 12), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(point_data(8, 16), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(point_data(8, 16), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(point_data(12, 8), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(point_data(12, 8), -1, 1)); + + data.push_back(Vertex45(point_data(6, 4), 1, -1)); + data.push_back(Vertex45(point_data(6, 4), 2, -1)); + data.push_back(Vertex45(point_data(6, 12), -1, 1)); + data.push_back(Vertex45(point_data(6, 12), 2, 1)); + data.push_back(Vertex45(point_data(10, 8), -1, -1)); + data.push_back(Vertex45(point_data(10, 8), 1, 1)); + + std::sort(data.begin(), data.end()); + std::vector > polys; + pf.scan(polys, data.begin(), data.end()); + polygon_45_set_data ps; + std::cout << "inserting1\n"; + //std::vector > points; + //points.push_back(point_data(0,0)); + //points.push_back(point_data(0,10)); + //points.push_back(point_data(10,10)); + //points.push_back(point_data(10,0)); + //Polygon45 poly; + //poly.set(points.begin(), points.end()); + //ps.insert(poly); + ps.insert(polys[0]); + + polygon_45_set_data ps2; + std::cout << "inserting2\n"; + ps2.insert(polys[0]); + std::cout << "applying boolean\n"; + ps |= ps2; + std::vector > polys2; + std::cout << "getting result\n"; + ps.get_polygons(polys2); + std::cout << ps2 << std::endl; + std::cout << ps << std::endl; + std::cout << polys[0] << std::endl; + std::cout << polys2[0] << std::endl; + if(polys != polys2) std::cout << "test Polygon45Set failed\n"; + return polys == polys2; + } + + inline bool testPolygon45SetPerterbation() { + polygon_45_formation::Polygon45Formation pf(true); + typedef boolean_op_45::Vertex45 Vertex45; + std::vector data; + // result == 0 8 -1 1 + data.push_back(Vertex45(point_data(0, 80), -1, 1)); + // result == 0 8 1 -1 + data.push_back(Vertex45(point_data(0, 80), 1, -1)); + // result == 4 0 1 1 + data.push_back(Vertex45(point_data(40, 0), 1, 1)); + // result == 4 0 2 1 + data.push_back(Vertex45(point_data(40, 0), 2, 1)); + // result == 4 4 2 -1 + data.push_back(Vertex45(point_data(40, 40), 2, -1)); + // result == 4 4 -1 -1 + data.push_back(Vertex45(point_data(40, 40), -1, -1)); + // result == 4 12 1 1 + data.push_back(Vertex45(point_data(40, 120), 1, 1)); + // result == 4 12 2 1 + data.push_back(Vertex45(point_data(40, 120), 2, 1)); + // result == 4 16 2 -1 + data.push_back(Vertex45(point_data(40, 160), 2, 1)); + // result == 4 16 -1 -1 + data.push_back(Vertex45(point_data(40, 160), -1, -1)); + // result == 6 2 1 -1 + data.push_back(Vertex45(point_data(60, 20), 1, -1)); + // result == 6 14 -1 1 + data.push_back(Vertex45(point_data(60, 140), -1, 1)); + // result == 6 2 -1 1 + data.push_back(Vertex45(point_data(60, 20), -1, 1)); + // result == 6 14 1 -1 + data.push_back(Vertex45(point_data(60, 140), 1, -1)); + // result == 8 0 -1 -1 + data.push_back(Vertex45(point_data(80, 0), -1, -1)); + // result == 8 0 2 -1 + data.push_back(Vertex45(point_data(80, 0), 2, -1)); + // result == 8 4 2 1 + data.push_back(Vertex45(point_data(80, 40), 2, 1)); + // result == 8 4 1 1 + data.push_back(Vertex45(point_data(80, 40), 1, 1)); + // result == 8 12 -1 -1 + data.push_back(Vertex45(point_data(80, 120), -1, -1)); + // result == 8 12 2 -1 + data.push_back(Vertex45(point_data(80, 120), 2, -1)); + // result == 8 16 2 1 + data.push_back(Vertex45(point_data(80, 160), 2, 1)); + // result == 8 16 1 1 + data.push_back(Vertex45(point_data(80, 160), 1, 1)); + // result == 12 8 1 -1 + data.push_back(Vertex45(point_data(120, 80), 1, -1)); + // result == 12 8 -1 1 + data.push_back(Vertex45(point_data(120, 80), -1, 1)); + + data.push_back(Vertex45(point_data(60, 40), 1, -1)); + data.push_back(Vertex45(point_data(60, 40), 2, -1)); + data.push_back(Vertex45(point_data(60, 120), -1, 1)); + data.push_back(Vertex45(point_data(60, 120), 2, 1)); + data.push_back(Vertex45(point_data(100, 80), -1, -1)); + data.push_back(Vertex45(point_data(100, 80), 1, 1)); + + std::sort(data.begin(), data.end()); + std::vector > polys; + pf.scan(polys, data.begin(), data.end()); + polygon_45_set_data ps; + std::cout << "inserting1\n"; + //std::vector > points; + //points.push_back(point_data(0,0)); + //points.push_back(point_data(0,10)); + //points.push_back(point_data(10,10)); + //points.push_back(point_data(10,0)); + //Polygon45 poly; + //poly.set(points.begin(), points.end()); + //ps.insert(poly); + polygon_45_set_data preps(polys[0]); + + ps.insert(polys[0]); + convolve(polys[0], point_data(0, 1) ); + + polygon_45_set_data ps2; + std::cout << "inserting2\n"; + ps2.insert(polys[0]); + std::cout << "applying boolean\n"; + ps |= ps2; + std::vector > polys2; + std::cout << "getting result\n"; + ps.get_polygons(polys2); + std::cout << preps << std::endl; + std::cout << ps2 << std::endl; + std::cout << ps << std::endl; + std::cout << polys[0] << std::endl; + std::cout << polys2[0] << std::endl; + if(polys != polys2) std::cout << "test Polygon45Set failed\n"; + return polys == polys2; + //return true; + } + + inline int testPolygon45SetDORA() { + std::cout << "testPolygon45SetDORA" << std::endl; + std::vector > pts; + pts.push_back(point_data(0, 0)); + pts.push_back(point_data(10, 0)); + pts.push_back(point_data(10, 10)); + pts.push_back(point_data(0, 10)); + polygon_45_data apoly; + apoly.set(pts.begin(), pts.end()); + polygon_45_set_data ps(apoly); + polygon_45_set_data ps2(ps); + ps2 = apoly; + std::vector > apolys; + apolys.push_back(apoly); + ps2.insert(apolys.begin(), apolys.end()); + apolys.clear(); + ps2.get(apolys); + std::cout << apolys.size() << std::endl; + std::cout << (ps == ps2) << std::endl; + std::cout << !(ps != ps2) << std::endl; + ps2.clear(); + std::cout << (ps2.value().empty()) << std::endl; + ps2.set(apolys.begin(), apolys.end()); + ps2.set(ps.value()); + ps.clean(); + ps2.set_clean(ps.value()); + ps2.insert(ps.value().begin(), ps.value().end()); + ps2.clear(); + for(polygon_45_set_data::iterator_type itr = ps.begin(); + itr != ps.end(); ++itr) { + ps2.insert(*itr); + } + std::vector > apolywhs; + ps2.get_polygons_with_holes(apolywhs); + std::cout << apolywhs.size() << std::endl; + ps2 += 1; + apolywhs.clear(); + ps2.get_polygons_with_holes(apolywhs); + if(apolywhs.size()) std::cout << apolywhs[0] << std::endl; + ps2 -= 1; + apolywhs.clear(); + ps2.get_polygons_with_holes(apolywhs); + if(apolywhs.size()) std::cout << apolywhs[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + rectangle_data rect; + extents(rect, apolywhs[0]); + ps2.clear(); + ps2.insert(rect); + ps2.extents(rect); + ps2.clear(); + ps2.insert(rect); + ps2.clear(); + ps2.insert(apolywhs[0]); + apolywhs.clear(); + ps2.get_trapezoids(apolywhs); + if(apolywhs.size()) std::cout << apolywhs[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + ps2 *= ps; + std::cout << (ps2 == ps) << std::endl; + ps2 ^= ps; + std::cout << ps2.empty() << std::endl; + axis_transformation atr(axis_transformation::WS); + ps2 = ps; + ps.transform(atr); + transformation tr(atr); + tr.invert(); + ps.transform(tr); + ps.scale_up(2); + ps.scale_down(2); + std::cout << (ps2 == ps) << std::endl; + pts.clear(); + pts.push_back(point_data(0,0)); + pts.push_back(point_data(10,10)); + pts.push_back(point_data(10,11)); + pts.push_back(point_data(0,21)); + apoly.set(pts.begin(), pts.end()); + ps2.clear(); + ps2.insert(apoly); + ps2 -= 1; + apolywhs.clear(); + ps2.get_polygons_with_holes(apolywhs); + if(apolywhs.size()) std::cout << apolywhs[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + pts.clear(); + pts.push_back(point_data(0, 0)); + pts.push_back(point_data(10, 10)); + pts.push_back(point_data(0, 20)); + apoly.set(pts.begin(), pts.end()); + ps2.clear(); + ps2.insert(apoly); + pts.clear(); + pts.push_back(point_data(0, 5)); + pts.push_back(point_data(10, 15)); + pts.push_back(point_data(0, 25)); + apoly.set(pts.begin(), pts.end()); + ps2.insert(apoly); + apolywhs.clear(); + ps2.get_polygons_with_holes(apolywhs); + if(apolywhs.size()) std::cout << apolywhs[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + return 0; + + } +} +} +using namespace gtl; + +bool testInterval() { + interval_data interval(0, 10), interval2(10, 20); + if(!abuts(interval, interval2)) return false; + if(!boundaries_intersect(interval, interval2)) return false; + if(boundaries_intersect(interval, interval2, false)) return false; + if(intersect(interval, interval2, false)) return false; + if(!intersect(interval, interval2)) return false; + if(euclidean_distance(interval, interval2) != 0) return false; + encompass(interval, interval2); + set(interval, LOW, 0); + high(interval, 10); + scale(interval, 2.0f); + scale(interval, 0.5f); + if(low(interval) != 0) return false; + if(high(interval) != 10) return false; + move(interval, 10); + if(!equivalence(interval, interval2)) return false; + flip(interval, 10); + bloat(interval, -2); + shrink(interval, -2); + flip(interval, 10); + if(!equivalence(interval, interval2)) return false; + interval_data half = get_half(interval, LOW); + if(high(half) != 15) return false; + convolve(interval, interval2); + if(high(interval) != 40) return false; + deconvolve(interval, interval2); + if(!equivalence(interval, interval2)) return false; + reflected_convolve(interval, interval2); + if(low(interval) != -10) return false; + reflected_deconvolve(interval, interval2); + if(!equivalence(interval, interval2)) return false; + euclidean_distance(interval, 0); + move(interval, 20); + if(euclidean_distance(interval, interval2) != 10) return false; + interval = interval2; + move(interval, -5); + if(!intersects(interval, interval2)) return false; + move(interval, 15); + if(!abuts(interval, interval2)) return false; + if(abuts(interval, interval2, HIGH)) return false; + move(interval, 10); + generalized_intersect(interval, interval2); + move(interval, -10); + if(!equivalence(interval, interval2)) return false; + if(get(interval, LOW) != low(interval)) return false; + if(get(interval, HIGH) != high(interval)) return false; + if(center(interval2) != 15) return false; + if(delta(interval2) != 10) return false; + assign(interval, interval2); + low(interval, 0); + if(low(interval) != 0) return false; + high(interval, 10); + join_with(interval, interval2); + if(high(interval) != high(interval2)) return false; + return true; +} + +bool testRectangle() { + rectangle_data rect, rect2; +#ifdef BOOST_POLYGON_MSVC + horizontal(rect, interval_data(0, 10)); + vertical(rect, interval_data(20, 30)); +#else + horizontal(rect, interval_data(0, 10)); + vertical(rect, interval_data(20, 30)); +#endif + xl(rect2, 0); + xh(rect2, 10); + yl(rect2, 20); + yh(rect2, 30); + if(euclidean_distance(rect, rect2) != 0) return false; + if(euclidean_distance(rect2, rect) != 0) return false; +#ifdef BOOST_POLYGON_MSVC + set(rect, HORIZONTAL, interval_data(0, 10)); + if(!equivalence(horizontal(rect), interval_data(0, 10))) return false; + if(!equivalence(vertical(rect2), interval_data(20, 30))) return false; +#else + set(rect, HORIZONTAL, interval_data(0, 10)); + if(!equivalence(horizontal(rect), interval_data(0, 10))) return false; + if(!equivalence(vertical(rect2), interval_data(20, 30))) return false; +#endif + if(xl(rect) != 0) return false; + if(xh(rect) != 10) return false; + if(yl(rect) != 20) return false; + if(yh(rect) != 30) return false; + move(rect, HORIZONTAL, 10); + if(xl(rect) != 10) return false; +#ifdef BOOST_POLYGON_MSVC + set_points(rect, point_data(0, 20), point_data(10, 30)); +#else + set_points(rect, point_data(0, 20), point_data(10, 30)); +#endif + if(xl(rect) != 0) return false; + convolve(rect, rect2); + if(xh(rect) != 20) return false; + deconvolve(rect, rect2); + if(xh(rect) != 10) return false; + reflected_convolve(rect, rect2); + reflected_deconvolve(rect, rect2); + if(!equivalence(rect, rect2)) return false; +#ifdef BOOST_POLYGON_MSVC + convolve(rect, point_data(100, 200)); +#else + convolve(rect, point_data(100, 200)); +#endif + if(xh(rect) != 110) return false; + deconvolve(rect, point_data(100, 200)); + if(!equivalence(rect, rect2)) return false; + xh(rect, 100); + if(delta(rect, HORIZONTAL) != 100) return false; + if(area(rect) != 1000) return false; + if(half_perimeter(rect) != 110) return false; + if(perimeter(rect) != 220) return false; + if(guess_orientation(rect) != HORIZONTAL) return false; + return true; +} + + +bool testPolygon() { + int rect[4] = {0, 10, 20, 30}; + iterator_compact_to_points > itr(rect, rect+4); + iterator_compact_to_points > itr_end(rect, rect+4); + std::vector > points; + points.insert(points.end(), itr, itr_end); + polygon_90_data p90; + assign(p90, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p90) != COUNTERCLOCKWISE) return false; + polygon_45_data p45; + assign(p45, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p45) != COUNTERCLOCKWISE) return false; + polygon_data p; + assign(p, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p) != COUNTERCLOCKWISE) return false; + set_compact(p90, rect, rect+4); + if(winding(p90) != COUNTERCLOCKWISE) return false; + points.clear(); + points.push_back(point_data(0, 0)); + points.push_back(point_data(10, 10)); + points.push_back(point_data(0, 20)); + points.push_back(point_data(-10, 10)); + set_points(p45, points.begin(), points.end()); + if(winding(p45) != COUNTERCLOCKWISE) return false; + std::swap(points[1], points[3]); + set_points(p, points.begin(), points.end()); + if(winding(p) == COUNTERCLOCKWISE) return false; + point_data cp; + center(cp, p); + if(cp != point_data(0, 10)) return false; + move(p, HORIZONTAL, 3); + rectangle_data bounding_box; + extents(bounding_box, p); + if(bounding_box != rectangle_data(interval_data(-7, 13), interval_data(0, 20))) return false; + if(area(p90) != 400) return false; + if(area(p45) != 200) return false; + if(perimeter(p90) != 80) return false; + return true; +} + +bool testPolygonAssign() { + polygon_data p; + polygon_data p1; + polygon_45_data p_45; + polygon_45_data p_451; + polygon_90_data p_90; + polygon_90_data p_901; + polygon_with_holes_data p_wh; + polygon_with_holes_data p_wh1; + polygon_45_with_holes_data p_45_wh; + polygon_45_with_holes_data p_45_wh1; + polygon_90_with_holes_data p_90_wh; + polygon_90_with_holes_data p_90_wh1; + assign(p, p1); + assign(p, p_45); + assign(p, p_90); + //assign(p, p_wh); + //assign(p, p_45_wh); + //assign(p, p_90_wh); + //assign(p_45, p); + assign(p_451, p_45); + assign(p_45, p_90); + //assign(p_45, p_wh); + //assign(p_45, p_45_wh); + //assign(p_45, p_90_wh); + //assign(p_90, p); + //assign(p_90, p_45); + assign(p_901, p_90); + //assign(p_90, p_wh); + //assign(p_90, p_45_wh); + //assign(p_90, p_90_wh); + assign(p_wh, p); + assign(p_wh, p_45); + assign(p_wh, p_90); + assign(p_wh1, p_wh); + assign(p_wh, p_45_wh); + assign(p_wh, p_90_wh); + //assign(p_45_wh, p); + assign(p_45_wh, p_45); + assign(p_45_wh, p_90); + //assign(p_45_wh, p_wh); + assign(p_45_wh1, p_45_wh); + //assign(p_90_wh, p); + //assign(p_90_wh, p_45); + assign(p_90_wh, p_90); + assign(p_90_wh1, p_90_wh); + return true; +} + +int testPropertyMerge() { + rectangle_data rect1 = construct >(0, 1, 10, 11); + rectangle_data rect2 = construct >(5, 6, 17, 18); + property_merge_90 pm; + pm.insert(rect1, 0); + pm.insert(rect2, 1); + std::map, polygon_90_set_data > result; + pm.merge(result); + std::vector > rects; + std::set key; + key.insert(0); + result[key].get(rects); + std::cout << rects.size() << std::endl; + std::vector > polys; + result[key].get(polys); + std::cout << polys.size() << std::endl; + std::vector > polywhs; + result[key].get(polywhs); + std::cout << polys.size() << std::endl; + return result.size(); +} + +bool testPolygonWithHoles() { + int rect[4] = {0, 10, 20, 30}; + iterator_compact_to_points > itr(rect, rect+4); + iterator_compact_to_points > itr_end(rect, rect+4); + std::vector > points; + points.insert(points.end(), itr, itr_end); + polygon_45_with_holes_data p45wh; + assign(p45wh, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p45wh) != COUNTERCLOCKWISE) return false; + polygon_45_with_holes_data p45; + assign(p45, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p45) != COUNTERCLOCKWISE) return false; + polygon_45_with_holes_data p; + assign(p, rectangle_data(interval_data(0, 10), interval_data(20, 30))); + if(winding(p) != COUNTERCLOCKWISE) return false; + set_compact(p45wh, rect, rect+4); + if(winding(p45wh) != COUNTERCLOCKWISE) return false; + points.clear(); + points.push_back(point_data(0, 0)); + points.push_back(point_data(10, 10)); + points.push_back(point_data(0, 20)); + points.push_back(point_data(-10, 10)); + set_points(p45, points.begin(), points.end()); + if(winding(p45) != COUNTERCLOCKWISE) return false; + std::swap(points[1], points[3]); + set_points(p, points.begin(), points.end()); + if(winding(p) == COUNTERCLOCKWISE) return false; + point_data cp; + center(cp, p); + if(cp != point_data(0, 10)) return false; + move(p, HORIZONTAL, 3); + rectangle_data bounding_box; + extents(bounding_box, p); + if(bounding_box != rectangle_data(interval_data(-7, 13), interval_data(0, 20))) return false; + if(area(p45wh) != 400) return false; + if(area(p45) != 200) return false; + if(perimeter(p45wh) != 80) return false; + return true; +} + +using namespace gtl; + +typedef int Unit; +typedef point_data Point; +typedef interval_data Interval; +typedef rectangle_data Rectangle; +typedef polygon_90_data Polygon; +typedef polygon_90_with_holes_data PolygonWithHoles; +typedef polygon_45_data Polygon45; +typedef polygon_45_with_holes_data Polygon45WithHoles; +typedef polygon_90_set_data PolygonSet; +typedef polygon_45_set_data Polygon45Set; +typedef axis_transformation AxisTransform; +typedef transformation Transform; + +bool getRandomBool() { + return rand()%2 != 0; +} +int getRandomInt() { + return rand()%6-2; +} +Point getRandomPoint() { + int x = rand()%8; + int y = rand()%8; + return Point(x, y); +} +Polygon45 getRandomTriangle() { + Point pts[3]; + pts[0] = getRandomPoint(); + pts[1] = pts[2] = pts[0]; + int disp = getRandomInt(); + bool dir = getRandomBool(); + x(pts[2], x(pts[2]) + disp); + x(pts[1], x(pts[1]) + disp); + if(dir) + y(pts[1], y(pts[1]) + disp); + else + y(pts[1], y(pts[1]) - disp); + return Polygon45(pts, pts+3); +} + +bool nonInteger45StessTest() { + for(unsigned int tests = 0; tests < 10; ++tests) { + Polygon45Set ps1, ps2; + std::vector p45s; + for(unsigned int i = 0; i < 10; ++i) { + Polygon45 p45 = getRandomTriangle(); + p45s.push_back(p45); + ps1.insert(p45); + scale_up(p45, 2); + ps2.insert(p45); + } + std::vector polys; + ps1.get(polys); + Polygon45Set ps3; + for(unsigned int i = 0; i < polys.size(); ++i) { + scale_up(polys[i], 2); + ps3.insert(polys[i]); + } + Polygon45Set ps4 = ps3 ^ ps2; + std::vector polys_error; + ps4.get(polys_error); + for(unsigned int i = 0; i < polys_error.size(); ++i) { + //if(polys_error[i].size() > 3) return false; + if(area(polys_error[i]) != 1) { + if(area(polys_error[i]) == 2) { + //if two area 1 errors merge it will have area 2 + continue; + } + std::cout << "test failed\n"; + for(unsigned int j =0; j < p45s.size(); ++j) { + std::cout << p45s[j] << std::endl; + } + return false; + } + } + } + return true; +} + +bool validate_polygon_set_op(Polygon45Set& ps45_o, + const Polygon45Set& ps45_1, + const Polygon45Set& ps45_2, + int op_type) { + Polygon45Set s_ps_45_o(ps45_o); + Polygon45Set s_ps_45_1(ps45_1); + Polygon45Set s_ps_45_2(ps45_2); + s_ps_45_o.scale_up(2); + s_ps_45_1.scale_up(2); + s_ps_45_2.scale_up(2); + Polygon45Set s_ps_45_validate; + if(op_type == 0) { + s_ps_45_validate = s_ps_45_1 + s_ps_45_2; + s_ps_45_validate += Rectangle(4, 4, 6, 6); + } else if(op_type == 1) { + s_ps_45_validate = s_ps_45_1 * s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } else if(op_type == 2) { + s_ps_45_validate = s_ps_45_1 ^ s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } else { + s_ps_45_validate = s_ps_45_1 - s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } + if(s_ps_45_validate != s_ps_45_o) { + std::cout << "TEST FAILED\n"; + std::vector polys; + s_ps_45_o.get(polys); + std::cout << "Result:\n"; + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + polys.clear(); + s_ps_45_validate.get(polys); + std::cout << "Expected Result:\n"; + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + //redo the operation, set breakpoints here + switch (op_type) { + case 0: + ps45_o = ps45_1 + ps45_2; + ps45_o.get(polys);//needed to force clean + break; + case 1: + ps45_o = ps45_1 * ps45_2; + break; + case 2: + ps45_o = ps45_1 ^ ps45_2; + break; + default: + ps45_o = ps45_1 - ps45_2; + }; + //redo the check, set breakpoints here + if(op_type == 0) { + s_ps_45_validate = s_ps_45_1 + s_ps_45_2; + s_ps_45_validate += Rectangle(4, 4, 6, 6); + s_ps_45_validate.get(polys); + } else if(op_type == 1) { + s_ps_45_validate = s_ps_45_1 * s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } else if(op_type == 2) { + s_ps_45_validate = s_ps_45_1 ^ s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } else { + s_ps_45_validate = s_ps_45_1 - s_ps_45_2; + s_ps_45_validate -= Rectangle(4, 4, 6, 6); + } + return false; + } + return true; +} + +bool test_two_polygon_sets(const Polygon45Set& ps45_1, + const Polygon45Set& ps45_2) { + std::cout << "test two polygon sets \n"; + std::vector polys; + ps45_1.get(polys); + std::cout << "LVALUE:\n"; + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + polys.clear(); + ps45_2.get(polys); + std::cout << "RVALUE:\n"; + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + Polygon45Set ps45_o; + std::cout << "OR\n"; + ps45_o = ps45_1 + ps45_2; + polys.clear(); + ps45_o.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(!validate_polygon_set_op(ps45_o, ps45_1, ps45_2, 0)) return false; + std::cout << "AND\n"; + ps45_o = ps45_1 * ps45_2; + polys.clear(); + ps45_o.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(!validate_polygon_set_op(ps45_o, ps45_1, ps45_2, 1)) return false; + std::cout << "XOR\n"; + ps45_o = ps45_1 ^ ps45_2; + polys.clear(); + ps45_o.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(!validate_polygon_set_op(ps45_o, ps45_1, ps45_2, 2)) return false; + std::cout << "SUBTRACT\n"; + ps45_o = ps45_1 - ps45_2; + polys.clear(); + ps45_o.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(!validate_polygon_set_op(ps45_o, ps45_1, ps45_2, 3)) return false; + return true; +} + +bool test_two_polygons(const Polygon45& p45_1, + const Polygon45& p45_2) { + Polygon45Set ps45_1, ps45_2; + ps45_1.insert(p45_1); + ps45_2.insert(p45_2); + ps45_1.insert(rectangle_data(10, -100, 20, 100)); + ps45_2.insert(rectangle_data(0, 10, 100, 20)); + if(!test_two_polygon_sets(ps45_1, ps45_2)) return false; + Polygon45Set ps45_1_c = ps45_1 - Rectangle(0, 0, 2, 5); + Polygon45Set ps45_2_c = ps45_2 - Rectangle(0, 0, 2, 5); + if(!test_two_polygon_sets(ps45_1_c, ps45_2_c)) return false; + if(!test_two_polygon_sets(ps45_1_c, ps45_2)) return false; + if(!test_two_polygon_sets(ps45_1, ps45_2_c)) return false; + return true; +} + +bool test_45_touch() { + using namespace gtl; + connectivity_extraction_45 ce; + rectangle_data rect1(0, 0, 10, 10); + rectangle_data rect2(5, 5, 15, 15); + rectangle_data rect3(5, 20, 15, 25); + ce.insert(rect1); + ce.insert(rect2); + ce.insert(rect3); + std::vector > graph(3); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1 && graph[2].size() == 0) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_45_touch_ur() { + using namespace gtl; + connectivity_extraction_45 ce; + rectangle_data rect1(0, 0, 5, 5); + rectangle_data rect2(5, 5, 10, 10); + ce.insert(rect1); + ce.insert(rect2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_45_touch_r() { + using namespace gtl; + connectivity_extraction_45 ce; + rectangle_data rect1(0, 0, 5, 5); + rectangle_data rect2(5, 0, 10, 5); + ce.insert(rect1); + ce.insert(rect2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_45_touch_boundaries() { + using namespace gtl; + connectivity_extraction_45 ce; + rectangle_data rect1(0, 0, 10, 10); + rectangle_data rect2(10, 0, 20, 10); + rectangle_data rect3(20, 0, 30, 10); + rectangle_data rect4(0, 10, 10, 20); + rectangle_data rect5(10, 10, 20, 20); + rectangle_data rect6(20, 10, 30, 20); + rectangle_data rect7(0, 20, 10, 30); + rectangle_data rect8(10, 20, 20, 30); + rectangle_data rect9(20, 20, 30, 30); + ce.insert(rect1); + ce.insert(rect2); + ce.insert(rect3); + ce.insert(rect4); + ce.insert(rect5); + ce.insert(rect6); + ce.insert(rect7); + ce.insert(rect8); + ce.insert(rect9); + std::vector > graph(9); + ce.extract(graph); + for(unsigned int i = 0; i < 9; ++i) { + std::cout << i << ": "; + for(std::set::iterator itr = graph[i].begin(); itr != graph[i].end(); ++itr) { + std::cout << *itr << " "; + } std::cout << std::endl; + } + if(graph[0].size() == 3 && graph[1].size() == 5 && graph[2].size() == 3 && + graph[3].size() == 5 && graph[4].size() == 8 && graph[5].size() == 5 && + graph[6].size() == 3 && graph[7].size() == 5 && graph[8].size() == 3) { + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_45_concept_interact() { + using namespace gtl; + std::vector > polys; + polys += rectangle_data(10, 10, 20, 20); + polys += rectangle_data(15, 15, 25, 25); + polys += rectangle_data(5, 25, 10, 35); + interact(polys, rectangle_data(0, 0, 13, 13)); + if(polys.size() != 1) return false; + return true; +} + +bool test_aa_touch() { + using namespace gtl; + connectivity_extraction ce; + rectangle_data rect1(0, 0, 10, 10); + rectangle_data rect2(5, 5, 15, 15); + rectangle_data rect3(5, 20, 15, 25); + ce.insert(rect1); + ce.insert(rect2); + ce.insert(rect3); + std::vector > graph(3); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1 && graph[2].size() == 0) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_aa_touch_ur() { + using namespace gtl; + connectivity_extraction ce; + rectangle_data rect1(0, 0, 5, 5); + rectangle_data rect2(5, 5, 10, 10); + ce.insert(rect1); + ce.insert(rect2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_aa_touch_ur2() { + using namespace gtl; + connectivity_extraction ce; + rectangle_data rect2(5, 5, 10, 10); + point_data pts[3] = { + point_data(0, 0), + point_data(5, 5), + point_data(0, 5) + }; + polygon_data poly; + poly.set(pts, pts+3); + ce.insert(poly); + ce.insert(rect2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_aa_touch_r() { + using namespace gtl; + connectivity_extraction ce; + rectangle_data rect1(0, 0, 5, 5); + rectangle_data rect2(5, 0, 10, 5); + ce.insert(rect1); + ce.insert(rect2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1 && graph[1].size() == 1) { + std::set::iterator itr = graph[0].begin(); + std::cout << *itr << std::endl; + std::set::iterator itr1 = graph[1].begin(); + std::cout << *itr1 << std::endl; + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_aa_touch_boundaries() { + using namespace gtl; + connectivity_extraction ce; + rectangle_data rect1(0, 0, 10, 10); + rectangle_data rect2(10, 0, 20, 10); + rectangle_data rect3(20, 0, 30, 10); + rectangle_data rect4(0, 10, 10, 20); + rectangle_data rect5(10, 10, 20, 20); + rectangle_data rect6(20, 10, 30, 20); + rectangle_data rect7(0, 20, 10, 30); + rectangle_data rect8(10, 20, 20, 30); + rectangle_data rect9(20, 20, 30, 30); + ce.insert(rect1); + ce.insert(rect2); + ce.insert(rect3); + ce.insert(rect4); + ce.insert(rect5); + ce.insert(rect6); + ce.insert(rect7); + ce.insert(rect8); + ce.insert(rect9); + std::vector > graph(9); + ce.extract(graph); + for(unsigned int i = 0; i < 9; ++i) { + std::cout << i << ": "; + for(std::set::iterator itr = graph[i].begin(); itr != graph[i].end(); ++itr) { + std::cout << *itr << " "; + } std::cout << std::endl; + } + if(graph[0].size() == 3 && graph[1].size() == 5 && graph[2].size() == 3 && + graph[3].size() == 5 && graph[4].size() == 8 && graph[5].size() == 5 && + graph[6].size() == 3 && graph[7].size() == 5 && graph[8].size() == 3) { + return true; + } + std::cout << "test failed\n"; + return false; +} + +bool test_aa_concept_interact() { + using namespace gtl; + std::vector > polys; + polys += rectangle_data(10, 10, 20, 20); + polys += rectangle_data(15, 15, 25, 25); + polys += rectangle_data(5, 25, 10, 35); + interact(polys, rectangle_data(0, 0, 13, 13)); + if(polys.size() != 1) return false; + return true; +} + +bool test_get_rectangles() { + using namespace gtl; + polygon_90_set_data ps(VERTICAL); + ps += rectangle_data(0, 0, 10, 10); + ps += rectangle_data(5, 5, 15, 15); + std::vector > polys; + ps.get_rectangles(polys, HORIZONTAL); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(polys.size() != 3) return false; + std::vector > rects; + ps.get_rectangles(rects, HORIZONTAL); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() != 3) return false; + if(!equivalence(rects[2], rectangle_data(5,10,15,15))) return false; + + get_rectangles(polys, rects, VERTICAL); + get_rectangles(rects, polys, HORIZONTAL); + return equivalence(rects, polys); +} + +bool test_get_trapezoids() { + using namespace gtl; + polygon_45_set_data ps; + ps += rectangle_data(0, 0, 10, 10); + ps += rectangle_data(5, 5, 15, 15); + std::vector > polys; + ps.get_trapezoids(polys, HORIZONTAL); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + if(polys.size() != 3) return false; + std::vector > rects; + ps.get_trapezoids(rects, HORIZONTAL); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() != 3) return false; + if(!equivalence(rects[2], rectangle_data(5,10,15,15))) return false; + get_trapezoids(polys, rects, VERTICAL); + get_trapezoids(rects, polys, HORIZONTAL); + return equivalence(rects, polys); +} + +bool test_SQRT1OVER2() { + Point pts[] = { + Point(100, 100), + Point(0, 100), + Point(100, 200), + Point(0, 300), + Point(100, 400), + Point(0, 500), + Point(100, 500), + Point(100, 600), + Point(200, 500), + Point(300, 600), + Point(400, 500), + Point(500, 600), + Point(500, 500), + Point(600, 500), + Point(500, 400), + Point(600, 300), + Point(500, 200), + Point(600, 100), + Point(500, 100), + Point(500, 0), + Point(400, 100), + Point(300, 0), + Point(200, 100), + Point(100, 0), + Point(100, 100) + }; + Polygon45 p45(pts, pts+25); + std::cout << is_45(p45) << std::endl; + std::cout << p45 << std::endl; + Polygon45Set ps45; + ps45 += p45; + ps45.resize(10, SQRT1OVER2, ORTHOGONAL); + std::vector polys; + ps45.get(polys); + if(polys.size() != 1) return false; + Point pts2[] = { + Point(90, 90), + Point(-10, 90), + Point(-10, 100), + Point(90, 200), + Point(-10, 300), + Point(90, 400), + Point(-10, 500), + Point(-10, 510), + Point(90, 510), + Point(90, 610), + Point(100, 610), + Point(200, 510), + Point(300, 610), + Point(400, 510), + Point(500, 610), + Point(510, 610), + Point(510, 510), + Point(610, 510), + Point(610, 500), + Point(510, 400), + Point(610, 300), + Point(510, 200), + Point(610, 100), + Point(610, 90), + Point(510, 90), + Point(510, -10), + Point(500, -10), + Point(400, 90), + Point(300, -10), + Point(200, 90), + Point(100, -10), + Point(90, -10), + Point(90, 90) + }; + Polygon45 p45reference(pts2, pts2+33); + std::cout << is_45(polys[0]) << std::endl; + std::cout << polys[0] << std::endl; + std::cout << p45reference << std::endl; + std::cout << is_45(p45reference) << std::endl; + if(!equivalence(polys[0], p45reference)) { + std::cout << "polys don't match\n"; + return false; + } + ps45.resize(-10, SQRT1OVER2, ORTHOGONAL); + polys.clear(); + ps45.get(polys); + if(polys.size() != 1) return false; + std::cout << is_45(polys[0]) << std::endl; + std::cout << polys[0] << std::endl; + if(!equivalence(polys[0], p45)) { + std::cout << "polys don't match\n"; + return false; + } + ps45.resize(11, SQRT1OVER2, UNFILLED); + polys.clear(); + ps45.get(polys); + if(polys.size() != 1) return false; + std::cout << is_45(polys[0]) << std::endl; + std::cout << polys[0] << std::endl; + return true; +} + +bool test_scaling_by_floating(){ + Point pts[] = { + Point(1, 1), + Point(10, 1), + Point(1, 10) + }; + Polygon45 poly(pts, pts+3); + Polygon45Set ps45; + ps45 += poly; + ps45.scale(double(2.5)); + std::vector polys; + ps45.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + std::cout << area(polys[i]) << std::endl; + } + if(polys.size() != 1) return false; + if(area(polys[0]) != 242) return false; + scale(ps45, double(1)/double(2.5)); + polys.clear(); + ps45.get(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + return equivalence(polys, poly); +} + +bool test_directional_resize() { + std::vector rects; + rects.push_back(Rectangle(0, 0, 100, 100)); + resize(rects, -10, 10, -10, 10); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() != 1) return false; + if(rects[0] != Rectangle(10, 10, 110, 110)) return false; + + return true; +} + +bool test_self_xor() { + std::vector rects; + rects.push_back(Rectangle(0, 0, 10, 10)); + rects.push_back(Rectangle(5, 5, 15, 15)); + self_xor(rects); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() == 4) return true; + else return false; +} + +bool test_grow_and_45() { + polygon_45_set_data ps; + ps.insert(Rectangle(0, 0, 5, 5)); + ps.insert(Rectangle(5, 5, 15, 15)); + grow_and(ps, 2); + std::vector > rects; + ps.get_trapezoids(rects); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() != 1) return false; + return equivalence(rects, Rectangle(3, 3, 7, 7)); +} + +bool test_self_xor_45() { + polygon_45_set_data ps; + ps.insert(Rectangle(0, 0, 10, 10)); + ps.insert(Rectangle(5, 5, 15, 15)); + self_xor(ps); + std::vector > rects; + ps.get_trapezoids(rects); + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + if(rects.size() == 4) return true; + else return false; +} + +bool testViewCopyConstruct() { + PolygonSet ps1, ps2; + ps1.insert(Rectangle(0, 0, 10, 10)); + ps2.insert(Rectangle(5, 5, 15, 15)); + PolygonSet psr = ps1 - ps2; + std::vector rects; + rects += psr; + for(unsigned int i = 0; i < rects.size(); ++i) + std::cout << rects[i] << std::endl; + if( rects.size() != 2) return false; + Polygon45Set ps45_1, ps45_2; + ps45_1.insert(Rectangle(0, 0, 10, 10)); + ps45_2.insert(Rectangle(5, 5, 15, 15)); + Polygon45Set ps45_r = ps45_1 - ps45_2; + std::vector polys; + ps45_r.get_trapezoids(polys); + for(unsigned int i = 0; i < polys.size(); ++i) + std::cout << polys[i] << std::endl; + if( polys.size() != 2) return false; + return true; +} + +bool testpip() { + std::vector pts; + pts.push_back(Point(0, 0)); + pts.push_back(Point(10, 0)); + pts.push_back(Point(20, 10)); + pts.push_back(Point(0, 20)); + pts.push_back(Point(30, 40)); + pts.push_back(Point(-10, 50)); + pts.push_back(Point(-20, -20)); + pts.push_back(Point(0, 0)); + polygon_data poly; + polygon_with_holes_data poly2; + polygon_45_data poly45; + polygon_45_with_holes_data poly245; + polygon_90_data poly90; + polygon_90_with_holes_data poly290; + poly.set(pts.begin(), pts.end()); + poly2.set(pts.begin(), pts.end()); + assign(poly45, Rectangle(0, 0, 100, 100)); + assign(poly245, Rectangle(0, 0, 100, 100)); + assign(poly90, Rectangle(0, 0, 100, 100)); + assign(poly290, Rectangle(0, 0, 100, 100)); + for(unsigned int i = 0; i < pts.size(); ++i) { + if(!contains(poly, pts[i], true)) return false; + if(contains(poly, pts[i], false)) return false; + if(!contains(poly2, pts[i], true)) return false; + if(contains(poly2, pts[i], false)) return false; + } + if(!contains(poly45, pts[0], true)) return false; + if(contains(poly245, pts[0], false)) return false; + if(!contains(poly90, pts[0], true)) return false; + if(contains(poly290, pts[0], false)) return false; + Point pt(0, -10); + if(contains(poly, pt)) return false; + Point p2(0, 1); + if(!contains(poly, p2)) return false; + return true; +} + +void testHand() { + using namespace gtl; + int handcoords[] = { +12375, 11050, 13175, 10200, 15825, 9275, 18750, 8525, 24150, 8300, 27575, 8400, 31775, 7800, +35975, 7200, 41375, 4800, 42575, 4200, 43175, 4200, 47375, 2400, 49175, 1800, 51150, 2200, +52275, 2825, 52625, 4150, 52375, 4975, 51575, 6000, 49275, 6850, 45700, 7950, 43175, 9600, +39575, 10800, 37775, 12000, 37775, 12600, 37775, 13800, 38975, 14400, 41375, 14400, 45575, 13200, +48600, 13000, 51575, 13200, 55175, 12600, 58775, 12600, 61175, 13200, 62375, 14400, 62550, 15700, +61975, 16875, 60775, 17600, 60100, 17675, 58525, 17675, 56150, 17575, 52175, 18000, 47975, 18600, +45575, 19200, 44375, 19200, 42675, 19325, 41600, 19775, 41600, 20500, 42100, 20825, 44975, 20400, +48575, 20400, 52775, 21000, 53975, 21000, 57575, 21000, 62375, 21000, 65450, 22000, 66300, 23100, +66100, 24550, 64750, 25925, 62975, 26400, 61175, 26400, 58775, 26400, 56025, 26050, 53450, 26025, +50975, 26400, 48575, 26400, 46775, 26400, 43650, 26075, 41375, 26400, 40775, 27000, 40775, 27600, +42225, 28650, 44375, 29400, 48575, 30000, 50975, 31200, 53975, 31800, 58775, 33000, 61200, 34300, +62375, 35400, 62375, 37200, 61175, 38400, 60000, 38700, 57575, 38400, 54550, 37575, 50975, 36600, +49075, 36125, 47750, 36125, 45700, 35425, 42350, 34350, 38900, 33775, 30575, 33000, 26975, 33600, +25975, 34900, 26375, 36600, 28175, 38400, 30575, 40800, 32375, 43800, 33200, 46200, 33200, 48000, +32650, 49300, 31425, 50000, 29950, 50125, 28825, 49375, 27575, 48000, 25825, 46000, 23975, 44100, +22175, 42600, 19775, 39600, 17325, 37300, 14975, 34800, 13175, 31800, 10775, 29400, 9600, 27400, +10175, 27000, 11375, 27600, 12575, 28800, 14375, 31800, 16175, 34800, 18575, 37200, 21575, 39000, +22775, 40200, 23975, 41400, 24575, 42600, 26375, 44400, 28325, 46000, 29850, 46775, 31175, 46200, +31550, 44575, 30575, 43200, 28775, 40800, 25775, 38400, 24575, 34800, 24750, 33175, 26975, 31800, +29975, 31800, 33575, 31800, 37775, 32400, 39575, 33000, 41975, 33600, 45150, 34175, 46975, 34750, +48575, 35400, 50975, 35400, 51575, 34800, 51875, 33725, 50775, 32575, 48575, 31800, 45750, 30875, +43775, 30600, 41375, 29400, 38975, 28800, 35975, 28200, 34775, 27600, 34175, 27000, 34775, 25800, +37175, 25200, 40175, 25200, 43175, 25200, 46775, 25200, 50975, 25425, 53375, 25200, 55175, 24600, +55525, 23450, 53975, 22200, 52775, 22200, 49075, 21850, 45950, 21925, 40775, 21600, 37775, 21600, +35150, 21350, 34325, 20950, 34175, 19800, 35975, 19200, 38375, 19200, 40750, 18900, 42575, 18600, +44375, 18000, 47975, 17400, 50375, 17125, 52025, 16625, 52775, 15600, 52100, 14625, 49675, 14125, +48625, 14125, 46775, 14400, 44375, 15000, 41375, 15150, 37700, 15275, 34775, 15600, 32850, 15925, +31775, 15600, 31425, 14875, 32375, 13800, 36575, 11400, 38975, 10200, 41375, 9000, 43075, 8150, +43650, 7200, 43325, 6250, 42225, 5825, 40800, 6275, 38900, 6925, 35375, 8400, 32375, 10200, +27575, 11400, 22775, 12600, 19775, 13225, 16775, 13800, 14975, 14400, 13050, 14000, 11975, 12600, + 0, 0 }; + std::vector handpoints; + for(unsigned int i = 0; i < 100000; i += 2) { + Point pt(handcoords[i], handcoords[i+1]); + if(pt == Point(0, 0)) break; + handpoints.push_back(pt); + } + polygon_data handpoly; + handpoly.set(handpoints.begin(), handpoints.end()); + int spiralcoords [] = { +37200, 3600, 42075, 4025, 47475, 5875, 51000, 7800, 55800, 12300, 59000, 17075, 60000, 20400, +61200, 25800, 61200, 29400, 60600, 33600, 58800, 38400, 55800, 42600, 53200, 45625, +49200, 48600, 43200, 51000, 35400, 51600, 29400, 50400, 23400, 47400, 19200, 43800, +16200, 39600, 14400, 35400, 13200, 29400, 13200, 24000, 15000, 18600, 17400, 13800, +20525, 10300, 24600, 7200, 29400, 4800, 32450, 4000, 34825, 3675, 35625, 3625, +35825, 7275, 39600, 7200, 43800, 8400, 46800, 9600, 50400, 12000, 53400, 15000, +55800, 18600, 57000, 23400, 57600, 27000, 57000, 32400, 55200, 37200, 52200, 41400, +48000, 45000, 42000, 47400, 35400, 48000, 30000, 46800, 24600, 43800, 20325, 39100, +17850, 34275, 16800, 27600, 17400, 22200, 20400, 16200, 24600, 11400, 28800, 9000, +32400, 7800, 33200, 7575, 33925, 11050, 35400, 10800, 37200, 10800, 41400, 11400, +46200, 13200, 49800, 16200, 51600, 19200, 53400, 23400, 54000, 29400, 52800, 33600, +49800, 39000, 45000, 42600, 39000, 44400, 33600, 43800, 28200, 42000, 24000, 37800, +21000, 33000, 20400, 26400, 21600, 21000, 24600, 16200, 28200, 13200, 31875, 11625, +33200, 15625, 36000, 15000, 39000, 15000, 43800, 16800, 46800, 19200, 49200, 23400, +49800, 27600, 48750, 32700, 46350, 36275, 42600, 39000, 38400, 40200, 31800, 39000, +28200, 36600, 25200, 31200, 24600, 26400, 26025, 21800, 28200, 18600, 30600, 16800, +32575, 19875, 34200, 19200, 36000, 18600, 37200, 18600, 40375, 19125, 43200, 21000, +45600, 24000, 46200, 27600, 45600, 30600, 43800, 33600, 41475, 35625, 37800, 36600, +33600, 36000, 30000, 33600, 28200, 28800, 28800, 24600, 30000, 22200, 31200, 23400, +30600, 25200, 30000, 27000, 30600, 30000, 31800, 32400, 34200, 34200, 38400, 34800, +41400, 33000, 44025, 30225, 44400, 26400, 43200, 23400, 40900, 21200, 37800, 20400, +34950, 20675, 32400, 22200, 30175, 19475, 28425, 21300, 27000, 24000, 26400, 27600, +27000, 31800, 31200, 36600, 36600, 38400, 42600, 37200, 46200, 33600, 48000, 30000, +47650, 24425, 45600, 20400, 42650, 18200, 39000, 16800, 35400, 16800, 33600, 17400, +32875, 17675, 31100, 13850, 28200, 15600, 25200, 18600, 22800, 22800, 22200, 27000, +23400, 33600, 26400, 38400, 31675, 41575, 37800, 42600, 40850, 42150, 42800, 41550, +47050, 39025, 50100, 35375, 52200, 29400, 51675, 23950, 49800, 19200, 46200, 15600, +41400, 13200, 37800, 12600, 35025, 12750, 33350, 13050, 32400, 9600, 30025, 10325, +25925, 12725, 22200, 16800, 19800, 21000, 18600, 25800, 18600, 30000, 20400, 35400, +22575, 39250, 25225, 41825, 28200, 43800, 33600, 46200, 39000, 46200, 44400, 45000, +48650, 42350, 52800, 37800, 55200, 32400, 55800, 26400, 54600, 21000, 53400, 18000, +50400, 14400, 47400, 12000, 42600, 9600, 39000, 9000, 36000, 9000, 34775, 9125, +34300, 5600, 30000, 6600, 25800, 8400, 22025, 11350, 18725, 15125, 16200, 20400, +15000, 24600, 15000, 30600, 16800, 36600, 20400, 42600, 25800, 46800, 31200, 49200, +38400, 49800, 45000, 48600, 51000, 45000, 55475, 40225, 58200, 34800, 59400, 30000, +59400, 25200, 58200, 19800, 55200, 14400, 52225, 11150, 47400, 7800, 44175, 6500, +40200, 5400, 38400, 5400, 37200, 5400, 0, 0 }; + std::vector spiralpoints; + for(unsigned int i = 0; i < 100000; i += 2) { + Point pt(spiralcoords[i], spiralcoords[i+1]); + if(pt == Point(0, 0)) break; + spiralpoints.push_back(pt); + } + polygon_data spiralpoly; + spiralpoly.set(spiralpoints.begin(), spiralpoints.end()); + polygon_set_data handset; + handset += handpoly; + polygon_set_data spiralset; + spiralset += spiralpoly; + polygon_set_data xorset = handset ^ spiralset; + std::vector > polys; + polys += xorset; + std::cout << polys.size() << std::endl; + for(unsigned int i = 0; i < polys.size(); ++i) + std::cout << polys[i] << std::endl; +} + +//void testHandFloat() { +// using namespace gtl; +// double handcoords[] = { +//12375, 11050, 13175, 10200, 15825, 9275, 18750, 8525, 24150, 8300, 27575, 8400, 31775, 7800, +//35975, 7200, 41375, 4800, 42575, 4200, 43175, 4200, 47375, 2400, 49175, 1800, 51150, 2200, +//52275, 2825, 52625, 4150, 52375, 4975, 51575, 6000, 49275, 6850, 45700, 7950, 43175, 9600, +//39575, 10800, 37775, 12000, 37775, 12600, 37775, 13800, 38975, 14400, 41375, 14400, 45575, 13200, +//48600, 13000, 51575, 13200, 55175, 12600, 58775, 12600, 61175, 13200, 62375, 14400, 62550, 15700, +//61975, 16875, 60775, 17600, 60100, 17675, 58525, 17675, 56150, 17575, 52175, 18000, 47975, 18600, +//45575, 19200, 44375, 19200, 42675, 19325, 41600, 19775, 41600, 20500, 42100, 20825, 44975, 20400, +//48575, 20400, 52775, 21000, 53975, 21000, 57575, 21000, 62375, 21000, 65450, 22000, 66300, 23100, +//66100, 24550, 64750, 25925, 62975, 26400, 61175, 26400, 58775, 26400, 56025, 26050, 53450, 26025, +//50975, 26400, 48575, 26400, 46775, 26400, 43650, 26075, 41375, 26400, 40775, 27000, 40775, 27600, +//42225, 28650, 44375, 29400, 48575, 30000, 50975, 31200, 53975, 31800, 58775, 33000, 61200, 34300, +//62375, 35400, 62375, 37200, 61175, 38400, 60000, 38700, 57575, 38400, 54550, 37575, 50975, 36600, +//49075, 36125, 47750, 36125, 45700, 35425, 42350, 34350, 38900, 33775, 30575, 33000, 26975, 33600, +//25975, 34900, 26375, 36600, 28175, 38400, 30575, 40800, 32375, 43800, 33200, 46200, 33200, 48000, +//32650, 49300, 31425, 50000, 29950, 50125, 28825, 49375, 27575, 48000, 25825, 46000, 23975, 44100, +//22175, 42600, 19775, 39600, 17325, 37300, 14975, 34800, 13175, 31800, 10775, 29400, 9600, 27400, +//10175, 27000, 11375, 27600, 12575, 28800, 14375, 31800, 16175, 34800, 18575, 37200, 21575, 39000, +//22775, 40200, 23975, 41400, 24575, 42600, 26375, 44400, 28325, 46000, 29850, 46775, 31175, 46200, +//31550, 44575, 30575, 43200, 28775, 40800, 25775, 38400, 24575, 34800, 24750, 33175, 26975, 31800, +//29975, 31800, 33575, 31800, 37775, 32400, 39575, 33000, 41975, 33600, 45150, 34175, 46975, 34750, +//48575, 35400, 50975, 35400, 51575, 34800, 51875, 33725, 50775, 32575, 48575, 31800, 45750, 30875, +//43775, 30600, 41375, 29400, 38975, 28800, 35975, 28200, 34775, 27600, 34175, 27000, 34775, 25800, +//37175, 25200, 40175, 25200, 43175, 25200, 46775, 25200, 50975, 25425, 53375, 25200, 55175, 24600, +//55525, 23450, 53975, 22200, 52775, 22200, 49075, 21850, 45950, 21925, 40775, 21600, 37775, 21600, +//35150, 21350, 34325, 20950, 34175, 19800, 35975, 19200, 38375, 19200, 40750, 18900, 42575, 18600, +//44375, 18000, 47975, 17400, 50375, 17125, 52025, 16625, 52775, 15600, 52100, 14625, 49675, 14125, +//48625, 14125, 46775, 14400, 44375, 15000, 41375, 15150, 37700, 15275, 34775, 15600, 32850, 15925, +//31775, 15600, 31425, 14875, 32375, 13800, 36575, 11400, 38975, 10200, 41375, 9000, 43075, 8150, +//43650, 7200, 43325, 6250, 42225, 5825, 40800, 6275, 38900, 6925, 35375, 8400, 32375, 10200, +//27575, 11400, 22775, 12600, 19775, 13225, 16775, 13800, 14975, 14400, 13050, 14000, 11975, 12600, +// 0, 0 }; +// std::vector > handpoints; +// for(unsigned int i = 0; i < 100000; i += 2) { +// point_data pt(handcoords[i], handcoords[i+1]); +// if(pt == point_data (0, 0)) break; +// handpoints.push_back(pt); +// } +// polygon_data handpoly; +// handpoly.set(handpoints.begin(), handpoints.end()); +// double spiralcoords [] = { +//37200, 3600, 42075, 4025, 47475, 5875, 51000, 7800, 55800, 12300, 59000, 17075, 60000, 20400, +//61200, 25800, 61200, 29400, 60600, 33600, 58800, 38400, 55800, 42600, 53200, 45625, +//49200, 48600, 43200, 51000, 35400, 51600, 29400, 50400, 23400, 47400, 19200, 43800, +//16200, 39600, 14400, 35400, 13200, 29400, 13200, 24000, 15000, 18600, 17400, 13800, +//20525, 10300, 24600, 7200, 29400, 4800, 32450, 4000, 34825, 3675, 35625, 3625, +//35825, 7275, 39600, 7200, 43800, 8400, 46800, 9600, 50400, 12000, 53400, 15000, +//55800, 18600, 57000, 23400, 57600, 27000, 57000, 32400, 55200, 37200, 52200, 41400, +//48000, 45000, 42000, 47400, 35400, 48000, 30000, 46800, 24600, 43800, 20325, 39100, +//17850, 34275, 16800, 27600, 17400, 22200, 20400, 16200, 24600, 11400, 28800, 9000, +//32400, 7800, 33200, 7575, 33925, 11050, 35400, 10800, 37200, 10800, 41400, 11400, +//46200, 13200, 49800, 16200, 51600, 19200, 53400, 23400, 54000, 29400, 52800, 33600, +//49800, 39000, 45000, 42600, 39000, 44400, 33600, 43800, 28200, 42000, 24000, 37800, +//21000, 33000, 20400, 26400, 21600, 21000, 24600, 16200, 28200, 13200, 31875, 11625, +//33200, 15625, 36000, 15000, 39000, 15000, 43800, 16800, 46800, 19200, 49200, 23400, +//49800, 27600, 48750, 32700, 46350, 36275, 42600, 39000, 38400, 40200, 31800, 39000, +//28200, 36600, 25200, 31200, 24600, 26400, 26025, 21800, 28200, 18600, 30600, 16800, +//32575, 19875, 34200, 19200, 36000, 18600, 37200, 18600, 40375, 19125, 43200, 21000, +//45600, 24000, 46200, 27600, 45600, 30600, 43800, 33600, 41475, 35625, 37800, 36600, +//33600, 36000, 30000, 33600, 28200, 28800, 28800, 24600, 30000, 22200, 31200, 23400, +//30600, 25200, 30000, 27000, 30600, 30000, 31800, 32400, 34200, 34200, 38400, 34800, +//41400, 33000, 44025, 30225, 44400, 26400, 43200, 23400, 40900, 21200, 37800, 20400, +//34950, 20675, 32400, 22200, 30175, 19475, 28425, 21300, 27000, 24000, 26400, 27600, +//27000, 31800, 31200, 36600, 36600, 38400, 42600, 37200, 46200, 33600, 48000, 30000, +//47650, 24425, 45600, 20400, 42650, 18200, 39000, 16800, 35400, 16800, 33600, 17400, +//32875, 17675, 31100, 13850, 28200, 15600, 25200, 18600, 22800, 22800, 22200, 27000, +//23400, 33600, 26400, 38400, 31675, 41575, 37800, 42600, 40850, 42150, 42800, 41550, +//47050, 39025, 50100, 35375, 52200, 29400, 51675, 23950, 49800, 19200, 46200, 15600, +//41400, 13200, 37800, 12600, 35025, 12750, 33350, 13050, 32400, 9600, 30025, 10325, +//25925, 12725, 22200, 16800, 19800, 21000, 18600, 25800, 18600, 30000, 20400, 35400, +//22575, 39250, 25225, 41825, 28200, 43800, 33600, 46200, 39000, 46200, 44400, 45000, +//48650, 42350, 52800, 37800, 55200, 32400, 55800, 26400, 54600, 21000, 53400, 18000, +//50400, 14400, 47400, 12000, 42600, 9600, 39000, 9000, 36000, 9000, 34775, 9125, +//34300, 5600, 30000, 6600, 25800, 8400, 22025, 11350, 18725, 15125, 16200, 20400, +//15000, 24600, 15000, 30600, 16800, 36600, 20400, 42600, 25800, 46800, 31200, 49200, +//38400, 49800, 45000, 48600, 51000, 45000, 55475, 40225, 58200, 34800, 59400, 30000, +//59400, 25200, 58200, 19800, 55200, 14400, 52225, 11150, 47400, 7800, 44175, 6500, +//40200, 5400, 38400, 5400, 37200, 5400, 0, 0 }; +// std::vector > spiralpoints; +// for(unsigned int i = 0; i < 100000; i += 2) { +// point_data pt(spiralcoords[i], spiralcoords[i+1]); +// if(pt == point_data (0, 0)) break; +// spiralpoints.push_back(pt); +// } +// polygon_data spiralpoly; +// spiralpoly.set(spiralpoints.begin(), spiralpoints.end()); +// polygon_set_data handset; +// handset += handpoly; +// polygon_set_data spiralset; +// spiralset += spiralpoly; +// polygon_set_data xorset = handset ^ spiralset; +// std::vector > polys; +// polys += xorset; +// std::cout << polys.size() << std::endl; +// for(unsigned int i = 0; i < polys.size(); ++i) +// std::cout << polys[i] << std::endl; +//} + +bool testDirectionalSize() { + { + PolygonSet ps(VERTICAL); + ps += Rectangle(0, 0, 100, 100); + ps.resize(0, -10, 0, -10); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(0, 0, 90, 90) << std::endl; + if(rects[0] != Rectangle(0, 0, 90, 90)) return false; + } + { + PolygonSet ps(VERTICAL); + ps += Rectangle(0, 0, 100, 100); + ps.resize(0, 0, 0, -10); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(0, 0, 100, 90) << std::endl; + if(rects[0] != Rectangle(0, 0, 100, 90)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(0, -10, 0, 0); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(0, 0, 90, 100) << std::endl; + if(rects[0] != Rectangle(0, 0, 90, 100)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(0, 0, -10, 0); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(0, 10, 100, 100) << std::endl; + if(rects[0] != Rectangle(0, 10, 100, 100)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(-10, 0, 0, 0); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(10, 0, 100, 100) << std::endl; + if(rects[0] != Rectangle(10, 0, 100, 100)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(-10, 10, 0, 0); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(10, 0, 110, 100) << std::endl; + if(rects[0] != Rectangle(10, 0, 110, 100)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(-10, 10, 10, -10); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(10, -10, 110, 90) << std::endl; + if(rects[0] != Rectangle(10, -10, 110, 90)) return false; + } + { + PolygonSet ps; + ps += Rectangle(0, 0, 100, 100); + ps.resize(10, 10, -10, -10); + std::vector rects; + ps.get(rects); + if(rects.size() != 1) return false; + std::cout << rects[0] << std::endl; + std::cout << Rectangle(-10, 10, 110, 90) << std::endl; + if(rects[0] != Rectangle(-10, 10, 110, 90)) return false; + } + return true; +} + +bool testMaxCover() { + std::vector rects; + rects.push_back(Rectangle(Interval(60, 124), Interval( 1, 3))); + rects.push_back(Rectangle(Interval(59, 83), Interval( 9, 28))); + rects.push_back(Rectangle(Interval(90, 124), Interval( 3, 29))); + rects.push_back(Rectangle(Interval(64, 124), Interval( 29, 35))); + rects.push_back(Rectangle(Interval(64, 102), Interval( 35, 49))); + rects.push_back(Rectangle(Interval(1, 20), Interval( 44, 60))); + rects.push_back(Rectangle(Interval(50, 102), Interval( 49, 71))); + rects.push_back(Rectangle(Interval(49, 102), Interval( 71, 72))); + rects.push_back(Rectangle(Interval(49, 94), Interval( 72, 75))); + rects.push_back(Rectangle(Interval(50, 74), Interval( 75, 81))); + rects.push_back(Rectangle(Interval(90, 127), Interval( 75, 81))); + rects.push_back(Rectangle(Interval(50, 127), Interval( 81, 82))); + rects.push_back(Rectangle(Interval(3, 7), Interval( 60, 88))); + rects.push_back(Rectangle(Interval(50, 92), Interval( 82, 94))); + rects.push_back(Rectangle(Interval(58, 92), Interval( 94, 111))); + std::vector expected_result; + expected_result.push_back(Rectangle(Interval(60, 124), Interval( 1, 3))); + expected_result.push_back(Rectangle(Interval(90, 124), Interval( 1, 35))); + expected_result.push_back(Rectangle(Interval(90, 102), Interval( 1, 72))); + expected_result.push_back(Rectangle(Interval(90, 94 ), Interval(1 ,82))); + expected_result.push_back(Rectangle(Interval(90, 92), Interval( 1, 111))); + expected_result.push_back(Rectangle(Interval(59, 83 ), Interval(9, 28))); + expected_result.push_back(Rectangle(Interval(64, 124), Interval( 29, 35))); + expected_result.push_back(Rectangle(Interval(64, 102), Interval( 29, 72))); + expected_result.push_back(Rectangle(Interval(64, 94), Interval( 29, 75))); + expected_result.push_back(Rectangle(Interval(64, 74), Interval( 29, 111))); + expected_result.push_back(Rectangle(Interval(1, 20), Interval( 44, 60))); + expected_result.push_back(Rectangle(Interval(3, 7), Interval( 44, 88))); + expected_result.push_back(Rectangle(Interval(50, 102 ), Interval(49, 72))); + expected_result.push_back(Rectangle(Interval(50, 94), Interval( 49, 75))); + expected_result.push_back(Rectangle(Interval(50, 74), Interval( 49, 94))); + expected_result.push_back(Rectangle(Interval(58, 74), Interval( 49, 111))); + expected_result.push_back(Rectangle(Interval(49, 102 ), Interval(71, 72))); + expected_result.push_back(Rectangle(Interval(49, 94 ), Interval(71, 75))); + expected_result.push_back(Rectangle(Interval(90, 127), Interval( 75, 82))); + expected_result.push_back(Rectangle(Interval(50, 127), Interval( 81, 82))); + expected_result.push_back(Rectangle(Interval(50, 92), Interval( 81, 94))); + expected_result.push_back(Rectangle(Interval(58, 92), Interval( 81, 111))); + std::vector result; + get_max_rectangles(result, rects); + std::cout << "result XOR clean: " << equivalence(result, rects) << std::endl; + std::cout << "expected result XOR clean: " << equivalence(expected_result, rects) << std::endl; + std::vector& output = result; + std::vector& voutput = expected_result; + std::sort(output.begin(), output.end(), less_rectangle_concept< Rectangle, Rectangle>()); + std::sort(voutput.begin(), voutput.end(), less_rectangle_concept< Rectangle, Rectangle>()); + if(output != voutput) { + std::cerr << "Max Rectangle TEST failed\n"; + for(unsigned int i = 0; i < output.size(); ++i) { + std::cerr << output[i] << std::endl; + } + std::cerr << "Incorrect result\n"; + for(unsigned int i = 0; i < voutput.size(); ++i) { + std::cerr << voutput[i] << std::endl; + } + std::cerr << "Max Rectangle TEST failed\n"; + for(unsigned int i = 0; i < rects.size(); ++i) { + std::cout << rects[i] << std::endl; + } + return false; + } + return true; +} + +void max_cover_stress_test() { + for(unsigned int k = 3; k < 20; k++) { + for(unsigned int i = 0; i < k * k; ++i) { + std::vector rects, result; + //std::cout << "test " << i << std::endl; + for(unsigned int j = 0; j < k; ++j) { + int x1 = rand() % 100; + int x2 = rand() % 50; + int y1 = rand() % 100; + int y2 = rand() % 50; + rects.push_back(Rectangle(x1, y1, x1+x2, y1+y2)); + //std::cout << rects.back() << std::endl; + } + get_max_rectangles(result, rects); + } + } +} + +// namespace boost { namespace polygon{ +// template +// struct view_of {}; + +// template +// struct view_of { +// const T* t; +// view_of(const T& obj) : t(&obj) {} +// typedef typename polygon_traits::coordinate_type coordinate_type; +// typedef typename polygon_traits::iterator_type iterator_type; +// typedef typename polygon_traits::point_type point_type; + +// /// Get the begin iterator +// inline iterator_type begin() const { +// return polygon_traits::begin_points(*t); +// } + +// /// Get the end iterator +// inline iterator_type end() const { +// return polygon_traits::end_points(*t); +// } + +// /// Get the number of sides of the polygon +// inline unsigned int size() const { +// return polygon_traits::size(*t); +// } + +// /// Get the winding direction of the polygon +// inline winding_direction winding() const { +// return polygon_traits::winding(*t); +// } +// }; + +// template +// view_of view_as(const T2& obj) { return view_of(obj); } + +// template +// struct geometry_concept > { +// typedef polygon_45_concept type; +// }; + +// template +// struct view_of { +// const T* t; +// view_of(const T& obj) : t(&obj) {} +// typedef typename polygon_traits::coordinate_type coordinate_type; +// typedef typename polygon_traits::iterator_type iterator_type; +// typedef typename polygon_traits::point_type point_type; +// typedef iterator_points_to_compact compact_iterator_type; + +// /// Get the begin iterator +// inline compact_iterator_type begin_compact() const { +// return compact_iterator_type(polygon_traits::begin_points(*t), +// polygon_traits::end_points(*t)); +// } + +// /// Get the end iterator +// inline compact_iterator_type end_compact() const { +// return compact_iterator_type(polygon_traits::end_points(*t), +// polygon_traits::end_points(*t)); +// } + +// /// Get the number of sides of the polygon +// inline unsigned int size() const { +// return polygon_traits::size(*t); +// } + +// /// Get the winding direction of the polygon +// inline winding_direction winding() const { +// return polygon_traits::winding(*t); +// } +// }; + +// template +// struct geometry_concept > { +// typedef polygon_90_concept type; +// }; +// }} +using namespace gtl; + +//this test fails and I'd like to get it to pass +bool test_colinear_duplicate_points() { + Point pts[6] = { Point(0, 10), Point(0, 0), Point(100, 0), Point(100, 100), Point(0, 100), Point(0, 10)}; + Polygon45 p1; + p1.set(pts, pts+5); + Polygon45 pg; + pg.set(pts, pts+6); + Polygon45 p2; + p2.set(pts+1, pts+6); + std::cout << p2 << std::endl; + if(!equivalence(view_as(p2), view_as(pg))) return false; + std::cout << p1 << std::endl; + if(!equivalence(view_as(p1), view_as(pg))) return false; + return true; +} + +bool test_extents() { + PolygonSet psT(gtl::VERTICAL); + //int xy[] = { 126, 69, 54, 69, 54, 81, 126, 81 }; + //CPolygonQuery polygon(0, 4, xy); + //Rectangle rectIn(54, 69, 126, 81); + polygon_data polygon; + std::vector pts; + pts.push_back(Point(126, 69)); + pts.push_back(Point(54, 69)); + pts.push_back(Point(54, 81)); + pts.push_back(Point(126, 81)); + set_points(polygon, pts.begin(), pts.end()); + psT.insert(view_as(polygon)); + + Rectangle rect, rect2; + psT.extents(rect2); + gtl::extents(rect, psT); + + if (rect != rect2) { + std::cout << "gtl::Rectangles differ: " << gtl::xl(rect) << " " << gtl::xh(rect) << " " << gtl::yl(rect) << " " << gtl::yh(rect) << std::endl; + std::cout << " " << gtl::xl(rect2) << " " << gtl::xh(rect2) << " " << gtl::yl(rect2) << " " << gtl::yh(rect2) << std::endl; + return false; + } + return true; +} + +bool test_extents2() { + Polygon45Set psT; + Point xy[] = { Point(130, 50), Point(50, 50), Point(50, 100), Point(119, 100), + Point(119, 59), Point(89, 89), Point(59, 59), Point(119, 59), Point(119, 100), Point(130, 100) }; + Polygon45 polygon(xy, xy+10); + + psT.insert(polygon); + psT += 2; + + Rectangle rect, rect2; + psT.extents(rect2); + gtl::extents(rect, psT); + std::cout << "Extents: " << gtl::xl(rect) << " " << gtl::xh(rect) << " " << gtl::yl(rect) << " " << gtl::yh(rect) << std::endl; + std::cout << "Extents: " << gtl::xl(rect2) << " " << gtl::xh(rect2) << " " << gtl::yl(rect2) << " " << gtl::yh(rect2) << std::endl; + std::vector pwhs; + psT.get(pwhs); + for(unsigned int i = 0; i < pwhs.size(); ++i) { + std::cout << pwhs[i] << std::endl; + } + return gtl::equivalence(rect, rect2); +} + +int main() { + test_view_as(); + //this test fails and I'd like to get it to pass + //if(!test_colinear_duplicate_points()) return 1; + if(!test_extents2()) return 1; + if(!test_extents()) return 1; + if(!testMaxCover()) return 1; + //max_cover_stress_test(); //does not include functional testing + if(!testDirectionalSize()) return 1; + testHand(); + //testHandFloat(); + if(!testpip()) return 1; + { + PolygonSet ps; + Polygon p; + assign(ps, p); + } + if(!testViewCopyConstruct()) return 1; + if(!test_grow_and_45()) return 1; + if(!test_self_xor_45()) return 1; + if(!test_self_xor()) return 1; + if(!test_directional_resize()) return 1; + if(!test_scaling_by_floating()) return 1; + if(!test_SQRT1OVER2()) return 1; + if(!test_get_trapezoids()) return 1; + if(!test_get_rectangles()) return 1; + if(!test_45_concept_interact()) return 1; + if(!test_45_touch_r()) return 1; + if(!test_45_touch_ur()) return 1; + if(!test_45_touch()) return 1; + if(!test_45_touch_boundaries()) return 1; + { + Point pts[] = {Point(0,0), Point(5, 5), Point(5, 0)}; + Polygon45 p45(pts, pts+3); + pts[1] = Point(0, 5); + Polygon45 p452(pts, pts+3); + if(!test_two_polygons(p45,p452)) return 1; + pts[2] = Point(5,5); + p45.set(pts, pts+3); + if(!test_two_polygons(p45,p452)) return 1; + pts[0] = Point(5,0); + p452.set(pts, pts+3); + if(!test_two_polygons(p45, p452)) return 1; + Point pts2[] = {Point(0,5), Point(5, 5), Point(5, 0)}; + Point pts3[] = {Point(0,0), Point(5, 5), Point(5, 0)}; + p45.set(pts2, pts2 + 3); + p452.set(pts3, pts3+3); + if(!test_two_polygons(p45, p452)) return 1; + Point pts4[] = {Point(0, 5), Point(3, 2), Point(3,5)}; + Point pts5[] = {Point(0,0), Point(5, 5), Point(5, 0)}; + p45.set(pts4, pts4+3); + p452.set(pts5, pts5+3); + if(!test_two_polygons(p45, p452)) return 1; + } + { + std::vector > pts; + pts.push_back(point_data(0, 0)); + pts.push_back(point_data(10, 0)); + pts.push_back(point_data(10, 10)); + pts.push_back(point_data(0, 10)); + std::vector > pts2; + pts2.push_back(point_data(0, 0)); + pts2.push_back(point_data(10, 10)); + pts2.push_back(point_data(0, 20)); + pts2.push_back(point_data(-10, 10)); + std::vector > pts3; + pts3.push_back(point_data(0, 0)); + pts3.push_back(point_data(10, 11)); + pts3.push_back(point_data(0, 20)); + pts3.push_back(point_data(-100, 8)); + polygon_data p, p1; p.set(pts3.begin(), pts3.end()); + polygon_45_data p45, p451; p45.set(pts2.begin(), pts2.end()); + polygon_90_data p90, p901; p90.set(pts.begin(), pts.end()); + polygon_with_holes_data pwh, pwh1; pwh.set(pts3.begin(), pts3.end()); + polygon_45_with_holes_data p45wh, p45wh1; p45wh.set(pts2.begin(), pts2.end()); + polygon_90_with_holes_data p90wh, p90wh1; p90wh.set(pts.begin(), pts.end()); + assign(p, p90); + assign(p, p45); + assign(p1, p); + //illegal: assign(p, p90wh); + //illegal: assign(p, p45wh); + //illegal: assign(p, pwh); + + assign(p45, p90); + assign(p451, p45); + //illegal: assign(p45, p); + //illegal: assign(p45, p90wh); + //illegal: assign(p45, p45wh); + //illegal: assign(p45, pwh); + + assign(p901, p90); + //illegal: assign(p90, p45); + //illegal: assign(p90, p); + //illegal: assign(p90, p90wh); + //illegal: assign(p90, p45wh); + //illegal: assign(p90, pwh); + + assign(pwh, p90); + assign(pwh, p45); + assign(pwh, p); + assign(pwh, p90wh); + assign(pwh, p45wh); + assign(pwh1, pwh); + + assign(p45wh, p90); + assign(p45wh, p45); + //illegal: assign(p45wh, p); + assign(p45wh, p90wh); + assign(p45wh1, p45wh); + //illegal: assign(p45wh, pwh); + + assign(p90wh, p90); + //illegal: assign(p90wh, p45); + //illegal: assign(p90wh, p); + assign(p90wh1, p90wh); + //illegal: assign(p90wh, p45wh); + //illegal: assign(p90wh, pwh); + pts.clear(); + pts.push_back(point_data(0, 0)); + pts.push_back(point_data(3, 0)); + pts.push_back(point_data(0, 1)); + p.set(pts.begin(), pts.end()); + std::cout << std::endl; std::cout << (area(p90)); + std::cout << std::endl; std::cout << (area(p45)); + std::cout << std::endl; std::cout << (area(p)); + std::cout << std::endl; std::cout << (area(p90wh)); + std::cout << std::endl; std::cout << (area(p45wh)); + std::cout << std::endl; std::cout << (area(pwh)); + std::cout << std::endl; + point_data pt(1, 1); + std::cout << contains(p, pt) << std::endl; + std::cout << contains(p90, pt) << std::endl; + + interval_data ivl = construct >(0, 10); + std::cout << get(ivl, LOW) << std::endl; + set(ivl, HIGH, 20); + + std::cout << perimeter(p) << std::endl; + if(winding(p) == LOW) std::cout << "LOW" << std::endl; + if(winding(p) == HIGH) std::cout << "HIGH" << std::endl; + rectangle_data rd; + std::cout << extents(rd, p) << std::endl; + std::cout << rd << std::endl; + + boolean_op::testBooleanOr(); + + std::vector > rects1, rects2; + rects2.push_back(rectangle_data(0, 0, 10, 10)); + print_is_polygon_90_set_concept((polygon_90_set_data())); + print_is_mutable_polygon_90_set_concept((polygon_90_set_data())); + print_is_polygon_90_set_concept((polygon_90_data())); + print_is_polygon_90_set_concept((std::vector >())); + assign(rects1, rects2); + polygon_90_set_data ps90; + assign(ps90, rects2); + assign(rects2, ps90); + assign(ps90, p90); + assign(rects2, p90); + std::cout << p90 << std::endl; + for(unsigned int i = 0; i < rects2.size(); ++i) { + std::cout << rects2[i] << std::endl; + } + bloat(rects2, 10); + shrink(rects2[0], 10); + for(unsigned int i = 0; i < rects2.size(); ++i) { + std::cout << rects2[i] << std::endl; + } + move(rects2[0], HORIZONTAL, 30); + assign(rects1, rects2 + p90); + std::cout << "result of boolean or\n"; + for(unsigned int i = 0; i < rects1.size(); ++i) { + std::cout << rects1[i] << std::endl; + } + rects1 -= p90; + std::cout << "result of boolean not\n"; + for(unsigned int i = 0; i < rects1.size(); ++i) { + std::cout << rects1[i] << std::endl; + } + rects1 += p90; + std::cout << "result of boolean OR\n"; + for(unsigned int i = 0; i < rects1.size(); ++i) { + std::cout << rects1[i] << std::endl; + } + rects1 *= p90; + std::cout << "result of boolean AND\n"; + for(unsigned int i = 0; i < rects1.size(); ++i) { + std::cout << rects1[i] << std::endl; + } + rects1 ^= rects2; + std::cout << "result of boolean XOR\n"; + for(unsigned int i = 0; i < rects1.size(); ++i) { + std::cout << rects1[i] << std::endl; + } + rects2.clear(); + get_max_rectangles(rects2, p90); + std::cout << "result of max rectangles\n"; + for(unsigned int i = 0; i < rects2.size(); ++i) { + std::cout << rects2[i] << std::endl; + } + rects2.clear(); + //operator += and -= don't support polygons, so + and - should not exist +// rects2 += p90 + 6; +// std::cout << "result of resize\n"; +// for(unsigned int i = 0; i < rects2.size(); ++i) { +// std::cout << rects2[i] << std::endl; +// } +// std::cout << "result of resize\n"; + std::vector > polyswh1, polyswh2; +// polyswh1 += p90 -2; +// for(unsigned int i = 0; i < polyswh1.size(); ++i) { +// std::cout << polyswh1[i] << std::endl; +// } +// std::cout << "result of resize\n"; + std::vector > polys1, polys2; + polys1 += p90; + polys1 -= 2; +// polys1 += p90 -2; + for(unsigned int i = 0; i < polys1.size(); ++i) { + std::cout << polys1[i] << std::endl; + } + + boolean_op_45::testScan45(std::cout); + polygon_45_formation::testPolygon45Formation(std::cout); + polygon_45_formation::testPolygon45Tiling(std::cout); + + axis_transformation atr; + transform(p, atr); + transform(p45, atr); + transform(p90, atr); + transform(pwh, atr); + transform(p45wh, atr); + transform(p90wh, atr); + scale_up(p, 2); + scale_up(p45, 2); + scale_up(p90, 2); + scale_up(pwh, 2); + scale_up(p45wh, 2); + scale_up(p90wh, 2); + scale_down(p, 2); + scale_down(p45, 2); + scale_down(p90, 2); + scale_down(pwh, 2); + scale_down(p45wh, 2); + scale_down(p90wh, 2); + std::vector > p45s1, p45s2; + std::cout << equivalence(p45s1, p45s2) << std::endl; + std::cout << equivalence(p45, p45wh) << std::endl; + std::cout << equivalence(p90, p45wh) << std::endl; + gtl::assign(p45s1, p90); + p90 = polys1[0]; + move(p90, orientation_2d(HORIZONTAL), 8); + std::cout << p90 << std::endl << p45wh << std::endl; + polygon_45_set_data ps45 = p90 + p45wh; + assign(p45s1, ps45); + std::cout << "result\n"; + for(unsigned int i = 0; i < p45s1.size(); ++i) { + std::cout << p45s1[i] << std::endl; + } + std::cout << equivalence(p, pwh) << std::endl; + std::cout << equivalence(p90, pwh) << std::endl; + std::cout << equivalence(p45, pwh) << std::endl; + std::cout << equivalence(pwh, pwh) << std::endl; + p + pwh; + p90 + pwh; + p45 + pwh; + std::cout << testInterval() << std::endl; + std::cout << testRectangle() << std::endl; + std::cout << testPolygon() << std::endl; + std::cout << testPropertyMerge() << std::endl; + std::cout << testPolygonAssign() << std::endl; + std::cout << testPolygonWithHoles() << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationRect(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationP1(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationP2(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationPolys(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationSelfTouch1(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationSelfTouch2(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationSelfTouch3(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testSegmentIntersection(std::cout)) << std::endl; + std::cout << (property_merge::test_insertion(std::cout)) << std::endl; + std::cout << (line_intersection::test_verify_scan(std::cout)) << std::endl; + std::cout << (line_intersection::test_validate_scan(std::cout)) << std::endl; + std::cout << (scanline::test_scanline(std::cout)) << std::endl; + std::cout << (property_merge::test_merge(std::cout)) << std::endl; + std::cout << (property_merge::test_intersection(std::cout)) << std::endl; + std::cout << (polygon_arbitrary_formation::testPolygonArbitraryFormationColinear(std::cout)) << std::endl; + std::cout << (property_merge::test_manhattan_intersection(std::cout)) << std::endl; + std::cout << (test_arbitrary_boolean_op(std::cout)) << std::endl; + } + { + polygon_set_data psd; + rectangle_data rect; + set_points(rect, point_data(0, 0), point_data(10, 10)); + psd.insert(rect); + polygon_set_data psd2; + set_points(rect, point_data(5, 5), point_data(15, 15)); + psd2.insert(rect); + std::vector > pv; + polygon_set_data psd3; + psd3 = psd + psd2; + psd3.get(pv); + for(unsigned int i = 0; i < pv.size(); ++i) { + std::cout << pv[i] << std::endl; + } + psd += psd2; + pv.clear(); + psd3.get(pv); + for(unsigned int i = 0; i < pv.size(); ++i) { + std::cout << pv[i] << std::endl; + } + } + { + polygon_90_set_data psd; + rectangle_data rect; + set_points(rect, point_data(0, 0), point_data(10, 10)); + psd.insert(rect); + polygon_90_set_data psd2; + set_points(rect, point_data(5, 5), point_data(15, 15)); + psd2.insert(rect); + std::vector > pv; + interact(psd, psd2); + assign(pv, psd); + for(unsigned int i = 0; i < pv.size(); ++i) { + std::cout << pv[i] << std::endl; + } + + connectivity_extraction_90 ce; + ce.insert(pv[0]); + ce.insert(psd2); + std::vector > graph(2); + ce.extract(graph); + if(graph[0].size() == 1) std::cout << "connectivity extraction is alive\n"; + + //std::vector > lobs; + //get_max_rectangles(lobs, psd); + //if(lobs.size() == 1) std::cout << "max rectangles is alive\n"; + + std::vector > rv; + rv.push_back(rect); + set_points(rect, point_data(0, 0), point_data(10, 10)); + rv.push_back(rect); + self_intersect(rv); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + + assign(rv, rv + 1); + std::cout << rv.size() << std::endl; + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + assign(rv, rv - 1); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + rv += 1; + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + rv -= 1; + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + rv.clear(); + set_points(rect, point_data(0, 0), point_data(10, 10)); + rv.push_back(rect); + set_points(rect, point_data(12, 12), point_data(20, 20)); + rv.push_back(rect); + grow_and(rv, 7); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + std::cout << area(rv) << std::endl; + std::cout << area(rv) << std::endl; + + scale_up(rv, 10); + std::cout << area(rv) << std::endl; + scale_down(rv, 7); + std::cout << area(rv) << std::endl; + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + keep(rv, 290, 300, 7, 24, 7, 24); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + keep(rv, 300, 310, 7, 24, 7, 24); + if(rv.empty()) std::cout << "keep is alive\n"; + } + { +// typedef int Unit; +// typedef point_data Point; +// typedef interval_data Interval; +// typedef rectangle_data Rectangle; +// typedef polygon_90_data Polygon; +// typedef polygon_90_with_holes_data PolygonWithHoles; +// typedef polygon_45_data Polygon45; +// typedef polygon_45_with_holes_data Polygon45WithHoles; +// typedef polygon_90_set_data PolygonSet; +// //typedef polygon_45_set_data Polygon45Set; +// typedef axis_transformation AxisTransform; +// typedef transformation Transform; + //test polygon45 area, polygon45 with holes area + std::vector pts; + pts.clear(); + pts.push_back(Point(10, 10)); + pts.push_back(Point(15, 10)); + pts.push_back(Point(10, 15)); + Polygon45 polyHole; + polyHole.set(pts.begin(), pts.end()); + pts.clear(); + pts.push_back(Point(10, 0)); + pts.push_back(Point(20, 10)); + pts.push_back(Point(20, 30)); + pts.push_back(Point(0, 50)); + pts.push_back(Point(0, 10)); + Polygon45WithHoles polyWHoles; + polyWHoles.set(pts.begin(), pts.end()); + polyWHoles.set_holes(&polyHole, (&polyHole)+1); + std::cout << polyWHoles << std::endl; + std::cout << area(polyWHoles) << std::endl; + std::cout << area(polyWHoles) << std::endl; + //test polygon45, polygon45with holes transform + AxisTransform atr(AxisTransform::EAST_SOUTH); + Polygon45WithHoles p45wh(polyWHoles); + transform(polyWHoles, atr); + std::cout << polyWHoles << std::endl; + Transform tr(atr); + tr.invert(); + transform(polyWHoles, tr); + std::cout << polyWHoles << std::endl; + if(area(polyWHoles) != 687.5) return 1; + //test polygon, polygon with holes transform + Polygon ph; + assign(ph, Rectangle(10, 10, 20, 20)); + PolygonWithHoles pwh; + assign(pwh, Rectangle(0, 0, 100, 100)); + pwh.set_holes(&ph, (&ph)+1); + std::cout << area(pwh) << std::endl; + transform(pwh, atr); + std::cout << pwh << std::endl; + std::cout << area(pwh) << std::endl; + transform(pwh, tr); + std::cout << pwh << std::endl; + std::cout << area(pwh) << std::endl; + if(area(pwh) != 9900) return 1; + + //test point scale up / down + Point pt(10, 10); + scale_up(pt, 25); + if(pt != Point(250, 250)) return 1; + std::cout << pt << std::endl; + scale_down(pt, 25); + if(pt != Point(10, 10)) return 1; + std::cout << pt << std::endl; + scale_down(pt, 25); + if(pt != Point(0, 0)) return 1; + std::cout << pt << std::endl; + + //test polygon, polygon with holes scale up down + PolygonWithHoles tmpPwh(pwh); + scale_up(pwh, 25); + std::cout << pwh << std::endl; + scale_down(pwh, 25); + if(area(pwh) != area(tmpPwh)) return 1; + std::cout << pwh << std::endl; + scale_down(pwh, 25); + std::cout << pwh << std::endl; + //test polygon45, polygon45 with holes is45 + std::cout << is_45(polyHole) << std::endl; + if(is_45(polyHole) != true) return 1; + pts.clear(); + pts.push_back(Point(10, 10)); + pts.push_back(Point(15, 10)); + pts.push_back(Point(10, 16)); + polyHole.set(pts.begin(), pts.end()); + std::cout << is_45(polyHole) << std::endl; + if(is_45(polyHole) != false) return 1; + //test polygon45, polygon45 with holes snap 45 + snap_to_45(polyHole); + std::cout << is_45(polyHole) << std::endl; + if(is_45(polyHole) != true) return 1; + std::cout << polyHole << std::endl; + //test polygon45, polygon45 with holes scalue up down + scale_up(polyHole, 10000); + std::cout << polyHole << std::endl; + scale_down(polyHole, 3); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 5); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 7); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 13); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_up(polyHole, 3); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + pts.clear(); + pts.push_back(Point(11, 1)); + pts.push_back(Point(21, 11)); + pts.push_back(Point(11, 21)); + pts.push_back(Point(1, 11)); + polyHole.set(pts.begin(), pts.end()); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 3); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_up(polyHole, 10000); + std::cout << polyHole << std::endl; + scale_down(polyHole, 3); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 5); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 7); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 13); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_up(polyHole, 3); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + scale_down(polyHole, 2); + std::cout << is_45(polyHole) << " " << polyHole << std::endl; + if(is_45(polyHole) != true) return 1; + + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_up(polyWHoles, 100013); + std::cout << polyWHoles << std::endl; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 3); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + scale_down(polyWHoles, 2); + std::cout << is_45(polyWHoles) << " " << polyWHoles << std::endl; + if(is_45(polyWHoles) != true) return 1; + + std::cout << (boolean_op_45::testScan45(std::cout)) << std::endl; + std::cout << (polygon_45_formation::testPolygon45Formation(std::cout)) << std::endl; + std::cout << (polygon_45_formation::testPolygon45Tiling(std::cout)) << std::endl; + + + { + PolygonSet ps; + Rectangle rect; + ps.insert(Rectangle(0, 0, 10, 10)); + std::cout << area(ps) << std::endl; + if(area(ps) != 100) return 1; + scale_up(ps, 3); + std::cout << area(ps) << std::endl; + if(area(ps) != 900) return 1; + scale_down(ps, 2); + std::cout << area(ps) << std::endl; + if(area(ps) != 225) return 1; + transform(ps, atr); + std::vector rv; + rv.clear(); + ps.get(rv); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + transform(ps, tr); + rv.clear(); + ps.get(rv); + if(rv.size() == 1) { + assign(rect, rv.back()); + std::cout << rect << std::endl; + } + } + //test polygon45set transform + pts.clear(); + pts.push_back(Point(10, 10)); + pts.push_back(Point(15, 10)); + pts.push_back(Point(10, 15)); + polyHole.set(pts.begin(), pts.end()); + Polygon45Set ps451, ps452; + ps451.insert(polyHole); + ps452 = ps451; + std::cout << (ps451 == ps452) << std::endl; + if(ps451 != ps452) return 1; + ps451.transform(atr); + std::cout << (ps451 == ps452) << std::endl; + if(ps451 == ps452) return 1; + ps451.transform(tr); + std::cout << (ps451 == ps452) << std::endl; + if(ps451 != ps452) return 1; + + //test polygon45set area + std::cout << area(ps451) << std::endl; + if(area(ps451) != 12.5) return 1; + //test polygon45set scale up down + ps451.scale_up(3); + std::cout << area(ps451) << std::endl; + if(area(ps451) != 112.5) return 1; + ps451.scale_down(2); + std::cout << area(ps451) << std::endl; + if(area(ps451) != 32) return 1; + //test polygonset scalue up down + } + { + std::cout << (testPolygon45SetRect()) << std::endl; + testPolygon45SetPerterbation(); //re-enable after non-intersection fix + testPolygon45Set(); + testPolygon45SetDORA(); //re-enable after non-intersection fix + polygon_45_set_data ps45_1, ps45_2, ps45_3; + ps45_1.insert(rectangle_data(0, 0, 10, 10)); + ps45_2.insert(rectangle_data(5, 5, 15, 15)); + std::vector > p45s; + ps45_3 = ps45_1 | ps45_2; + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + p45s.clear(); + ps45_3 = ps45_1 + ps45_2; + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + p45s.clear(); + ps45_3 = ps45_1 * ps45_2; + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + p45s.clear(); + ps45_3 = ps45_1 - ps45_2; + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + p45s.clear(); + ps45_3 = ps45_1 ^ ps45_2; + ps45_3.get(p45s); + if(p45s.size() == 2) std::cout << p45s[0] << " " << p45s[1] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + std::vector > pts; + pts.clear(); + pts.push_back(point_data(7, 0)); + pts.push_back(point_data(20, 13)); + pts.push_back(point_data(0, 13)); + pts.push_back(point_data(0, 0)); + polygon_45_data p45_1(pts.begin(), pts.end()); + ps45_3.clear(); + ps45_3.insert(p45_1); + p45s.clear(); + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + ps45_3 += 1; + p45s.clear(); + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + ps45_3 -= 1; + p45s.clear(); + ps45_3.get(p45s); + if(p45s.size()) std::cout << p45s[0] << std::endl; + else { + std::cout << "test failed\n"; + return 1; + } + } + { + polygon_90_set_data p90sd; + p90sd.insert(rectangle_data(0, 0, 10, 10)); + std::vector > rects; + std::vector > polys90; + std::vector > pwhs90; + assign(rects, p90sd); + assign(polys90, p90sd); + assign(pwhs90, p90sd); + std::cout << equivalence(rects, polys90) << std::endl; + std::cout << equivalence(pwhs90, polys90) << std::endl; + pwhs90.clear(); + assign(pwhs90, polys90); + std::cout << equivalence(pwhs90, polys90) << std::endl; + } + { + polygon_45_set_data p45sd; + p45sd.insert(rectangle_data(0, 0, 10, 10)); + std::vector > rects; + std::vector > polys45; + std::vector > pwhs45; + get_trapezoids(polys45, p45sd); + assign(polys45, p45sd); + assign(pwhs45, p45sd); + std::cout << equivalence(pwhs45, polys45) << std::endl; + pwhs45.clear(); + assign(pwhs45, polys45); + std::cout << equivalence(pwhs45, polys45) << std::endl; + } + { + polygon_set_data psd; + psd.insert(rectangle_data(0, 0, 10, 10)); + std::vector > polys; + std::vector > pwhs; + assign(polys, psd); + assign(pwhs, psd); + std::cout << equivalence(pwhs, polys) << std::endl; + pwhs.clear(); + assign(pwhs, polys); + std::cout << equivalence(pwhs, polys) << std::endl; + } + { + typedef point_3d_data Point3D; + Point3D p3d1(0, 1, 3), p3d2(0, 1, 2); + if(equivalence(p3d1, p3d2)) return 1; + if(euclidean_distance(p3d1, p3d2) != 1) return 1; + if(euclidean_distance(p3d1, p3d2, PROXIMAL) != 1) return 1; + if(manhattan_distance(p3d1, p3d2) != 1) return 1; + assign(p3d1, p3d2); + if(!equivalence(p3d1, p3d2)) return 1; + p3d1 = construct(x(p3d1), y(p3d1), z(p3d1)); + if(!equivalence(p3d1, p3d2)) return 1; + convolve(p3d1, p3d2); + if(equivalence(p3d1, p3d2)) return 1; + deconvolve(p3d1, p3d2); + if(!equivalence(p3d1, p3d2)) return 1; + if(get(p3d1, PROXIMAL) != 2) return 1; + scale(p3d1, anisotropic_scale_factor(2, 2, 2)); + if(equivalence(p3d1, p3d2)) return 1; + scale_down(p3d1, 2); + if(!equivalence(p3d1, p3d2)) return 1; + scale_up(p3d1, 2); + if(equivalence(p3d1, p3d2)) return 1; + scale_down(p3d1, 2); + set(p3d1, PROXIMAL, 3); + if(equivalence(p3d1, p3d2)) return 1; + axis_transformation atr = axis_transformation::END; + transform(p3d1, atr); + if(z(p3d1) != -3) return 1; + z(p3d1, 2); + if(!equivalence(p3d1, p3d2)) return 1; + } + { + polygon_90_set_data ps1(HORIZONTAL), ps2(VERTICAL); + ps1 += rectangle_data(0, 0, 10, 120); + assign(ps1, ps2); + std::cout << equivalence(ps1, ps2) << std::endl; + } + { + std::vector > lobs, input; + input.push_back(rectangle_data(0, 0, 10, 10)); + input.push_back(rectangle_data(10, 5, 15, 15)); + get_max_rectangles(lobs, input); + if(lobs.size() == 3) std::cout << "max rectangles is correct\n"; + } + { + polygon_set_data ps1, ps2, ps3; + ps1.insert(rectangle_data(0, 0, 10, 10)); + ps2.insert(rectangle_data(0, 0, 15, 5)); + ps3.insert(rectangle_data(0, 0, 20, 2)); + std::cout << area(ps1 + ps2) << std::endl; + keep(ps1, 0, 100, 0, 100, 0, 100); + if(empty(ps1)) return 1; + rectangle_data bbox; + extents(bbox, ps1); + std::cout << bbox << std::endl; + //resize(ps1, 1); + //shrink(ps1, 1); + //bloat(ps1, 1); + scale_up(ps1, 2); + scale_down(ps1, 2); + axis_transformation atr; + transform(ps1, atr); + std::cout << area(ps1) << std::endl; + if(area(ps1) != 100) return 1; + clear(ps1); + if(!empty(ps1)) return 1; + ps1 = ps2 * ps3; + ps1 *= ps2; + ps1 - ps2; + ps1 -= ps2; + ps1 ^ ps2; + ps1 ^= ps2; + ps1 | ps2; + ps1 |= ps2; + } + { + polygon_45_set_data ps45_1, ps45_2; + ps45_1.insert(rectangle_data(0, 0, 10, 10)); + keep(ps45_1, 0, 1000, 0, 1000, 0, 1000); + std::cout << area(ps45_1) << std::endl; + std::cout << empty(ps45_1) << std::endl; + rectangle_data bbox; + extents(bbox, ps45_1); + std::cout << bbox << std::endl; + resize(ps45_1, 1); + shrink(ps45_1, 1); + bloat(ps45_1, 1); + scale_up(ps45_1, 2); + scale_down(ps45_1, 2); + axis_transformation atr; + transform(ps45_1, atr); + std::cout << area(ps45_1) << std::endl; + if(area(ps45_1) != 144) return 1; + clear(ps45_1); + if(!empty(ps45_1)) return 1; + } + { + std::vector > p45v; + p45v + p45v; + p45v *= p45v; + p45v += p45v; + p45v - p45v; + p45v -= p45v; + p45v ^ p45v; + p45v ^= p45v; + p45v | p45v; + p45v |= p45v; + p45v + 1; + p45v += 1; + p45v - 1; + p45v -= 1; + p45v + (p45v + p45v); + } + { + polygon_45_set_data ps45; + polygon_90_set_data ps90; + std::vector > p90whv; + ps45.insert(ps90); + ps45.insert(p90whv); + ps45.insert(p90whv + p90whv); + + ps45.insert(polygon_90_with_holes_data()); + polygon_with_holes_data pwh; + snap_to_45(pwh); + } + { + point_data pt(1,2); + point_3d_data pt3d(1,2,3); + equivalence(pt, pt3d); + deconvolve(pt, pt3d); + manhattan_distance(pt, pt3d); + move(pt, HORIZONTAL, 1); + scale(pt, anisotropic_scale_factor(2, 2, 2)); + pt = pt3d; + } + { + polygon_90_set_data ps90_1, ps90_2; + ps90_1.insert(rectangle_data(0, 0, 10, 10)); + keep(ps90_1, 0, 1000, 0, 1000, 0, 1000); + std::cout << area(ps90_1) << std::endl; + std::cout << empty(ps90_1) << std::endl; + rectangle_data bbox; + extents(bbox, ps90_1); + std::cout << bbox << std::endl; + resize(ps90_1, 1); + shrink(ps90_1, 1); + bloat(ps90_1, 1); + scale_up(ps90_1, 2); + scale_down(ps90_1, 2); + scale(ps90_1, anisotropic_scale_factor(2, 2, 2)); + scale(ps90_1, anisotropic_scale_factor(0.5, 0.5, 0.5)); + axis_transformation atr; + transform(ps90_1, atr); + std::cout << area(ps90_1) << std::endl; + if(area(ps90_1) != 144) return 1; + clear(ps90_1); + if(!empty(ps90_1)) return 1; + } + if(!nonInteger45StessTest()) return 1; + { + using namespace gtl; + typedef polygon_45_property_merge p45pm; + p45pm::MergeSetData msd; + polygon_45_set_data ps; + ps += rectangle_data(0, 0, 10, 10); + p45pm::populateMergeSetData(msd, ps.begin(), ps.end(), 444); + ps.clear(); + ps += rectangle_data(5, 5, 15, 15); + p45pm::populateMergeSetData(msd, ps.begin(), ps.end(), 333); + std::map, polygon_45_set_data > result; + p45pm::performMerge(result, msd); + int i = 0; + for(std::map, polygon_45_set_data >::iterator itr = result.begin(); + itr != result.end(); ++itr) { + for(std::set::const_iterator itr2 = (*itr).first.begin(); + itr2 != (*itr).first.end(); ++itr2) { + std::cout << *itr2 << " "; + } std::cout << " : "; + std::cout << area((*itr).second) << std::endl; + if(i == 1) { + if(area((*itr).second) != 100) return 1; + } else + if(area((*itr).second) != 300) return 1; + ++i; + } + + + property_merge_45 pm; + pm.insert(rectangle_data(0, 0, 10, 10), 444); + pm.insert(rectangle_data(5, 5, 15, 15), 333); + std::map, polygon_45_set_data > mp; + pm.merge(mp); + i = 0; + for(std::map, polygon_45_set_data >::iterator itr = mp.begin(); + itr != mp.end(); ++itr) { + for(std::set::const_iterator itr2 = (*itr).first.begin(); + itr2 != (*itr).first.end(); ++itr2) { + std::cout << *itr2 << " "; + } std::cout << " : "; + std::cout << area((*itr).second) << std::endl; + if(i == 1) { + if(area((*itr).second) != 25) return 1; + } else + if(area((*itr).second) != 75) return 1; + ++i; + } + std::map, polygon_45_set_data > mp2; + pm.merge(mp2); + i = 0; + for(std::map, polygon_45_set_data >::iterator itr = mp2.begin(); + itr != mp2.end(); ++itr) { + for(std::vector::const_iterator itr2 = (*itr).first.begin(); + itr2 != (*itr).first.end(); ++itr2) { + std::cout << *itr2 << " "; + } std::cout << " : "; + std::cout << area((*itr).second) << std::endl; + if(i == 1) { + if(area((*itr).second) != 25) return 1; + } else + if(area((*itr).second) != 75) return 1; + ++i; + } + } + { + std::cout << trapezoid_arbitrary_formation::testTrapezoidArbitraryFormationRect(std::cout) << std::endl; + std::cout << trapezoid_arbitrary_formation::testTrapezoidArbitraryFormationP1(std::cout) << std::endl; + std::cout << trapezoid_arbitrary_formation::testTrapezoidArbitraryFormationP2(std::cout) << std::endl; + std::cout << trapezoid_arbitrary_formation::testTrapezoidArbitraryFormationPolys(std::cout) << std::endl; + std::cout << polygon_arbitrary_formation::testPolygonArbitraryFormationSelfTouch1(std::cout) << std::endl; + std::cout << trapezoid_arbitrary_formation::testTrapezoidArbitraryFormationSelfTouch1(std::cout) << std::endl; + typedef rectangle_data Rectangle; + polygon_set_data ps; + ps += Rectangle(0, 1, 10, 11); + ps += Rectangle(5, 6, 15, 16); + std::vector > polys; + ps.get_trapezoids(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + ps.transform(axis_transformation(axis_transformation::FLIP_X)); + polys.clear(); + ps.get_trapezoids(polys); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + polys.clear(); + ps.get_trapezoids(polys, HORIZONTAL); + for(unsigned int i = 0; i < polys.size(); ++i) { + std::cout << polys[i] << std::endl; + } + } + + if(!test_aa_touch()) { + std::cout << "test_aa_touch failed\n"; + return 1; + } + if(!test_aa_touch_ur()) { + std::cout << "test_aa_touch_ur failed\n"; + return 1; + } + if(!test_aa_touch_ur()) { + std::cout << "test_aa_touch_ur failed\n"; + return 1; + } + if(!test_aa_touch_r()) { + std::cout << "test_aa_touch_r failed\n"; + return 1; + } + if(!test_aa_touch_boundaries()) { + std::cout << "test_aa_touch_boundaries failed\n"; + return 1; + } + if(!test_aa_concept_interact()) { + std::cout << "test_aa_concept_interact failed\n"; + return 1; + } + + { + polygon_set_data ps; + polygon_90_set_data ps90; + rectangle_data rect(0, 1, 10, 100); + ps.insert(rect); + ps90.insert(rect); + ps.bloat(10); + ps90.bloat(10, 10, 10, 10); + if(!equivalence(ps, ps90)) { + std::cout << "test manhattan vs general resize up failed\n"; + return 1; + } + ps.shrink(10); + ps90.shrink(10, 10, 10, 10); + if(!equivalence(ps, rect)) { + std::cout << "test manhattan vs general resize down failed\n"; + return 1; + } + rectangle_data rect2(3, 4, 6, 80); + ps -= rect2; + ps90 -= rect2; + ps.bloat(1); + ps90.bloat(1, 1, 1, 1); + if(!equivalence(ps, ps90)) { + std::cout << "test manhattan vs general with hole resize up failed\n"; + return 1; + } + ps.shrink(1); + ps90.shrink(1, 1, 1, 1); + if(!equivalence(ps, ps90)) { + std::cout << "test manhattan vs general with hole resize down failed\n"; + return 1; + } + ps.clear(); + polygon_45_data poly; + std::vector > pts; + pts.push_back(point_data(0, 0)); + pts.push_back(point_data(10, 0)); + pts.push_back(point_data(0, 10)); + polygon_45_set_data ps45; + set_points(poly, pts.begin(), pts.end()); + ps.insert(poly); + ps45.insert(poly); + ps.bloat(9); + ps45.resize(9); + if(!equivalence(ps, ps45)) { + std::cout << "test 45 vs general resize up failed\n"; + return 1; + } + ps.shrink(9); + ps45.resize(-9); + if(!equivalence(ps, ps45)) { + std::cout << "test 45 vs general resize down failed\n"; + return 1; + } + pts.clear(); + pts.push_back(point_data(1, 1)); + pts.push_back(point_data(7, 1)); + pts.push_back(point_data(1, 7)); + set_points(poly, pts.begin(), pts.end()); + ps.insert(poly, true); + ps45.insert(poly, true); + ps.bloat(1); + ps45.resize(1); + if(!equivalence(ps, ps45)) { + std::cout << "test 45 vs general resize up with holes failed\n"; + return 1; + } + ps.shrink(1); + ps45.resize(-1); + if(!equivalence(ps, ps45)) { + std::cout << "test 45 vs general resize down with holes failed\n"; + return 1; + } + ps.shrink(10); + ps45.resize(-10); + if(!equivalence(ps, ps45)) { + std::cout << "test 45 vs general resize down 2 with holes failed\n"; + return 1; + } + } + + + std::cout << "ALL TESTS COMPLETE\n"; + return 0; +} From a85f1daab150503d8f4d0c47e676dea1756277bf Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Mon, 21 Jun 2010 22:44:34 +0000 Subject: [PATCH 02/32] restoring images lost during copy from trunk [SVN r63213] --- doc/images/convolution1.PNG | Bin 0 -> 8470 bytes doc/images/convolution2.PNG | Bin 0 -> 15769 bytes doc/images/convolve_edges.PNG | Bin 0 -> 10950 bytes doc/images/perimeter_convolve.PNG | Bin 0 -> 16797 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/images/convolution1.PNG create mode 100644 doc/images/convolution2.PNG create mode 100644 doc/images/convolve_edges.PNG create mode 100644 doc/images/perimeter_convolve.PNG diff --git a/doc/images/convolution1.PNG b/doc/images/convolution1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..410fcb7f5374285838445e5104e614a5ed091a3d GIT binary patch literal 8470 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 literal 0 HcmV?d00001 diff --git a/doc/images/convolution2.PNG b/doc/images/convolution2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..c534cd0b8a741f48828fa31ac288cc48aba08fbe GIT binary patch literal 15769 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 literal 0 HcmV?d00001 diff --git a/doc/images/perimeter_convolve.PNG b/doc/images/perimeter_convolve.PNG new file mode 100644 index 0000000000000000000000000000000000000000..ea68817155bd889a1f281130ad47eeefa63f46e2 GIT binary patch literal 16797 zcmeAS@N?(olHy`uVBq!ia0y~yU{YdWVBEmL#K6EHJz?ew1_lPk;vjb?hIQv;UNSH+ zu%tWsIx;Y9?C1WI$jZRLppfhlCp`Gy@#qs#lgyOWPEK+=9iXfjoibO)RW)*xS>l>R zo}^9F=1wq8_U-97V~{z;NagAliPW<})52W7{;WS|bM|xnv+JL2zW;moeqQnUz2A%D z_wG5gH@&j{{NDNZZ`v(aYmnOI;=tmfu$^UI%_g_g(@e|mnr>%U6F$diu{Vp0151(D zgNg1NF1p<)i@sAP9k%X_Cd=uo>k=(%RrQ&a6qxo2?f74}*w8d_&VIjtJf>}qs`|{6kq1I!1y2|^ zzB+zNOV;`ErH0z?N4xc(Nk(^;PCqk+BcQ*#fn!OF!;FoaR;6W|-Itjj+qTp@I4E>~ zm*&im+HzXG932g!OftW@?8CyQ-Y9v+vd;hVw^>TcDl;{OX5@)83VO&kZnB*b+UdUW z|KBH*4YR{uNvK35ob+k>Fm)?OM?)>soc_r2dY_G#f(q(SPuuZauIBgJzn9V#*-!e2 zEm~pK(ZCVnw_wW884j9{zRl_scD0+(kfJ6qF;9R|&_kW^Te8>u{*`e#X1965V_RFf zFLRyjDDao<+UUp6W^c@x=x$=8(Uo$n zSz!f-k^)nqV8Q+V$nZJe?#r*=FBjfwG@&m=joC3o)Ww12pL4@!!;R}>`>q|$yuffh zuG`-}G{M8cXmOeXlhOoECc!_a7I}L7SRS?Y&}9Flv$K3Y^u}?X^eHK;3Sx0NAkM^Z zEAr;8e4Jd;p3Q!;GKDPvKJv#qs0Q+#^bxu;bvZ|eLl4Ue!+AYZLznvd&YEGkWsjVO z!pzQ%8?`kB1sI>R>_}WXtJom<&GaerLbm5se2ZKY_jXR;AxW<^A-;x9;*5eFeht~v z=e|9t6PtEw+x0oce9zAJ$2}FX)12v&WCrntmcDvj;TXAl&6#b+%6I0YCCx$L{QRrrgsrubMrM)8m^##T&7gfED z#B5Ib9AjGbs>8vJ^T&fu$@MEjrb@*!FY`SeB%*2@*|qGI5|gCrfjXbNy9z!}{jMmk z$GhXTUd`7~vqPFQPrAv3atof&Yy9&inM-6{to5D`PHc~~W}b8q2xS#Kp~qOi=dbX~ zr&m_DZ$9r=z1_`d^4;&jroxR|gcqo%?b?%~;~Dt-+m5HxzRX(anRe-)(yBj769Sp; zRsD{>H0eM}zpdE&J(G_mc&A;GFr6C7vdK^3d2(u~r(d_2gq28q&BS#dywfg;>Q4=0 zDRNM7z4xy%RzTW(OKx}J;|*D%QL~y-)O05XS-L97vjjbVoA2zwba_c`#`$?Otj$Gp zos1@T8LXV3G=ZP#)o~UspQF;-?uwP)c~}o}W&if@ts;#7IhWkMyth}T=2-2mO8l0y{?>$)W2*~R z7${9JW}5l^n|_!|($4zXxduf`?AwdH(u%%?t=^^dfFD#0xk*1gQEn;5$vOXo-S31y z74nO8XMR-V(rV^-($BCrrRXU%*%v1BNVUA*=e@1cGi}n-^>)NV*hfl zRZ>iIt(y-_-mPMMa%1>8r3wB_pR~PQM1Friz9zDBi^WMFr5jUMay*&Zu;;Jv#TlD? z%5QOgzx%w7$Jc1`_3g1=#TdV{n1oGRaBNEY-s^EQEH0*gP&L-e)Yca~VaV7!_2&Y^ z)YKL6^5%CQoH2DUn*8{BT&Or>I?I#Jm;J}4Okd(FZSKviVtnqNajFVarK*F!&(Eoq z8pb-8*rXpUnf&2qdf4n`DaW+pRP~s4sw?PA+OsZ8S{b#~C^_TWw(A~gMgK(w7z8)C zJETwfx!&-ps?C>xKY!nw-D*lX#umC%lSzr;#BF<5so=1Xs{eDUwCw&_+a_QzYVf4JyAand#ClY$er*H`^EWL3RimCYmBB&zL|<1=Zd z5aX+lD_G)cMfd-3J#c>SEYn_Fx9{&H%y=FjOT4&f#mtwM;VdsymGl3fIpGuO%4fx) zzbC+pdD59FPX6cJR6ktbKPzz4qI<`pwqDq_HuGcooyO<$j3<45+#k64dT|-YiQD^E zsLfq8+j33qyPY%4^`mxAJmd0s*>W!hfo1Z-KiJ-F;^woH*nX$UF!@Z?|EsILH73aQ zHZz#I-TT-0*6gbJmh5)*`A7WiMQ_Kb7#|h7{CBCK#_Z4iA5&Kcv)|6|SME1q&VHk! z8=-JgQ`c$Yyk*BS=GXVEy>)wuMPKa+#TjO6SA;3e)a06;r`OBy+wk?dpT~c=ee~Xb zx9r7T>F}7wlasx*SI^_~b(lB9aNENWm7|eYZ|5KX^i*+nM~a$?#@#R@#&5|?&;KOX z9Is#~*kAYKLGz^3YgtyQ9@u(%*603>cb92s%AGp-)>KjNqz{M3uB9bR+kP8{?wzy$ z*VLQc>rM+XR-Ftu7yKnPB=E87fsf6_=MElfy}DihWY5y?{wKo}4rmHb|2v~eywm$i zpS|4UFONyj zo%?vo-!z5%|5Lo0_9n?!>n!tIyXC2O+NS@G9-G?M?@1~@xBo`@vh489QogI_d*=v$ z`li3_;nOE|dP+~_n)CN*X2egLDHLyE8)wSs|I3gy-{Sdde;dL1HH%KTsvM~6Id-Z@ zN&4cdowxIjnJzf=?&Xo9{bwC!_fm=iLh>b_r=4f5=+Co@>jVo^t+WOSez4W3p*; z2=`!mbvz=geWvHMu-SX7W)>RvP5b=d`Tst@^nkRygSuM-f7?&XH|;wVSbzAw(>|A7 zx^hf?-;YoE(Pfs|w0hkn{*riJW|X0qgas-+%t*AJ+5s zXkXqZ+k04eY3jF}KOdaG`f3Cl6&vTp@xKneGULQvEVawxeFU+WX;IQY1(!FZ^ zTWJkFCwP7vzE1w@_1lp3|3=GM{Kr4c-&n@!vdv!bUDotzmj5Tbm#E+LvG>x_VgqNh z89jI19`od-+r2TkQ)7IuPCC9W^3m!EtTQFs5}y|TOPsPyElaMY*`zHj>GIG2$1j^c zm;cm#VTa*4dwKci6<+=GW_|Oltq?yh1o!c`S8JP=S zuU+=|)8FrAQq{Xs+y2goS|RF~d`kXh&pH1Go$>-3f)26$(pmCyjr`_+zbxL{yxEz~ zly)E{r1)Co3_Dxyk6e-LmA`lYIi)@+{PeUJmsp+KX2b`^*UN5-b=jwT)abC~|BSyg zm?9rZM9F{oDgIAXGRaTAC3?E61>*~a9H3!Ry~4)Z&He>cNORc1lSJ=Oer_W9MvBMW@qTyQQtYdXVZ<)ZU5 zPP5JOn#mcnTSh}G^zH`pZ*{!uck(!BeJAV#zg1!3syEJC{zMP}>bYJ88 zeO{>#R_Slq^H-L;VegwAWzEWG-u&v9Zr@ofoWJ_z;GhD}FR}Y- za?<|X57x*#_exrAvEtA<*=MbGd2QzHYZVvLUOuYn*^~07_Pgv7pVx)I_I-KD{4eG~ z%0B<<{XuHR-+mdg9=gmZD|di-^#(2P_(>A49-Xad zSEhyw0#A`ssrJhf?3T@XwJs`E?fLebYBSHX#4_(_)xDaWF{l6HzZsY8zv~4*(3%nd z|5i>x;_3Ou>Ye$Hg_Xg6n=#`s=hWOQ!0HDiy`m=tpfm^srre_TTC8dZ&VP zKDN!|o4L_eUU)@BjFbWAWTF1BB-VmuhB4t`+sZ5teZB1e?09U@y}5I4?D!H?e9Wy& zukyG1zZcfk8v>O}UZv<9omYJ>r{L#%$3)GnRGloYlw&t*e7+`amNb*@Imo?1A(pXk z;g)lI{#uF%L?)klee%+$FWl+zjZHm2sy}bLeW1|hzkXKFu~U<>)UQ52efC65@~7SR z6R&7&m>u_UOY;BOp-WZ2#HQUje>_CrZ0*Hgf;N*bCAe#D+r0I(Y4))NhN-51zD36r zFuu^4eZsv()bd+|eAvV=@x0!ts+Y`GouAU}_2T9!!DPRtX>Y4*GuFt_4bACVaG2op3z7J~C zM7fmwede&=}|Kf)xvb3e#LrQ&~ztSjwa#dl{c#qZw-zd62RruTD$lBK`@B)b@=`54WcojTw6Tz!GR zvuOH~;}NF=JTv*znxqb!et#2pdGDk1^~aviZ|@2Z%lj0Vrd0j=_&TLTp(hei^duQ5qS=ah)i?E-8 z^=JD(2C=IrBxhI1tuyJqD{R~oGNsO+dy7PCVC0Ky7N5U8ci;b|H1%P8>($kUNi8#t z3jeRwJijqq|BPS8_Vs)I#vZG^oqM+Exc2%ZEu3*P_qEi=KH7VE{XL%Jr;?7oxXj4 z+nJmVjT6P#rmOGR^M9ZB?AqnInn7uDCw)M5K+_i0ZBM?qIRd1}MoyDQad^>`n66`G6hO%aM=nW&Ir9$C!wc}DV?88?1>tekPC z|5{q@L`nZ|32rZrg#0?;Xz@bRMpRejq|MRwacR%~92R);=%QKfq!6ih@9e(EoS7rJ zY{SL(6Swc@-I(~M&+611_JgS{+mt12zscFYY(1m$PE~mNt`ML0_9DI`2P$Vg58Sd^ zt7~%|&+}xRwXuAjGv%iD+xKO!KbqLC`fOX|$HVTK@@8kQY3_^)7h8O+V8-;ksmyE- z*6mi&RlL9L)9p#qCC?rIvB!Ry3u{*Qw*JS3>-nF4IeUBm4K;~hVrSgxjFQ2lc!b$3RS7vx>a%{t%zuug_H#grgJ(HNSE0j;FWqKTw^rUqjEJD*H z@9#j8L@wI>4{Ex)!?5nFw(*jabAQU$vP5lqrPb>&$!PM%pEF*mt`d|A z4BmgZeCbi`Ys=^UoN9Sn{_uLU^Sn&4mOmtW5{WcHqRPL@}x9!wLlis%Yoqr&y zFEw}b*3(NXez&U}O+EGfPV%`;cS^(ehlO6;u(Q6tVD0rMC;Mv3wz6;5XuO$YT=FvM z+O=X)qvvneoT@)@Y|hc!lP1oL`I^jCk|CT^Waal?rgN9Cg|znOE%s?=rHmgP5w@_{ z|(b#ti0IZ-=xS z{U0xs?_A;M`O^G-+ugS0AK!o6bL`>XT=1+@a`E>1NZAad6NfezADGK^=efkQ*^i#d zofG}+UU+}sv(sM-owhm8`F#D~jI2XvA8+Zm5o%_ap8a=8(v$g(2Wm0M^i2)j zY|?OU_UetdVxv7`?b{YVnRDiO#D%BRXB!&6+gi3*rg7&78|ihzi(^G?UGG(CKU`Zm z>+^b(xHua1V`nV!?t(_Y3-JMh@z_F~)X#s3@RWnAy4+Allu z*U)Cxo3rMHM@4^}%|CE|VWWI)y7`BO33toQ=PBvj`}4DpDZJKfR{u(gzrAKg%_~y# zrvCpWJ}vG03O;?Q_!Uk&CeO^NI5}m7tUlD(Q zaUb{o7~ASc*P?rGOZN*cIKDYQ{M>KDH#-UrvL?IyTpq1jePGufl?P5~JK~p!WljCJ z(J!29i`fm)-EzH)<&QMm^s0Fp`=)14Km7jSpD)2avr??|WbPy!KYDXQc!Jv+CR?$7;yV%zVwO^^S!I{oES^?U73k<%s5{ak+i_Wp>(#r-$0 z-PmQlD>&*{;+-U&xYkh4_M0=0v8;=Iwv45(v#|crN%h(C3;*RPKGBG8=SvecnmhY= z-_i2>sxq4lZf=%;e11XFf{N*N%+cb>CHE@Rbmh1E|NB!c;j!zuFjHBo+T?jNUT5)N zPcLr#)ViZU=h!(nr{`gzw-(IF^f9eA*#GmG$LW{LljqkSxLdHazVMOPLPutqsudq^ zKJ8CB&VFFZk8jV@?b-|%{V9I0E317;bg_{0oVCYwPx)-KH8elc=6msrhfJmVyEz@5 z-4EukooDQSru4Vr9F_X_wx3HaUMOtIeLXQ+wVGjz#bY*csY@Sp7^3DcefQ{}gq~-I zcebrh`!Sm@=j~qW?D@d7%=dGlmriM}+DoR}lV+}|N-}e3j@@vYbw@*TQe9~bSCmlt z+S#VX9}OR=zkj#;dYa$zht}_pysytU+wo(w@%+oWCeBZ$cTY?D|7ZEkGyd&c;Wb9m2T5! z<5NFME&kUO=RGLBzOcI7B=eEe4X1w$&-;_A6z5kilic+CgR}dzq_AkWZ+re)s+B!x zOcOOqPC2>eR+h_@3Ja!>pyvP03p3g>PBZOEWgs@OBL3|giq_Wtbdok^sJq=p3L@?o_+p@@-=VGUb=jd zP)B5%(S`n-lGgKEH@hVqG4c5=nHhcIkY&Ajx~{cA&xgo@_bR$aZ!FgOeDmzRqot{t z-?bk%7R4|Z{ry_;T(&@d-8vh=j^MOQuiwUtmwrFG@A~7avKXOnetJtkT3Xwy?P0jF zdvf&W7tY0Z3LgXryBC|IN56urltdaEEVN z(DnYCBD2d}uTL)gl+iP<=j6%!0?myptv(;wvRtN7v$&c2_=_E;{dT**h@3oJ;r;5_ zA4%oDXd}1lG0mOA#e$24?%$EIk?TLRB*QLEI_L1*pWzR>JZF4S-t_77shR3&3xsa$ zXk2&Z&5oFoi5m;%Tbr}zKdoOqV^Q6iHt9vd>O4{@J(Vw3to3Hm66kPD+hKpKIKN&h ztjH&afz77vct*s`t!xMS^S?byw(xODPV4LZSR$EMaPr~8oojYHPfkrWT(nqYx_Uu# zcX;2T$m)}qW9J8@9!t;vAOAr7i_@}1)#FE|DJ`yh@aFiAoASwvXK%`zWuvgfo&V3r z{%1do);XPf`*gFqTDao&{Cq1tVYMe#ZaZ`591Y*2GIQavAI~~Z8gA@+QK6}~SN!{> z4Vx+yR#qK)dMmZs$XU3t>}^l%RoQZh`LVHb^R}KT^tS3M>KEC5zvzyU=(hYUk9z_g zdd71;FMsH@@!2G^cj<;ZjOQEceSiF~a>jSreV^IZpKY@E{B66U!JV1@-+iLG?iO`_ z6#4lpd-jr`sb!SvXRoA82e$zQzlmr6PYCe2>J|iN%WLctWZTy^h z{9>FXXZS5YAL$8C-eFwdZ)=diFt7gJAEjx_JsdZGIC6Wxuk@Vib(Xb7*VfFqy>`-R z)kY1Y$qDvt>0AXqJ+jk(7u@GLQ&7HVV|cG}tkhvc!@6xh7SE6sfBS3QGDX!FZ_l4o zJ+8ZxYv$u=Z+7T>x#xFs_4mM5PNje?XA1b!a<6PN{1)mvYj$$6+@m7#cU7|MpQrk) zS#@G*D!-b0T}F86W#2TT__9#P_X{J}Jgu8=pL}KQ?2Wb3#%$exHcRlgERzm$T3|7= z@a5a{p(o}PS_-Fs5}5w|!@aB@w5O|%se;$iNSscjn5~%3VHjB@3uqC zyZ(pYPKK>L6Ug!9*~0hS=Vx73Wtzq*qG-(bEurXcl(31VNPE!vWl33GwedQwz0o3% z=jwE-n&!>3cx%EVnZ$Q|$?}eMi#Q7A?{EHV*ekU#JG}UZNj+oDx5z-&D`%Aglo~e} zC13SUXc zH?7yqiaTK<`gG!re*3&9_Wbv3j()oS*N>xRlBD#VVPM|u|I_+-P{Oqd}r?W|Ef)dlz z(>@#T{fkb1{kZT?>W&;GHNAtAM6TMWy7qdfWwhMcw)W=q^4qzS#L9CQ+}L_Lb?)g+ z&M`%$7y5Qj&`=j=(V94O!o7cQc5HFp-Cbz7cf#}Jecgw&`h!xImF`PeCAWL zbZKqg?O>1m`m&g)?Z@8N=hwt*=x(YlmR5b5*6gtG3`^BX6X(sz1!n|!7AB_NtBucL zS@O$7`2>&u8QTX8G4*>bE4<=D-#Ld(OI|SDXR?~b8-wBvhQ6*(Tjzw#n6h4$>A$jZ zXk}7f>)MQnlYQLNyUre*6B?1a+`!AU!@*RRSZmY?Tj}r*r{eSNdB$nZD_w}Nl=7p zLP{F%wSt?4Gmn`#EzWyk#=snRq`P~AhphPOFWr8BE_wg|-yFJm*~de-s`EE%zCT}Y zR;?bsM#IX{Heu?4z2DdMiu0S@tFNC^r8TcM%${kDQure|p%spb3-5YoZ+X`!H|Nj% zwoJKcL9S8W54yAu+|`|HwJ_ekM<(;ywk(G;w~rkxO?|VYK=jkr>$956>i*rlJ!w^f zQo_`Ri8IST^iAuETq+a&XimmL?oZqAADgy7Xp?(GwqC}91>P)0{t7oP>wNEEaRAMS zyC_&O!X`37^X7=jS^?0sql1y~+`02a7zG6w1vyj{W^%eLkp|7LJFqMgo^Zw`eYv_T z*cc{Gk2EI1muw()0*xEN=g}?w7}USIcJ$ru$4@4Ie9&C+*;glW zQohNmS_a0GJ+nGEIvfNVO|uK`Rc4zm^T|B*-z2Bw+grl~hIc#Jjnk8kb}iWQ<$tle zgVE&O6ILHm3Xoy!>!12PnagC^gLrAvLwdU<9Cv;8J2Rtk{XQ){<-2nOnI_HbVGFw| z)EL3>=TC7&ujYg~YQ7h?t$q3QPMvky*+b^{j|9o6PI6m9$O=IVX7j>s_gq8 z_t4Xt@ubf!Jvp7A{F3H$Vjb-ste^3`2 zx$)7JEh{5q*ZR&~dfaNEh>9_1WB4|u2h5CBNyj#w-yiX`qo97eo`n59_B1W$jVzF9 zNu>#*Ow+#obe}L`Lcd8ygYo$zUtUIXI>fzFoO#lFNvOZz4|%3L^1_$OEtjxa?9Sc& z_QM6|2Q`z{O%a%IW{FCG)-sMG9twK?KIxY><+-WPP0_hnvb3=wMU6KwNYYiojY)1@ zY@b^A?EJpf>n;g08=CQYdwQnnG=^?cdZ5bKXSy`?oc)q-7vBHuHQ$r6)@iM(!py*6 zfyO%m9(U)|dn{cUFRwnQq4IN)@QEp*Ax4uoHLTpBBrwsT>iHk%F5lH*X_*ar|2aI; z{&aVGsW5F6POv|AGvcP+?gt-_7am~bj41fTFgtGVhwuB3pY!LO=Hy@$%w=n<&6KI| zV3Yjk)$tGae&?Cu+FkJV>VwFciocZ%?;SHKc1hN*t`Ziq8F z_sei?^!lqaitbESOYFB53Xtl$c98w?)9JmcE7mRH^hlf3*YHW4v6>~ODk&&=neXZ) zTK8+3?f(hJ)W{^)tEL3WI9opzsrl4td%(+*hw-G3gx4;2mLQJ_;fRmyZZKui`)z3bzNh>??>f%Ee|~@Wcgr-p!O$+N zcD><&#Lb<~M#=4~gG3uyICtE6e!eu-IK6GH_R;s9>KhL8o$LTDg_-32;UIgW_v+tC zN(wVOIhRZlWc26Q5fd)9Nj}&i?On`;i9PPqj#^uY8JWI%WPH9tX!RTsXUL+Pp9&9( zVkNKZxqo|-Uf<1bu(?_=Ncz#R=y2P^-|xLwHqPU9b}$ldoAgeQ@ja(ST)0@;IeVVXqS^&dr`|~F zK62#Q0cPj5@f^Y8cY|3$|K`M`<@C4p%S$4}|)xp2{ZmXvU~{jvpBU)mNr``q2tr?qJv$J=eQZ^kV? z&BS=JhjoQl5X&6F2Xpps-aKvRI-PHIK8!0kg)eN)PV(A(QqAHqkI&3UI#re@Js|#% zRN0W$Yu&r@l($;hy7-#JY1Zra*Ci!g-eLG|kMJCmOQOPzCw+VrruJ}Hs6E&rFI@Sy z$V7+VzQ-(AC|HVbrED>enqN;?nQf?pgVAC&MJ7#^2Ssm-G=C?1IsSgwZt>RS%DTBT zZhR1FZe%{&$+pW&Sz)GT@BDdUjNe&e-W`m&e*1o5ZKcz#{JP0AE^UZ*zTQyySSH*m z`KD)@kyt>e`fHX9?q{F=%<$U#SJt@hqpL~&yd{?k{z~&d-LmD#Im0t5nHJJ7;=Z1iDTf)yz84FK;4xTjA z#y!5&UzBmWl<-;M%`S89SbaVwz2kq~m$%(_%fCBCof7HZD>;v`>P}(B14f;=m?Yie zA3IXi+8x8E274TMYFB^m=k7Ph&&+IoKJT!r_`>AlD(Zi@e>rT;n#s()tK59Ho4WtC zl^IL-7*CoR^x|ctV1biD@?VL(?~%JizMQT3;3!kAv+b_gPsWW!y$|`$?)`S?>Gau( z)^mM?gI`ZObA%=6WJiN4lb)^N+I6vU+jwFYpDA2^Z|}u@wr00Zh?m|h3C`JT>SrU^ zZ`ZXl*z~thwez$yNBTlIyBum*Wae*;*|q)uuF(H~ia-C{_e!heRZIN8OX8V{-&?i0 ze|kMIB2GqkI+fmgJ5gbFO5%Xe@8-)}#wmD$8n&Vb?fd;YwI+qZ1kaUMBa{GQy9wo-A}OJfXNEUf$;a zjtI#OCHBXUe7hsO|G#Zq1>>Do=W4lFPQeLhR9NC}b~%Ky$W$k}MeN>FqzYO@ZqDT;&TUITzp_7e0t?+W~ND!{7nm#Ivgw+^}dz9R1Kce$Q7<= z|KFzWyY-vh`IC-ot-t;I;kT1{cMD#xt$1r{8C&(k$TQ7`r>kp9IFnpeQr+LJ6UFB3 zKlHxh_O^XI9f6rrCI*K~=CDf{vzf#_4wCYU}Iu=F%}HYSSi_yBJNLc_(|BzYtv$Kcd8n%qgqej?%t??lRhCuoi^bs&xDA~3tL<8 zpfSzcZ2R)skE}2LFFftf)Mu&|Wv_g1xki!i>{*u$D%I4?chr2JJAY!}$|QA#nVqsL z&$2M5E_+m-cwDyd0OPZOWy|Ls3Xi|3GwqVzqz3Q(n<|znIb}uXG{*nGwPx{Sqir`g zcdIPDz1hLRX!0rzF;(NI@h!KuI-a!r9&@LNJMAo!`JI zT;I-&z@|M@OCPbQ73N;Sh~HwWuALy zf5G;%iS3Ce1pYkL|M5gPAfU9fL1tF)H8!v5GrR5!Ms3}m-QLK2ws2>RqOW*#Y#3)s z(V8Cnn2M&;H`5>g`+e4t;ZFK0Z);~W(j^g<+JliLEbd?1;tPK%MTYm-Gq{F!n`)!&&KK?4GY31|U&f&Z6ujbaDHPzMp*PV->pLJwkSYL0fb}Tuqq{*8{ zS6STCBP~cY&D<#XqxbfY$I@O`?5|rk-MDho8Lq`9;?wW_+qn8l)oV#%sl0;9XOfp0 zOzsLTWqtBj@}$qIsD|p9D}UU4bhE?8xXV86{Z97$y-Rn_3Gh9>bbEb|l(TY5l}}9N z(urbGS+9f|g*ZIYyc(YWyO@%ic2_jp=HaTGiCeba3cV!}Q}uiLIzt(q)bn2#b)QMl zo)MbNQonz;Yy}25ZtI4k_EzM}3x@^&t4?ALJ{kvDO z_~xg%&$E9Pt$+TfvWYufF}|?XuyM77VK?}WX*zW3PUialakSKa@XRuxY>TYy=sx5vf3(Y-^;k!6_TAmH zFQ-;Cb@$CX;}!jRznrOC;+6V0(bxa2Y_>Xk;Z1=|ouOWuemdW?HBH+-RSCPVPia%z zz5893U3B^V-i^t+fZe>s~HV`PuCG zas{`vtVL38~#$R*}~#| zP2qcYq^|4vRc8t&N|-;LTk$9=bK&fcbthQXoZ<1PQQfB9B+oO8MTM{13 zxRJShrlH|C{i}tY+Cg5&?HVgm+Fo5^l>N2%e*w?@22L5b%V&D0-Z-jce0J8tVD*@? znHx19r{%x3YvHW*(O_UOw~hkHvpCJ+p2}e&1tHo?ejX{<5i~yrCfRmezt#YVHn3lVz%(>M&_4Zb;#*`eGmz{BOCh zG>?4W)z!g4jH1S%kw2G@+Qot&<~dZ_FI#kG%HO^D@n>c}u4N55fEYIE=L|^Z`en$P zwD~aKj(=4(KbIaa4Y)W-O<|^|71ODBmKxOnU;AYaIlD>@{`j~r%=xL;tcDb|mmC`P zf*&RwD8JA8C7EkV+GXFur&E8tP}bL8?4;`DU^H2yE>({yPAFoR$Z^^4_Qn5R`<)5- z6~FDiT)$nHY4)BqQ@N%JFrM^rdN6e@#}BUsH|l&E@2%M`SM~ka@Ato>Y^R>KWIWkZ z{Nz*si;dcWpEE$~bT?++lL?PyUAD{{G-AlCq`;KT86aBqt;Z-V?CON5>+7PV7F=UJ z*(24+(b1rIVB@Cb{@&o^Q(KmM3O|-IC|{@We0oEQ+Ww8KU z>~r={x}GodHLNh0rXMa)e*2J!P5ur>lmAMrZd2Nz*I2suudv|kZMnVK4eN4* zC!9&K-nVKlM~IWc9`$9+Z&wDh|NWi(D#TT5GmDDxOy0FxYD`mwIKF%tX5XnXuKN?Hc$SF~ zx;xL|D~pBvWTjrs>+=@(AA54LEB6(rM_Q1)Q>X)r(MrSAq|0k0*X{O8&Ul&kc+$+0 z3QjYDOu);w}fV*+2_uH!9>Plv}^STocmn?A5;XM+oG)c02&D6;p7Rm?eeEQ{1 z&X{_0+Wc9j7x!8(^DRCWBstZ~!6;bE(N>>npWudCx0$($oRj}ui=ORlDX#OOckiiS zPS7w{D@RIK!~8g-#3{;$Z0A}fo|)m(sy}(^#4{;IYgUE$aRww;eLwdsA~IBI%SE>x zADsTYj<@Ws&|0NC)6;cEh=(AD+JnyR^(}s$FZ)e0n*^0NB)J->-hDW)A?28D@ly?^ zkHRMs?Uy;s*FC97|?5JiqsEDSwBn$HLly9_~&q6{bXvC0B0mcL~(2pL1!`{W=LFmi+y_=k58KeZH%>IT%frs7lpg zn#lPiIQi9e_t|F8a(w$bYd>*L)9*jy&u^uwFte~LdS<7?OO{U$RD(BO-h8+0#bx&I zcbe<}IA02?`s}H|deVpK!qlZ4E@}?`XKc>=+@8^xcemhbsD!Q5=jZOrma^|vP?-5q ziASr2qeamn|9{+GquuM)l;svE7Tw=h@gs4rw(v5`CC}te`eZpRZF)AxL2d8f$_UB5 z)B5eC#A93b|CgOpd}*pJ)1;Yij)s_?QfTZsd%VDCf2?&(5ocUA@B97p4_2)766N$r zyCUaupq%OEheDp7KtT@l2Vr=K`o_gB4aZ1&1^Squu*}`*{6(1bW%yN&h>bs z$)DL4y!!3k@OMVZTJ7w+x7IkxneqJpqdradv-ldXXEPd7ju{rDsxvL*Sh7_9@W~pl z(=V6LK0HZWk0;dh?i6#TNi+Aj#(ec-q*$QQ zWS#n_dQ7b>d%k|lzbEte_w2bpgO@#6+%IAw$l>i^Bs^`(J7Gq4mYUDs?xzU9+1P&5 z+OkN+?%xeYhSZ6UOp|8vu!V+tX)^koq+RyCxJtCoUhaBq`W-FPne#6_d*Z)Q)%f2L zC)JatjYp23vQWFWQkae3Y?*$ySmM`LG40M%`zJP}sJYGX@?udEO0ZX(xb^hbtcA|( zn~nef`~C5K{o~{E%G2WeI~_n1JDFK>x1LQ~meH!WIywLU*K3Evq9rpQ-aA?N*x`D5 zX^hixFLO6Vg_)gBx+~M=s(B8#Kb{)?Wwr52jwAEe8|VK&Yj*fy`|Pno_Eu{ziP46m8P?QIq>Rqj-2 zFY}-N(z|Q6*Q##4nV!Kv{(Wdaq`Y>AMhBm~4d<&i=?~9l|M>OVBvk!*>Q)o^!!O06 zx;8#8x|v$>khSKc>p8>KzfKBIIHMxp{6RG$JWWe(X54zY9T6|KTs~uUrTpGO_4zIS z5#_to9C|yyuSu0se7{BboE7(Z+xGKzhyCq$uABHtn2~o@>O$TSePdD8^lse^f4{jE zwecLhvNB?W0{7MPKC($)zNJq&Z^2xCw{`pdW7Ff)+9qgC(qwvdc8TVkhoH`VLBl+G z<#*eptwbiPJzTy1QpnRcQ>PaHn-jiTVnNdXb0`1o{cd)6iNF2Y!v{BAcQA@jKIt>7 zNy;}(tL~`TEsou9+aC8Fo?AZa=o*=b$NJf8(@U>$C{-sF39Tzm|MD`~Cw_-<{ZX!T z*DyDw04>IoJ}X&b?c#Tx37H~uE3~lkb%&r^W{IVOK%!ln+X;8s*469H?gqS_TOy#G zn%LX`+PfH?IZe;_PoR&pVAKx#F9K?QCX0XmiCuHAXKh2M$MmRkekn6PZroMsd%V@K z>WN^@hsNebn%sgLyd8{^r|0ik={|YpCgEasz9Y5Y6K|P(jeXSXx#9|wX`Aio+--)* zNq1)czgL~G-+ekqN?SvUn(sm$edCyWyFQ=W@qp=0A^W}hc;Ta-Zaby!KUMQRvng%f zgHOL+M>Wh#>6x-UlxdRW>WXB)JykOwny-$vo>M;W<|o_iX@%?;rdlv&`5cV6`Rlc` zFuRo1g(HdQ<{aT(!PL=E$}~yxbw~1<2ba9L*}qGhnegqF5m!B0jCI|I zgK8-yt8*^1xyvMq{n-0O=*85P-YlP-9gHR~iXtP zpIf*rSr-Ng>IzRd6T!CT38>?xaGyoR_-Eh#EbtKn(>OiSbeO|FfjV9j@|pg#Z(7Uw V{P(qKF$@e044$rjF6*2UngHKq4;=si literal 0 HcmV?d00001 From 8d910f2b58e1d51ce52107cbd3b11b19f236f445 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Mon, 21 Jun 2010 22:59:33 +0000 Subject: [PATCH 03/32] restoring lost file [SVN r63214] --- doc/tutorial/minkowski.cpp | 154 +++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 doc/tutorial/minkowski.cpp diff --git a/doc/tutorial/minkowski.cpp b/doc/tutorial/minkowski.cpp new file mode 100644 index 0000000..c329d6e --- /dev/null +++ b/doc/tutorial/minkowski.cpp @@ -0,0 +1,154 @@ +/* +Copyright 2010 Intel Corporation + +Use, modification and distribution are subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt). +*/ +#include +#include + +typedef boost::polygon::point_data point; +typedef boost::polygon::polygon_set_data polygon_set; +typedef boost::polygon::polygon_with_holes_data polygon; +typedef std::pair edge; +using namespace boost::polygon::operators; + +void convolve_two_segments(std::vector& figure, const edge& a, const edge& b) { + using namespace boost::polygon; + figure.clear(); + figure.push_back(point(a.first)); + figure.push_back(point(a.first)); + figure.push_back(point(a.second)); + figure.push_back(point(a.second)); + convolve(figure[0], b.second); + convolve(figure[1], b.first); + convolve(figure[2], b.first); + convolve(figure[3], b.second); +} + +template +void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { + using namespace boost::polygon; + if(ab == ae || bb == be) + return; + point first_a = *ab; + point prev_a = *ab; + std::vector vec; + polygon poly; + ++ab; + for( ; ab != ae; ++ab) { + point first_b = *bb; + point prev_b = *bb; + itrT2 tmpb = bb; + ++tmpb; + for( ; tmpb != be; ++tmpb) { + convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); + set_points(poly, vec.begin(), vec.end()); + result.insert(poly); + prev_b = *tmpb; + } + prev_a = *ab; + } +} + +template +void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector& polygons) { + using namespace boost::polygon; + for(std::size_t i = 0; i < polygons.size(); ++i) { + convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); + for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygons[i]); + itrh != end_holes(polygons[i]); ++itrh) { + convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); + } + } +} + +void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { + using namespace boost::polygon; + result.clear(); + std::vector a_polygons; + std::vector b_polygons; + a.get(a_polygons); + b.get(b_polygons); + for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { + convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), + end_points(a_polygons[ai]), b_polygons); + for(polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); + itrh != end_holes(a_polygons[ai]); ++itrh) { + convolve_point_sequence_with_polygons(result, begin_points(*itrh), + end_points(*itrh), b_polygons); + } + for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { + polygon tmp_poly = a_polygons[ai]; + result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); + tmp_poly = b_polygons[bi]; + result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); + } + } +} + +namespace boost { namespace polygon{ + + template + std::ostream& operator<<(std::ostream& o, const polygon_data& poly) { + o << "Polygon { "; + for(typename polygon_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } + o << " } "; + return o; + } + + template + std::ostream& operator<<(std::ostream& o, const polygon_with_holes_data& poly) { + o << "Polygon With Holes { "; + for(typename polygon_with_holes_data::iterator_type itr = poly.begin(); + itr != poly.end(); ++itr) { + if(itr != poly.begin()) o << ", "; + o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); + } o << " { "; + for(typename polygon_with_holes_data::iterator_holes_type itr = poly.begin_holes(); + itr != poly.end_holes(); ++itr) { + o << (*itr); + } + o << " } } "; + return o; + } +}} + +int main(int argc, char **argv) { + polygon_set a, b, c; + a += boost::polygon::rectangle_data(0, 0, 1000, 1000); + a -= boost::polygon::rectangle_data(100, 100, 900, 900); + a += boost::polygon::rectangle_data(1000, -1000, 1010, -990); + std::vector polys; + std::vector pts; + pts.push_back(point(-40, 0)); + pts.push_back(point(-10, 10)); + pts.push_back(point(0, 40)); + pts.push_back(point(10, 10)); + pts.push_back(point(40, 0)); + pts.push_back(point(10, -10)); + pts.push_back(point(0, -40)); + pts.push_back(point(-10, -10)); + pts.push_back(point(-40, 0)); + polygon poly; + boost::polygon::set_points(poly, pts.begin(), pts.end()); + b+=poly; + pts.clear(); + pts.push_back(point(1040, 1040)); + pts.push_back(point(1050, 1045)); + pts.push_back(point(1045, 1050)); + boost::polygon::set_points(poly, pts.begin(), pts.end()); + b+=poly; + polys.clear(); + convolve_two_polygon_sets(c, a, b); + c.get(polys); + for(int i = 0; i < polys.size(); ++i ){ + std::cout << polys[i] << std::endl; + } + return 0; +} From e65a766cd5df9a49e525a44d2c261330e81b1569 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 22 Jun 2010 17:27:33 +0000 Subject: [PATCH 04/32] removing bad file [SVN r63243] --- doc/GTL_boostcon_draft03.htm | 79 ------------------------------------ 1 file changed, 79 deletions(-) delete mode 100644 doc/GTL_boostcon_draft03.htm diff --git a/doc/GTL_boostcon_draft03.htm b/doc/GTL_boostcon_draft03.htm deleted file mode 100644 index 784ba92..0000000 --- a/doc/GTL_boostcon_draft03.htm +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - -GTL Geometry Template Library - - - - - - - - - - -

This presentation contains content that your browser may not be able to show -properly. This presentation was optimized for more recent versions of Microsoft -Internet Explorer.

- -

If you would like to proceed anyway, click here.

- -
- - - From 70ea0a2e6bd5265ffbd2bad163a616ce50664e61 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 22 Jun 2010 21:59:24 +0000 Subject: [PATCH 05/32] fixing colinear and duplicate points in hole fracturing of 45-degree polygons [SVN r63251] --- include/boost/polygon/detail/polygon_45_formation.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp index 8596c8b..b040f18 100644 --- a/include/boost/polygon/detail/polygon_45_formation.hpp +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -251,12 +251,14 @@ namespace boost { namespace polygon{ return; } Unit firstY = (*iter).y(); + Unit firstX = (*iter).x(); ++iter; if(iter == tailp_->points.end()) { tailp_->points.push_front(point); return; } - if(iter->y() == point.y() && firstY == point.y()) { + if((iter->y() == point.y() && firstY == point.y()) || + (iter->x() == point.x() && firstX == point.x())){ --iter; *iter = point; } else { @@ -274,12 +276,14 @@ namespace boost { namespace polygon{ return; } Unit firstY = (*iter).y(); + Unit firstX = (*iter).x(); ++iter; if(iter == tailp_->points.rend()) { tailp_->points.push_back(point); return; } - if(iter->y() == point.y() && firstY == point.y()) { + if((iter->y() == point.y() && firstY == point.y()) || + (iter->x() == point.x() && firstX == point.x())){ --iter; *iter = point; } else { From 19e8233a30c19d9d42b7cff1e571d668cda9b110 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 22 Jun 2010 22:04:18 +0000 Subject: [PATCH 06/32] cleanup of html [SVN r63253] --- doc/analysis.htm | 4 +--- doc/gtl_connectivity_extraction.htm | 4 +--- doc/gtl_connectivity_extraction_45.htm | 4 +--- doc/gtl_connectivity_extraction_90.htm | 4 +--- doc/gtl_coordinate_concept.htm | 4 +--- doc/gtl_design_overview.htm | 4 +--- doc/gtl_interval_concept.htm | 4 +--- doc/gtl_isotropy.htm | 4 +--- doc/gtl_point_concept.htm | 4 +--- doc/gtl_polygon_45_concept.htm | 4 +--- doc/gtl_polygon_45_set_concept.htm | 4 +--- doc/gtl_polygon_45_with_holes_concept.htm | 4 +--- doc/gtl_polygon_90_concept.htm | 4 +--- doc/gtl_polygon_90_set_concept.htm | 4 +--- doc/gtl_polygon_90_with_holes_concept.htm | 4 +--- doc/gtl_polygon_concept.htm | 4 +--- doc/gtl_polygon_set_concept.htm | 4 +--- doc/gtl_polygon_with_holes_concept.htm | 4 +--- doc/gtl_property_merge.htm | 4 +--- doc/gtl_property_merge_45.htm | 4 +--- doc/gtl_property_merge_90.htm | 4 +--- doc/gtl_rectangle_concept.htm | 4 +--- doc/index.htm | 4 +--- 23 files changed, 23 insertions(+), 69 deletions(-) diff --git a/doc/analysis.htm b/doc/analysis.htm index 5e64cc6..88c5f22 100644 --- a/doc/analysis.htm +++ b/doc/analysis.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Performance Analysis -
@@ -52,8 +51,7 @@
- - +
diff --git a/doc/gtl_connectivity_extraction.htm b/doc/gtl_connectivity_extraction.htm index bd2ae18..4ced224 100644 --- a/doc/gtl_connectivity_extraction.htm +++ b/doc/gtl_connectivity_extraction.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Connectivity Extraction 45 -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_connectivity_extraction_45.htm b/doc/gtl_connectivity_extraction_45.htm index 9abe542..e1ee2cf 100644 --- a/doc/gtl_connectivity_extraction_45.htm +++ b/doc/gtl_connectivity_extraction_45.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Connectivity Extraction 45 -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_connectivity_extraction_90.htm b/doc/gtl_connectivity_extraction_90.htm index 64a4b12..aff3bc9 100644 --- a/doc/gtl_connectivity_extraction_90.htm +++ b/doc/gtl_connectivity_extraction_90.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Connectivity Extraction 90 -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_coordinate_concept.htm b/doc/gtl_coordinate_concept.htm index b106a94..afa081d 100644 --- a/doc/gtl_coordinate_concept.htm +++ b/doc/gtl_coordinate_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Coordinate Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_design_overview.htm b/doc/gtl_design_overview.htm index 60cf0a7..a2dcdaa 100644 --- a/doc/gtl_design_overview.htm +++ b/doc/gtl_design_overview.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Overview -
@@ -51,8 +50,7 @@
- - +
diff --git a/doc/gtl_interval_concept.htm b/doc/gtl_interval_concept.htm index e06bbdd..05d4b41 100644 --- a/doc/gtl_interval_concept.htm +++ b/doc/gtl_interval_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Interval Concept - +
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_isotropy.htm b/doc/gtl_isotropy.htm index f97b3a0..e63391f 100755 --- a/doc/gtl_isotropy.htm +++ b/doc/gtl_isotropy.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Isotropy -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_point_concept.htm b/doc/gtl_point_concept.htm index 4283c2b..993d4ca 100644 --- a/doc/gtl_point_concept.htm +++ b/doc/gtl_point_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Point Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_45_concept.htm b/doc/gtl_polygon_45_concept.htm index d9d60e8..0e5abe5 100644 --- a/doc/gtl_polygon_45_concept.htm +++ b/doc/gtl_polygon_45_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 45 Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_45_set_concept.htm b/doc/gtl_polygon_45_set_concept.htm index 36ef8b6..a819024 100644 --- a/doc/gtl_polygon_45_set_concept.htm +++ b/doc/gtl_polygon_45_set_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 45 Set Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_45_with_holes_concept.htm b/doc/gtl_polygon_45_with_holes_concept.htm index 20afcac..9469eb2 100644 --- a/doc/gtl_polygon_45_with_holes_concept.htm +++ b/doc/gtl_polygon_45_with_holes_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 45 With Holes Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_90_concept.htm b/doc/gtl_polygon_90_concept.htm index f425e7e..542c660 100644 --- a/doc/gtl_polygon_90_concept.htm +++ b/doc/gtl_polygon_90_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 90 Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_90_set_concept.htm b/doc/gtl_polygon_90_set_concept.htm index 12151b1..d4c6daa 100644 --- a/doc/gtl_polygon_90_set_concept.htm +++ b/doc/gtl_polygon_90_set_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 90 Set Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_90_with_holes_concept.htm b/doc/gtl_polygon_90_with_holes_concept.htm index 2683e8a..914d907 100644 --- a/doc/gtl_polygon_90_with_holes_concept.htm +++ b/doc/gtl_polygon_90_with_holes_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon 90 With Holes Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_concept.htm b/doc/gtl_polygon_concept.htm index b95a721..11ead5f 100644 --- a/doc/gtl_polygon_concept.htm +++ b/doc/gtl_polygon_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm index 6ea39be..09cf8bc 100644 --- a/doc/gtl_polygon_set_concept.htm +++ b/doc/gtl_polygon_set_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon Set Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_polygon_with_holes_concept.htm b/doc/gtl_polygon_with_holes_concept.htm index 5fb6bc9..a205648 100644 --- a/doc/gtl_polygon_with_holes_concept.htm +++ b/doc/gtl_polygon_with_holes_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Polygon With Holes Concept -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_property_merge.htm b/doc/gtl_property_merge.htm index 684a198..51b4717 100644 --- a/doc/gtl_property_merge.htm +++ b/doc/gtl_property_merge.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Property Merge -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_property_merge_45.htm b/doc/gtl_property_merge_45.htm index 7dd551c..851e217 100644 --- a/doc/gtl_property_merge_45.htm +++ b/doc/gtl_property_merge_45.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Property Merge 90 -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_property_merge_90.htm b/doc/gtl_property_merge_90.htm index 9441396..cd58023 100644 --- a/doc/gtl_property_merge_90.htm +++ b/doc/gtl_property_merge_90.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Property Merge 90 -
@@ -50,8 +49,7 @@
- - +
diff --git a/doc/gtl_rectangle_concept.htm b/doc/gtl_rectangle_concept.htm index 25505d0..951fddb 100644 --- a/doc/gtl_rectangle_concept.htm +++ b/doc/gtl_rectangle_concept.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Rectangle Concept - + + + + From f3c8a67eab9f52f8305586998330b7d6191c7ed3 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Sun, 16 Sep 2012 22:48:03 +0000 Subject: [PATCH 20/32] Polygon: merge from trunk. New functionality: Voronoi diagram, segment concept, segment utils. [SVN r80546] --- benchmark/Jamfile.v2 | 39 + .../benchmark_results/benchmark_points.txt | 60 + .../benchmark_results/benchmark_segments.txt | 44 + .../plots/benchmark_points_10.png | Bin 0 -> 15729 bytes .../plots/benchmark_points_100.png | Bin 0 -> 16377 bytes .../plots/benchmark_points_1000.png | Bin 0 -> 16148 bytes .../plots/benchmark_points_10000.png | Bin 0 -> 16407 bytes .../plots/benchmark_points_100000.png | Bin 0 -> 16169 bytes .../plots/benchmark_points_1000000.png | Bin 0 -> 16201 bytes .../plots/benchmark_points_all.png | Bin 0 -> 22818 bytes .../plots/benchmark_points_memory.png | Bin 0 -> 24251 bytes .../plots/benchmark_segments_10.png | Bin 0 -> 13036 bytes .../plots/benchmark_segments_100.png | Bin 0 -> 13089 bytes .../plots/benchmark_segments_1000.png | Bin 0 -> 13067 bytes .../plots/benchmark_segments_10000.png | Bin 0 -> 13387 bytes .../plots/benchmark_segments_100000.png | Bin 0 -> 13245 bytes .../plots/benchmark_segments_1000000.png | Bin 0 -> 13223 bytes .../plots/benchmark_segments_all.png | Bin 0 -> 19244 bytes .../plots/benchmark_segments_memory.png | Bin 0 -> 24333 bytes benchmark/input_data/voronoi_point.txt | 10001 ++++++++++++++++ benchmark/input_data/voronoi_segment.txt | 5915 +++++++++ benchmark/voronoi_benchmark.cpp | 156 + benchmark/voronoi_benchmark_points.cpp | 141 + benchmark/voronoi_benchmark_segments.cpp | 180 + doc/analysis.htm | 126 +- doc/gtl_connectivity_extraction.htm | 85 +- doc/gtl_connectivity_extraction_45.htm | 85 +- doc/gtl_connectivity_extraction_90.htm | 85 +- doc/gtl_coordinate_concept.htm | 114 +- doc/gtl_design_overview.htm | 56 +- doc/gtl_interval_concept.htm | 255 +- doc/gtl_isotropy.htm | 127 +- doc/gtl_minkowski_tutorial.htm | 5 +- doc/gtl_point_concept.htm | 207 +- doc/gtl_polygon_45_concept.htm | 202 +- doc/gtl_polygon_45_set_concept.htm | 237 +- doc/gtl_polygon_45_with_holes_concept.htm | 190 +- doc/gtl_polygon_90_concept.htm | 188 +- doc/gtl_polygon_90_set_concept.htm | 350 +- doc/gtl_polygon_90_with_holes_concept.htm | 194 +- doc/gtl_polygon_concept.htm | 204 +- doc/gtl_polygon_set_concept.htm | 243 +- doc/gtl_polygon_with_holes_concept.htm | 194 +- doc/gtl_property_merge.htm | 87 +- doc/gtl_property_merge_45.htm | 87 +- doc/gtl_property_merge_90.htm | 87 +- doc/gtl_rectangle_concept.htm | 401 +- doc/gtl_segment_concept.htm | 572 + doc/images/benchmark_points_10.png | Bin 0 -> 15729 bytes doc/images/benchmark_points_100.png | Bin 0 -> 16377 bytes doc/images/benchmark_points_1000.png | Bin 0 -> 16148 bytes doc/images/benchmark_points_10000.png | Bin 0 -> 16407 bytes doc/images/benchmark_points_100000.png | Bin 0 -> 16169 bytes doc/images/benchmark_points_1000000.png | Bin 0 -> 16201 bytes doc/images/benchmark_points_all.png | Bin 0 -> 22818 bytes doc/images/benchmark_points_memory.png | Bin 0 -> 24251 bytes doc/images/benchmark_segments_10.png | Bin 0 -> 13036 bytes doc/images/benchmark_segments_100.png | Bin 0 -> 13089 bytes doc/images/benchmark_segments_1000.png | Bin 0 -> 13067 bytes doc/images/benchmark_segments_10000.png | Bin 0 -> 13387 bytes doc/images/benchmark_segments_100000.png | Bin 0 -> 13245 bytes doc/images/benchmark_segments_1000000.png | Bin 0 -> 13223 bytes doc/images/benchmark_segments_all.png | Bin 0 -> 19244 bytes doc/images/benchmark_segments_memory.png | Bin 0 -> 24333 bytes doc/images/rover.jpg | Bin 0 -> 66283 bytes doc/images/vlsi.jpg | Bin 0 -> 37541 bytes doc/images/voronoi.png | Bin 0 -> 53336 bytes doc/images/voronoi2.png | Bin 0 -> 6462 bytes doc/images/voronoi3.png | Bin 0 -> 32558 bytes doc/images/voronoi4.png | Bin 0 -> 9406 bytes doc/index.htm | 203 +- doc/voronoi_advanced_tutorial.htm | 462 + doc/voronoi_basic_tutorial.htm | 336 + doc/voronoi_benchmark.htm | 534 + doc/voronoi_builder.htm | 389 + doc/voronoi_diagram.htm | 994 ++ doc/voronoi_main.htm | 419 + doc/voronoi_predicates.htm | 251 + doc/voronoi_robust_fpt.htm | 212 + example/Jamfile.v2 | 37 + example/input_data/polygon/polygon_001.txt | 10 + example/input_data/polygon/polygon_002.txt | 16 + example/input_data/polygon/polygon_003.txt | 10 + example/input_data/polygon/polygon_004.txt | 10 + example/input_data/polygon/polygon_005.txt | 8 + example/input_data/polygon/polygon_006.txt | 9 + example/input_data/polygon/polygon_007.txt | 14 + example/input_data/polygon/polygon_008.txt | 12 + example/input_data/polygon/polygon_009.txt | 6 + example/input_data/polygon/polygon_010.txt | 25 + example/input_data/polygon/polygon_011.txt | 11 + example/input_data/polygon/polygon_012.txt | 14 + example/input_data/primary/primary_001.txt | 2 + example/input_data/primary/primary_002.txt | 3 + example/input_data/primary/primary_003.txt | 3 + example/input_data/primary/primary_004.txt | 3 + example/input_data/primary/primary_005.txt | 11 + example/input_data/primary/primary_006.txt | 11 + example/input_data/primary/primary_007.txt | 12 + example/input_data/primary/primary_008.txt | 11 + example/input_data/primary/primary_009.txt | 11 + example/input_data/primary/primary_010.txt | 4 + example/input_data/primary/primary_011.txt | 4 + example/input_data/primary/primary_012.txt | 5 + example/input_data/primary/primary_013.txt | 14 + example/input_data/primary/primary_014.txt | 13 + example/input_data/primary/primary_015.txt | 5 + example/input_data/primary/primary_016.txt | 101 + example/input_data/primary/primary_017.txt | 3 + example/input_data/primary/primary_018.txt | 6 + example/input_data/primary/primary_019.txt | 5 + example/input_data/primary/primary_020.txt | 7 + example/input_data/primary/primary_021.txt | 4 + example/input_data/primary/primary_022.txt | 5 + example/input_data/primary/primary_023.txt | 6 + example/input_data/primary/primary_024.txt | 4 + example/input_data/primary/primary_025.txt | 5 + example/input_data/primary/primary_026.txt | 6 + example/input_data/primary/primary_027.txt | 12 + example/input_data/primary/primary_028.txt | 5 + example/input_data/primary/primary_029.txt | 10 + example/input_data/primary/primary_030.txt | 14 + example/input_data/primary/primary_031.txt | 15 + example/input_data/primary/primary_032.txt | 6 + example/input_data/primary/primary_033.txt | 7 + example/input_data/primary/primary_034.txt | 6 + example/input_data/primary/primary_035.txt | 22 + example/input_data/primary/primary_036.txt | 102 + example/input_data/primary/primary_037.txt | 102 + example/input_data/primary/primary_038.txt | 222 + example/input_data/primary/primary_039.txt | 322 + example/input_data/primary/primary_040.txt | 11 + example/input_data/primary/primary_041.txt | 8 + example/input_data/primary/primary_042.txt | 5 + example/input_data/primary/primary_043.txt | 5 + example/input_data/primary/primary_044.txt | 5 + example/input_data/primary/primary_045.txt | 5 + example/input_data/primary/primary_046.txt | 5 + example/input_data/primary/primary_047.txt | 5 + example/input_data/primary/primary_048.txt | 11 + example/input_data/primary/primary_049.txt | 11 + example/input_data/primary/primary_050.txt | 5 + example/input_data/primary/primary_051.txt | 5 + example/input_data/primary/primary_052.txt | 5 + example/input_data/primary/primary_053.txt | 5 + example/input_data/primary/primary_054.txt | 4 + example/input_data/primary/primary_055.txt | 5 + example/input_data/primary/primary_056.txt | 5 + example/input_data/primary/primary_057.txt | 6 + example/input_data/primary/primary_058.txt | 9 + example/input_data/primary/primary_059.txt | 12 + example/input_data/primary/primary_060.txt | 12 + example/input_data/primary/primary_061.txt | 9 + example/input_data/primary/primary_062.txt | 4 + example/input_data/primary/primary_063.txt | 4 + example/input_data/primary/primary_064.txt | 4 + example/input_data/primary/primary_065.txt | 89 + example/input_data/primary/primary_066.txt | 195 + example/input_data/primary/primary_067.txt | 193 + example/input_data/primary/primary_068.txt | 98 + example/input_data/primary/primary_069.txt | 83 + example/input_data/primary/primary_070.txt | 5 + example/input_data/primary/primary_071.txt | 94 + example/input_data/random/random_001.txt | 11 + example/input_data/random/random_002.txt | 11 + example/input_data/random/random_003.txt | 11 + example/input_data/random/random_004.txt | 101 + example/input_data/random/random_005.txt | 101 + example/input_data/random/random_006.txt | 6 + example/input_data/random/random_007.txt | 6 + example/input_data/random/random_008.txt | 6 + example/input_data/random/random_009.txt | 7 + example/input_data/random/random_010.txt | 5 + example/input_data/random/random_011.txt | 7 + example/input_data/random/random_012.txt | 6 + example/input_data/random/random_013.txt | 6 + example/input_data/random/random_014.txt | 7 + example/input_data/random/random_015.txt | 5 + example/input_data/random/random_016.txt | 8 + example/input_data/random/random_017.txt | 5 + example/input_data/random/random_018.txt | 7 + example/input_data/random/random_019.txt | 7 + example/input_data/random/random_020.txt | 7 + example/input_data/random/random_021.txt | 7 + example/input_data/random/random_022.txt | 5 + example/input_data/random/random_023.txt | 8 + example/input_data/random/random_024.txt | 7 + example/input_data/random/random_025.txt | 4 + example/input_data/random/random_026.txt | 6 + example/input_data/random/random_027.txt | 8 + example/input_data/random/random_028.txt | 7 + example/output_data/polygon/polygon_001.png | Bin 0 -> 9500 bytes example/output_data/polygon/polygon_002.png | Bin 0 -> 12207 bytes example/output_data/polygon/polygon_003.png | Bin 0 -> 7968 bytes example/output_data/polygon/polygon_004.png | Bin 0 -> 8940 bytes example/output_data/polygon/polygon_005.png | Bin 0 -> 7298 bytes example/output_data/polygon/polygon_006.png | Bin 0 -> 6019 bytes example/output_data/polygon/polygon_007.png | Bin 0 -> 14067 bytes example/output_data/polygon/polygon_008.png | Bin 0 -> 10448 bytes example/output_data/polygon/polygon_009.png | Bin 0 -> 3888 bytes example/output_data/polygon/polygon_010.png | Bin 0 -> 8950 bytes example/output_data/polygon/polygon_011.png | Bin 0 -> 14867 bytes example/output_data/polygon/polygon_012.png | Bin 0 -> 11417 bytes example/output_data/primary/primary_001.png | Bin 0 -> 2842 bytes example/output_data/primary/primary_002.png | Bin 0 -> 2861 bytes example/output_data/primary/primary_003.png | Bin 0 -> 2877 bytes example/output_data/primary/primary_004.png | Bin 0 -> 5182 bytes example/output_data/primary/primary_005.png | Bin 0 -> 3211 bytes example/output_data/primary/primary_006.png | Bin 0 -> 2981 bytes example/output_data/primary/primary_007.png | Bin 0 -> 9544 bytes example/output_data/primary/primary_008.png | Bin 0 -> 17041 bytes example/output_data/primary/primary_009.png | Bin 0 -> 14278 bytes example/output_data/primary/primary_010.png | Bin 0 -> 6278 bytes example/output_data/primary/primary_011.png | Bin 0 -> 4652 bytes example/output_data/primary/primary_012.png | Bin 0 -> 2953 bytes example/output_data/primary/primary_013.png | Bin 0 -> 12323 bytes example/output_data/primary/primary_014.png | Bin 0 -> 13061 bytes example/output_data/primary/primary_015.png | Bin 0 -> 4778 bytes example/output_data/primary/primary_016.png | Bin 0 -> 47851 bytes example/output_data/primary/primary_017.png | Bin 0 -> 6351 bytes example/output_data/primary/primary_018.png | Bin 0 -> 8900 bytes example/output_data/primary/primary_019.png | Bin 0 -> 9141 bytes example/output_data/primary/primary_020.png | Bin 0 -> 5768 bytes example/output_data/primary/primary_021.png | Bin 0 -> 4957 bytes example/output_data/primary/primary_022.png | Bin 0 -> 7705 bytes example/output_data/primary/primary_023.png | Bin 0 -> 5431 bytes example/output_data/primary/primary_024.png | Bin 0 -> 5344 bytes example/output_data/primary/primary_025.png | Bin 0 -> 6234 bytes example/output_data/primary/primary_026.png | Bin 0 -> 12161 bytes example/output_data/primary/primary_027.png | Bin 0 -> 15319 bytes example/output_data/primary/primary_028.png | Bin 0 -> 8837 bytes example/output_data/primary/primary_029.png | Bin 0 -> 14114 bytes example/output_data/primary/primary_030.png | Bin 0 -> 27849 bytes example/output_data/primary/primary_031.png | Bin 0 -> 26276 bytes example/output_data/primary/primary_032.png | Bin 0 -> 7399 bytes example/output_data/primary/primary_033.png | Bin 0 -> 5549 bytes example/output_data/primary/primary_034.png | Bin 0 -> 10666 bytes example/output_data/primary/primary_035.png | Bin 0 -> 31164 bytes example/output_data/primary/primary_036.png | Bin 0 -> 61406 bytes example/output_data/primary/primary_037.png | Bin 0 -> 50157 bytes example/output_data/primary/primary_038.png | Bin 0 -> 7359 bytes example/output_data/primary/primary_039.png | Bin 0 -> 7862 bytes example/output_data/primary/primary_040.png | Bin 0 -> 8257 bytes example/output_data/primary/primary_041.png | Bin 0 -> 7631 bytes example/output_data/primary/primary_042.png | Bin 0 -> 10438 bytes example/output_data/primary/primary_043.png | Bin 0 -> 10944 bytes example/output_data/primary/primary_044.png | Bin 0 -> 9482 bytes example/output_data/primary/primary_045.png | Bin 0 -> 12269 bytes example/output_data/primary/primary_046.png | Bin 0 -> 8573 bytes example/output_data/primary/primary_047.png | Bin 0 -> 7449 bytes example/output_data/primary/primary_048.png | Bin 0 -> 11755 bytes example/output_data/primary/primary_049.png | Bin 0 -> 14124 bytes example/output_data/primary/primary_050.png | Bin 0 -> 5447 bytes example/output_data/primary/primary_051.png | Bin 0 -> 12672 bytes example/output_data/primary/primary_052.png | Bin 0 -> 7824 bytes example/output_data/primary/primary_053.png | Bin 0 -> 6396 bytes example/output_data/primary/primary_054.png | Bin 0 -> 11227 bytes example/output_data/primary/primary_055.png | Bin 0 -> 12364 bytes example/output_data/primary/primary_056.png | Bin 0 -> 4297 bytes example/output_data/primary/primary_057.png | Bin 0 -> 7456 bytes example/output_data/primary/primary_058.png | Bin 0 -> 11550 bytes example/output_data/primary/primary_059.png | Bin 0 -> 13852 bytes example/output_data/primary/primary_060.png | Bin 0 -> 13852 bytes example/output_data/primary/primary_061.png | Bin 0 -> 12784 bytes example/output_data/primary/primary_062.png | Bin 0 -> 6202 bytes example/output_data/primary/primary_063.png | Bin 0 -> 10667 bytes example/output_data/primary/primary_064.png | Bin 0 -> 12733 bytes example/output_data/primary/primary_065.png | Bin 0 -> 38011 bytes example/output_data/primary/primary_066.png | Bin 0 -> 48815 bytes example/output_data/primary/primary_067.png | Bin 0 -> 47665 bytes example/output_data/primary/primary_068.png | Bin 0 -> 42123 bytes example/output_data/primary/primary_069.png | Bin 0 -> 36872 bytes example/output_data/primary/primary_070.png | Bin 0 -> 5049 bytes example/output_data/primary/primary_071.png | Bin 0 -> 37845 bytes example/output_data/random/random_001.png | Bin 0 -> 8550 bytes example/output_data/random/random_002.png | Bin 0 -> 7787 bytes example/output_data/random/random_003.png | Bin 0 -> 7724 bytes example/output_data/random/random_004.png | Bin 0 -> 27628 bytes example/output_data/random/random_005.png | Bin 0 -> 27628 bytes example/output_data/random/random_006.png | Bin 0 -> 8754 bytes example/output_data/random/random_007.png | Bin 0 -> 10159 bytes example/output_data/random/random_008.png | Bin 0 -> 11149 bytes example/output_data/random/random_009.png | Bin 0 -> 10923 bytes example/output_data/random/random_010.png | Bin 0 -> 9809 bytes example/output_data/random/random_011.png | Bin 0 -> 9952 bytes example/output_data/random/random_012.png | Bin 0 -> 7909 bytes example/output_data/random/random_013.png | Bin 0 -> 12090 bytes example/output_data/random/random_014.png | Bin 0 -> 11311 bytes example/output_data/random/random_015.png | Bin 0 -> 8121 bytes example/output_data/random/random_016.png | Bin 0 -> 12758 bytes example/output_data/random/random_017.png | Bin 0 -> 8311 bytes example/output_data/random/random_018.png | Bin 0 -> 9593 bytes example/output_data/random/random_019.png | Bin 0 -> 11819 bytes example/output_data/random/random_020.png | Bin 0 -> 12134 bytes example/output_data/random/random_021.png | Bin 0 -> 9570 bytes example/output_data/random/random_022.png | Bin 0 -> 9476 bytes example/output_data/random/random_023.png | Bin 0 -> 10424 bytes example/output_data/random/random_024.png | Bin 0 -> 9721 bytes example/output_data/random/random_025.png | Bin 0 -> 7163 bytes example/output_data/random/random_026.png | Bin 0 -> 11099 bytes example/output_data/random/random_027.png | Bin 0 -> 12574 bytes example/output_data/random/random_028.png | Bin 0 -> 12887 bytes example/voronoi_advanced_tutorial.cpp | 145 + example/voronoi_basic_tutorial.cpp | 193 + example/voronoi_visual_utils.hpp | 186 + example/voronoi_visualizer.cpp | 509 + include/boost/polygon/detail/boolean_op.hpp | 68 +- .../boost/polygon/detail/boolean_op_45.hpp | 132 +- .../detail/iterator_compact_to_points.hpp | 5 +- .../detail/iterator_geometry_to_set.hpp | 43 +- include/boost/polygon/detail/max_cover.hpp | 12 +- include/boost/polygon/detail/minkowski.hpp | 14 +- .../polygon/detail/polygon_45_formation.hpp | 250 +- .../polygon/detail/polygon_45_set_view.hpp | 85 +- .../boost/polygon/detail/polygon_45_touch.hpp | 30 +- .../polygon/detail/polygon_90_set_view.hpp | 121 +- .../boost/polygon/detail/polygon_90_touch.hpp | 38 +- .../detail/polygon_arbitrary_formation.hpp | 328 +- .../polygon/detail/polygon_formation.hpp | 249 +- .../boost/polygon/detail/polygon_set_view.hpp | 96 +- .../boost/polygon/detail/polygon_simplify.hpp | 28 +- .../polygon/detail/polygon_sort_adaptor.hpp | 30 +- .../boost/polygon/detail/property_merge.hpp | 24 +- .../polygon/detail/property_merge_45.hpp | 18 +- .../polygon/detail/rectangle_formation.hpp | 59 +- .../boost/polygon/detail/scan_arbitrary.hpp | 333 +- .../boost/polygon/detail/transform_detail.hpp | 177 +- .../boost/polygon/detail/voronoi_ctypes.hpp | 650 + .../polygon/detail/voronoi_predicates.hpp | 1520 +++ .../polygon/detail/voronoi_robust_fpt.hpp | 519 + .../polygon/detail/voronoi_structures.hpp | 461 + include/boost/polygon/gmp_override.hpp | 13 +- include/boost/polygon/gtl.hpp | 2 +- include/boost/polygon/interval_concept.hpp | 388 +- include/boost/polygon/interval_data.hpp | 34 +- include/boost/polygon/interval_traits.hpp | 11 +- include/boost/polygon/isotropy.hpp | 40 +- include/boost/polygon/point_3d_concept.hpp | 92 +- include/boost/polygon/point_3d_data.hpp | 10 +- include/boost/polygon/point_3d_traits.hpp | 3 +- include/boost/polygon/point_concept.hpp | 238 +- include/boost/polygon/point_data.hpp | 27 +- include/boost/polygon/point_traits.hpp | 11 +- include/boost/polygon/polygon.hpp | 9 +- include/boost/polygon/polygon_45_data.hpp | 7 +- .../boost/polygon/polygon_45_set_concept.hpp | 34 +- include/boost/polygon/polygon_45_set_data.hpp | 191 +- .../boost/polygon/polygon_45_set_traits.hpp | 19 +- .../polygon/polygon_45_with_holes_data.hpp | 13 +- include/boost/polygon/polygon_90_data.hpp | 11 +- .../boost/polygon/polygon_90_set_concept.hpp | 65 +- include/boost/polygon/polygon_90_set_data.hpp | 103 +- .../boost/polygon/polygon_90_set_traits.hpp | 52 +- .../polygon/polygon_90_with_holes_data.hpp | 13 +- include/boost/polygon/polygon_data.hpp | 7 +- include/boost/polygon/polygon_set_concept.hpp | 90 +- include/boost/polygon/polygon_set_data.hpp | 149 +- include/boost/polygon/polygon_set_traits.hpp | 21 +- include/boost/polygon/polygon_traits.hpp | 265 +- .../boost/polygon/polygon_with_holes_data.hpp | 15 +- include/boost/polygon/rectangle_concept.hpp | 446 +- include/boost/polygon/rectangle_data.hpp | 7 +- include/boost/polygon/rectangle_traits.hpp | 3 +- include/boost/polygon/segment_concept.hpp | 754 ++ include/boost/polygon/segment_data.hpp | 108 + include/boost/polygon/segment_traits.hpp | 38 + include/boost/polygon/segment_utils.hpp | 159 + include/boost/polygon/transform.hpp | 323 +- include/boost/polygon/voronoi.hpp | 155 + include/boost/polygon/voronoi_builder.hpp | 517 + include/boost/polygon/voronoi_diagram.hpp | 620 + .../boost/polygon/voronoi_geometry_type.hpp | 46 + test/Jamfile.v2 | 16 +- test/gtl_boost_unit_test.cpp | 261 +- test/polygon_segment_test.cpp | 431 + test/voronoi_builder_test.cpp | 636 + test/voronoi_ctypes_test.cpp | 295 + test/voronoi_diagram_test.cpp | 113 + test/voronoi_geometry_type_test.cpp | 28 + test/voronoi_predicates_test.cpp | 463 + test/voronoi_robust_fpt_test.cpp | 355 + test/voronoi_structures_test.cpp | 131 + test/voronoi_test_helper.hpp | 260 + 383 files changed, 37489 insertions(+), 4244 deletions(-) create mode 100644 benchmark/Jamfile.v2 create mode 100644 benchmark/benchmark_results/benchmark_points.txt create mode 100644 benchmark/benchmark_results/benchmark_segments.txt create mode 100644 benchmark/benchmark_results/plots/benchmark_points_10.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_100.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_1000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_10000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_100000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_1000000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_all.png create mode 100644 benchmark/benchmark_results/plots/benchmark_points_memory.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_10.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_100.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_1000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_10000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_100000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_1000000.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_all.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments_memory.png create mode 100644 benchmark/input_data/voronoi_point.txt create mode 100644 benchmark/input_data/voronoi_segment.txt create mode 100644 benchmark/voronoi_benchmark.cpp create mode 100644 benchmark/voronoi_benchmark_points.cpp create mode 100644 benchmark/voronoi_benchmark_segments.cpp create mode 100644 doc/gtl_segment_concept.htm create mode 100644 doc/images/benchmark_points_10.png create mode 100644 doc/images/benchmark_points_100.png create mode 100644 doc/images/benchmark_points_1000.png create mode 100644 doc/images/benchmark_points_10000.png create mode 100644 doc/images/benchmark_points_100000.png create mode 100644 doc/images/benchmark_points_1000000.png create mode 100644 doc/images/benchmark_points_all.png create mode 100644 doc/images/benchmark_points_memory.png create mode 100644 doc/images/benchmark_segments_10.png create mode 100644 doc/images/benchmark_segments_100.png create mode 100644 doc/images/benchmark_segments_1000.png create mode 100644 doc/images/benchmark_segments_10000.png create mode 100644 doc/images/benchmark_segments_100000.png create mode 100644 doc/images/benchmark_segments_1000000.png create mode 100644 doc/images/benchmark_segments_all.png create mode 100644 doc/images/benchmark_segments_memory.png create mode 100644 doc/images/rover.jpg create mode 100644 doc/images/vlsi.jpg create mode 100644 doc/images/voronoi.png create mode 100644 doc/images/voronoi2.png create mode 100644 doc/images/voronoi3.png create mode 100644 doc/images/voronoi4.png create mode 100644 doc/voronoi_advanced_tutorial.htm create mode 100644 doc/voronoi_basic_tutorial.htm create mode 100644 doc/voronoi_benchmark.htm create mode 100644 doc/voronoi_builder.htm create mode 100644 doc/voronoi_diagram.htm create mode 100644 doc/voronoi_main.htm create mode 100644 doc/voronoi_predicates.htm create mode 100644 doc/voronoi_robust_fpt.htm create mode 100644 example/Jamfile.v2 create mode 100644 example/input_data/polygon/polygon_001.txt create mode 100644 example/input_data/polygon/polygon_002.txt create mode 100644 example/input_data/polygon/polygon_003.txt create mode 100644 example/input_data/polygon/polygon_004.txt create mode 100644 example/input_data/polygon/polygon_005.txt create mode 100644 example/input_data/polygon/polygon_006.txt create mode 100644 example/input_data/polygon/polygon_007.txt create mode 100644 example/input_data/polygon/polygon_008.txt create mode 100644 example/input_data/polygon/polygon_009.txt create mode 100644 example/input_data/polygon/polygon_010.txt create mode 100644 example/input_data/polygon/polygon_011.txt create mode 100644 example/input_data/polygon/polygon_012.txt create mode 100644 example/input_data/primary/primary_001.txt create mode 100644 example/input_data/primary/primary_002.txt create mode 100644 example/input_data/primary/primary_003.txt create mode 100644 example/input_data/primary/primary_004.txt create mode 100644 example/input_data/primary/primary_005.txt create mode 100644 example/input_data/primary/primary_006.txt create mode 100644 example/input_data/primary/primary_007.txt create mode 100644 example/input_data/primary/primary_008.txt create mode 100644 example/input_data/primary/primary_009.txt create mode 100644 example/input_data/primary/primary_010.txt create mode 100644 example/input_data/primary/primary_011.txt create mode 100644 example/input_data/primary/primary_012.txt create mode 100644 example/input_data/primary/primary_013.txt create mode 100644 example/input_data/primary/primary_014.txt create mode 100644 example/input_data/primary/primary_015.txt create mode 100644 example/input_data/primary/primary_016.txt create mode 100644 example/input_data/primary/primary_017.txt create mode 100644 example/input_data/primary/primary_018.txt create mode 100644 example/input_data/primary/primary_019.txt create mode 100644 example/input_data/primary/primary_020.txt create mode 100644 example/input_data/primary/primary_021.txt create mode 100644 example/input_data/primary/primary_022.txt create mode 100644 example/input_data/primary/primary_023.txt create mode 100644 example/input_data/primary/primary_024.txt create mode 100644 example/input_data/primary/primary_025.txt create mode 100644 example/input_data/primary/primary_026.txt create mode 100644 example/input_data/primary/primary_027.txt create mode 100644 example/input_data/primary/primary_028.txt create mode 100644 example/input_data/primary/primary_029.txt create mode 100644 example/input_data/primary/primary_030.txt create mode 100644 example/input_data/primary/primary_031.txt create mode 100644 example/input_data/primary/primary_032.txt create mode 100644 example/input_data/primary/primary_033.txt create mode 100644 example/input_data/primary/primary_034.txt create mode 100644 example/input_data/primary/primary_035.txt create mode 100644 example/input_data/primary/primary_036.txt create mode 100644 example/input_data/primary/primary_037.txt create mode 100644 example/input_data/primary/primary_038.txt create mode 100644 example/input_data/primary/primary_039.txt create mode 100644 example/input_data/primary/primary_040.txt create mode 100644 example/input_data/primary/primary_041.txt create mode 100644 example/input_data/primary/primary_042.txt create mode 100644 example/input_data/primary/primary_043.txt create mode 100644 example/input_data/primary/primary_044.txt create mode 100644 example/input_data/primary/primary_045.txt create mode 100644 example/input_data/primary/primary_046.txt create mode 100644 example/input_data/primary/primary_047.txt create mode 100644 example/input_data/primary/primary_048.txt create mode 100644 example/input_data/primary/primary_049.txt create mode 100644 example/input_data/primary/primary_050.txt create mode 100644 example/input_data/primary/primary_051.txt create mode 100644 example/input_data/primary/primary_052.txt create mode 100644 example/input_data/primary/primary_053.txt create mode 100644 example/input_data/primary/primary_054.txt create mode 100644 example/input_data/primary/primary_055.txt create mode 100644 example/input_data/primary/primary_056.txt create mode 100644 example/input_data/primary/primary_057.txt create mode 100644 example/input_data/primary/primary_058.txt create mode 100644 example/input_data/primary/primary_059.txt create mode 100644 example/input_data/primary/primary_060.txt create mode 100644 example/input_data/primary/primary_061.txt create mode 100644 example/input_data/primary/primary_062.txt create mode 100644 example/input_data/primary/primary_063.txt create mode 100644 example/input_data/primary/primary_064.txt create mode 100644 example/input_data/primary/primary_065.txt create mode 100644 example/input_data/primary/primary_066.txt create mode 100644 example/input_data/primary/primary_067.txt create mode 100644 example/input_data/primary/primary_068.txt create mode 100644 example/input_data/primary/primary_069.txt create mode 100644 example/input_data/primary/primary_070.txt create mode 100644 example/input_data/primary/primary_071.txt create mode 100644 example/input_data/random/random_001.txt create mode 100644 example/input_data/random/random_002.txt create mode 100644 example/input_data/random/random_003.txt create mode 100644 example/input_data/random/random_004.txt create mode 100644 example/input_data/random/random_005.txt create mode 100644 example/input_data/random/random_006.txt create mode 100644 example/input_data/random/random_007.txt create mode 100644 example/input_data/random/random_008.txt create mode 100644 example/input_data/random/random_009.txt create mode 100644 example/input_data/random/random_010.txt create mode 100644 example/input_data/random/random_011.txt create mode 100644 example/input_data/random/random_012.txt create mode 100644 example/input_data/random/random_013.txt create mode 100644 example/input_data/random/random_014.txt create mode 100644 example/input_data/random/random_015.txt create mode 100644 example/input_data/random/random_016.txt create mode 100644 example/input_data/random/random_017.txt create mode 100644 example/input_data/random/random_018.txt create mode 100644 example/input_data/random/random_019.txt create mode 100644 example/input_data/random/random_020.txt create mode 100644 example/input_data/random/random_021.txt create mode 100644 example/input_data/random/random_022.txt create mode 100644 example/input_data/random/random_023.txt create mode 100644 example/input_data/random/random_024.txt create mode 100644 example/input_data/random/random_025.txt create mode 100644 example/input_data/random/random_026.txt create mode 100644 example/input_data/random/random_027.txt create mode 100644 example/input_data/random/random_028.txt create mode 100644 example/output_data/polygon/polygon_001.png create mode 100644 example/output_data/polygon/polygon_002.png create mode 100644 example/output_data/polygon/polygon_003.png create mode 100644 example/output_data/polygon/polygon_004.png create mode 100644 example/output_data/polygon/polygon_005.png create mode 100644 example/output_data/polygon/polygon_006.png create mode 100644 example/output_data/polygon/polygon_007.png create mode 100644 example/output_data/polygon/polygon_008.png create mode 100644 example/output_data/polygon/polygon_009.png create mode 100644 example/output_data/polygon/polygon_010.png create mode 100644 example/output_data/polygon/polygon_011.png create mode 100644 example/output_data/polygon/polygon_012.png create mode 100644 example/output_data/primary/primary_001.png create mode 100644 example/output_data/primary/primary_002.png create mode 100644 example/output_data/primary/primary_003.png create mode 100644 example/output_data/primary/primary_004.png create mode 100644 example/output_data/primary/primary_005.png create mode 100644 example/output_data/primary/primary_006.png create mode 100644 example/output_data/primary/primary_007.png create mode 100644 example/output_data/primary/primary_008.png create mode 100644 example/output_data/primary/primary_009.png create mode 100644 example/output_data/primary/primary_010.png create mode 100644 example/output_data/primary/primary_011.png create mode 100644 example/output_data/primary/primary_012.png create mode 100644 example/output_data/primary/primary_013.png create mode 100644 example/output_data/primary/primary_014.png create mode 100644 example/output_data/primary/primary_015.png create mode 100644 example/output_data/primary/primary_016.png create mode 100644 example/output_data/primary/primary_017.png create mode 100644 example/output_data/primary/primary_018.png create mode 100644 example/output_data/primary/primary_019.png create mode 100644 example/output_data/primary/primary_020.png create mode 100644 example/output_data/primary/primary_021.png create mode 100644 example/output_data/primary/primary_022.png create mode 100644 example/output_data/primary/primary_023.png create mode 100644 example/output_data/primary/primary_024.png create mode 100644 example/output_data/primary/primary_025.png create mode 100644 example/output_data/primary/primary_026.png create mode 100644 example/output_data/primary/primary_027.png create mode 100644 example/output_data/primary/primary_028.png create mode 100644 example/output_data/primary/primary_029.png create mode 100644 example/output_data/primary/primary_030.png create mode 100644 example/output_data/primary/primary_031.png create mode 100644 example/output_data/primary/primary_032.png create mode 100644 example/output_data/primary/primary_033.png create mode 100644 example/output_data/primary/primary_034.png create mode 100644 example/output_data/primary/primary_035.png create mode 100644 example/output_data/primary/primary_036.png create mode 100644 example/output_data/primary/primary_037.png create mode 100644 example/output_data/primary/primary_038.png create mode 100644 example/output_data/primary/primary_039.png create mode 100644 example/output_data/primary/primary_040.png create mode 100644 example/output_data/primary/primary_041.png create mode 100644 example/output_data/primary/primary_042.png create mode 100644 example/output_data/primary/primary_043.png create mode 100644 example/output_data/primary/primary_044.png create mode 100644 example/output_data/primary/primary_045.png create mode 100644 example/output_data/primary/primary_046.png create mode 100644 example/output_data/primary/primary_047.png create mode 100644 example/output_data/primary/primary_048.png create mode 100644 example/output_data/primary/primary_049.png create mode 100644 example/output_data/primary/primary_050.png create mode 100644 example/output_data/primary/primary_051.png create mode 100644 example/output_data/primary/primary_052.png create mode 100644 example/output_data/primary/primary_053.png create mode 100644 example/output_data/primary/primary_054.png create mode 100644 example/output_data/primary/primary_055.png create mode 100644 example/output_data/primary/primary_056.png create mode 100644 example/output_data/primary/primary_057.png create mode 100644 example/output_data/primary/primary_058.png create mode 100644 example/output_data/primary/primary_059.png create mode 100644 example/output_data/primary/primary_060.png create mode 100644 example/output_data/primary/primary_061.png create mode 100644 example/output_data/primary/primary_062.png create mode 100644 example/output_data/primary/primary_063.png create mode 100644 example/output_data/primary/primary_064.png create mode 100644 example/output_data/primary/primary_065.png create mode 100644 example/output_data/primary/primary_066.png create mode 100644 example/output_data/primary/primary_067.png create mode 100644 example/output_data/primary/primary_068.png create mode 100644 example/output_data/primary/primary_069.png create mode 100644 example/output_data/primary/primary_070.png create mode 100644 example/output_data/primary/primary_071.png create mode 100644 example/output_data/random/random_001.png create mode 100644 example/output_data/random/random_002.png create mode 100644 example/output_data/random/random_003.png create mode 100644 example/output_data/random/random_004.png create mode 100644 example/output_data/random/random_005.png create mode 100644 example/output_data/random/random_006.png create mode 100644 example/output_data/random/random_007.png create mode 100644 example/output_data/random/random_008.png create mode 100644 example/output_data/random/random_009.png create mode 100644 example/output_data/random/random_010.png create mode 100644 example/output_data/random/random_011.png create mode 100644 example/output_data/random/random_012.png create mode 100644 example/output_data/random/random_013.png create mode 100644 example/output_data/random/random_014.png create mode 100644 example/output_data/random/random_015.png create mode 100644 example/output_data/random/random_016.png create mode 100644 example/output_data/random/random_017.png create mode 100644 example/output_data/random/random_018.png create mode 100644 example/output_data/random/random_019.png create mode 100644 example/output_data/random/random_020.png create mode 100644 example/output_data/random/random_021.png create mode 100644 example/output_data/random/random_022.png create mode 100644 example/output_data/random/random_023.png create mode 100644 example/output_data/random/random_024.png create mode 100644 example/output_data/random/random_025.png create mode 100644 example/output_data/random/random_026.png create mode 100644 example/output_data/random/random_027.png create mode 100644 example/output_data/random/random_028.png create mode 100644 example/voronoi_advanced_tutorial.cpp create mode 100644 example/voronoi_basic_tutorial.cpp create mode 100644 example/voronoi_visual_utils.hpp create mode 100644 example/voronoi_visualizer.cpp mode change 100755 => 100644 include/boost/polygon/detail/polygon_sort_adaptor.hpp create mode 100644 include/boost/polygon/detail/voronoi_ctypes.hpp create mode 100644 include/boost/polygon/detail/voronoi_predicates.hpp create mode 100644 include/boost/polygon/detail/voronoi_robust_fpt.hpp create mode 100644 include/boost/polygon/detail/voronoi_structures.hpp mode change 100755 => 100644 include/boost/polygon/gmp_override.hpp mode change 100755 => 100644 include/boost/polygon/gtl.hpp mode change 100755 => 100644 include/boost/polygon/interval_concept.hpp mode change 100755 => 100644 include/boost/polygon/interval_data.hpp mode change 100755 => 100644 include/boost/polygon/interval_traits.hpp mode change 100755 => 100644 include/boost/polygon/isotropy.hpp mode change 100755 => 100644 include/boost/polygon/point_3d_concept.hpp mode change 100755 => 100644 include/boost/polygon/point_3d_data.hpp mode change 100755 => 100644 include/boost/polygon/point_3d_traits.hpp mode change 100755 => 100644 include/boost/polygon/point_concept.hpp mode change 100755 => 100644 include/boost/polygon/point_data.hpp mode change 100755 => 100644 include/boost/polygon/point_traits.hpp mode change 100755 => 100644 include/boost/polygon/polygon.hpp mode change 100755 => 100644 include/boost/polygon/polygon_45_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_45_set_concept.hpp mode change 100755 => 100644 include/boost/polygon/polygon_45_set_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_45_set_traits.hpp mode change 100755 => 100644 include/boost/polygon/polygon_45_with_holes_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_90_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_90_set_concept.hpp mode change 100755 => 100644 include/boost/polygon/polygon_90_set_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_90_set_traits.hpp mode change 100755 => 100644 include/boost/polygon/polygon_90_with_holes_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_set_concept.hpp mode change 100755 => 100644 include/boost/polygon/polygon_set_data.hpp mode change 100755 => 100644 include/boost/polygon/polygon_set_traits.hpp mode change 100755 => 100644 include/boost/polygon/polygon_traits.hpp mode change 100755 => 100644 include/boost/polygon/polygon_with_holes_data.hpp mode change 100755 => 100644 include/boost/polygon/rectangle_concept.hpp mode change 100755 => 100644 include/boost/polygon/rectangle_data.hpp mode change 100755 => 100644 include/boost/polygon/rectangle_traits.hpp create mode 100644 include/boost/polygon/segment_concept.hpp create mode 100644 include/boost/polygon/segment_data.hpp create mode 100644 include/boost/polygon/segment_traits.hpp create mode 100644 include/boost/polygon/segment_utils.hpp mode change 100755 => 100644 include/boost/polygon/transform.hpp create mode 100644 include/boost/polygon/voronoi.hpp create mode 100644 include/boost/polygon/voronoi_builder.hpp create mode 100644 include/boost/polygon/voronoi_diagram.hpp create mode 100644 include/boost/polygon/voronoi_geometry_type.hpp create mode 100644 test/polygon_segment_test.cpp create mode 100644 test/voronoi_builder_test.cpp create mode 100644 test/voronoi_ctypes_test.cpp create mode 100644 test/voronoi_diagram_test.cpp create mode 100644 test/voronoi_geometry_type_test.cpp create mode 100644 test/voronoi_predicates_test.cpp create mode 100644 test/voronoi_robust_fpt_test.cpp create mode 100644 test/voronoi_structures_test.cpp create mode 100644 test/voronoi_test_helper.hpp diff --git a/benchmark/Jamfile.v2 b/benchmark/Jamfile.v2 new file mode 100644 index 0000000..41b7bd0 --- /dev/null +++ b/benchmark/Jamfile.v2 @@ -0,0 +1,39 @@ +# Copyright Andrii Sydorchuk 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import testing ; + +project voronoi-benchmark + : + requirements + $(CGAL_ROOT)/include + $(SHULL_ROOT) + msvc:$(CGAL_ROOT)/auxiliary/gmp/include + msvc:$(CGAL_ROOT)/lib/libCGAL-vc90-mt-4.0.lib + msvc:$(CGAL_ROOT)/lib/libCGAL_Core-vc90-mt-4.0.lib + msvc:$(CGAL_ROOT)/auxiliary/gmp/lib/libgmp-10.lib + msvc:$(CGAL_ROOT)/auxiliary/gmp/lib/libmpfr-4.lib + msvc:$(BOOST_ROOT)/libs/thread/build//boost_thread + msvc:$(BOOST_ROOT)/libs/test/build//boost_unit_test_framework + gcc:$(CGAL_ROOT)/lib/libCGAL.so + gcc:$(CGAL_ROOT)/lib/libCGAL_Core.so + gcc:$(SHULL_ROOT)/s_hull.so + gcc:$(BOOST_ROOT)/libs/test/build//boost_unit_test_framework + ; + +alias "benchmark-general" + : + [ run voronoi_benchmark.cpp ] + ; + +alias "benchmark-points" + : + [ run voronoi_benchmark_points.cpp ] + ; + +alias "benchmark-segments" + : + [ run voronoi_benchmark_segments.cpp ] + ; diff --git a/benchmark/benchmark_results/benchmark_points.txt b/benchmark/benchmark_results/benchmark_points.txt new file mode 100644 index 0000000..eb4ec61 --- /dev/null +++ b/benchmark/benchmark_results/benchmark_points.txt @@ -0,0 +1,60 @@ +System: CPU i5-7600 2.8 GHz, 4Gb RAM. +OS: Windows 7 Professional 32 bit. +Compiler: MSVC-9.0. + +Boost.Polygon Voronoi of Points: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000027 | +| 100 | 10000 | 0.000392 | +| 1000 | 1000 | 0.004541 | +| 10000 | 100 | 0.047540 | +| 100000 | 10 | 0.530200 | +| 1000000 | 1 | 5.882000 | + +CGAL Triangulation of Points: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000116 | +| 100 | 10000 | 0.002649 | +| 1000 | 1000 | 0.039140 | +| 10000 | 100 | 0.684090 | +| 100000 | 10 | 16.904600 | +| 1000000 | 1 | 566.056000 | + +S-Hull Triangulation of Points: +| 10 | 100000 | 0.000043 | +| 100 | 10000 | 0.000521 | +| 1000 | 1000 | 0.007125 | +| 10000 | 100 | 0.091640 | +| 100000 | 10 | 1.218000 | +| 1000000 | 1 | 15.394000 | + +System: CPU i5-7600 2.8 GHz, 4Gb RAM. +OS: Ubuntu 11.10 64 bit. +Compiler: gcc 4.6.1. + +Boost.Polygon Voronoi of Points: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000013 | +| 100 | 10000 | 0.000192 | +| 1000 | 1000 | 0.002130 | +| 10000 | 100 | 0.022900 | +| 100000 | 10 | 0.274000 | +| 1000000 | 1 | 3.290000 | + +CGAL Triangulation of Points: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000052 | +| 100 | 10000 | 0.001150 | +| 1000 | 1000 | 0.016680 | +| 10000 | 100 | 0.297900 | +| 100000 | 10 | 8.047000 | +| 1000000 | 1 | 315.740000 | + +S-Hull Triangulation of Points: +| 10 | 100000 | 0.000012 | +| 100 | 10000 | 0.000139 | +| 1000 | 1000 | 0.002010 | +| 10000 | 100 | 0.028300 | +| 100000 | 10 | 0.432000 | +| 1000000 | 1 | 6.350000 | + diff --git a/benchmark/benchmark_results/benchmark_segments.txt b/benchmark/benchmark_results/benchmark_segments.txt new file mode 100644 index 0000000..da27ac1 --- /dev/null +++ b/benchmark/benchmark_results/benchmark_segments.txt @@ -0,0 +1,44 @@ +System: CPU i5-7600 2.8 GHz, 4Gb RAM. +OS: Windows 7 Professional 32 bit. +Compiler: MSVC-9.0. + +Boost.Polygon Voronoi of Segments: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000290 | +| 100 | 10000 | 0.003655 | +| 1000 | 1000 | 0.038158 | +| 10000 | 100 | 0.389470 | +| 100000 | 10 | 4.031300 | +| 1000000 | 1 | 40.912000 | + +CGAL Triangulation of Segments: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.001047 | +| 100 | 10000 | 0.014812 | +| 1000 | 1000 | 0.177315 | +| 10000 | 100 | 2.561340 | +| 100000 | 10 | 49.314600 | +| 1000000 | 1 | 1640.830000 | + +System: CPU i5-7600 2.8 GHz, 4Gb RAM. +OS: Ubuntu 11.10 64 bit. +Compiler: gcc 4.6.1. + +Boost.Polygon Voronoi of Segments: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000165 | +| 100 | 10000 | 0.002006 | +| 1000 | 1000 | 0.020440 | +| 10000 | 100 | 0.209700 | +| 100000 | 10 | 2.228000 | +| 1000000 | 1 | 22.250000 | + +CGAL Triangulation of Segments: +| Number of points | Number of tests | Time per one test | +| 10 | 100000 | 0.000483 | +| 100 | 10000 | 0.007006 | +| 1000 | 1000 | 0.084000 | +| 10000 | 100 | 1.191900 | +| 100000 | 10 | 23.538000 | +| 1000000 | 1 | 856.650000 | + diff --git a/benchmark/benchmark_results/plots/benchmark_points_10.png b/benchmark/benchmark_results/plots/benchmark_points_10.png new file mode 100644 index 0000000000000000000000000000000000000000..98d4eafaae14facb09f006b2ee3575ae790246f4 GIT binary patch literal 15729 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_points_100.png b/benchmark/benchmark_results/plots/benchmark_points_100.png new file mode 100644 index 0000000000000000000000000000000000000000..b876cbaecd40dd1c153aa708bd132873fc41dc7b GIT binary patch literal 16377 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

FBNOl9xx-1NG;;~8jlLd#<&$! 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 gkPksc^*lrj3=9lxN#5=*4F5rJ!QSPQ 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_points_1000000.png b/benchmark/benchmark_results/plots/benchmark_points_1000000.png new file mode 100644 index 0000000000000000000000000000000000000000..470962695be86ef2aaa950d855b7abdeb36fc427 GIT binary patch literal 16201 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_points_all.png b/benchmark/benchmark_results/plots/benchmark_points_all.png new file mode 100644 index 0000000000000000000000000000000000000000..68f89ca1571e09918b8af03fe01b273ea1d29f06 GIT binary patch literal 22818 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%0AlP2}s|NHUk>gspz z-W@%9v~P~QnzeQH+gn?8rhQH?E39MjznT;OVXJ;f+WM_o*1cP+XYO^AuYP~ew!FOD z+}xbu!-o$U4+6L6-=Ak$tY%yNTRgtz;M1bzzO%1&aFvh z&j}0+40TUFe&k3+MFk5BOOK>++P6116&0^~*Ic;Vb@6o8)?aJ4-^*&6FqcQQoW(JU zVQ<|3ljieT+}N-ES@EInVNyiQS5-Bh!~cFf?mu(p%>BCGx@Kl&kB{{}KHk5+ilhDT z!t{Sk4Odr(PoFl;Eb)b36DZB&uMS`T z^YioPPe9rVLk=X}9vL&@_# z1&{3Htx@87F+Uz0WZoEIlW?HH{C>^mMt0B)h@4f4#_Y4p)Wx$~7A;!T$}K+6zW(0n z)2laZ*bu+J4m1|#qn3T=<~(*#_j(J1Mc-#1o1>hrXZt;rU;e!G|I3z=cXwvWeF@SQ z>kcg~c=G%G{`}~9MyaQ!Xa=u(=hL5CURaoULZO`D#;(%U{r&z?QM0Pvx_%8PTdjsi#W;_Cl?Jvmu@`I03rE-oo)X>t2%DzC4L z_3LB-#pf)|+W}wFRxDby$a{K}SG$Y5d;Fe?k3T*>Ub%8*^0A(qI|`NmE?V>0)U!xm zTYI)mWl>pKnVVZ%gbrK7lqpl5JbCit$B)d*%MvBR{$~ZZv?zF-ZhHKqfsuKRtn1tt zS|VE~c`ZHM&j0<}x4y2fMZyb$O+4pY$Cj=ye}C`Gs3cw1B%! z#;PRa-k!=5$-IRD7Wwz~FthW46seSlr13jWxR(3k!org$PcmFs?mvIAd;hI%^0rl5 z{O8;Gah?=}lut`atKV+D9=0aJFyn%PT>tipkB<@$x9P_0D7dj9v0Gd}FLZJ01ItzK zuG)l3YX-KRdb2ewclpL|x|^?`iPRC3Ii9;Zc6Zs{!pCk^Rli!f#dCsh@<N3@n!z=-)&G>oyE8q)E1QKRl0f0d(Wr)oOLVwzF9G3 z)Yt|5*4tdf#Bf08RrmCF>%Z>sxBojO?tp=gg~bictHGI|mP1p>@zB37tKRc=Xh*n4zK{!cv<*=|~{Y zJL9?PMn;>S9qZ}g`R(#k2i$sGdsw6UO;vnbsOJYKNf*|WMN19(E|!)k`)#fMo>$eV za`MZUFL!sB@BebiyNq|+La-j)L#3H}KJBf#DbjSi@le6k|I=BvGauxxJ$JdSrRB!7 z!-o#B@kkgXALChW6I^;EW9Ft!n|}QGao~W%)+pb6Pft%zA0HntuSFWGo@q5HcuW?0 zu3Nm{c2fK%-s|CIGbCc&?d#LlpFDp2c!r4(OX7E9`>D#4ejA70Eq1U0HP>f^p4Rq$ zHub;TdZ}3V)qkgnyDyWzbIkPZ_oN#yFE3wx^+_?0drj)!(C;Zmkyo!qrT=vmV97Lz znXh?Pu6rWe<`w*N&z?P$vDsjk=00t!UDGZvTeeJ1U44Dj)~i_E1$&^h{Bf^g9rgOQMG8rs8soM9TY>7e4)9*`@_wD&J zDHOIAVAr#N6RO_RT-@BemIkp;Usm8$)ZfwZmUY!`}q9E?M&A#6)EV2Y=OP z27F%cc-QX=|9rzNXe;;Bo7rn``6bT{P4i!H=Y80ZdY?r;sBT!viyn{=Q4f17#?5f{p_YF1wl%k=xps?Ls!oD5 z!Eb6zT5QQK!pWfG-4(f2YCUVJB0EENnPkqVCnv9N^O<3AP;=sz2J3Pb$6H2;7uD)6 ziY;5ZU`_C*$SdLoVUZ^o)7e9pN2&8|E_}k11j<*J-WcepN(hAAk!Fy1#>8zO^Y-7) zrI~TooAhrVNo1HXZ{EJz-`_x0?yDAKzGhIX;4H_w^FmtJ3a+Yuz2q|We>lT}yzlkr z_+CkdoPDgQsCe+;LGS5$wlzOCJXX#uvkl{D+F~nm`AbLKArISi=dVV8*hj=Yl4*s09%D1&EpR|*GXa*)LA_+8Bp*fN)P`ak=9EGjRJy`iaz>Gr1S)2}b{ zoxNz$qB%mGpz_gzFS@ufepByio1lwz-JV7g25z3uFN-Yxy64H)r_=dn9eK7gV7_&e zf-j#k?-!=<(w@bZ>!9`8L3 zkDlYX;y1-D)i2XeJaYOh`B2&C^JdQcd0KzJ&rGAEjSK%C<~%uf-7fR&YdTd|!_x8( zHnCb-TCNZhZrWmTs44%&89s&?p>NCbqY|%Mi!|p8x`?*NZz%dRS9)HpZHS#s*?$So ziCfjaXFa|HT3vB=wt3y33U;=Llbp5hzJ}i|uCd{0vXSpvZ25hEw8xzQOXDQ%({C6G zA`53OIl=ZW$3&{Tt813Yyj>Ri&+m=8YMb8PtZ>3uKx^N#>2DKeiT>X#njE#`pkLRD zOxrN~FsZ3u-xw4>vwt5qb=tJFl$1Tc-|hC557(VD|IX^ryTxS|98ET?c{@CfTEhC| z84T8@vgn8C&(;cAb5uilZ}YjwzFnFHSv_UR8zkhi<%|v7CS(gRywKV8>wAA^=SJQ1 zv@{_W!_rq*mho=nJLmuI>Z*5^)-o)Pua1Pu2|leqW@LNeWL)^~T0VwVWv5^E_vk5C zxY`F!<63=Np!s&h^0rL#pRfKLF6U=%h*4QSxte`DpI*%L!{z+5*FKBlpJ`WHb@giU z@xHTjt;=6uTg%t6P3pPI_o`LzuHM<%J4M4e^;^{HY4;+weN;O=XSp~(GeeJ1(Tzs0 zn>l+kIDYQ$HA>tUbv||K)EPco)%T^HbBfBFdROa;=&ZHR0^hnbHnga|e04KaZ;JQM zpxg3`T2w1{K0f{P)t|OG#wI2vwzhjYo7c@Qp7eX3ZS|^kYG7ccD#YUW>d+<)o8sk< zmdR+pTPn`adZ6czoZElhbA6}hT}dn5xNb*tHakN?LeH8>I-KrG;-@sb4jJ^EO>sY= zlqGjGvG9*e-PU;px3}ePdpc>-q{Z(2R;ep^Oxp8iF3(a{Jq0ePQccCo?>y4z&)R#B zwTCmuUfbT~{m-_GsTS4FpK^2a;wiH=pSBe-d?@`mwLq2OL)4LMi_b6hBVsQ< z{I7d>dPV4!KQG?g+`KK7pTB=+@$+NHj@{CIlzx#3RHF1L?lqpbb|-_xX%)$whvket zk%C{EH#cvRZgrcu`b=ns2=gEI3Jx0vg$Su0~K{0vNWc zeV4EQb8%myxs=yCj!R`5efW2Xw)-sFC*~N=V6dytWJiz5uDuzv?H9NzYi@E0KXkY< zsZWC8-L(6A!|VL@CfzQ3@hI|iw1@v!--Q#Ze#M;wwUo959y-*!=(sjRa>M!kFQ2TN z>|6gTQ1|HBNwdX2>kFv}z7&;wEX>ScXlMBM?=Rzd>z94gWqv(xtkTi%%B_eJ?1>IDb09 z&?dw-Btt}L+luA>{tN|=ce3tgujbyHyZu$nwafC-A;}9Leh3((X}9W`7o@jddHpprGxP4Q(#IdQ)J>*&Ee%@fY`q&~^R>>* zQ%^Pd3$H9cZT-h9aYw88s;upIo){fD^{o`-O%I9wd)85Fw9|}l1}iORXz0hoW7(&x>3TorZJF!)C6he-^42h#&I=bmz|6jS^>KkwT)o6|o(JmMDJdVi1h)KmO+ zKOX$}_&8|gmOXoFUR+qH9kynIhst@$2<0uEjpZDd*gW6+i9B6@z=Qd)lYdO>OWS2z zFPw?X(>Skl%BJW&hi$U>^rKHV?TFpG>lo|NKoM33o}P;xXXY(Cd|jjE@q3T;ueI4v zvJ|epZ2Kkp_VnsUVO8G#3wLIvE&nJPQonHFwc>ZTwsIfdQ2hK{?5+~fEEtR9k|j%Q zvJ=W0-`x>hVww=ewL`Rhrzrc@d&MvN#HaqxYP!4bso$v;W-EVM%s-mIcwl4o@esAC z+UG;FuU&GEZ`&q+tD`tdL&vwh`oT4ZK2e4`EwMLiAG8+fu2QdkA^&^TeB(E=)@7hI zMe}$r-o9N88e>m8JIgTnSn<4Vf}n7p)}zFb%*e3+g?i$}?P7H*0aLfnQ46$R?slz0 zvQ=`sSN=-hSBY=ifA0Rld|<)?#hN+i56@q%aNl3G>FG};=FYv(m;OEA&debHBjewB z|F?&7Ui{h18yFS!>iz%o_A4428@XB+&HFo>50t?^8LZLDyZL@kS8bRdL+n1k_dna> z%#NPQeE#ObyqQxsiDhwpHvM_eDc`t(05@ypMfHZ5(ow2`i^uASYzclR#| zob!KYy84|WN04^Um0%t_1_NJy)k<&9xD6AdE$x;h0a)X3NpyenxQS%ZS|2OTI;>K(N|&9pFDZl*Ve4u zB_%8zTq=~{UQ}1KKCG1Aal$JNr+{6((RCA2cSOp}bWD`twqK<3N9JH=JmrAfPIIeTdvoX(KSneG6cl~K+;o=v%GmmvuKDxGrLz%&a`>dp(tI?f# zv3k1QpC?yuT~*D|bU`9a^yq_N2|kJL_${mk)6RX)RXBU#34=rN={Hi7)pqMdr(a=> zVE&`}zr;$KbFtIn3(;R5$~|N_aAd~OU5^~5A7GfyP{nTO?qjcpa+|6YMmj3T{XoqdFwQFF_9C zU-Dp^;Qj@P`<1S8&k*5m)>UOvJK(U<)7vO!h6;1@`M>kZ7kF!f8jL2~Jd0#DuUb2Y zf#CqJ`HX4Dqt=(}`rlK?JvUR9!KlmV#hJLBQ8O+^UW+^-Rup+>-`iiOSd7Z&{oX9L zXd%NIkqrh64Ij&wh;Pkd;CLulvj6AD3qpat51)I4zED+TDKxrMa9B6JD?Kgz<73e; zV!hY*Oxh4E^;5~}x_Pncu1T{}JHLq8?iEnup8PTO{FIyh8awmvmG_?bU=tB&`K_?a zXTP4q%v(!ud~?~tn)*%Edz!`5>e)x^s`{Xx>S9S`e|SgQS5 z)F*vF?H4C6!-SO&V=r%FOV8RC9 z6<4|nd1mUl#v7mQ*ZI@Ib-rG3hYW*3(EEwzvsc^lOK9sq;X3)i+WJiTViV2(vp>go zEmDy==`9<-$b1&Z<%xHcMUQbYBp62gt@-`4d;X`iHPcc!Bvlx4^o46f6j&QN*Ug%0 zm&)M4aIEQBU9zA0_gSgSkM&3zm%X`h;)F+Z=+?~3%l`iPeEvg*KNy%(ylTx-2T(Bd~bkI*_He8v}K*QZRbTxnR7ojd}N)))EoEs{k!<{Pj>P9 zthvhdkd@bZhWndW5qu2JOT+Y{uezu3JrZD$S@8dUQfhj-|7^3huf$}I%g(%(8|6^s zK4Dr%^uFom-k7ijDrwwYG_jt6;i+u7mHxWr#t}UIrv1z@Oc6X{%*ipKF{ztxFzPXi zT{@Ju$&lyuyV%p-ZqrNWo_d~`}q%)akyXy3iWwb@yxr|GWVmU?lKt6%35){@gEw?Dk`UVZh`&p&2G&(~ed za8a7Ld2xnQ(<9xcL%nBCy_C=n-SWTxVrt7~r>q6S{C;<|_p>u7TlIYq{ms;HG^_H} zYuD#j-gH_9eew+V+SC1U`8QF91>20Q(kr4gKO8yf9ov;FxnFdFJe$ewc!y}W?L18; z^%ALR*?JL{|5(%o7z$#ojy`FAI$u^}*#(^!FSq=7wZJe_Zl(Ow)t{a3I=>A6zqciB zT}*iVM*Ub8W~ngas_K;uYbI^~A5yfrx5D7MQre`~%u^C=yw&9{s?AedXjIK{Y1Rkt zZJqM}<fHHXTe7svd_w=SUHg%;;e5pQThDFt*9OeAWyw4k(U!CB zmBdkz3!+Oo^W68AEb^4e7W=yL4s$YN!@1-(KQrIuS|U4sSQti0x4ISDy{~CqsC2?K z!{Y*|bMRV5jr;NA^JYou^{nsL%&PS~Z6^|>l@^qwc6Fk6%FF*d4}L$gHulG~s&f~* zu6}(ZGWDkOglBzgE%o;rGa4*ASjux^8FNGAmD@V6Vt?P0n4DsjyY6z4bLBj({skPr z1U04~efs#1-zC4dN2VGxn-{cwN#cH-ue*Hy36<1|3>$U^d^m8VOK|2?7Uwftm=64V zuxaM^*uGUe7!=Z@_w$Ar-SW`);oYkCy{CugxI1Xz{R;bHojYC3F;@epJuLIQ;mL4D zsV9sr&!m%m;+kg`69V%uUM_zmHCgRx8W%$ahs}#8?~WBq-zZf-86G_66Md(nz1i#6GouyrtwS_?A|_rFd3WsC?W{ERhP%7VZ%;EeHm?8qbh>8n zG7D89P!pA{>qu#)n4?O94wuBEJ^dQXE@*TfUQ^YjxxnDggKwKQJFn?mw1WGm_@|J{ zsLf?wPejZn>ptpeE0uV5@O#BFCb#g?H}_9hikrN-p7QH@sue?r=bTcN#Q_R%&TuQ*&=m<>TZ1n-YqWjIXScL ze(#cm1v@^iUDWxm?W9p{^tp(*f_x;W_WrR=g>CXcTq6+RZO;>x#IvG&M(o z;N^a$UMhXw@4S|NI?%{$UH&d+LxQ89pWpF5*_UruoRNEEAd#7}`g~F7agS-MkEL@m z%y6wW`BXnM=8?{xbh-O?mw0sPT$~!6gl52Al@`HC>GDIE6vrFc`53 zF-7OkoOyF|vwHKvj?T`LXU=R<1&!ioX3Yq7H)M4*#}<^E#qf0>vDs1TS8F zH2Le}LmgMnjWTg$HYTWYUXwO{M{C@I3stj&5cQcg>o`S^SnvLd+cRD<&5YUEWX&q8mDXPO$EI&*D~dH1g%iP?v4{MnS!^fvp$y#7Eju4Kkz zCZ2HxDK=4?w?)MFeEyJS`?zF%_woyqwf*MCBYN34 z#ZBG_u5+uJ@F-WAPvmRg@~|^&ba>_}WYdpbFIzI%&uupw9wn> z?&9+2&*$?ho^iWMUd}DQw=rsM*4A5Bw_5IFYuXa-HShS38-&ux7_+ z$tpF5B`TbA+E4XRnHzu>K$7;zt5=g=DnqRV>FJhk*JmZ!L#pX&bsG0&$r(B zdQ|Tv+c}r;v&%mfF?fh*vwtwT$TYdZ(QNX5B@tIamWyux4qXdP>tA;L_2o;Ks=mB< zc*L?X`asRQ6=&jJCr>x3)>D;^?Yb6lAf!q!7X2!!G9=BYy9HX?lQY7DB?B?;_Xpt{@`p=0|9~W;In4{2q`?SjD$ezWv zQ>(M8pM9GWt?71%gTZEw`I^HUR!!bj!DVa9BDYm;_12{P`{li7zQ~juzU#%v;POG& z^R4zecd^{p0q-V!5ZrxpbNcz+@ArB0zn|u{^#8Bx`?uxae>cS=>cCvOGLF=>Zesy#F-+73P0-cOi#r_glgD_a}Z_a{leSiKUK*_pL}>|1JEZ#FPo1nw)Q3#hv9h z&SXhoGBA{QcFE^=+=O4Y6(1A~3@&V26`)~bJJ-0D)$3iyV#5xuKEv53zixkYFLb-{ zS+2fUGY;m;92E(YkT$<##+}?V$>KKOxwCJ?R<|;BolRjraFShJex=;TnQy+Wd;9W< zokc;x*1yHRYfkd-DG94*U|^Qnmu)K(<#oRO-?7^3In1kt`zvzN${q+YY}hTl%Q;`w zs^rCl$&)Xy3|8+x`sr$T{L&>$bmI5j(VV#8NuPzt{*vVu`I>H04+WQfu5iBlF1Tv< z>E_5ipK2K#Htp@5w2&b{>Q}ol^V&xXUnPbGhArH-Vfmi)CE+RzU#5J2qxt^jvEtRw z8GrmMT6gZ(`Q?>q&+5BayPrxi+z?ps<;Ys2IVBDsI+}H(ws~?2Oi_qQ^T~cd=diylcbEH|ONG`uxvcxS%KD($~&9?Z;>9UobIDzVo%DX#T^6 zvmY*8U3P+p|E|c)e~zvDnzh%T73*=E!>U?-Bu`>mP~WpH7gJS^J_wRHr~hwe%FdUm z!3LK+3|kuvc`kLjO%FV@$alssDK(BuRr|aj8L_kPe11%BX&@&$UFwR=c*SeNu_6+$m+gwkb>p5;`-BCv4h&;meiwMHX(Ak6BK=>3F>GN#Bk3(|>2~ z>0)LGsdP7=Tp_?PrDg7-^uYC9NnEC%>N8zH3(y)?e7gFRe+vJnt3UNw_Brf#7I`Fh zD6y#K=su>h)SRnEyIY&Qqt3DNT3b-dkOsmG$cG?s9G}u0MbNSe3oGvA_QR#^mGIjKzI}Gj5rO1P28P2@6l2G)bdt zRd#h`WMoZEO+o@_&GDrK0qZ1z)IFc}>g_DHT($p&Zdzb|@ApHO9x$t2WT^5!d*&U3 zimO-__tj;m<}a-l{a$pc_)bOMHd!Sb<)*vMxijZ3+nn^=H0M|P6s9*@cdwJ?YTcwh!x` z`o94EV!wqaR^^G@-|^*#kfYGVxQT{#h71Cag)iS+_NcFb5YOXCyIm8`7}3ZTV2tInm!iH1f#U%g<#frFm~OcIOMuU;2-_U(!@ zamMY^c^smvEoXgp`vXAeCyPXaDtbBEGP3gV~x^EQUGcx4WY!~=0 z5WjJKu0z$?M;D)8d6TU5j+M81>Hb~q2Y46^or-%d+zC(NdlKfy=acU~A^p+2cX8)^ zS8d<^egD6&`tHXrx10p|dBwfB&+UO}+nzC9p0WD-3^oQ4gTmTr2TQjE3i-cJIBLsS zeyB$>ZFOX7(8(W03>wB${(gO+FL&Y}8wP7c9TA_SmN*|8{?^ z3B!gf;hQhTpFJ2bo%@o?qQ#4|^L%`Lef|96wq}K9Wvx1_lnJ(SZ`SSEdJIb%Eml32 zx$4>XttRsWW0$5c`tHm{g2oPA}g^r_ERf3n_c+Ofcb?brhYOP-#KM;CXm zzcF2I!np$ySB-w_GQVD)bdZ(T+AZUsl>;jSvx{1s^{W08GN;zoZ10%2i`#LQM{Mdh zHh#G~D}&YD-7dA%m%d)LIy~2Ufl)QXgAYd4Il*QJKdH@3VkkHrf7I-*A=e_#TE>HE z%nc{M>M}4GGu-(9NLVFsnf~G#BJGiTS2a&G*fcZe*U#q@=O{~Ub~__BJ^Qq4jv&L4 zpW){OGFN*{&px*Pm8F}|>^I988;X>_-7m`XZ`{c4@BjZs%O;X7=4LBYsq)3v`#gH|?opIT^CeYW-RsW+Xc>%^wV-|$?(z#y?7bS^+{;>^$9wc**Z z#~2w-|G9AL(-MiR^KH#qV?y8E@7jMh%$O}=iF?Wt_ow$;q?ei(O|kS^T(sf;gR(_s z3;}EOpKbo}rDa#BXhg(43q}S@HJf+q_!(M?&bC`?Ff=S_U`jCCY~J=JD0qXbL+ZB$ zeNX01ocM6Uf`5&t-k2);hNbl%;@xiXDwt)vvaPw5@N=OwM$oB%izE`HEzzigO*=Zc8R!k-dGe6xnlc~*?p^Im&aaB))g@`5C62i zZSkh0?Tfo^NQfS5-1_fS#zfT#&L+1{6<=5}t4UWxYco5;?(+BBbnox0{e3;YUe>Z` zNw88T<4M`f9`(zmAHD0R+WZku;F)`Tc1h9o)61-~eSZD@^t&W&d*y-}2lemoKE1nI zwr}0>;L1&6@s*Az|Ar z{b%9wKc$}hI$xlv&1%lGL;m=yLn@33p7Wlp5_^9@Rc`i7AvsQl>gLl7j!`0f?a2lf z&&60&zl-%dPI>%`r^-s4!6#zNNu>^xPObUg(S`YYO)hFSri!FJSykj+qAGk?o$IEP z*<@Rdf(!F2U*;^@v}BIt<6k>N_OWesQ~a|rV!<|}Ypfc=OV}8GT=G{L#$*S$# zqSN6|PrDWgy0b8F^)@MVa-8S5efxh}+zWG;?~DbvWW7oiY`njo*A!U89l+FJK3nE# z)*EFbeu2=wts8uM`V@3M932~TZ=OD#{q@z=ZIT=^JgVQPwPaQu37r3Eh5yRiwP~rp znT{E8C-6f$>-pK?r-J|7=i1+Tzx1#$R0+k#Pt2eCYf+Ch+n=VkyTJ*4LJ8e5KjS?h@B8MH~0cm{)(%%y|0zBl?$&FZJqQjnY0ovwo$( z(Yq!8E&TsXUsaTIr{7Vuq~1z*QvOT@*Tb;_OFS1?mp?DwYtC$bhk-#YP)RG|tiq`) zb*C8{GBs0Xeg3jZQ!O#S%Aec*j;3IkgjU}j>qTZOV=LDQA5vp*Xi!P;dNO6z`Wg3( z9?b4$Nxw2DVq;-$0~f=w9g??;JNGGV=HFfPLz%m|l<^d2(BG?Eo0?~sh9sq!ZWiwo zSaQ|jZ^?gfDIf!>HI>nP(`D#y*^G|R`zeBm`>CUogrQbw< zhqawem=^hgTdQx{k+{<9%nf}<&Sl^Ddvuw_^!j-n*M0?TS${%?k#E(J7KL0fuXpF1 zBUx0VcRu~SD%Xs=+Co)kuj~2bj|M!88>}jxFSwai_IT&aHEMj54<~JC+bYk-Af@g0 zUFxp+#$U1185``6d#QhyWBNQ*@2Fp=jN`2S?Ca||S(+X^NMO*=(o*ugbbI$NlPi6R z&+WdqUAfx4EjFz`^VDGtZU%;9LL&c9D4bfmBmAmt&$`7jGC@^|Rj1BQi8rd(G@io9 zz?{sJYyahHNBHsf-sRSD99+}vg!p%9cAxoT5-7pIQqwK9Tr>x_@j|bW1 zGfboyetbS}pPZcR-Xk$_%9JNlJl@Q_ll%3vk&#hRQPHbgak-&7V()KlU0weEURlqQ z%16`R7VS5^^SFv9x>kyTVZ)^d&8iQ@PdWWJ*wL#z!>H+Y;M?yz9cNv*GEt-V)a#?y zPxC(A7RopIa`3&$?cshupJ;v9nNsjqC4S8oBZh|7gQ2pwg}0ykd~KE|0|Un>)BwbY*|=W$w$23dhXb*2&09 z3ve@}b?GHIG9EaxJ8$~d9KGhQa>H*zvlt(ozi??8ACF@cqrboZ-njKwv)SJO3P^PTR@V%&%Xqy!vWeKwAG|OZ9Wn$Ba^>mk3W`ywA{Z>^bvse(!LpsW($^ z_FwJa+Y(oM>nmf!w{>r0cj(zE$umYfyx+XP>3cROsE^V*ze{e_juX*`lN`(&TYI&{ z6i;k^aee*$IhMsdY|c(jOnr|lD=Up=p3$6miCDKNIAY~IQ($W zzhAGb_S)&{u66I1i;IgZac_Nm(|D)(hIMjniE9_0k#jBja-C(?Vo|xznr!?I84t=# zz2mQUwnd#yQC@Y~blsV_h3f(qhKjuIYG>s=%#a+Yvoqk`!S55epMEK=PDxvOTar|n9rS-uFbhvJ1KKWkrPuOhFnR&<7JbYZEc8sNA${P{e zh2_t89{+XpQ)CUp3FFOruXgaC{qcLAC_{jgf&0@FzqxpuUE2bM?tVU=DUM|Ageg;| z%$)i2<8k?ZIoqoH`)cRcev5Q*InpC(EF&YQwfTC2$ia*M&aSn{m~v#MiZjE37ltQY z`pkFnERM)4>s+sx`t1_;<^1XQ!e(DNY|WFep2^N|*osHE_{h?*dD^$R7^;M-AGR%T zJ+wrpXy5wA^9yP$C&*<=cirPzr^2vh>8aui)14K%1#==RnE^r<`v-M6((RJ@zGh>W+Cg0mq znSHorW}5-$TgS>w&(DXJShlILp4-^0_`o4aM(1XcPUJPOO>tqjekb=XjB%Q<_UgK_ z{qy&$uwM9l^uvP}H~-r1|Nr;%d3*gB#)z1hJ;}%W*ySn|zMq|2(Edtx)2}$4FK-@6 zGN-Q)ob`K0v9nnH-+vqbt^T)KZ1U2TJ3K9T=5|!flke=~X<>^Ao4)&kuS?9V;u$iZ zPe1dYx97*4{r}z?2G_^@{`co$RPw1c59hCzo}KzAOXQj!Q0I zCZB&>&ml6y^beDF(X>wGMe$eJj;`QhSoUn=ak*|6C6_CA?&KIqe0zJl{PU?dF;2zm zN=B@GqAdN=H-Zm;_WvBEou0*Urb;(4_o=Dc#{0X{cRZg~T(M%j49qX60(4O1%@) zdt6dvtNdn5bXdQ;yhK@Z?bMD(+p3RLTsE2iPw7|d^siRjb4)Rj1Z1^@^v-X?2yv=#{$$<|)E}iJ@t}ko* z+S1yR!8Zas?|JD8%Wc1%d_2AXkGtq^UvH(?p^Oa@d@>dX49=_! zUhX&FuJ+Rt&%VceayA;Cs#!nJ#U5rgS!sAK!rkT9$L?Pq-z!f3jX8LPF;4R_kKsKN z5&pSf=gCS)7l>J0H(RT^D9U|pV0Ot2?YU~gf~u8OFT4V0%n4t)tjosGD0cCyuV!mR zSxy}i|~yMwf~w6^8n-&guNEQU*y>+g@_t=H@Fc)nBl4Z}19ThJvEj@I0#?Iwuo~`rcd#QZa z@VJ+fSN57+KdyS*bDQV>Jy`dD z$Nzto-?_`>YR!JlJp4p}&r^NT{U191)j2Z$_NzGF7i@Mp^6^XPZQY`>dAnsctm!IS zu}VG1YHpv~;;_}Bubhe;Eu7r9ZGT*~_uk8GlQiF4U7WN2=H+ASqiXfDb_6Otl1x4o zAX%3C`Mlk{yXWRTyL@=!!*>hc1=K9^tG}}T@{4_e|9IEBdAl5(vTXMJ@5S+d_1V<_ zsp)T0sSi2#FZ0`p{b3spY2S!uS&$=N_aiYsfBlCW&p-3>@p*-w+%oI;m2a<7%g@gH z`>Ox+IelH3AO6hMS�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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_10.png b/benchmark/benchmark_results/plots/benchmark_segments_10.png new file mode 100644 index 0000000000000000000000000000000000000000..cee2c5419c35827640f0f69468071c0344e25bad GIT binary patch literal 13036 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 B`)2?E literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_1000.png b/benchmark/benchmark_results/plots/benchmark_segments_1000.png new file mode 100644 index 0000000000000000000000000000000000000000..01b61638439f62ca3550c14fc300a1e12c0d0ba7 GIT binary patch literal 13067 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_10000.png b/benchmark/benchmark_results/plots/benchmark_segments_10000.png new file mode 100644 index 0000000000000000000000000000000000000000..4f0e840cba6f65ad5e2aa695fff7e576431c86ad GIT binary patch literal 13387 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_100000.png b/benchmark/benchmark_results/plots/benchmark_segments_100000.png new file mode 100644 index 0000000000000000000000000000000000000000..126bd9f07920fafd853c3592e8ed0ec418a41bdf GIT binary patch literal 13245 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_1000000.png b/benchmark/benchmark_results/plots/benchmark_segments_1000000.png new file mode 100644 index 0000000000000000000000000000000000000000..a484504809a55132bfbdf29f33255d3cbce83e6f GIT binary patch literal 13223 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_all.png b/benchmark/benchmark_results/plots/benchmark_segments_all.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c77a130226b2926bcd6b2e914627c5cc49d302 GIT binary patch literal 19244 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 literal 0 HcmV?d00001 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_memory.png b/benchmark/benchmark_results/plots/benchmark_segments_memory.png new file mode 100644 index 0000000000000000000000000000000000000000..fe25346368b331835a90448c2bfdba9e4d76950d GIT binary patch literal 24333 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 +#include +#include +#include +#include +#include +#include + +#define BOOST_TEST_MODULE benchmark_test +#include +#include +#include +#include + +#include +#include +using boost::polygon::point_data; +using boost::polygon::segment_data; +using boost::polygon::voronoi_diagram; + +typedef boost::mpl::list test_types; +const char *BENCHMARK_FILE = "voronoi_benchmark.txt"; +const char *POINT_INPUT_FILE = "input_data/voronoi_point.txt"; +const char *SEGMENT_INPUT_FILE = "input_data/voronoi_segment.txt"; +const int POINT_RUNS = 10; +const int SEGMENT_RUNS = 10; + +boost::mt19937 gen(static_cast(time(NULL))); +boost::timer timer; + +BOOST_AUTO_TEST_CASE_TEMPLATE(benchmark_test_random, T, test_types) { + typedef T coordinate_type; + typedef point_data point_type; + voronoi_diagram test_output; + + std::ofstream bench_file(BENCHMARK_FILE, std::ios_base::out | std::ios_base::app); + bench_file << "Voronoi Benchmark Test (time in seconds):" << std::endl; + bench_file << "| Number of points | Number of tests | Time per one test |" << std::endl; + bench_file << std::setiosflags(std::ios::right | std::ios::fixed) << std::setprecision(6); + int max_points = 100000; + std::vector points; + coordinate_type x, y; + for (int num_points = 10; num_points <= max_points; num_points *= 10) { + points.resize(num_points); + timer.restart(); + int num_tests = max_points / num_points; + for (int cur = 0; cur < num_tests; cur++) { + test_output.clear(); + for (int cur_point = 0; cur_point < num_points; cur_point++) { + x = static_cast(gen()); + y = static_cast(gen()); + points[cur_point] = point_type(x, y); + } + construct_voronoi(points.begin(), points.end(), &test_output); + } + double elapsed_time = timer.elapsed(); + double time_per_test = elapsed_time / num_tests; + + bench_file << "| " << std::setw(16) << num_points << " "; + bench_file << "| " << std::setw(15) << num_tests << " "; + bench_file << "| " << std::setw(17) << time_per_test << " "; + bench_file << "| " << std::endl; + } + bench_file.close(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(benchmark_test_points, T, test_types) { + typedef T coordinate_type; + typedef point_data point_type; + + std::vector points; + { + std::ifstream input_file(POINT_INPUT_FILE); + int num_points; + coordinate_type x, y; + input_file >> num_points; + points.reserve(num_points); + for (int i = 0; i < num_points; ++i) { + input_file >> x >> y; + points.push_back(point_type(x, y)); + } + input_file.close(); + } + + std::vector periods; + { + for (int i = 0; i < POINT_RUNS; ++i) { + voronoi_diagram test_output; + timer.restart(); + construct_voronoi(points.begin(), points.end(), &test_output); + periods.push_back(timer.elapsed()); + } + } + std::sort(periods.begin(), periods.end()); + // Using olympic system to evaluate average time. + double elapsed_time = + std::accumulate(periods.begin() + 2, periods.end() - 2, 0.0); + elapsed_time /= (periods.size() - 4); + + std::ofstream bench_file( + BENCHMARK_FILE, std::ios_base::out | std::ios_base::app); + bench_file << std::setiosflags(std::ios::right | std::ios::fixed) << std::setprecision(6); + bench_file << "Static test of " << points.size() << " points: " << elapsed_time << std::endl; + bench_file.close(); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(benchmark_test_segments, T, test_types) { + typedef T coordinate_type; + typedef point_data point_type; + typedef segment_data segment_type; + + std::vector segments; + { + std::ifstream input_file(SEGMENT_INPUT_FILE); + int num_segments; + coordinate_type x0, y0, x1, y1; + input_file >> num_segments; + segments.reserve(num_segments); + for (int i = 0; i < num_segments; ++i) { + input_file >> x0 >> y0 >> x1 >> y1; + point_type p0(x0, y0), p1(x1, y1); + segments.push_back(segment_type(p0, p1)); + } + input_file.close(); + } + + std::vector periods; + { + for (int i = 0; i < SEGMENT_RUNS; ++i) { + voronoi_diagram test_output; + timer.restart(); + construct_voronoi(segments.begin(), segments.end(), &test_output); + periods.push_back(timer.elapsed()); + } + } + std::sort(periods.begin(), periods.end()); + // Using olympic system to evaluate average time. + double elapsed_time = + std::accumulate(periods.begin() + 2, periods.end() - 2, 0.0); + elapsed_time /= (periods.size() - 4); + + std::ofstream bench_file( + BENCHMARK_FILE, std::ios_base::out | std::ios_base::app); + bench_file << std::setiosflags(std::ios::right | std::ios::fixed) << std::setprecision(6); + bench_file << "Static test of " << segments.size() << " segments: " << elapsed_time << std::endl; + bench_file.close(); +} diff --git a/benchmark/voronoi_benchmark_points.cpp b/benchmark/voronoi_benchmark_points.cpp new file mode 100644 index 0000000..15e123f --- /dev/null +++ b/benchmark/voronoi_benchmark_points.cpp @@ -0,0 +1,141 @@ +// Boost.Polygon library voronoi_benchmark.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef boost::int32_t int32; + +// Include for the Boost.Polygon Voronoi library. +#include +typedef boost::polygon::default_voronoi_builder VB_BOOST; +typedef boost::polygon::voronoi_diagram VD_BOOST; + +// Includes for the CGAL library. +#include +#include +#include +#include +#include +typedef CGAL::Quotient ENT; +typedef CGAL::Simple_cartesian CK; +typedef CGAL::Simple_cartesian EK; +typedef CGAL::Segment_Delaunay_graph_filtered_traits_2< + CK, CGAL::Field_with_sqrt_tag, EK, CGAL::Field_tag> Gt; +typedef CGAL::Segment_Delaunay_graph_2 SDT_CGAL; +typedef SDT_CGAL::Point_2 Point_CGAL; + +// Includes for the S-Hull library. +#include + +const int RANDOM_SEED = 27; +const int NUM_TESTS = 6; +const int NUM_POINTS[] = {10, 100, 1000, 10000, 100000, 1000000}; +const int NUM_RUNS[] = {100000, 10000, 1000, 100, 10, 1}; +std::ofstream bf("benchmark_points.txt", + std::ios_base::out | std::ios_base::app); +boost::timer timer; + +void format_line(int num_points, int num_tests, double time_per_test) { + bf << "| " << std::setw(16) << num_points << " "; + bf << "| " << std::setw(15) << num_tests << " "; + bf << "| " << std::setw(17) << time_per_test << " "; + bf << "|" << std::endl; +} + +void run_boost_test() { + boost::mt19937 gen(RANDOM_SEED); + bf << "Boost.Polygon Voronoi of Points:\n"; + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + VB_BOOST vb; + VD_BOOST vd; + for (int k = 0; k < NUM_POINTS[i]; ++k) + vb.insert_point(static_cast(gen()), static_cast(gen())); + vb.construct(&vd); + } + double time_per_test = timer.elapsed() / NUM_RUNS[i]; + format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); + } + bf << "\n"; +} + +void run_cgal_test() { + boost::mt19937 gen(RANDOM_SEED); + bf << "CGAL Triangulation of Points:\n"; + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + SDT_CGAL dt; + for (int k = 0; k < NUM_POINTS[i]; ++k) { + dt.insert(Point_CGAL( + static_cast(gen()), static_cast(gen()))); + } + } + double time_per_test = timer.elapsed() / NUM_RUNS[i]; + format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); + } + bf << "\n"; +} + +void run_shull_test() { + boost::mt19937 gen(RANDOM_SEED); + bf << "S-Hull Triangulation of Points:\n"; + // This value is required by S-Hull as it doesn't seem to support properly + // coordinates with the absolute value higher than 100. + float koef = 100.0 / (1 << 16) / (1 << 15); + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + // S-Hull doesn't deal properly with duplicates so we need + // to eliminate them before running the algorithm. + std::vector< pair > upts; + std::vector pts; + std::vector triads; + Shx pt; + for (int k = 0; k < NUM_POINTS[i]; ++k) { + int32 x = static_cast(gen()); + int32 y = static_cast(gen()); + upts.push_back(std::make_pair(x, y)); + } + // Absolutely the same code is used by the Boost.Polygon Voronoi library. + std::sort(upts.begin(), upts.end()); + upts.erase(std::unique(upts.begin(), upts.end()), upts.end()); + for (int k = 0; k < upts.size(); ++k) { + pt.r = koef * upts[k].first; + pt.c = koef * upts[k].second; + pt.id = k; + pts.push_back(pt); + } + s_hull_del_ray2(pts, triads); + } + double time_per_test = timer.elapsed() / NUM_RUNS[i]; + format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); + } + bf << "\n"; +} + +int main() { + bf << std::setiosflags(std::ios::right | std::ios::fixed) + << std::setprecision(6); + run_boost_test(); + run_cgal_test(); + run_shull_test(); + bf.close(); + return 0; +} diff --git a/benchmark/voronoi_benchmark_segments.cpp b/benchmark/voronoi_benchmark_segments.cpp new file mode 100644 index 0000000..7dd777c --- /dev/null +++ b/benchmark/voronoi_benchmark_segments.cpp @@ -0,0 +1,180 @@ +// Boost.Polygon library voronoi_benchmark.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef boost::int32_t int32; + +// Include for the Boost.Polygon Voronoi library. +#include +typedef boost::polygon::voronoi_diagram VD_BOOST; + +// Includes for the CGAL library. +#include +#include +#include +#include +#include +typedef CGAL::Quotient ENT; +typedef CGAL::Simple_cartesian CK; +typedef CGAL::Simple_cartesian EK; +typedef CGAL::Segment_Delaunay_graph_filtered_traits_2< + CK, CGAL::Field_with_sqrt_tag, EK, CGAL::Field_tag> Gt; +typedef CGAL::Segment_Delaunay_graph_2 SDT_CGAL; +typedef SDT_CGAL::Point_2 Point_CGAL; +typedef SDT_CGAL::Site_2 Site_CGAL; + +// Include for the Boost.Polygon library. +#include +typedef boost::polygon::point_data POINT_POLYGON; +typedef boost::polygon::segment_data SEGMENT_POLYGON; +typedef std::vector SSD_POLYGON; + +const int RANDOM_SEED = 27; +const int NUM_TESTS = 6; +const int NUM_SEGMENTS[] = {10, 100, 1000, 10000, 100000, 1000000}; +const int NUM_RUNS[] = {100000, 10000, 1000, 100, 10, 1}; +std::ofstream bf("benchmark_segments.txt", + std::ios_base::out | std::ios_base::app); +boost::timer timer; + +void format_line(int num_points, int num_tests, double time_per_test) { + bf << "| " << std::setw(16) << num_points << " "; + bf << "| " << std::setw(15) << num_tests << " "; + bf << "| " << std::setw(17) << time_per_test << " "; + bf << "|" << std::endl; +} + +void clean_segment_set(std::vector &data) { + typedef int32 Unit; + typedef boost::polygon::scanline_base::Point Point; + typedef boost::polygon::scanline_base::half_edge half_edge; + typedef int segment_id; + std::vector > half_edges; + std::vector > half_edges_out; + segment_id id = 0; + half_edges.reserve(data.size()); + for (std::vector::iterator it = data.begin(); + it != data.end(); ++it) { + POINT_POLYGON l = it->low(); + POINT_POLYGON h = it->high(); + half_edges.push_back(std::make_pair(half_edge(l, h), id++)); + } + half_edges_out.reserve(half_edges.size()); + // Apparently no need to pre-sort data when calling validate_scan. + boost::polygon::line_intersection::validate_scan( + half_edges_out, half_edges.begin(), half_edges.end()); + std::vector result; + result.reserve(half_edges_out.size()); + for (std::size_t i = 0; i < half_edges_out.size(); ++i) { + id = half_edges_out[i].second; + POINT_POLYGON l = half_edges_out[i].first.first; + POINT_POLYGON h = half_edges_out[i].first.second; + SEGMENT_POLYGON orig_seg = data[id]; + if (orig_seg.high() < orig_seg.low()) + std::swap(l, h); + result.push_back(SEGMENT_POLYGON(l, h)); + } + std::swap(result, data); +} + +std::vector get_intersection_runtime() { + std::vector running_times; + boost::mt19937 gen(RANDOM_SEED); + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + SSD_POLYGON ssd; + for (int k = 0; k < NUM_SEGMENTS[i]; ++k) { + int32 x1 = gen(); + int32 y1 = gen(); + int32 dx = (gen() & 1023) + 1; + int32 dy = (gen() & 1023) + 1; + ssd.push_back(SEGMENT_POLYGON( + POINT_POLYGON(x1, y1), POINT_POLYGON(x1 + dx, y1 + dy))); + } + clean_segment_set(ssd); + } + running_times.push_back(timer.elapsed()); + } + return running_times; +} + +void run_voronoi_test(const std::vector &running_times) { + boost::mt19937 gen(RANDOM_SEED); + bf << "Boost.Polygon Voronoi of Segments:\n"; + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + SSD_POLYGON ssd; + VD_BOOST vd; + for (int k = 0; k < NUM_SEGMENTS[i]; ++k) { + int32 x1 = gen(); + int32 y1 = gen(); + int32 dx = (gen() & 1023) + 1; + int32 dy = (gen() & 1023) + 1; + ssd.push_back(SEGMENT_POLYGON( + POINT_POLYGON(x1, y1), POINT_POLYGON(x1 + dx, y1 + dy))); + } + clean_segment_set(ssd); + boost::polygon::construct_voronoi(ssd.begin(), ssd.end(), &vd); + } + double time_per_test = (timer.elapsed() - running_times[i]) / NUM_RUNS[i]; + format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test); + } + bf << "\n"; +} + +void run_cgal_test(const std::vector &running_times) { + boost::mt19937 gen(RANDOM_SEED); + bf << "CGAL Triangulation of Segments:\n"; + for (int i = 0; i < NUM_TESTS; ++i) { + timer.restart(); + for (int j = 0; j < NUM_RUNS[i]; ++j) { + SSD_POLYGON ssd; + for (int k = 0; k < NUM_SEGMENTS[i]; ++k) { + int32 x1 = gen(); + int32 y1 = gen(); + int32 dx = (gen() & 1023) + 1; + int32 dy = (gen() & 1023) + 1; + ssd.push_back(SEGMENT_POLYGON(POINT_POLYGON(x1, y1), + POINT_POLYGON(x1 + dx, y1 + dy))); + } + clean_segment_set(ssd); + SDT_CGAL dt; + for (SSD_POLYGON::iterator it = ssd.begin(); it != ssd.end(); ++it) { + dt.insert(Site_CGAL::construct_site_2( + Point_CGAL(it->low().x(), it->low().y()), + Point_CGAL(it->high().x(), it->high().y()))); + } + } + double time_per_test = (timer.elapsed() - running_times[i]) / NUM_RUNS[i]; + format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test); + } + bf << "\n"; +} + +int main() { + bf << std::setiosflags(std::ios::right | std::ios::fixed) + << std::setprecision(6); + std::vector running_times = get_intersection_runtime(); + run_voronoi_test(running_times); + run_cgal_test(running_times); + bf.close(); + return 0; +} diff --git a/doc/analysis.htm b/doc/analysis.htm index 88c5f22..2f3d6c3 100644 --- a/doc/analysis.htm +++ b/doc/analysis.htm @@ -2,63 +2,85 @@ -Boost Polygon Library: Performance Analysis - -

@@ -50,8 +49,7 @@
- - +
diff --git a/doc/index.htm b/doc/index.htm index 33d5130..2b074ae 100644 --- a/doc/index.htm +++ b/doc/index.htm @@ -5,7 +5,6 @@ --> Boost Polygon Library: Main Page -
@@ -51,8 +50,7 @@
- - +
From 76265a1203e05914526fdc6713a2aa03cbe73c6a Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Wed, 10 Nov 2010 18:07:40 +0000 Subject: [PATCH 07/32] merge from trunk [SVN r66485] --- .../boost/polygon/detail/boolean_op_45.hpp | 2 +- .../detail/iterator_geometry_to_set.hpp | 14 +- include/boost/polygon/detail/max_cover.hpp | 2 +- .../polygon/detail/polygon_45_formation.hpp | 42 ++--- .../polygon/detail/polygon_45_set_view.hpp | 2 +- .../boost/polygon/detail/polygon_45_touch.hpp | 2 +- .../polygon/detail/polygon_90_set_view.hpp | 176 +++++++++++------- .../detail/polygon_arbitrary_formation.hpp | 68 ++++--- .../boost/polygon/detail/property_merge.hpp | 6 +- .../polygon/detail/property_merge_45.hpp | 2 +- .../boost/polygon/detail/scan_arbitrary.hpp | 35 ++-- include/boost/polygon/gmp_override.hpp | 2 +- include/boost/polygon/interval_concept.hpp | 2 +- include/boost/polygon/isotropy.hpp | 12 ++ include/boost/polygon/polygon.hpp | 1 + include/boost/polygon/polygon_45_set_data.hpp | 14 +- include/boost/polygon/polygon_90_set_data.hpp | 94 +++++----- include/boost/polygon/polygon_set_data.hpp | 92 ++++----- 18 files changed, 330 insertions(+), 238 deletions(-) diff --git a/include/boost/polygon/detail/boolean_op_45.hpp b/include/boost/polygon/detail/boolean_op_45.hpp index f5d4d90..b4a82d8 100644 --- a/include/boost/polygon/detail/boolean_op_45.hpp +++ b/include/boost/polygon/detail/boolean_op_45.hpp @@ -445,7 +445,7 @@ namespace boost { namespace polygon{ }; template static inline void sortScan45Vector(S45V& vec) { - std::sort(vec.begin(), vec.end(), lessScan45Vertex()); + gtlsort(vec.begin(), vec.end(), lessScan45Vertex()); } template diff --git a/include/boost/polygon/detail/iterator_geometry_to_set.hpp b/include/boost/polygon/detail/iterator_geometry_to_set.hpp index f784a8b..4f62873 100644 --- a/include/boost/polygon/detail/iterator_geometry_to_set.hpp +++ b/include/boost/polygon/detail/iterator_geometry_to_set.hpp @@ -253,8 +253,13 @@ public: typename polygon_with_holes_traits::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { - itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + //in this case we have no holes so we just need the iterhib == itrhie, which + //is always true if they were default initialized in the initial case or + //both point to end of the previous hole processed + //no need to explicitly reset them, and it causes an stl debug assertion to use + //the default constructed iterator this way + //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } else { ++itrhib; @@ -266,8 +271,9 @@ public: typename polygon_with_holes_traits::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { - itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + //this is the same case as above + //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } } diff --git a/include/boost/polygon/detail/max_cover.hpp b/include/boost/polygon/detail/max_cover.hpp index 68ef4b6..343e29a 100644 --- a/include/boost/polygon/detail/max_cover.hpp +++ b/include/boost/polygon/detail/max_cover.hpp @@ -213,7 +213,7 @@ namespace boost { namespace polygon{ Interval rectIvl = nodep->rect.get(orient); leadingEdges.push_back(EdgeAssociation(std::pair(leading, rectIvl), nodep)); } - std::sort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); + gtlsort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); typename std::vector::iterator leadingBegin = leadingEdges.begin(); iT trailingBegin = beginNode; while(leadingBegin != leadingEdges.end()) { diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp index b040f18..e814a15 100644 --- a/include/boost/polygon/detail/polygon_45_formation.hpp +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -478,7 +478,7 @@ namespace boost { namespace polygon{ ct counts[4]; }; - typedef Vertex45CountT Vertex45Count; + typedef Vertex45CountT Vertex45Count; // inline std::ostream& operator<< (std::ostream& o, const Vertex45Count& c) { // o << c[0] << ", " << c[1] << ", "; @@ -904,7 +904,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -928,7 +928,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -953,7 +953,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); data.push_back(Vertex45(Point(20, 10), 0, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1018,7 +1018,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1051,7 +1051,7 @@ namespace boost { namespace polygon{ stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); - std::sort(result.begin(), result.end()); + gtlsort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1123,7 +1123,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1195,7 +1195,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1239,7 +1239,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1668,7 +1668,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1692,7 +1692,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1716,7 +1716,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); data.push_back(Vertex45(Point(20, 10), 0, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1742,7 +1742,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, 1)); data.push_back(Vertex45(Point(20, 20), 1, 1)); data.push_back(Vertex45(Point(20, 20), 2, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1768,7 +1768,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, 10), 0, 1)); data.push_back(Vertex45(Point(20, -10), -1, -1)); data.push_back(Vertex45(Point(20, -10), 2, -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1801,7 +1801,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(2, 2), 0, 1)); data.push_back(Vertex45(Point(3, 2), 1, 1)); data.push_back(Vertex45(Point(3, 2), 0, -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1835,7 +1835,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(2, 2), 2, -1)); data.push_back(Vertex45(Point(2, 2), 0, -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1899,7 +1899,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1933,7 +1933,7 @@ namespace boost { namespace polygon{ stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); - std::sort(result.begin(), result.end()); + gtlsort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2005,7 +2005,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2077,7 +2077,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2121,7 +2121,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { diff --git a/include/boost/polygon/detail/polygon_45_set_view.hpp b/include/boost/polygon/detail/polygon_45_set_view.hpp index 1a66f51..3442386 100644 --- a/include/boost/polygon/detail/polygon_45_set_view.hpp +++ b/include/boost/polygon/detail/polygon_45_set_view.hpp @@ -119,7 +119,7 @@ namespace boost { namespace polygon{ // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); - // std::sort(output_.begin(), output_.end()); + // gtlsort(output_.begin(), output_.end()); // } }; diff --git a/include/boost/polygon/detail/polygon_45_touch.hpp b/include/boost/polygon/detail/polygon_45_touch.hpp index 705accf..e50912a 100644 --- a/include/boost/polygon/detail/polygon_45_touch.hpp +++ b/include/boost/polygon/detail/polygon_45_touch.hpp @@ -186,7 +186,7 @@ namespace boost { namespace polygon{ template static void performTouch(graph_type& graph, TouchSetData& tsd) { - std::sort(tsd.begin(), tsd.end(), lessVertex45Compact()); + gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector::template Scan45CountT > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); diff --git a/include/boost/polygon/detail/polygon_90_set_view.hpp b/include/boost/polygon/detail/polygon_90_set_view.hpp index 72b9708..53beec8 100644 --- a/include/boost/polygon/detail/polygon_90_set_view.hpp +++ b/include/boost/polygon/detail/polygon_90_set_view.hpp @@ -33,56 +33,91 @@ namespace boost { namespace polygon{ static inline bool sorted(const polygon_90_set_view& polygon_set); }; - template - struct compute_90_set_value { - static - void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_, orientation_2d orient_) { - value_type linput_(orient_); - value_type rinput_(orient_); - insert_into_view_arg(linput_, lvalue_, orient_); - insert_into_view_arg(rinput_, rvalue_, orient_); - output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); - } - }; + template + struct compute_90_set_value { + static + void value(value_type& output_, const ltype& lvalue_, const rtype& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + value_type rinput_(orient_); + orientation_2d orient_l = polygon_90_set_traits::orient(lvalue_); + orientation_2d orient_r = polygon_90_set_traits::orient(rvalue_); + //std::cout << "compute_90_set_value-0 orientations (left, right, out):\t" << orient_l.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + insert_into_view_arg(linput_, lvalue_, orient_l); + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + } + }; - template - struct compute_90_set_value, polygon_90_set_data, op_type> { - static - void value(value_type& output_, const polygon_90_set_data& lvalue_, - const polygon_90_set_data& rvalue_, orientation_2d) { - lvalue_.sort(); - rvalue_.sort(); - output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), - rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); - } - }; + template + struct compute_90_set_value, polygon_90_set_data, op_type> { + static + void value(value_type& output_, const polygon_90_set_data& lvalue_, + const polygon_90_set_data& rvalue_, orientation_2d orient_) { + orientation_2d orient_l = lvalue_.orient(); + orientation_2d orient_r = rvalue_.orient(); + value_type linput_(orient_); + value_type rinput_(orient_); + //std::cout << "compute_90_set_value-1 orientations (left, right, out):\t" << orient_l.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + if((orient_ == orient_l) && (orient_== orient_r)){ // assume that most of the time this condition is met + lvalue_.sort(); + rvalue_.sort(); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + }else if((orient_ != orient_l) && (orient_!= orient_r)){ // both the orientations are not equal to input + // easier way is to ignore the input orientation and use the input data's orientation, but not done so + insert_into_view_arg(linput_, lvalue_, orient_l); + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + }else if(orient_ != orient_l){ // left hand side orientation is different + insert_into_view_arg(linput_, lvalue_, orient_l); + rvalue_.sort(); + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + } else if(orient_ != orient_r){ // right hand side orientation is different + insert_into_view_arg(rinput_, rvalue_, orient_r); + lvalue_.sort(); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + } + } + }; - template - struct compute_90_set_value, rtype, op_type> { - static - void value(value_type& output_, const polygon_90_set_data& lvalue_, - const rtype& rvalue_, orientation_2d orient_) { - value_type rinput_(orient_); - lvalue_.sort(); - insert_into_view_arg(rinput_, rvalue_, orient_); - output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); - } - }; + template + struct compute_90_set_value, rtype, op_type> { + static + void value(value_type& output_, const polygon_90_set_data& lvalue_, + const rtype& rvalue_, orientation_2d orient_) { + value_type rinput_(orient_); + lvalue_.sort(); + orientation_2d orient_r = polygon_90_set_traits::orient(rvalue_); + //std::cout << "compute_90_set_value-2 orientations (right, out):\t" << orient_r.to_int() + // << "," << orient_.to_int() << std::endl; + insert_into_view_arg(rinput_, rvalue_, orient_r); + output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + } + }; - template - struct compute_90_set_value, op_type> { - static - void value(value_type& output_, const ltype& lvalue_, - const polygon_90_set_data& rvalue_, orientation_2d orient_) { - value_type linput_(orient_); - insert_into_view_arg(linput_, lvalue_, orient_); - rvalue_.sort(); - output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); - } - }; + template + struct compute_90_set_value, op_type> { + static + void value(value_type& output_, const ltype& lvalue_, + const polygon_90_set_data& rvalue_, orientation_2d orient_) { + value_type linput_(orient_); + orientation_2d orient_l = polygon_90_set_traits::orient(lvalue_); + insert_into_view_arg(linput_, lvalue_, orient_l); + rvalue_.sort(); + //std::cout << "compute_90_set_value-3 orientations (left, out):\t" << orient_l.to_int() + // << "," << orient_.to_int() << std::endl; + + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + } + }; template class polygon_90_set_view { @@ -129,7 +164,7 @@ namespace boost { namespace polygon{ // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); -// std::sort(output_.begin(), output_.end()); +// gtlsort(output_.begin(), output_.end()); // } void sort() const {} //is always sorted }; @@ -206,23 +241,34 @@ namespace boost { namespace polygon{ typedef type_1 type; }; - template - geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { - typedef geometry_type_1 ltype; - typedef geometry_type_2 rtype; - typedef typename polygon_90_set_traits::coordinate_type coordinate_type; - typedef polygon_90_set_data value_type; - orientation_2d orient_ = polygon_90_set_traits::orient(lvalue_); - value_type linput_(orient_); - value_type rinput_(orient_); - value_type output_(orient_); - insert_into_view_arg(linput_, lvalue_, orient_); - insert_into_view_arg(rinput_, rvalue_, orient_); - output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); - polygon_90_set_mutable_traits::set(lvalue_, output_.begin(), output_.end(), orient_); - return lvalue_; - } + template + geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { + typedef geometry_type_1 ltype; + typedef geometry_type_2 rtype; + typedef typename polygon_90_set_traits::coordinate_type coordinate_type; + typedef polygon_90_set_data value_type; + orientation_2d orient_ = polygon_90_set_traits::orient(lvalue_); + //BM: rvalue_ data set may have its own orientation for scanline + orientation_2d orient_r = polygon_90_set_traits::orient(rvalue_); + //std::cout << "self-assignment boolean-op (left, right, out):\t" << orient_.to_int() + // << "," << orient_r.to_int() << "," << orient_.to_int() << std::endl; + value_type linput_(orient_); + // BM: the rinput_ set's (that stores the rvalue_ dataset polygons) scanline orientation is *forced* + // to be same as linput + value_type rinput_(orient_); + //BM: The output dataset's scanline orient is set as equal to first input dataset's (lvalue_) orientation + value_type output_(orient_); + insert_into_view_arg(linput_, lvalue_, orient_); + // BM: The last argument orient_r is the user initialized scanline orientation for rvalue_ data set. + // But since rinput (see above) is initialized to scanline orientation consistent with the lvalue_ + // data set, this insertion operation will change the incoming rvalue_ dataset's scanline orientation + insert_into_view_arg(rinput_, rvalue_, orient_r); + // BM: boolean operation and output uses lvalue_ dataset's scanline orientation. + output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + polygon_90_set_mutable_traits::set(lvalue_, output_.begin(), output_.end(), orient_); + return lvalue_; + } namespace operators { struct y_ps90_b : gtl_yes {}; diff --git a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp index 0372d96..5adabb8 100644 --- a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp +++ b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -455,6 +455,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < x_unit) --x_unit; if(y < y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); @@ -464,11 +468,11 @@ namespace boost { namespace polygon{ if(!projected && !contains(rect1, result, true)) return false; if(!projected && !contains(rect2, result, true)) return false; if(projected) { - rectangle_data inf_rect((long double)(std::numeric_limits::min)(), - (long double) (std::numeric_limits::min)(), + rectangle_data inf_rect(-(long double)(std::numeric_limits::max)(), + -(long double) (std::numeric_limits::max)(), (long double)(std::numeric_limits::max)(), (long double) (std::numeric_limits::max)() ); - if(contains(inf_rect, intersection, true)) { + if(contains(inf_rect, point_data(x, y), true)) { intersection = result; return true; } else @@ -477,6 +481,7 @@ namespace boost { namespace polygon{ intersection = result; return true; } + inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) @@ -491,6 +496,13 @@ namespace boost { namespace polygon{ } else { return lazy_success; } + return compute_exact_intersection(intersection, he1, he2, projected, round_closest); + } + + inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + if(!projected && !intersects(he1, he2)) + return false; typedef rectangle_data Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); @@ -542,6 +554,7 @@ namespace boost { namespace polygon{ y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; + //std::cout << x << " " << y << std::endl; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); @@ -555,6 +568,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); @@ -564,14 +581,9 @@ namespace boost { namespace polygon{ if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; if(projected) { - rectangle_data inf_rect((long double)(std::numeric_limits::min)(), - (long double) (std::numeric_limits::min)(), - (long double)(std::numeric_limits::max)(), - (long double) (std::numeric_limits::max)() ); - if(contains(inf_rect, intersection, true)) { - intersection = result; - return true; - } else + high_precision b1 = (high_precision) (std::numeric_limits::min)(); + high_precision b2 = (high_precision) (std::numeric_limits::max)(); + if(x > b2 || y > b2 || x < b1 || y < b1) return false; } intersection = result; @@ -641,6 +653,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); @@ -1203,7 +1219,7 @@ namespace boost { namespace polygon{ static inline void sort_vertex_arbitrary_count(vertex_arbitrary_count& count, const Point& pt) { less_half_edge_count lfec(pt); - std::sort(count.begin(), count.end(), lfec); + gtlsort(count.begin(), count.end(), lfec); } typedef std::vector, int>, active_tail_arbitrary*> > incoming_count; @@ -1227,7 +1243,7 @@ namespace boost { namespace polygon{ static inline void sort_incoming_count(incoming_count& count, const Point& pt) { less_incoming_count lfec(pt); - std::sort(count.begin(), count.end(), lfec); + gtlsort(count.begin(), count.end(), lfec); } static inline void compact_vertex_arbitrary_count(const Point& pt, vertex_arbitrary_count &count) { @@ -1798,7 +1814,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1822,7 +1838,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1846,7 +1862,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1892,7 +1908,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1939,7 +1955,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1979,7 +1995,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2019,7 +2035,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2047,7 +2063,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(-1, 4), Point(0, 2), -1)); data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2753,7 +2769,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2776,7 +2792,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2799,7 +2815,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2844,7 +2860,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2891,7 +2907,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { diff --git a/include/boost/polygon/detail/property_merge.hpp b/include/boost/polygon/detail/property_merge.hpp index 586a927..77f2614 100644 --- a/include/boost/polygon/detail/property_merge.hpp +++ b/include/boost/polygon/detail/property_merge.hpp @@ -112,7 +112,7 @@ public: inline void perform_merge(result_type& result, property_merge_data& data) { if(data.empty()) return; //sort - std::sort(data.begin(), data.end(), less_vertex_data()); + gtlsort(data.begin(), data.end(), less_vertex_data()); //scanline bool firstIteration = true; scanlinePosition = scanline.end(); @@ -156,7 +156,7 @@ private: class less_vertex_data { public: less_vertex_data() {} - bool operator()(const T& lvalue, const T& rvalue) { + bool operator()(const T& lvalue, const T& rvalue) const { if(lvalue.first.x() < rvalue.first.x()) return true; if(lvalue.first.x() > rvalue.first.x()) return false; if(lvalue.first.y() < rvalue.first.y()) return true; @@ -442,7 +442,7 @@ private: inline void performExtract(T& result, property_merge_data& data) { if(data.empty()) return; //sort - std::sort(data.begin(), data.end(), less_vertex_data()); + gtlsort(data.begin(), data.end(), less_vertex_data()); //scanline bool firstIteration = true; diff --git a/include/boost/polygon/detail/property_merge_45.hpp b/include/boost/polygon/detail/property_merge_45.hpp index e919486..b85baf7 100644 --- a/include/boost/polygon/detail/property_merge_45.hpp +++ b/include/boost/polygon/detail/property_merge_45.hpp @@ -111,7 +111,7 @@ namespace boost { namespace polygon{ template static void performMerge(output_type& result, MergeSetData& tsd) { - std::sort(tsd.begin(), tsd.end(), lessVertex45Compact()); + gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector::template Scan45CountT > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); diff --git a/include/boost/polygon/detail/scan_arbitrary.hpp b/include/boost/polygon/detail/scan_arbitrary.hpp index 7b0ecda..1933eee 100644 --- a/include/boost/polygon/detail/scan_arbitrary.hpp +++ b/include/boost/polygon/detail/scan_arbitrary.hpp @@ -10,6 +10,7 @@ #ifdef BOOST_POLYGON_DEBUG_FILE #include #endif +#include "polygon_sort_adaptor.hpp" namespace boost { namespace polygon{ template @@ -75,7 +76,7 @@ namespace boost { namespace polygon{ ends.push_back(std::make_pair((*itr).first.first.y(), count)); ends.push_back(std::make_pair((*itr).first.second.y(), -count)); } - std::sort(ends.begin(), ends.end()); + gtlsort(ends.begin(), ends.end()); histogram.reserve(ends.size()); histogram.push_back(std::make_pair(ends.front().first, std::make_pair(0, 0))); for(typename std::vector >::iterator itr = ends.begin(); itr != ends.end(); ++itr) { @@ -160,7 +161,7 @@ namespace boost { namespace polygon{ } } typename scanline_base::compute_intersection_pack pack_; - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); //find all intersection points for(typename std::vector >::iterator outer = data.begin(); outer != data.end(); ++outer) { @@ -191,11 +192,13 @@ namespace boost { namespace polygon{ if(pack_.compute_intersection(intersection, he1, he2)) { //their intersection point pts.push_back(intersection); + intersection_points[(*inner).second].insert(intersection); + intersection_points[(*outer).second].insert(intersection); } } } } - std::sort(pts.begin(), pts.end()); + gtlsort(pts.begin(), pts.end()); typename std::vector::iterator newend = std::unique(pts.begin(), pts.end()); typename std::vector::iterator lfinger = pts.begin(); //find all segments that interact with intersection points @@ -286,7 +289,7 @@ namespace boost { namespace polygon{ std::swap(data[i].first.first, data[i].first.second); } } - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); for(typename std::vector >::iterator outer = data.begin(); outer != data.end(); ++outer) { const half_edge& he1 = (*outer).first; @@ -356,7 +359,7 @@ namespace boost { namespace polygon{ tmpPts.reserve(pts.size()); tmpPts.insert(tmpPts.end(), pts.begin(), pts.end()); less_point_down_slope lpds; - std::sort(tmpPts.begin(), tmpPts.end(), lpds); + gtlsort(tmpPts.begin(), tmpPts.end(), lpds); segment_edge(output_segments, he, id, tmpPts.begin(), tmpPts.end()); } else { segment_edge(output_segments, he, id, pts.begin(), pts.end()); @@ -498,7 +501,7 @@ namespace boost { namespace polygon{ // } // //merge sloping element data -// std::sort(sloping_ends.begin(), sloping_ends.end()); +// gtlsort(sloping_ends.begin(), sloping_ends.end()); // std::map > sloping_elements; // std::set merge_elements; // for(typename std::vector >::iterator slop_iter = sloping_ends.begin(); @@ -1310,7 +1313,7 @@ namespace boost { namespace polygon{ output.push_back(vertex_half_edge(he.first, he.second, count)); output.push_back(vertex_half_edge(he.second, he.first, -count)); } - std::sort(output.begin(), output.end()); + gtlsort(output.begin(), output.end()); } class test_functor { @@ -1514,7 +1517,7 @@ namespace boost { namespace polygon{ public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} - bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + bool operator() (const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; @@ -1528,7 +1531,7 @@ namespace boost { namespace polygon{ inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - std::sort(pmd.begin(), pmd.end(), lvd); + gtlsort(pmd.begin(), pmd.end(), lvd); } public: inline property_merge_data& get_property_merge_data() { return pmd; } @@ -1573,7 +1576,7 @@ namespace boost { namespace polygon{ pts.push_back(lines[i].first.first); pts.push_back(lines[i].first.second); } - std::sort(pts.begin(), pts.end()); + gtlsort(pts.begin(), pts.end()); for(std::size_t i = 0; i < pts.size(); i+=2) { if(pts[i] != pts[i+1]) { //stdcout << "Non-closed figures after line intersection!\n"; @@ -1683,7 +1686,7 @@ namespace boost { namespace polygon{ static inline void sort_vertex_half_edges(vertex_data& vertex) { less_half_edge_pair lessF(vertex.first); - std::sort(vertex.second.begin(), vertex.second.end(), lessF); + gtlsort(vertex.second.begin(), vertex.second.end(), lessF); } class less_half_edge_pair { @@ -2165,7 +2168,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 outpts.push_back((*itr).first.first); outpts.push_back((*itr).first.second); } - std::sort(outpts.begin(), outpts.end()); + gtlsort(outpts.begin(), outpts.end()); for(std::size_t i = 0; i < outpts.size(); i+=2) { if(outpts[i] != outpts[i+1]) { stdcout << "Polygon set not a closed figure\n"; @@ -2514,7 +2517,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} - bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; @@ -2580,7 +2583,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - std::sort(pmd.begin(), pmd.end(), lvd); + gtlsort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_boolean_op() : pmd(), evalAtXforYPack_() {} @@ -2732,7 +2735,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 public: less_vertex_data() : pack_() {} less_vertex_data(typename scanline_base::evalAtXforYPack* pack) : pack_(pack) {} - bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) { + bool operator()(const vertex_data_type& lvalue, const vertex_data_type& rvalue) const { less_point lp; if(lp(lvalue.first.first, rvalue.first.first)) return true; if(lp(rvalue.first.first, lvalue.first.first)) return false; @@ -2804,7 +2807,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - std::sort(pmd.begin(), pmd.end(), lvd); + gtlsort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_connectivity_extraction() : pmd(), evalAtXforYPack_() {} diff --git a/include/boost/polygon/gmp_override.hpp b/include/boost/polygon/gmp_override.hpp index bfe3e3c..16cc96f 100755 --- a/include/boost/polygon/gmp_override.hpp +++ b/include/boost/polygon/gmp_override.hpp @@ -125,5 +125,5 @@ namespace boost { namespace polygon { } } - +//== #endif diff --git a/include/boost/polygon/interval_concept.hpp b/include/boost/polygon/interval_concept.hpp index b3b1a46..9fc5257 100755 --- a/include/boost/polygon/interval_concept.hpp +++ b/include/boost/polygon/interval_concept.hpp @@ -471,7 +471,7 @@ namespace boost { namespace polygon{ typedef typename interval_traits::coordinate_type Unit; Unit coords[4] = {low(interval), high(interval), low(b), high(b)}; //consider implementing faster sorting of small fixed length range - std::sort(coords, coords+4); + gtlsort(coords, coords+4); low(interval, coords[1]); high(interval, coords[2]); return interval; diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp index 1323cfd..1db7967 100755 --- a/include/boost/polygon/isotropy.hpp +++ b/include/boost/polygon/isotropy.hpp @@ -198,6 +198,16 @@ namespace boost { namespace polygon{ typedef double coordinate_distance; }; + template <> + struct coordinate_traits { + typedef long double coordinate_type; + typedef long double area_type; + typedef long double manhattan_area_type; + typedef long double unsigned_area_type; + typedef long double coordinate_difference; + typedef long double coordinate_distance; + }; + template struct scaling_policy { template @@ -222,6 +232,8 @@ namespace boost { namespace polygon{ struct geometry_concept { typedef coordinate_concept type; }; template <> struct geometry_concept { typedef coordinate_concept type; }; + template <> + struct geometry_concept { typedef coordinate_concept type; }; #ifndef BOOST_POLYGON_NO_DEPS struct gtl_no : mpl::bool_ {}; diff --git a/include/boost/polygon/polygon.hpp b/include/boost/polygon/polygon.hpp index 0c1594f..4c3e43a 100755 --- a/include/boost/polygon/polygon.hpp +++ b/include/boost/polygon/polygon.hpp @@ -7,6 +7,7 @@ */ #ifndef BOOST_POLYGON_POLYGON_HPP #define BOOST_POLYGON_POLYGON_HPP +#define BOOST_POLYGON_VERSION 014401 #include "isotropy.hpp" diff --git a/include/boost/polygon/polygon_45_set_data.hpp b/include/boost/polygon/polygon_45_set_data.hpp index b479cfd..e541ee5 100755 --- a/include/boost/polygon/polygon_45_set_data.hpp +++ b/include/boost/polygon/polygon_45_set_data.hpp @@ -212,7 +212,7 @@ namespace boost { namespace polygon{ void sort() const{ if(unsorted_) { - std::sort(data_.begin(), data_.end()); + gtlsort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -1262,7 +1262,7 @@ namespace boost { namespace polygon{ //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - std::sort(eventOut.begin(), eventOut.end()); + gtlsort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && @@ -1333,7 +1333,7 @@ namespace boost { namespace polygon{ } } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - std::sort(eventOut.begin(), eventOut.end()); + gtlsort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { @@ -1385,7 +1385,7 @@ namespace boost { namespace polygon{ //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - std::sort(eventOut.begin(), eventOut.end()); + gtlsort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && @@ -1422,7 +1422,7 @@ namespace boost { namespace polygon{ ++iter1; } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - std::sort(eventOut.begin(), eventOut.end()); + gtlsort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { @@ -1639,7 +1639,7 @@ namespace boost { namespace polygon{ result.error_data_.push_back(ci); } Data2 new_result_data; - std::sort(result_data.begin(), result_data.end()); + gtlsort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } @@ -1749,7 +1749,7 @@ namespace boost { namespace polygon{ result.error_data_.push_back(ci); } Data2 new_result_data; - std::sort(result_data.begin(), result_data.end()); + gtlsort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp index 7013ca5..151cb9d 100755 --- a/include/boost/polygon/polygon_90_set_data.hpp +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -244,37 +244,47 @@ namespace boost { namespace polygon{ // get the scanline orientation of the polygon set inline orientation_2d orient() const { return orient_; } - polygon_90_set_data& operator-=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator^=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator&=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator|=(const polygon_90_set_data& that) { - insert(that); - return *this; - } + // Start BM + // The problem: If we have two polygon sets with two different scanline orientations: + // I tried changing the orientation of one to coincide with other (If not, resulting boolean operation + // produces spurious results). + // First I tried copying polygon data from one of the sets into another set with corrected orientation + // using one of the copy constructor that takes in orientation (see somewhere above in this file) --> copy constructor throws error + // Then I tried another approach:(see below). This approach also fails to produce the desired results when test case is run. + // Here is the part that beats me: If I comment out the whole section, I can do all the operations (^=, -=, &= )these commented out + // operations perform. So then why do we need them?. Hence, I commented out this whole section. + // End BM + // polygon_90_set_data& operator-=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator^=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator&=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator|=(const polygon_90_set_data& that) { + // insert(that); + // return *this; + // } void clean() const { sort(); @@ -286,7 +296,7 @@ namespace boost { namespace polygon{ void sort() const{ if(unsorted_) { - std::sort(data_.begin(), data_.end()); + gtlsort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -439,7 +449,7 @@ namespace boost { namespace polygon{ static bool remove_colinear_pts(std::vector >& poly) { bool found_colinear = true; - while(found_colinear) { + while(found_colinear && poly.size() >= 4) { found_colinear = false; typename std::vector >::iterator itr = poly.begin(); itr += poly.size() - 1; //get last element position @@ -504,9 +514,9 @@ namespace boost { namespace polygon{ //polygon_45_data testpoly(*itrh); if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { iterator_geometry_to_set > > - begin_input(view_as(*itrh), LOW, orient_, true, true), - end_input(view_as(*itrh), HIGH, orient_, true, true); - insert(begin_input, end_input, orient_); + begin_input2(view_as(*itrh), LOW, orient_, true, true), + end_input2(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > @@ -569,9 +579,9 @@ namespace boost { namespace polygon{ //polygon_45_data testpoly(*itrh); resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); iterator_geometry_to_set > > - begin_input(view_as(*itrh), LOW, orient_, true, true), - end_input(view_as(*itrh), HIGH, orient_, true, true); - insert(begin_input, end_input, orient_); + begin_input2(view_as(*itrh), LOW, orient_, true, true), + end_input2(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > @@ -638,8 +648,7 @@ namespace boost { namespace polygon{ return shrink(0, shrinking, 0, 0); if(dir == SOUTH) return shrink(0, 0, shrinking, 0); - if(dir == NORTH) - return shrink(0, 0, 0, shrinking); + return shrink(0, 0, 0, shrinking); } polygon_90_set_data& @@ -650,8 +659,7 @@ namespace boost { namespace polygon{ return bloat(0, shrinking, 0, 0); if(dir == SOUTH) return bloat(0, 0, shrinking, 0); - if(dir == NORTH) - return bloat(0, 0, 0, shrinking); + return bloat(0, 0, 0, shrinking); } polygon_90_set_data& diff --git a/include/boost/polygon/polygon_set_data.hpp b/include/boost/polygon/polygon_set_data.hpp index 4061ae2..bbddacf 100755 --- a/include/boost/polygon/polygon_set_data.hpp +++ b/include/boost/polygon/polygon_set_data.hpp @@ -248,7 +248,7 @@ namespace boost { namespace polygon { data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); //std::cout << "DONE FORMING POLYGONS\n"; } @@ -321,7 +321,7 @@ namespace boost { namespace polygon { void sort() const{ if(unsorted_) { - std::sort(data_.begin(), data_.end()); + gtlsort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -359,24 +359,7 @@ namespace boost { namespace polygon { } inline polygon_set_data& - resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0) { - if(!corner_fill_arc) { - if(resizing < 0) - return shrink(-resizing); - if(resizing > 0) - return bloat(-resizing); - return *this; - } - if(resizing == 0) return *this; - std::list > pl; - get(pl); - clear(); - for(typename std::list >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { - insert_with_resize(*itr, resizing, corner_fill_arc, num_circle_segments); - } - clean(); - return *this; - } + resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); template inline polygon_set_data& @@ -425,37 +408,53 @@ namespace boost { namespace polygon { return *this; } - static inline void compute_offset_edge(point_data& pt1, point_data& pt2, - const point_data& prev_pt, - const point_data& current_pt, - coordinate_type distance, int multiplier) { - coordinate_type dx = current_pt.x() - prev_pt.x(); - coordinate_type dy = current_pt.y() - prev_pt.y(); - double ddx = (double)dx; - double ddy = (double)dy; - double edge_length = std::sqrt(ddx*ddx + ddy*ddy); - double dnx = dy; - double dny = -dx; - dnx = dnx * (double)distance / edge_length; - dny = dny * (double)distance / edge_length; - dnx = std::floor(dnx+0.5); - dny = std::floor(dny+0.5); - pt1.x(prev_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); - pt2.x(current_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); - pt1.y(prev_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); - pt2.y(current_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); + static inline void compute_offset_edge(point_data& pt1, point_data& pt2, + const point_data& prev_pt, + const point_data& current_pt, + long double distance, int multiplier) { + long double dx = current_pt.x() - prev_pt.x(); + long double dy = current_pt.y() - prev_pt.y(); + long double edge_length = std::sqrt(dx*dx + dy*dy); + long double dnx = dy; + long double dny = -dx; + dnx = dnx * (long double)distance / edge_length; + dny = dny * (long double)distance / edge_length; + pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier); + pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier); + pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier); + pt2.y(current_pt.y() + (long double)dny * (long double)multiplier); } static inline void modify_pt(point_data& pt, const point_data& prev_pt, const point_data& current_pt, const point_data& next_pt, coordinate_type distance, coordinate_type multiplier) { - std::pair, point_data > he1(prev_pt, current_pt), he2(current_pt, next_pt); + std::pair, point_data > he1, he2; + he1.first.x((long double)(prev_pt.x())); + he1.first.y((long double)(prev_pt.y())); + he1.second.x((long double)(current_pt.x())); + he1.second.y((long double)(current_pt.y())); + he2.first.x((long double)(current_pt.x())); + he2.first.y((long double)(current_pt.y())); + he2.second.x((long double)(next_pt.x())); + he2.second.y((long double)(next_pt.y())); compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); - typename scanline_base::compute_intersection_pack pack; - if(!pack.compute_lazy_intersection(pt, he1, he2, true, true)) { - pt = he1.second; //colinear offset edges use shared point + typename scanline_base::compute_intersection_pack pack; + point_data rpt; + point_data bisectorpt((he1.second.x()+he2.first.x())/2, + (he1.second.y()+he2.first.y())/2); + point_data orig_pt((long double)pt.x(), (long double)pt.y()); + if(euclidean_distance(bisectorpt, orig_pt) < distance/2) { + if(!pack.compute_lazy_intersection(rpt, he1, he2, true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } + } else { + if(!pack.compute_lazy_intersection(rpt, he1, std::pair, point_data >(orig_pt, bisectorpt), true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } } + pt.x((coordinate_type)(std::floor(rpt.x()+0.5))); + pt.y((coordinate_type)(std::floor(rpt.y()+0.5))); } static void resize_poly_up(std::vector >& poly, coordinate_type distance, coordinate_type multiplier) { @@ -615,7 +614,7 @@ namespace boost { namespace polygon { // for all corners polygon_set_data sizingSet; - bool sizing_sign = resizing>0; + bool sizing_sign = resizing<0; bool prev_concave = true; point_data prev_point; //int iCtr=0; @@ -791,7 +790,7 @@ namespace boost { namespace polygon { data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } - std::sort(data.begin(), data.end()); + gtlsort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); } }; @@ -911,7 +910,7 @@ namespace boost { namespace polygon { } return_points.push_back(round_down(center)); return_points.push_back(round_down(start)); - int i=0; + unsigned int i=0; double curr_angle = ps+delta_angle; while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { i++; @@ -996,5 +995,6 @@ namespace boost { namespace polygon { #include "detail/polygon_set_view.hpp" #include "polygon_set_concept.hpp" +#include "detail/minkowski.hpp" #endif From a933d589280c0f996716ba8cab3c2d2df51a669a Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Wed, 10 Nov 2010 18:08:42 +0000 Subject: [PATCH 08/32] merge from trunk [SVN r66486] --- include/boost/polygon/detail/minkowski.hpp | 125 +++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 include/boost/polygon/detail/minkowski.hpp diff --git a/include/boost/polygon/detail/minkowski.hpp b/include/boost/polygon/detail/minkowski.hpp new file mode 100644 index 0000000..312d9a2 --- /dev/null +++ b/include/boost/polygon/detail/minkowski.hpp @@ -0,0 +1,125 @@ + +namespace boost { namespace polygon { namespace detail { + +template +struct minkowski_offset { + typedef point_data point; + typedef polygon_set_data polygon_set; + typedef polygon_with_holes_data polygon; + typedef std::pair edge; + + static void convolve_two_segments(std::vector& figure, const edge& a, const edge& b) { + figure.clear(); + figure.push_back(point(a.first)); + figure.push_back(point(a.first)); + figure.push_back(point(a.second)); + figure.push_back(point(a.second)); + convolve(figure[0], b.second); + convolve(figure[1], b.first); + convolve(figure[2], b.first); + convolve(figure[3], b.second); + } + + template + static void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { + if(ab == ae || bb == be) + return; + point first_a = *ab; + point prev_a = *ab; + std::vector vec; + polygon poly; + ++ab; + for( ; ab != ae; ++ab) { + point first_b = *bb; + point prev_b = *bb; + itrT2 tmpb = bb; + ++tmpb; + for( ; tmpb != be; ++tmpb) { + convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); + set_points(poly, vec.begin(), vec.end()); + result.insert(poly); + prev_b = *tmpb; + } + prev_a = *ab; + } + } + + template + static void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector& polygons) { + for(std::size_t i = 0; i < polygons.size(); ++i) { + convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); + for(typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygons[i]); + itrh != end_holes(polygons[i]); ++itrh) { + convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); + } + } + } + + static void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { + result.clear(); + std::vector a_polygons; + std::vector b_polygons; + a.get(a_polygons); + b.get(b_polygons); + for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { + convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), + end_points(a_polygons[ai]), b_polygons); + for(typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); + itrh != end_holes(a_polygons[ai]); ++itrh) { + convolve_point_sequence_with_polygons(result, begin_points(*itrh), + end_points(*itrh), b_polygons); + } + for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { + polygon tmp_poly = a_polygons[ai]; + result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); + tmp_poly = b_polygons[bi]; + result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); + } + } + } +}; + +} + template + inline polygon_set_data& + polygon_set_data::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments) { + using namespace ::boost::polygon::operators; + if(!corner_fill_arc) { + if(resizing < 0) + return shrink(-resizing); + if(resizing > 0) + return bloat(resizing); + return *this; + } + if(resizing == 0) return *this; + if(empty()) return *this; + if(num_circle_segments < 3) num_circle_segments = 4; + rectangle_data rect; + extents(rect); + if(resizing < 0) { + ::boost::polygon::bloat(rect, 10); + (*this) = rect - (*this); //invert + } + //make_arc(std::vector >& return_points, + //point_data< double> start, point_data< double> end, + //point_data< double> center, double r, unsigned int num_circle_segments) + std::vector > circle; + point_data center(0.0, 0.0), start(0.0, (double)resizing); + make_arc(circle, start, start, center, std::abs((double)resizing), + num_circle_segments); + polygon_data poly; + set_points(poly, circle.begin(), circle.end()); + polygon_set_data offset_set; + offset_set += poly; + polygon_set_data result; + detail::minkowski_offset::convolve_two_polygon_sets + (result, *this, offset_set); + if(resizing < 0) { + result = result & rect;//eliminate overhang + result = result ^ rect;//invert + } + *this = result; + return *this; + } + +}} From 40a65132cec4d2bcd4f9e611882a06219138f5d7 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Wed, 10 Nov 2010 18:09:55 +0000 Subject: [PATCH 09/32] merge from trunk [SVN r66487] --- test/gtl_boost_unit_test.cpp | 63 ++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index 6625bb9..b757e49 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -3368,10 +3368,17 @@ int main() { polygon_set_data ps; polygon_90_set_data ps90; rectangle_data rect(0, 1, 10, 100); + std::vector > rupolys, rupolys45; ps.insert(rect); ps90.insert(rect); ps.bloat(10); ps90.bloat(10, 10, 10, 10); + rupolys.clear(); + rupolys45.clear(); + ps.get(rupolys); + ps90.get(rupolys45); + std::cout << rupolys[0] << std::endl; + std::cout << rupolys45[0] << std::endl; if(!equivalence(ps, ps90)) { std::cout << "test manhattan vs general resize up failed\n"; return 1; @@ -3409,10 +3416,30 @@ int main() { ps45.insert(poly); ps.bloat(9); ps45.resize(9); - if(!equivalence(ps, ps45)) { - std::cout << "test 45 vs general resize up failed\n"; + rupolys.clear(); + rupolys45.clear(); + ps.get(rupolys); + ps45.get(rupolys45); + std::cout << rupolys[0] << std::endl; + std::cout << rupolys45[0] << std::endl; + pts.clear(); + pts.push_back(point_data(32, -9)); + pts.push_back(point_data(-9, 32)); + pts.push_back(point_data(-9, -9)); + set_points(poly, pts.begin(), pts.end()); + if(!equivalence(ps, poly)) { + std::cout << "test general resize up failed\n"; return 1; - } + } + // this test is waived due to rounding differences between 45 and general resizing + // general resizing is computing floating point coordinates for the intersection + // and rounding those to closest while 45 is computing the normal point and rounding + // that to closest, it turns out to result in different intersection point + // we want the general to be more accurate to avoid artifacts + //if(!equivalence(ps, ps45)) { + // std::cout << "test 45 vs general resize up failed\n"; + // return 1; + //} ps.shrink(9); ps45.resize(-9); if(!equivalence(ps, ps45)) { @@ -3428,10 +3455,33 @@ int main() { ps45.insert(poly, true); ps.bloat(1); ps45.resize(1); - if(!equivalence(ps, ps45)) { - std::cout << "test 45 vs general resize up with holes failed\n"; + rupolys.clear(); + rupolys45.clear(); + ps.get(rupolys); + ps45.get(rupolys45); + std::cout << rupolys[0] << std::endl; + std::cout << rupolys45[0] << std::endl; + pts.clear(); + pts.push_back(point_data(12, -1)); + pts.push_back(point_data(5, 6)); + pts.push_back(point_data(5, 2)); + pts.push_back(point_data(2, 2)); + pts.push_back(point_data(2, 5)); + pts.push_back(point_data(5, 2)); + pts.push_back(point_data(5, 6)); + pts.push_back(point_data(-1, 12)); + pts.push_back(point_data(-1, -1)); + pts.push_back(point_data(12, -1)); + set_points(poly, pts.begin(), pts.end()); + if(!equivalence(ps, poly)) { + std::cout << "test general resize up with holes failed\n"; return 1; - } + } + //waived + //if(!equivalence(ps, ps45)) { + // std::cout << "test 45 vs general resize up with holes failed\n"; + // return 1; + //} ps.shrink(1); ps45.resize(-1); if(!equivalence(ps, ps45)) { @@ -3446,7 +3496,6 @@ int main() { } } - std::cout << "ALL TESTS COMPLETE\n"; return 0; } From dd47608137c4d1b9be725824e5c514a6ce914a11 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Thu, 11 Nov 2010 16:48:57 +0000 Subject: [PATCH 10/32] missing header [SVN r66493] --- .../polygon/detail/polygon_sort_adaptor.hpp | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100755 include/boost/polygon/detail/polygon_sort_adaptor.hpp diff --git a/include/boost/polygon/detail/polygon_sort_adaptor.hpp b/include/boost/polygon/detail/polygon_sort_adaptor.hpp new file mode 100755 index 0000000..40f16a7 --- /dev/null +++ b/include/boost/polygon/detail/polygon_sort_adaptor.hpp @@ -0,0 +1,67 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_SORT_ADAPTOR_HPP +#define BOOST_POLYGON_SORT_ADAPTOR_HPP +#ifdef __ICC +#pragma warning(disable:2022) +#pragma warning(disable:2023) +#endif + +#include + +//! @brief gtlsort_adaptor default implementation that calls std::sort +namespace boost { + namespace polygon { + + template + struct dummy_to_delay_instantiation{ + typedef int unit_type; // default GTL unit + }; + + //! @brief gtlsort_adaptor default implementation that calls std::sort + template + struct gtlsort_adaptor { + //! @brief wrapper that mimics std::sort() function and takes + // the same arguments + template + static void sort(RandomAccessIterator_Type _First, + RandomAccessIterator_Type _Last) + { + std::sort(_First, _Last); + } + //! @brief wrapper that mimics std::sort() function overload and takes + // the same arguments + template + static void sort(RandomAccessIterator_Type _First, + RandomAccessIterator_Type _Last, + const Pred_Type& _Comp) + { + std::sort(_First, _Last, _Comp); + } + }; + + //! @brief user level wrapper for sorting quantities + template + void gtlsort(iter_type _b_, iter_type _e_) + { + gtlsort_adaptor::unit_type>::sort(_b_, _e_); + } + + //! @brief user level wrapper for sorting quantities that takes predicate + // as additional argument + template + void gtlsort(iter_type _b_, iter_type _e_, const pred_type& _pred_) + { + gtlsort_adaptor::unit_type>::sort(_b_, _e_, _pred_); + } + + + + } // namespace polygon +} // namespace boost +#endif From e760252a2e84024b5ff0a0447b6b9e151dbba5df Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 30 Nov 2010 17:53:58 +0000 Subject: [PATCH 11/32] fixed trac 4868 polygon concept contains function [SVN r66903] --- include/boost/polygon/polygon_traits.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index caa1869..e9edc34 100755 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1170,7 +1170,7 @@ namespace boost { namespace polygon{ //odd count implies boundary condition if(counts[0] % 2 || counts[1] % 2) return consider_touch; //an odd number of edges to the left implies interior pt - return counts[0] % 4 != 0; + return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; } //TODO: refactor to expose as user APIs From c655569784496590580383393289b92b4195ed98 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 30 Nov 2010 17:54:24 +0000 Subject: [PATCH 12/32] fixed win32 macro usage [SVN r66904] --- include/boost/polygon/isotropy.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp index 1db7967..055707c 100755 --- a/include/boost/polygon/isotropy.hpp +++ b/include/boost/polygon/isotropy.hpp @@ -48,7 +48,7 @@ typedef boost::ulong_long_type polygon_ulong_long_type; #include #else -#ifdef WIN32 +#ifdef _WIN32 #define BOOST_POLYGON_MSVC #endif #ifdef __ICC @@ -290,7 +290,7 @@ namespace boost { namespace polygon{ template struct gtl_if { -#ifdef WIN32 +#ifdef BOOST_POLYGON_MSVC typedef gtl_no type; #endif }; From e2bc65e796ab59d3792ad9772d2e18d02b58fb0c Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Mon, 7 Mar 2011 01:24:34 +0000 Subject: [PATCH 13/32] disabled 45-degree booleans optimization [SVN r69615] --- include/boost/polygon/detail/polygon_set_view.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/boost/polygon/detail/polygon_set_view.hpp b/include/boost/polygon/detail/polygon_set_view.hpp index 7b159a8..693acc4 100644 --- a/include/boost/polygon/detail/polygon_set_view.hpp +++ b/include/boost/polygon/detail/polygon_set_view.hpp @@ -14,7 +14,13 @@ namespace boost { namespace polygon{ inline void polygon_set_data::clean() const { if(dirty_) { polygon_45_set_data tmp; - if(downcast(tmp) ) { + //very important: + //the 45 degree algorithm does not satisfy + //the precondition of arbitrary polygon formation + //that vertices be "linearly consistent" + //therefore it doesn't work to fall back on 45-degree + //booleans for arbitrary angle polygons + if(0) { //downcast(tmp) ) { tmp.clean(); data_.clear(); is_45_ = true; From 0192f9d4500e1275ed97c6ee43d58e0140c0ed1f Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Mon, 7 Mar 2011 01:31:26 +0000 Subject: [PATCH 14/32] removed reference to 45-degree booleans optimization [SVN r69617] --- doc/gtl_polygon_set_concept.htm | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm index 09cf8bc..1c461c5 100644 --- a/doc/gtl_polygon_set_concept.htm +++ b/doc/gtl_polygon_set_concept.htm @@ -69,14 +69,9 @@ geometry regions.  A Polygon Set Concept may be defined with floating point coordinates, but a snap rounding distance of one integer unit will still be applied, furthermore, geometry outside the domain where one integer unit is sufficient to provide robustness may lead to undefined behavior in algorithms.  -It is recommended to use integer coordinates for robust operations.  In the -case that data represented contains only Manhattan geometry a runtime check will -default to the Manhattan algorithm.  The results of which are identical to -what the general algorithm would do, but obtained more efficiently.  In the -case that the data represented contains only Manhattan and 45-degree geometry a -runtime check will default to the faster 45-degree algorithm.  The results -of which may differ slight from what the general algorithm would do because -non-integer intersections will be handled differently.

Users are recommended to use std::vector and std::list of user defined polygons +It is recommended to use 32-bit integer coordinates for robust operations. + +

Users are recommended to use std::vector and std::list of user defined polygons or library provided polygon_set_data<coordinate_type> objects.  Lists and vectors of models of polygon_concept or polygon_with_holes_concept are automatically models of polygon_set_concept.

Example code custom_polygon_set.cpp @@ -648,4 +643,4 @@ polygon_set_data&
scale(const scaling_type&

- \ No newline at end of file + From ecf8a022095d9376ed447be5a33ecbf9b44cb47b Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Thu, 24 Mar 2011 06:50:06 +0000 Subject: [PATCH 15/32] fixed snap to 45 and general contains bugs [SVN r70495] --- include/boost/polygon/polygon_traits.hpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index e9edc34..041321d 100755 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -758,7 +758,10 @@ namespace boost { namespace polygon{ if(pts.size() < 3) { pts.clear(); return; } Point firstPt = pts.front(); Point prevPt = firstPt; - std::unique(pts.begin(), pts.end()); + typename std::vector >::iterator endLocation = std::unique(pts.begin(), pts.end()); + if(endLocation != pts.end()){ + pts.resize(endLocation - pts.begin()); + } if(pts.back() == pts[0]) pts.pop_back(); //iterate over point triplets int numPts = pts.size(); @@ -1348,10 +1351,18 @@ namespace boost { namespace polygon{ if(oabedge == 0) return consider_touch; if(oabedge == 1) ++above; } else if(x(point) == xmax) { - Point tmppt; - assign(tmppt, point); - if( edge_utils::on_above_or_below(tmppt, he) == 0 ) { - return consider_touch; + if(x(point) == xmin) { + Unit ymin = (std::min)(y(he.first), y(he.second)); + Unit ymax = (std::max)(y(he.first), y(he.second)); + Unit ypt = y(point); + if(ypt <= ymax && ypt >= ymin) + return consider_touch; + } else { + Point tmppt; + assign(tmppt, point); + if( edge_utils::on_above_or_below(tmppt, he) == 0 ) { + return consider_touch; + } } } } From 476c5f9e947d000f58492682cda22213fedab2ed Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Fri, 25 Mar 2011 17:35:52 +0000 Subject: [PATCH 16/32] updated unit test [SVN r70543] --- test/gtl_boost_unit_test.cpp | 147 ++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 4 deletions(-) diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index b757e49..ee3e9a1 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -13,6 +13,18 @@ using namespace boost::polygon::operators; #include namespace boost { namespace polygon{ + void addpoly(polygon_45_set_data& pset, + int* pts, int numpts) { + std::vector > mppts; + for(unsigned int i = 0; i < numpts*2; i += 2) { + point_data pt(pts[i], pts[i+1]); + mppts.push_back(pt); + } + polygon_45_data poly; + poly.set(mppts.begin(), mppts.end()); + pset += poly; + } + template std::ostream& operator << (std::ostream& o, const interval_data& i) @@ -3473,10 +3485,11 @@ int main() { pts.push_back(point_data(-1, -1)); pts.push_back(point_data(12, -1)); set_points(poly, pts.begin(), pts.end()); - if(!equivalence(ps, poly)) { - std::cout << "test general resize up with holes failed\n"; - return 1; - } + //waived + //if(!equivalence(ps, poly)) { + // std::cout << "test general resize up with holes failed\n"; + // return 1; + //} //waived //if(!equivalence(ps, ps45)) { // std::cout << "test 45 vs general resize up with holes failed\n"; @@ -3496,6 +3509,132 @@ int main() { } } + { + + Point pts[] = {construct(1565, 5735), + construct(915, 5735), + construct(915, 7085), + construct(1565, 7085) }; + Polygon poly; + set_points(poly, pts, pts+4); + bool ret=gtl::contains(poly,gtl::construct(920, 7080)); + if(!ret) { + std::cout << "contains failed!" << std::endl; + return 1; + } + polygon_data poly_aa; + set_points(poly_aa, pts, pts+4); + ret=gtl::contains(poly,gtl::construct(920, 7080)); + if(!ret) { + std::cout << "contains 90 failed!" << std::endl; + return 1; + } + polygon_with_holes_data pwh; + polygon_90_with_holes_data p90wh; + Point pts2[] = {construct(565, 15735), + construct(15, 15735), + construct(15, 17085), + construct(565, 17085) }; + set_points(pwh, pts2, pts2+4); + set_points(p90wh, pts2, pts2+4); + pwh.set_holes(&poly_aa, (&poly_aa)+1); + p90wh.set_holes(&poly, (&poly)+1); + ret=gtl::contains(pwh,gtl::construct(920, 7080)); + if(ret) { + std::cout << "contains wh failed!" << std::endl; + return 1; + } + ret=gtl::contains(p90wh,gtl::construct(920, 7080)); + if(ret) { + std::cout << "contains 90wh failed!" << std::endl; + return 1; + } + std::reverse(pts, pts+4); + set_points(poly, pts, pts+4); + ret=gtl::contains(poly,gtl::construct(920, 7080)); + if(!ret) { + std::cout << "reverse contains failed!" << std::endl; + return 1; + } + } + { +// //MULTIPOLYGON +// ( +// ((200 400,100 400,100 300,200 400)), +// ((300 100,200 100,200 0,300 0,300 100)), +// ((600 700,500 700,500 600,600 700)), +// ((700 300,600 300,600 200,700 300)), +// ((800 500,700 600,700 500,800 500)), +// ((900 800,800 700,900 700,900 800)), +// ((1000 200,900 100,1000 100,1000 200)), +// ((1000 800,900 900,900 800,1000 800))), + int mp1 [7][2*4] = { + {200,400,100,400,100,300,200,400}, + {600,700,500,700,500,600,600,700}, + {700,300,600,300,600,200,700,300}, + {800,500,700,600,700,500,800,500}, + {900,800,800,700,900,700,900,800}, + {1000,200,900,100,1000,100,1000,200}, + {1000,800,900,900,900,800,1000,800} + }; + int mp11 [2*5] = {300,100,200,100,200,0,300,0,300,100}; + polygon_45_set_data pset1; + polygon_45_set_data pset2; + for(int i = 0; i < 7; ++i) { + addpoly(pset1, mp1[i], 4); + } + addpoly(pset1, mp11, 5); +// //MULTIPOLYGON +// ( +// ((200 800,100 800,100 700,200 700,200 800)), +// ((400 200,300 100,400 100,400 200)), +// ((400 800,300 700,400 700,400 800)), +// ((700 100,600 0,700 0,700 100)), +// ((700 200,600 200,600 100,700 200)), +// ((900 200,800 200,800 0,900 0,900 200)), +// ((1000 300,900 200,1000 200,1000 300))) + int mp2 [5][2*4] = { + {400,200,300,100,400,100,400,200}, + {400,800,300,700,400,700,400,800}, + {700,100,600,0,700,0,700,100}, + {700,200,600,200,600,100,700,200}, + {1000,300,900,200,1000,200,1000,300}, + }; + int mp21 [2*5] = {200,800,100,800,100,700,200,700,200,800}; + int mp22 [2*5] = {900,200,800,200,800,0,900,0,900,200}; + for(int i = 0; i < 5; ++i) { + addpoly(pset2, mp2[i], 4); + } + addpoly(pset2, mp21, 5); + addpoly(pset2, mp22, 5); + polygon_45_set_data orr = pset1 + pset2; + polygon_45_set_data inr = pset1 & pset2; + std::cout << area(orr)< > polys; + assign(polys, orr); + std::cout << area(polys) << std::endl; + polygon_set_data testbug; + testbug.insert(orr); + std::cout << area(testbug) << std::endl; + polygon_set_data testbug2; + for(int i = 0; i < polys.size(); ++i) { + for(int j = 0; j < polys.size(); ++j) { + testbug2.clear(); + testbug2.insert(polys[i]); + testbug2.insert(polys[j]); + std::cout << i << " " << j << std::endl; + std::cout << polys[i] << std::endl; + std::cout << polys[j] << std::endl; + if(area(testbug2) == 0.0) { + std::cout << area(testbug2) << std::endl; + std::cout << "Self touch 45 through general interface failed!\n"; + return 1; + } + } + } + } std::cout << "ALL TESTS COMPLETE\n"; return 0; } + From 631f8c83fe2c966a944bf091cccff980b13a68b7 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 29 Mar 2011 23:52:50 +0000 Subject: [PATCH 17/32] added simplify algorithm [SVN r70725] --- include/boost/polygon/polygon_set_concept.hpp | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/include/boost/polygon/polygon_set_concept.hpp b/include/boost/polygon/polygon_set_concept.hpp index c6d015a..ecd2c70 100755 --- a/include/boost/polygon/polygon_set_concept.hpp +++ b/include/boost/polygon/polygon_set_concept.hpp @@ -8,6 +8,7 @@ #ifndef BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP #define BOOST_POLYGON_POLYGON_SET_CONCEPT_HPP #include "polygon_set_data.hpp" +#include "detail/polygon_simplify.hpp" namespace boost { namespace polygon{ template @@ -148,16 +149,39 @@ namespace boost { namespace polygon{ return retval; } - // TODO: Dafna add ngon parameter passing + template + typename enable_if< typename is_mutable_polygon_set_type::type, + std::size_t>::type + simplify(polygon_set_type& polygon_set, typename coordinate_traits< + typename polygon_set_traits::coordinate_type + >::coordinate_distance threshold) { + typedef typename polygon_set_traits::coordinate_type Unit; + typedef polygon_with_holes_data p_type; + std::vector polys; + assign(polys, polygon_set); + std::size_t retval = 0; + for(std::size_t i = 0; i < polys.size(); ++i) { + retval += detail::simplify_detail::simplify(polys[i].self_.coords_, + polys[i].self_.coords_, threshold); + for(typename std::list >::iterator itrh = + polys[i].holes_.begin(); itrh != (polys[i].holes_.end()); ++itrh) { + retval += detail::simplify_detail::simplify((*itrh).coords_, + (*itrh).coords_, threshold); + } + } + assign(polygon_set, polys); + return retval; + } + template typename enable_if< typename is_mutable_polygon_set_type::type, polygon_set_type>::type & - resize(polygon_set_type& polygon_set, coord_type resizing, bool corner_fill_arcs = false, int ngon=0) { + resize(polygon_set_type& polygon_set, coord_type resizing, bool corner_fill_arcs = false, int num_circle_segments = 0) { typedef typename polygon_set_traits::coordinate_type Unit; clean(polygon_set); polygon_set_data ps; assign(ps, polygon_set); - ps.resize(resizing, corner_fill_arcs,ngon); + ps.resize(resizing, corner_fill_arcs,num_circle_segments); assign(polygon_set, ps); return polygon_set; } From b30d93ad7ac2d73d6bb04da1558d4ff46c353050 Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 29 Mar 2011 23:53:03 +0000 Subject: [PATCH 18/32] added simplify algorithm [SVN r70726] --- .../boost/polygon/detail/polygon_simplify.hpp | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 include/boost/polygon/detail/polygon_simplify.hpp diff --git a/include/boost/polygon/detail/polygon_simplify.hpp b/include/boost/polygon/detail/polygon_simplify.hpp new file mode 100644 index 0000000..c9a92f3 --- /dev/null +++ b/include/boost/polygon/detail/polygon_simplify.hpp @@ -0,0 +1,116 @@ +// Copyright 2011, Andrew Ross +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +#ifndef BOOST_POLYGON_DETAIL_SIMPLIFY_HPP +#define BOOST_POLYGON_DETAIL_SIMPLIFY_HPP +#include + +namespace boost { namespace polygon { namespace detail { namespace simplify_detail { + + // Does a simplification/optimization pass on the polygon. If a given + // vertex lies within "len" of the line segment joining its neighbor + // vertices, it is removed. + template //T is a model of point concept + std::size_t simplify(std::vector& dst, const std::vector& src, + typename coordinate_traits< + typename point_traits::coordinate_type + >::coordinate_distance len) + { + using namespace boost::polygon; + typedef typename point_traits::coordinate_type coordinate_type; + typedef typename coordinate_traits::area_type ftype; + typedef typename std::vector::const_iterator iter; + + std::vector out; + out.reserve(src.size()); + dst = src; + std::size_t final_result = 0; + std::size_t orig_size = src.size(); + + //I can't use == if T doesn't provide it, so use generic point concept compare + bool closed = equivalence(src.front(), src.back()); + + //we need to keep smoothing until we don't find points to remove + //because removing points in the first iteration through the + //polygon may leave it in a state where more removal is possible + bool not_done = true; + while(not_done) { + if(dst.size() < 3) { + dst.clear(); + return orig_size; + } + + // Start with the second, test for the last point + // explicitly, and exit after looping back around to the first. + ftype len2 = ftype(len) * ftype(len); + for(iter prev=dst.begin(), i=prev+1, next; /**/; i = next) { + next = i+1; + if(next == dst.end()) + next = dst.begin(); + + // points A, B, C + ftype ax = x(*prev), ay = y(*prev); + ftype bx = x(*i), by = y(*i); + ftype cx = x(*next), cy = y(*next); + + // vectors AB, BC and AC: + ftype abx = bx-ax, aby = by-ay; + ftype bcx = cx-bx, bcy = cy-by; + ftype acx = cx-ax, acy = cy-ay; + + // dot products + ftype ab_ab = abx*abx + aby*aby; + ftype bc_bc = bcx*bcx + bcy*bcy; + ftype ac_ac = acx*acx + acy*acy; + ftype ab_ac = abx*acx + aby*acy; + + // projection of AB along AC + ftype projf = ab_ac / ac_ac; + ftype projx = acx * projf, projy = acy * projf; + + // perpendicular vector from the line AC to point B (i.e. AB - proj) + ftype perpx = abx - projx, perpy = aby - projy; + + // Squared fractional distance of projection. FIXME: can + // remove this division, the decisions below can be made with + // just the sign of the quotient and a check to see if + // abs(numerator) is greater than abs(divisor). + ftype f2 = (projx*acx + projy*acx) / ac_ac; + + // Square of the relevant distance from point B: + ftype dist2; + if (f2 < 0) dist2 = ab_ab; + else if(f2 > 1) dist2 = bc_bc; + else dist2 = perpx*perpx + perpy*perpy; + + if(dist2 > len2) { + prev = i; // bump prev, we didn't remove the segment + out.push_back(*i); + } + + if(i == dst.begin()) + break; + } + std::size_t result = dst.size() - out.size(); + if(result == 0) { + not_done = false; + } else { + final_result += result; + dst = out; + out.clear(); + } + } //end of while loop + if(closed) { + //if the input was closed we want the output to be closed + --final_result; + dst.push_back(dst.front()); + } + return final_result; + } + + +}}}} + +#endif From 65ebf0ba43ec7b281ae4142e1e5529000cbd2e1e Mon Sep 17 00:00:00 2001 From: Luke Simonson Date: Tue, 29 Mar 2011 23:53:22 +0000 Subject: [PATCH 19/32] added simplify algorithm documentation [SVN r70727] --- doc/gtl_polygon_set_concept.htm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm index 1c461c5..75ee77e 100644 --- a/doc/gtl_polygon_set_concept.htm +++ b/doc/gtl_polygon_set_concept.htm @@ -349,6 +349,17 @@ together.

circular arcs.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
template <typename T, typename + coord_type>
+ T& simplify(T& polygon_set, distance_type + threshold)
Simplify the polygon set by removing vertices that lie + within threshold distance of the line segment that + connects the two adjacent points in the polygon.  + Expected n log n runtime, worst case quadratic + runtime wrt. vertices + intersections.
template <typename T>
T& scale_up(T& polygon_set, unsigned_area_type factor)
+-->Boost Polygon Library: Performance Analysis + + + +
+algorithm without ever resorting to GMP.

+
  • Boost.Polygon Main Page
  • +
  • Design Overview
  • +
  • Isotropy
  • +
  • Coordinate Concept
  • +
  • Interval Concept
  • +
  • Point Concept
  • +
  • Segment Concept
  • +
  • Rectangle Concept
  • +
  • Polygon 90 Concept
  • +
  • Polygon 90 +With Holes Concept
  • +
  • Polygon 45 Concept
  • +
  • Polygon 45 +With Holes Concept
  • +
  • Polygon Concept
  • +
  • Polygon With +Holes Concept
  • +
  • Polygon 90 Set +Concept
  • +
  • Polygon 45 Set +Concept
  • +
  • Polygon Set Concept
  • +
  • Connectivity +Extraction 90
  • +
  • Connectivity +Extraction 45
  • +
  • Connectivity +Extraction
  • +
  • Property Merge 90
  • +
  • Property Merge 45
  • +
  • Property Merge
  • +
  • Voronoi Main Page +
  • +
  • Voronoi Benchmark
  • +
  • Voronoi Builder
    +
  • +
  • Voronoi Diagram
  • +
  • Voronoi Predicates
  • +
  • Voronoi Robust FPT
    +
  • + + +
  • GTL Boostcon 2009 Paper
  • +
  • GTL Boostcon 2009 +Presentation
  • +
  • Performance Analysis
  • +
  • Layout Versus Schematic Tutorial
  • +
  • Minkowski Sum Tutorial
  • +
  • Voronoi Basic Tutorial
  • +
  • Voronoi Advanced +Tutorial
  • +
    - + +
    -
    +

    Polygon Set Algorithms Analysis

    Most non-trivial algorithms in the Boost.Polygon library are @@ -86,25 +108,25 @@ input size grows.  Because intersection vertices are expected to be a constant factor of input vertices we can examine runtime complexity in terms of input vertices.  The operation performed was a union (Boolean OR) of the input rectangles by each of the Manhattan, 45-degree and arbitrary angle -Booleans algorithms, which are labeled "boolean 90", "boolean 45" and "boolean".  +Booleans algorithms, which are labeled "boolean 90", "boolean 45" and "boolean".  Also shown in the plot is the performance of the arbitrary angle Booleans algorithm as prior to the addition of divide and conquer recursive subdivision, which was described in the paper presented at boostcon 2009.  Finally, the time required to sort the input points is shown as a common reference for O(n log n) -runtime to put the data into context.

    +runtime to put the data into context.

    We can see in the log-log plot that sorting and the three Booleans algorithms -provided by the Boost.Polygon library have nearly 45 degree "linear" +provided by the Boost.Polygon library have nearly 45 degree "linear" scaling with empirical exponents just slightly larger than 1.0 and can be observed to scale proportional to O(n log n) for -these inputs.  The "old boolean" algorithm presented at boostcon 2009 +these inputs.  The "old boolean" algorithm presented at boostcon 2009 exhibits scaling close to the expected O(n1.5) scaling.  Because the speedup provided by the divide and conquer approach is algorithmic, the 10X potential performance improvement alluded to in the paper is realized at inputs of 200,000 rectangles and larger.  Even for small inputs of 2K rectangles the algorithm is 2X faster and now can be expected to be -roughly as fast as GPC at small scales, +roughly as fast as GPC at small scales, while algorithmically faster at large scales.

    @@ -116,10 +138,10 @@ work we can see that Manhattan Booleans cost roughly five units of O(n log n) work, 45-degree  Booleans cost roughly -ten units of O(n log n) work and arbitrary angle Booleans cost roughly +ten units of O(n log n) work and arbitrary angle Booleans cost roughly seventy units of O(n log n) work.  Sorting the input vertices is the first step in a Booleans algorithm and therefore provides a hard lower bound for the -runtime of an optimal Booleans algorithm.

    +runtime of an optimal Booleans algorithm.

    One final thing to note about performance of the arbitrary angle Booleans @@ -137,17 +159,17 @@ double computation of the intersection of two line segments fails to produce an intersection point within one integer unit of both line segments.  This means that there is effectively no runtime penalty for the use of infinite precision to ensure 100% robustness.  Most inputs will process through the -algorithm without ever resorting to GMP.

      - +
    - + - + @@ -160,6 +182,6 @@ algorithm without ever resorting to GMP. http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction.htm b/doc/gtl_connectivity_extraction.htm index 4ced224..2e52962 100644 --- a/doc/gtl_connectivity_extraction.htm +++ b/doc/gtl_connectivity_extraction.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Connectivity Extraction 45 - - +-->Boost Polygon Library: Connectivity Extraction 45 + + + +
    +
    - + +
    -
    +

    Connectivity Extraction

    -

    The connectivity extraction algorithm constructs the connectivity graph where +

    The connectivity extraction algorithm constructs the connectivity graph where input polygon sets are modeled as graph nodes and assigned node ids and overlap/touching between input polygon sets is modeled as graph edges.  One supported graph formats is std::vector<std::set<int> > where node ids index into @@ -71,33 +90,33 @@ sufficient elements to store the graph generated by the algorithm, because only the operator[] is used internally to access the graph   The other supported graph format is std::map<int, std::set<int> > which is slightly easier to work with, but potentially more expensive.  Improving the interface to -support more generic graph concepts is deferred to future work.

    The following -is the declaration of the connectivity extraction algorithm.

    -template <typename coordinate_type>
    -class connectivity_extraction;

    +support more generic graph concepts is deferred to future work.

    The following +is the declaration of the connectivity extraction algorithm.

    +template <typename coordinate_type>
    +class connectivity_extraction;

    Example code connectivity_extraction_usage.cpp demonstrates using the connectivity extraction algorithm to build a -connectivity graph on geometry.

    Member Functions

    - - +connectivity graph on geometry.

    Member Functions

    +
    + - +unsigned int
    insert(const polygon_set_data<coordinate_type>& ps)
    @@ -105,24 +124,24 @@ unsigned int insert(const GeoObjT& geoObj) -
    connectivity_extraction() Default constructor.
    connectivity_extraction(
         const +
    connectivity_extraction(
         const connectivity_extraction& that)
    Copy construct.
    -unsigned int
    insert(const polygon_set_data<coordinate_type>& ps)
    Insert a polygon set graph node, the value returned is the id of the graph node.
    -template <class GeoObjT>
    +template <class GeoObjT>
    unsigned int insert(const GeoObjT& geoObj)
    Insert a geometry object that is a refinement of polygon set as a graph node, the return value is the id of the graph node.
    -template <class GraphT>
    +template <class GraphT>
    void extract(GraphT& graph)
    Accepts a graph object that conforms to the expectations defined above.  Performs connectivity extraction and populates the graph object.
    -
    +
      - +
    - + - + @@ -135,6 +154,6 @@ void extract(GraphT& graph) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction_45.htm b/doc/gtl_connectivity_extraction_45.htm index e1ee2cf..3d54bad 100644 --- a/doc/gtl_connectivity_extraction_45.htm +++ b/doc/gtl_connectivity_extraction_45.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Connectivity Extraction 45 - - +-->Boost Polygon Library: Connectivity Extraction 45 + + + +
    +
    - + +
    -
    +

    Connectivity Extraction 45

    -

    The connectivity extraction algorithm constructs the connectivity graph where +

    The connectivity extraction algorithm constructs the connectivity graph where input polygon sets are modeled as graph nodes and assigned node ids and overlap/touching between input polygon sets is modeled as graph edges.  One supported graph formats is std::vector<std::set<int> > where node ids index into @@ -71,33 +90,33 @@ sufficient elements to store the graph generated by the algorithm, because only the operator[] is used internally to access the graph   The other supported graph format is std::map<int, std::set<int> > which is slightly easier to work with, but potentially more expensive.  Improving the interface to -support more generic graph concepts is deferred to future work.

    The following -is the declaration of the connectivity extraction algorithm.

    -template <typename coordinate_type>
    -class connectivity_extraction_45;

    +support more generic graph concepts is deferred to future work.

    The following +is the declaration of the connectivity extraction algorithm.

    +template <typename coordinate_type>
    +class connectivity_extraction_45;

    Example code connectivity_extraction_usage.cpp demonstrates using the connectivity extraction algorithm to build a -connectivity graph on geometry.

    Member Functions

    - - +connectivity graph on geometry.

    Member Functions

    +
    + - +unsigned int
    insert(const polygon_45_set_data<coordinate_type>& ps)
    @@ -105,24 +124,24 @@ unsigned int insert(const GeoObjT& geoObj) -
    connectivity_extraction_45() Default constructor.
    connectivity_extraction_45(
         const +
    connectivity_extraction_45(
         const connectivity_extraction_45& that)
    Copy construct.
    -unsigned int
    insert(const polygon_45_set_data<coordinate_type>& ps)
    Insert a polygon set graph node, the value returned is the id of the graph node.
    -template <class GeoObjT>
    +template <class GeoObjT>
    unsigned int insert(const GeoObjT& geoObj)
    Insert a geometry object that is a refinement of polygon 45 set as a graph node, the return value is the id of the graph node.
    -template <class GraphT>
    +template <class GraphT>
    void extract(GraphT& graph)
    Accepts a graph object that conforms to the expectations defined above.  Performs connectivity extraction and populates the graph object.
    -
    +
      - +
    - + - + @@ -135,6 +154,6 @@ void extract(GraphT& graph) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_connectivity_extraction_90.htm b/doc/gtl_connectivity_extraction_90.htm index aff3bc9..f2f7be9 100644 --- a/doc/gtl_connectivity_extraction_90.htm +++ b/doc/gtl_connectivity_extraction_90.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Connectivity Extraction 90 - - +-->Boost Polygon Library: Connectivity Extraction 90 + + + +
    +
    - + +
    -
    +

    Connectivity Extraction 90

    -

    The connectivity extraction algorithm constructs the connectivity graph where +

    The connectivity extraction algorithm constructs the connectivity graph where input polygon sets are modeled as graph nodes and assigned node ids and overlap/touching between input polygon sets is modeled as graph edges.  One supported graph formats is std::vector<std::set<int> > where node ids index into @@ -71,33 +90,33 @@ sufficient elements to store the graph generated by the algorithm, because only the operator[] is used internally to access the graph   The other supported graph format is std::map<int, std::set<int> > which is slightly easier to work with, but potentially more expensive.  Improving the interface to -support more generic graph concepts is deferred to future work.

    The following -is the declaration of the connectivity extraction algorithm.

    -template <typename coordinate_type>
    -class connectivity_extraction_90;

    +support more generic graph concepts is deferred to future work.

    The following +is the declaration of the connectivity extraction algorithm.

    +template <typename coordinate_type>
    +class connectivity_extraction_90;

    Example code connectivity_extraction_usage.cpp demonstrates using the connectivity extraction algorithm to build a -connectivity graph on geometry.

    Member Functions

    - - +connectivity graph on geometry.

    Member Functions

    +
    + - +unsigned int
    insert(const polygon_90_set_data<coordinate_type>& ps)
    @@ -105,24 +124,24 @@ unsigned int insert(const GeoObjT& geoObj) -
    connectivity_extraction_90() Default constructor.
    connectivity_extraction_90(
         const +
    connectivity_extraction_90(
         const connectivity_extraction_90& that)
    Copy construct.
    -unsigned int
    insert(const polygon_90_set_data<coordinate_type>& ps)
    Insert a polygon set graph node, the value returned is the id of the graph node.
    -template <class GeoObjT>
    +template <class GeoObjT>
    unsigned int insert(const GeoObjT& geoObj)
    Insert a geometry object that is a refinement of polygon 90 set as a graph node, the return value is the id of the graph node.
    -template <class GraphT>
    +template <class GraphT>
    void extract(GraphT& graph)
    Accepts a graph object that conforms to the expectations defined above.  Performs connectivity extraction and populates the graph object.
    -
    +
      - +
    - + - + @@ -135,6 +154,6 @@ void extract(GraphT& graph) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_coordinate_concept.htm b/doc/gtl_coordinate_concept.htm index afa081d..ae5d3bb 100644 --- a/doc/gtl_coordinate_concept.htm +++ b/doc/gtl_coordinate_concept.htm @@ -1,14 +1,17 @@ - -Boost Polygon Library: Coordinate Concept - - +-->Boost Polygon Library: Coordinate Concept + + + + + +
    +with the library at present.

    - + +
    -
    +

    Coordinate Concept

    The coordinate concept tag is -coordinate_concept

    +coordinate_concept

    To register a user defined type as a model of coordinate concept, specialize the geometry concept meta-function for that type.  In the example below -CCoordinate is registered as a model of coordinate concept.

    -template <>
    -struct geometry_concept<CCoordinate> { typedef coordinate_concept type; };

    +CCoordinate is registered as a model of coordinate concept.

    +template <>
    +struct geometry_concept<CCoordinate> { typedef coordinate_concept type; };

    The coordinate type is expected to be integral and built-in numerical data types such as float and int already have concept type traits specializations in the library.  In the coordinate traits are type definitions for related types are provided to allow the library to choose the best type to cast to under various circumstances.  The definition of coordinate_traits and its -specialization for int are shown below.

    -template <typename T>
    -struct coordinate_traits {};
    -
    -template <>
    -struct coordinate_traits<int> {
    -     typedef int coordinate_type;
    -     typedef long double area_type;
    -     typedef long long manhattan_area_type;
    -     typedef unsigned long long unsigned_area_type;
    -     typedef long long coordinate_difference;
    -     typedef long double coordinate_distance;
    -};

    +specialization for int are shown below.

    +template <typename T>
    +struct coordinate_traits {};
    +
    +template <>
    +struct coordinate_traits<int> {
    +     typedef int coordinate_type;
    +     typedef long double area_type;
    +     typedef long long manhattan_area_type;
    +     typedef unsigned long long unsigned_area_type;
    +     typedef long long coordinate_difference;
    +     typedef long double coordinate_distance;
    +};

    By making use of the coordinate traits of int the library is able to avoid overflow and handle the normal issues encountered when programming integer geometry.  For the out of the ordinary issues there is a special @@ -94,37 +114,37 @@ numerical calculations.  It defaults to the highest precision data type available in most compilers, long double, but can be overridden by specializing for a particular coordinate type.  Use of gmp multi-precision rational or similar data type is recommended for numerically robust calculations in the -general polygon algorithms.

    -template <typename T>
    -struct high_precision_type {
    -     typedef long double type;
    -};

    -There is only one generic function on coordinate concepts, Euclidean distance.

    +general polygon algorithms.

    +template <typename T>
    +struct high_precision_type {
    +     typedef long double type;
    +};

    +There is only one generic function on coordinate concepts, Euclidean distance.

    template <typename coordinate_type_1, typename -coordinate_type_2>
    -coordinate_difference euclidean_distance(coordinate_type_1, coordinate_type_2)

    +coordinate_type_2>
    +coordinate_difference euclidean_distance(coordinate_type_1, coordinate_type_2)

    This function returns the absolution value of the difference between the two -coordinates.

    +coordinates.

    Note: older versions of the stl define a fully generic distance(T, T) function for computing the difference between two iterators.  We were forced to name -our distance function euclidean_distance to avoid name collision.

    +our distance function euclidean_distance to avoid name collision.

    The Algorithmic C ac_int<128> is an example of a user defined coordinate data type that satisfies the coordinate concept.  In general a data type should define std::numeric_limits and be integer-like.  Floating point coordinate types are not supported by all the algorithms and generally not suitable for use -with the library at present.

      - +
    - + - + @@ -137,6 +157,6 @@ with the library at present. http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_design_overview.htm b/doc/gtl_design_overview.htm index a2dcdaa..769d245 100644 --- a/doc/gtl_design_overview.htm +++ b/doc/gtl_design_overview.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Overview - - +-->Boost Polygon Library: Overview + + + +
    +individual polygons or rectangles.

    - + +
    -
    +

    Polygon Library Design Overview

    -

    The Polygon library uses C++-Concepts inspired template programming to +

    The Polygon library uses C++-Concepts inspired template programming to provide generic library functions overloaded on concept type.  There are currently thirteen concepts in the Polygon library type system.  A concept object in the Polygon library is just an empty struct similar to a tag that @@ -70,7 +90,7 @@ would be used for tag dispatching.   These concepts are shown in the refinement diagram below.

    -

    +

    The arrows between diagram bubbles show concept refinement relationships.  This is similar, but not identical to, inheritance relationships between normal classes.  A refinement of a concept narrows down the definition of a more general concept.  @@ -123,7 +143,7 @@ type has been mapped to a concept through traits it needs to be registered as that conceptual type with the library by specializing the geometry_concept meta-function.  Once mapped and registered, a user data type can be used interchangeably with library data types -in the generic free functions that are overloaded on concept.

    Traits for +in the generic free functions that are overloaded on concept.

    Traits for mapping a data type to a concept are broken down into mutable and read only traits.  Read only traits are specialized internally to work with any types that are refinements of a concept.  The mutable traits are defined only for @@ -135,7 +155,7 @@ registered as a polygon_concept and the read only traits but not the mutable traits defined for that triangle type.  This would allow the triangle type to be passed into any API that expects a const reference to an object that models polygon.  -

    An object that is a model of a given concept can usually be viewed as a model of any of its +

    An object that is a model of a given concept can usually be viewed as a model of any of its refinements if it is determined at runtime to conform to the restrictions of those concepts.  This concept casting is accomplished through the view_as<>() function.  For example if @@ -146,17 +166,17 @@ and can be viewed as a rectangle with the following syntax:

    passed into any interface that expects an object of the conceptual type specified in its template parameter.  The exception to this ability to concept cast geometric objects is that polygon set objects cannot be viewed as -individual polygons or rectangles.

      - +
    - + - + @@ -169,6 +189,6 @@ individual polygons or rectangles.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_interval_concept.htm b/doc/gtl_interval_concept.htm index 05d4b41..0caac08 100644 --- a/doc/gtl_interval_concept.htm +++ b/doc/gtl_interval_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Interval Concept - - +-->Boost Polygon Library: Interval Concept + + + +
    +
    - + +
    -
    +

    Interval Concept

    -

    The interval concept tag is +

    The interval concept tag is interval_concept

    To register a user defined type as a model of interval concept, specialize the geometry concept meta-function for that type.  In the example below -CInterval is registered as a model of interval  concept.

    -template <>
    -struct geometry_concept<CInterval> { typedef interval_concept type; };

    +CInterval is registered as a model of interval  concept.

    +template <>
    +struct geometry_concept<CInterval> { typedef interval_concept type; };

    The semantic of an interval is that it has a low and high coordinate and there is an invariant that low is less than or equal to high.  This invariant is enforced by the generic library functions that @@ -76,50 +96,51 @@ operate on intervals, and is not expected of the data type itself or the concept mapping of that data type to the interval concept through its traits.  In this way a std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> could all be made models of interval by simply providing indirect access to their -elements through traits.

    +elements through traits.

    Below is shown the default interval traits.  Specialization of these traits is required for types that don't conform to the -default behavior.

    -template <typename T>
    -struct interval_traits {
    -  typedef typename T::coordinate_type coordinate_type;
    -
    -  static inline coordinate_type get(const T& interval, direction_1d dir) {
    -    return interval.get(dir);
    -  }
    -};
    -
    -template <typename T>
    -struct interval_mutable_traits {
    +default behavior.

    +template <typename T>
    +struct interval_traits {
    +  typedef typename T::coordinate_type coordinate_type;
    +
    +  static inline coordinate_type get(const T& interval, direction_1d dir) {
    +    return interval.get(dir);
    +  }
    +};
    +
    +template <typename T>
    +struct interval_mutable_traits {
      static inline void set(T& interval, direction_1d dir,
    -
    -                         typename interval_traits<T>::coordinate_type value) {
    +
    +                         +typename interval_traits<T>::coordinate_type value) {
        -interval.set(dir, value);
    +interval.set(dir, value);
      -}
    +}
      static inline T construct(typename interval_traits<T>::coordinate_type low_value, -
    +
                                -typename interval_traits<T>::coordinate_type high_value) {
    +typename interval_traits<T>::coordinate_type high_value) {
        -return T(low_value, high_value);
    +return T(low_value, high_value);
      -}
    -};

    Functions

    - - -
    template <typename T>
    +}
    +};

    Functions

    + + + - - - + interval_type>
    + interval_type& scale_up(interval_type& interval,
    +                        +unsigned_area_type factor) + interval_type>
    + interval_type& scale_down(interval_type& interval,
    +                          +unsigned_area_type factor) + interval_type>
    + interval_type& convolve(interval_type& interval,
    +                        +coordinate_type b) + interval_type>
    + interval_type& deconvolve(interval_type& interval,
    +                          +coordinate_type b) - + T2>
    + bool boundaries_intersect(const T1& interval, const T2& b,
    +                          +bool consider_touch = true) - - - - - -
    template <typename T>
    coordinate_type get(const T& interval, direction_1d)
    Expects a model of interval.  Returns the low or high coordinate of the interval, depending on the - direction_1d value.
    + direction_1d value.

     
    template <typename T, typename - coordinate_type>
    + coordinate_type>
    void set(T& interval, direction_1d, coordinate_type)
    Expects a model of interval.   Sets the low or high coordinate of the interval to the coordinate, @@ -127,28 +148,28 @@ return T(low_value, high_value);
    high after this change then both are set to the input coordinate value.
    template <typename T>
    +
    template <typename T>
    T construct(coordinate_type low, coordinate_type high)
    Construct an object that is a model of interval given low and high coordinate values.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models interval into left object that models interval.
    template <typename T, typename - T2>
    + T2>
    bool equivalence(const T& interval1, const T2& interval2)
    Given two objects that model interval, compares and returns true if their low and high values are respectively equal to each other.
    template <typename T>
    - bool contains(const T&, coordinate_type,
    +
    template <typename T>
    + bool contains(const T&, coordinate_type,
                  bool consider_touch=true)
    Given an object that models interval and a coordinate, returns true @@ -158,8 +179,8 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    - bool contains(const T1& a, const T2& b,
    + T2>
    + bool contains(const T1& a, const T2& b,
                  bool consider_touch = true)
    Returns true if model of interval a contains both ends of model of @@ -168,25 +189,25 @@ return T(low_value, high_value);
    template <typename - interval_type>
    + interval_type>
    coordinate_type low(const interval_type& interval)
    Returns the low end of an object that models interval.
    template <typename - interval_type>
    + interval_type>
    coordinate_type high(const interval_type& interval)
    Returns the high end of an object that models interval.
    // get the center coordinate
    - template <typename interval_type>
    +
    // get the center coordinate
    + template <typename interval_type>
    coordinate_type center(const interval_type& interval)
    Returns the center coordinate of an object that models interval.
    template <typename - interval_type>
    + interval_type>
    void low(interval_type& interval, coordinate_type )
    Sets the low end of the object that models interval to the coordinate value.  If the low end would be set to larger than high @@ -194,7 +215,7 @@ return T(low_value, high_value);
    template <typename - interval_type>
    + interval_type>
    void high(interval_type& interval, coordinate_type )
    Sets the high end of the object that models interval to the coordinate value.  If the high end would be set to less than low @@ -202,15 +223,15 @@ return T(low_value, high_value);
    template <typename - interval_type>
    + interval_type>
    coordinate_difference delta(const interval_type& interval)
    Returns the distance from low to high end of an object that models interval.
    template <typename - interval_type>
    - interval_type& flip(interval_type& interval,
    + interval_type>
    + interval_type& flip(interval_type& interval,
                        coordinate_type axis = 0)
    Flips an object that models interval about the axis coordinate.  @@ -218,26 +239,26 @@ return T(low_value, high_value);
    template <typename - interval_type>
    - interval_type& scale_up(interval_type& interval,
    -                        - unsigned_area_type factor)
    Multiplies low and high ends of an object that models interval by unsigned factor.
    template <typename - interval_type>
    - interval_type& scale_down(interval_type& interval,
    -                          - unsigned_area_type factor)
    Divides low and high ends of an object that models interval by unsigned factor.
    template <typename - interval_type>
    - interval_type& scale(interval_type& interval,
    + interval_type>
    + interval_type& scale(interval_type& interval,
                         double factor)
    Multiplies low and high ends of an object that models interval by @@ -245,8 +266,8 @@ return T(low_value, high_value);
    template <typename - interval_type>
    - interval_type& move(interval_type& interval,
    + interval_type>
    + interval_type& move(interval_type& interval,
                        coordinate_difference displacement)
    Adds displacement value to low and high ends of an object that @@ -254,53 +275,53 @@ return T(low_value, high_value);
    template <typename - interval_type>
    - interval_type& convolve(interval_type& interval,
    -                        - coordinate_type b)
    Adds coordinate value to low and high ends of an object that models interval.
    template <typename - interval_type>
    - interval_type& deconvolve(interval_type& interval,
    -                          - coordinate_type b)
    Subtracts coordinate value from low and high ends of an object that models interval.
    template <typename T1, typename - T2>
    + T2>
    T1& convolve(T1& a, const T2& b)
    Adds low end of b to low end of a and adds high end of b to high end of a.
    template <typename T1, typename - T2>
    + T2>
    T1& deconvolve(T1& a, const T2& b)
    Subtracts low end of b from low end of a and subtracts high end of b from high end of a.
    template <typename T1, typename - T2>
    + T2>
    T1& reflected_convolve(T1& a, const T2& b)
    Adds high end of b to low end of a and adds low end of b to high end of a.
    template <typename T1, typename - T2>
    + T2>
    T1& reflected_deconvolve(T1& a, const T2& b)
    Subtracts high end of b from low end of a and subtracts low end of b from high end of a.
    template <typename T>
    - coordinate_difference euclidean_distance(const T&,
    +
    template <typename T>
    + coordinate_difference euclidean_distance(const T&,
                          coordinate_type)
    Returns the distance from an object that models interval to a @@ -309,8 +330,8 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    - bool intersects(const T1& interval, const T2& b,
    + T2>
    + bool intersects(const T1& interval, const T2& b,
                    bool consider_touch = true)
    Returns true if two objects that model interval overlap.  If @@ -319,10 +340,10 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    - bool boundaries_intersect(const T1& interval, const T2& b,
    -                          - bool consider_touch = true)
    Returns true is two objects that model interval partially overlap such that one end point of each is contained within the other.  If the consider_touch flag is true a coordinate is considered contained @@ -330,8 +351,8 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    - bool abuts(const T1& a, const T2& b,
    + T2>
    + bool abuts(const T1& a, const T2& b,
               direction_1d dir)
    Returns true if interval b abuts but down not overlap interval a on @@ -339,14 +360,14 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    + T2>
    bool abuts(const T1& a, const T2& b)
    Returns true if interval b abuts but down not overlap interval a.
    template <typename T1, typename - T2>
    - bool intersect(T1& a, const T2& b,
    + T2>
    + bool intersect(T1& a, const T2& b,
                   bool consider_touch = true)
    Sets interval a to the intersection of interval a and interval b and @@ -356,55 +377,55 @@ return T(low_value, high_value);
    template <typename T1, typename - T2>
    + T2>
    T& generalized_intersect(T1& a, const T2& b)
    Same as intersect, but if they do not intersect set a to the interval between a and b.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& interval, coordinate_type)
    Adds the coordinate value to high end of interval and subtracts it from low end of interval.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& interval, direction_1d, coordinate_type)
    Adds the coordinate value to high end of interval or subtracts it from low end of interval depending on the direction_1d.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& interval, coordinate_type)
    Subtracts the coordinate value from high end of interval and adds it to low end of interval.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& interval, direction_1d, coordinate_type)
    Subtracts the coordinate value from high end of interval or adds it to low end of interval depending on the direction_1d.
    template <typename T1, typename - T2>
    + T2>
    bool encompass(T1& a, const T2& b)
    Sets low of a to min of low of a and low of b and sets high of a to max of high of a and high of b.  Returns true if b was not contained within a to begin with.
    template <typename T>
    +
    template <typename T>
    bool encompass(T& a, coordinate_type)
    Sets low of a to min of low of a and coordinate value and sets high of a to max of high of a and coordinate value.  Returns true if coordinate value was not contained within a to begin with.
    +

    Interval Data

    -

    The library provides a model of interval concept declared +

    The library provides a model of interval concept declared template<typename T> interval_data where T is the coordinate type.

    This data type is used internally when an interval is needed and is available @@ -412,8 +433,8 @@ to the library user who finds it convenient to use a library interval data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -444,42 +465,42 @@ convenient to use with the library traits.

    +
    interval_data& operator=(const T2& that) const @@ -493,18 +514,18 @@ convenient to use with the library traits.

    dir, T value) -
    geometry_type interval_concept
    template <typename T2>  -
    interval_data& operator=(const T2& that) const
    Assign from an object that is a model of interval.
    template <typename T2> -
    bool +
    bool operator==(const T2& that) const
    Compare equality to an object that is a model of interval.
    template <typename T2> -
    bool +
    bool operator!=(const T2& that) const
    Compare inequality to an object that is a model of interval.
    template <typename T2> -
    bool +
    bool operator<(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator<=(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator>(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator>=(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    Sets the coordinate in the given direction to the value.
    -
    +
      - +
    - + - + @@ -517,6 +538,6 @@ convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_isotropy.htm b/doc/gtl_isotropy.htm index e63391f..778eb83 100755 --- a/doc/gtl_isotropy.htm +++ b/doc/gtl_isotropy.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Isotropy - - +-->Boost Polygon Library: Isotropy + + + +
    - + +
    -
    +

    Isotropy

    -

    What is isotropy?

    - -
    -

    - Isotropy - Function: adjective Etymology: International - Scientific Vocabulary
    +

    What is isotropy?

    + +
    +

    + Isotropy - Function: adjective Etymology: International + Scientific Vocabulary
    : exhibiting properties (as velocity of light transmission) with the same values when measured along axes in all directions <an isotropic - crystal>

    + crystal>

    In computational geometry things are often symmetric and invariant to direction and orientation.  This invariance to direction is called isotropy.  In such situations it is convenient to parameterize @@ -95,8 +113,8 @@ in various ways, such as casting.  Together they create a language for describing isotropic situations programmatically.  For instance, to get the positive direction_2d from an orientation_2d you would call a member function of orientation_2d and pass a direction_1d:

    -

    orientation_2d orient = HORIZONTAL;
    -direction_2d dir = orient.get_direction(direction_1d(HIGH));
    +

    orientation_2d orient = HORIZONTAL;
    +direction_2d dir = orient.get_direction(direction_1d(HIGH));
    assert(dir == EAST);

    The motivation for providing isotropic data types is to encourage programming at a higher level of abstraction where program behavior is @@ -114,7 +132,7 @@ points, intervals and rectangles.

    direction_1d

    -

    The direction_1d data type has two possible states.  These +

    The direction_1d data type has two possible states.  These are the positive and negative directions on a continuum such as the number line.   These states can be described by one of several direction_1d_enum values:  We make clockwise and counterclockwise winding orientation of polygons a @@ -122,24 +140,23 @@ direction 1d value instead of providing a separate winding_orientation data type.  This is because winding orientation can be thought of as positive and negative directions in a 1d (although cyclic) space.  We assign counterclockwise to be the positive direction of travel in the 1d cyclic space -to conform with the mathematical convention frequently described as the "right -hand rule" which assigns positive normal value to counterclockwise and negative +to conform with the mathematical convention frequently described as the "right +hand rule" which assigns positive normal value to counterclockwise and negative normal value to clockwise as well as the common convention that counterclockwise polygon winding corresponds to positive polygonal regions where as clockwise polygon winding corresponds to hole (negative) polygonal regions.

    enum direction_1d_enum {LOW = 0, HIGH = -1,
    -                        -LEFT = 0, RIGHT = 1,
    -                        -CLOCKWISE = 0, COUNTERCLOCKWISE = 1,
    -                        -REVERSE = 0, FORWARD = 1,
    -                        +1,
                            +LEFT = 0, RIGHT = 1,
    +                        +CLOCKWISE = 0, COUNTERCLOCKWISE = 1,
    +                        +REVERSE = 0, FORWARD = 1,
    +                        NEGATIVE = 0, POSITIVE = 1 };

    Member Functions

    - - +
    + @@ -193,18 +210,18 @@ const -
    direction_1d(direction_1d_enum val = LOW) Constructor defaults to LOW. Returns positive 1 if positive direction and negative one if negative direction.
    +

    orientation_2d

    -

    The orientation_2d data type has two possible states.  +

    The orientation_2d data type has two possible states.  These are the horizontal and vertical axis of a 2d Cartesian coordinate system.   These states can be described by one of the two orientation_2d_enum values:

    enum orientation_2d_enum { HORIZONTAL = 0, VERTICAL = 1 };

    Member Functions

    - - +
    + @@ -261,18 +278,18 @@ o) const -
    orientation_2d(orientation_2d_enum val = HORIZONTAL) Constructor defaults to HORIZONTAL. Returns the positive or negative direction_2d depending on the value of dir
    +

    direction_2d

    -

    The direction_2d data type has four possible states.  These +

    The direction_2d data type has four possible states.  These are the cardinal directions of the 2D Cartesian coordinate system.   These states can be described by one of several direction_2d_enum values:

    enum direction_2d_enum { WEST = 0, EAST = 1, SOUTH = 2, NORTH = 3 };

    Member Functions

    - - +
    + @@ -342,19 +359,19 @@ const -
    direction_2d(direction_2d_enum val = WEST) Constructor defaults to WEST. Returns positive 1 if positive direction and negative one if negative direction.
    +

    orientation_3d

    -

    The orientation_3d data type has three possible states.  +

    The orientation_3d data type has three possible states.  These are the horizontal, vertical and proximal (x, y, z) axis of a 3d Cartesian coordinate system.   These states can be described by one of the orientation_2d_enum values or by the orientation_3d_enum value:

    enum orientation_3d_enum { PROXIMAL = 2 };

    Member Functions

    - - +
    + @@ -416,19 +433,19 @@ o) const -
    orientation_3d(orientation_2d_enum val = HORIZONTAL) Constructor defaults to HORIZONTAL. Returns the positive or negative direction_2d depending on the value of dir
    +

    direction_3d

    -

    The direction_3d data type has six possible states.  These +

    The direction_3d data type has six possible states.  These are the cardinal directions of the 3D Cartesian coordinate system.   These states can be described by one of the direction_2d_enum values or the direction_3d_enum values:

    enum direction_3d_enum { DOWN = 4, UP = 5 };

    Member Functions

    - - +
    + @@ -490,18 +507,18 @@ const -
    direction_3d(direction_2d_enum val = WEST) Constructor defaults to LOW. Returns positive 1 if positive direction and negative one if negative direction.
    -
    +
      - +
    - + - + @@ -514,6 +531,6 @@ const http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_minkowski_tutorial.htm b/doc/gtl_minkowski_tutorial.htm index 0607a76..f657fed 100644 --- a/doc/gtl_minkowski_tutorial.htm +++ b/doc/gtl_minkowski_tutorial.htm @@ -96,7 +96,7 @@ all pairs edges convolutions and the all pairs of polygons to point convolutions.  First we implement a function that convolves all pairs of edges represented by iterator pairs over points.  We assume that the first point is equal to the last point in each sequence because we know the polygons -that gave rise to the iterators were produced by the Boost.Polygon algorithm for +that gave rise to the iterators were produce by the Boost.Polygon algorithm for general polygon formation.

    template <typename itrT1, typename itrT2>
    void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 @@ -177,7 +177,7 @@ end_points(*itrh), b_polygons);
        }
      }
    }

    -

    We test the convolution of two polygon sets with the code shown below that +

    We test the convolution of two polygon set with the code shown below that produces the first example shown in this tutorial.

    polygon_set a, b, c;
    @@ -197,6 +197,7 @@ pts.push_back(point(-40, 0+300));
    polygon poly;
    boost::polygon::set_points(poly, pts.begin(), pts.end());
    b+=poly;
    +polys.clear();
    convolve_two_polygon_sets(c, a, b);

    Output (a is blue, b is green and c is red):

    diff --git a/doc/gtl_point_concept.htm b/doc/gtl_point_concept.htm index 993d4ca..924df95 100644 --- a/doc/gtl_point_concept.htm +++ b/doc/gtl_point_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Point Concept - - +-->Boost Polygon Library: Point Concept + + + +
    +
    - + +
    -
    +

    Point Concept

    -

    +

    The point concept tag is -point_concept

    +point_concept

    To register a user defined type as a model of point concept, specialize the geometry concept meta-function for that type.  In the example below CPoint is registered as a model of -point  concept.

    -template <>
    -struct geometry_concept<CPoint> { typedef point_concept type; };

    +point  concept.

    +template <>
    +struct geometry_concept<CPoint> { typedef point_concept type; };

    The semantic of a point is that it has an x and y coordinate.  A std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> could all be made models of point by simply providing indirect access to their @@ -76,116 +96,115 @@ elements through traits, however, these objects cannot be made a model of both point and interval in the same compilation unit, for obvious reason that duplicate specialization of the geometry_concept struct is illegal, but also because it would make overloading generic function by concept ambiguous if a -type modeled more than one concept.

    +type modeled more than one concept.

    Below is shown the default point traits.  Specialization of these traits is required for types that don't conform to the -default behavior.

    -template <typename T>
    -struct point_traits {
    -     typedef typename T::coordinate_type coordinate_type;
    -
    +default behavior.

    +template <typename T>
    +struct point_traits {
    +     typedef typename T::coordinate_type coordinate_type;
    +
         static inline coordinate_type get(const T& point, -orientation_2d orient) {
    +orientation_2d orient) {
              return point.get(orient); -
    -     }
    -};
    -
    -template <typename T>
    -struct point_mutable_traits {
    +
    +     }
    +};
    +
    +template <typename T>
    +struct point_mutable_traits {
         static inline void set(T& point, orientation_2d orient, -typename point_traits<T>::coordinate_type value) {
    +typename point_traits<T>::coordinate_type value) {
              point.set(orient, value); -
    -     }
    +
    +     }
         static inline T construct(typename point_traits<T>::coordinate_type -x_value, typename point_traits<T>::coordinate_type y_value) {
    +x_value, typename point_traits<T>::coordinate_type y_value) {
              return T(x_value, y_value); -
    -     }
    -};

    +
    +     }
    +};

    Example code custom_point.cpp demonstrates how to map a - user defined point class to the library point_concept

    Functions

    - - -
    template <typename T>
    + user defined point class to the library point_concept

    Functions

    + + + - - - - - - + - + - + T2>
    + coordinate_distance euclidean_distance(const T1&,
    +                                       +const T2&) - + T2>
    + coordinate_difference manhattan_distance(const T1&,
    +                                       +const T2&) + T2>
    + coordinate_difference distance_squared(const T1&,
    +                                       +const T2&) -
    template <typename T>
    coordinate_type get(const T& point, orientation_2d)
    Expects a model of point.  Returns the x or y coordinate of the point, depending on the orientation_2d - value.
    + value.

     
    template <typename T, typename - coordinate_type>
    + coordinate_type>
    void set(T& point, orientation_2d, coordinate_type)
    Expects a model of point.   Sets the x or y coordinate of the point to the coordinate, depending on the orientation_2d  value.
    template <typename T>
    +
    template <typename T>
    T construct(coordinate_type x, coordinate_type y)
    Construct an object that is a model of point given x and y coordinate values.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models point into left object that models point.
    template <typename T, typename - T2>
    + T2>
    bool equivalence(const T& point1, const T2& point2)
    Given two objects that model point, compares and returns true if their x and y values are respectively equal to each other.
    template <typename point_type>
    +
    template <typename point_type>
    coordinate_type x(const point_type& point)
    Returns the x coordinate of an object that models point.
    template <typename point_type>
    +
    template <typename point_type>
    coordinate_type y(const point_type& point)
    Returns the y coordinate of an object that models point.
    template <typename point_type>
    +
    template <typename point_type>
    void x(point_type& point, coordinate_type )
    Sets the x coordinate of the object that models point to the coordinate value. 
    template <typename point_type>
    +
    template <typename point_type>
    void y(point_type& point, coordinate_type )
    Sets the y coordinate of the object that models point to the coordinate value. 
    template <typename point_type>
    - point_type& scale_up(point_type& point,
    -                        - unsigned_area_type factor)
    template <typename point_type>
    + point_type& scale_up(point_type& point,
                            +unsigned_area_type factor)
    Multiplies x and y coordinate of an object that models point by unsigned factor.
    template <typename point_type>
    - point_type& scale_down(point_type& point,
    -                          - unsigned_area_type factor)
    template <typename point_type>
    + point_type& scale_down(point_type& point,
    +                          +unsigned_area_type factor)
    Divides x and y coordinate of an object that models point by unsigned factor.
    template <typename point_type, - typename scaling_type>
    - point_type& scale(point_type& point,
    + typename scaling_type>
    + point_type& scale(point_type& point,
                      const scaling_type& factor)
    Calls the scale member function of scaling type on the x and y value @@ -193,8 +212,8 @@ how to map a
    template <typename point_type, - typename transform_type>
    - point_type& transform(point_type& point,
    + typename transform_type>
    + point_type& transform(point_type& point,
                          const transform_type& transform)
    Calls the transform member function of transform type on the x and y @@ -202,8 +221,8 @@ how to map a transformed values.
    template <typename point_type>
    - point_type& move(point_type& point, orientation_2d
    +
    template <typename point_type>
    + point_type& move(point_type& point, orientation_2d
                     coordinate_difference displacement)
    Adds displacement value to the coordinate of an object that models @@ -211,30 +230,30 @@ how to map a
    template <typename T1, typename - T2>
    + T2>
    T1& convolve(T1& a, const T2& b)
    Adds x coordinate of b to x coordinate of a and adds y coordinate of b to y coordinate of a.
    template <typename T1, typename - T2>
    + T2>
    T1& deconvolve(T1& a, const T2& b)
    Subtracts x coordinate of b from x coordinate of a and subtracts y coordinate of b from y coordinate of a.
    template <typename T1, typename - T2>
    - coordinate_distance euclidean_distance(const T1&,
    -                                       - const T2&)
    Returns the distance from an object that models point to a second object that models point.
    template <typename T>
    - coordinate_difference euclidean_distance(const T&,
    +
    template <typename T>
    + coordinate_difference euclidean_distance(const T&,
               orientation_2d, coordinate_type)
    Returns the distance from an object that models point to a @@ -242,28 +261,28 @@ how to map a
    template <typename T1, typename - T2>
    - coordinate_difference manhattan_distance(const T1&,
    -                                       - const T2&)
    Returns the distance in x plus the distance in y from an object that models point to a second object that models point.
    template <typename T1, typename - T2>
    - coordinate_difference distance_squared(const T1&,
    -                                       - const T2&)
    Returns the square of the distance in x plus the square of the distance in y from an object that models point to a second object that models point.
    +

    Point Data

    -

    The library provides a model of point concept declared +

    The library provides a model of point concept declared template<typename T> point_data where T is the coordinate type.

    This data type is used internally when a point is needed and is available to @@ -273,8 +292,8 @@ convenient to use with the library traits.

    Example code point_usage.cpp demonstrates using the library provided point data type and functions

    Members

    - - +
    + @@ -304,42 +323,42 @@ convenient to use with the library traits.

    +
    point_data& operator=(const T2& that) const @@ -369,18 +388,18 @@ convenient to use with the library traits.

    -
    geometry_type point_concept
    template <typename T2>  -
    point_data& operator=(const T2& that) const
    Assign from an object that is a model of point.
    template <typename T2> -
    bool +
    bool operator==(const T2& that) const
    Compare equality to an object that is a model of point.
    template <typename T2> -
    bool +
    bool operator!=(const T2& that) const
    Compare inequality to an object that is a model of point.
    template <typename T2> -
    bool +
    bool operator<(const T2& that) const
    Compares y coordinates then x coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator<=(const T2& that) const
    Compares y coordinates then x coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator>(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    template <typename T2> -
    bool +
    bool operator>=(const T2& that) const
    Compares low coordinates then high coordinates to break ties.
    void y(T value) Sets the coordinate in the vertical orientation to the value.
    -
    +
      - +
    - + - + @@ -393,6 +412,6 @@ convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_45_concept.htm b/doc/gtl_polygon_45_concept.htm index 0e5abe5..8f5fb2d 100644 --- a/doc/gtl_polygon_45_concept.htm +++ b/doc/gtl_polygon_45_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 45 Concept - - +-->Boost Polygon Library: Polygon 45 Concept + + + +
    +
    - + +
    -
    +

    Polygon 45 Concept

    -

    The polygon_45 concept tag is +

    The polygon_45 concept tag is polygon_45_concept

    To register a user defined type as a model of polygon_45 concept, specialize the geometry concept meta-function for that type.  In the example below CPolygon45 is registered as a model of -polygon_45  concept.

    -template <>
    -struct geometry_concept<CPolygon45> { typedef polygon_45_concept type; };

    +polygon_45  concept.

    +template <>
    +struct geometry_concept<CPolygon45> { typedef polygon_45_concept type; };

    The semantic of a polygon_45 is that it can provide iterators over the points that represent its vertices, angles formed as these vertices must be multiple of 45-degree relative to the coordinate axis.  It @@ -80,75 +99,75 @@ an interator range over such points.   A std::vector<point_data< or std::list<point_data<int> > could be made models of polygon_45_concept by simply providing access to their iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

    +require that those objects provide a default constructor.

    Below is shown the default polygon traits.  Specialization of these traits is required for types that don't conform to the default behavior.  Note that these traits are also used by several other polygon concepts through SFINAE enable template parameter.  The SFINAE enable parameter also allows the library to provide default specialization that work -for any object that models the 90 degree polygon concepts.

    -template <typename T, typename enable = gtl_yes>
    -struct polygon_traits {};
    -
    -template <typename T>
    -struct polygon_traits<T,
    -  typename gtl_or_4<
    +for any object that models the 90 degree polygon concepts.

    +template <typename T, typename enable = gtl_yes>
    +struct polygon_traits {};
    +
    +template <typename T>
    +struct polygon_traits<T,
    +  typename gtl_or_4<
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
    +polygon_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_45_concept>::type,
    +polygon_45_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type,
    +polygon_with_holes_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_45_with_holes_concept>::type
    -  >::type> {
    -     typedef typename T::coordinate_type coordinate_type;
    -     typedef typename T::iterator_type iterator_type;
    -     typedef typename T::point_type point_type;
    -     static inline iterator_type begin_points(const T& t) {
    -          return t.begin();
    -     }
    -     static inline iterator_type end_points(const T& t) {
    -          return t.end();
    -     }
    -     static inline unsigned int size(const T& t) {
    -          return t.size();
    -     }
    -     static inline winding_direction winding(const T& t) {
    -          return unknown_winding;
    -     }
    +polygon_45_with_holes_concept>::type
    +  >::type> {
    +     typedef typename T::coordinate_type coordinate_type;
    +     typedef typename T::iterator_type iterator_type;
    +     typedef typename T::point_type point_type;
    +     static inline iterator_type begin_points(const T& t) {
    +          return t.begin();
    +     }
    +     static inline iterator_type end_points(const T& t) {
    +          return t.end();
    +     }
    +     static inline unsigned int size(const T& t) {
    +          return t.size();
    +     }
    +     static inline winding_direction winding(const T& t) {
    +          return unknown_winding;
    +     }
    };

    -

    template <typename T, typename enable = void>
    -struct polygon_mutable_traits {
    -     template <typename iT>
    +

    template <typename T, typename enable = void>
    +struct polygon_mutable_traits {
    +     template <typename iT>
         static inline T& set_points(T& t, iT input_begin, iT -input_end) {
    +input_end) {
              t.set(input_begin, -input_end);
    -          return t;
    -     }
    +input_end);
    +          return t;
    +     }
    };

    An object that is a model of polygon_45_concept can be viewed as a model of any of its refinements if it is determined at runtime to conform to the restriction of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<rectangle_concept>(polygon_45_object)
    +

    view_as<rectangle_concept>(polygon_45_object)
    view_as<polygon_90_concept>(polygon_45_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - + -
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon_45.  Returns the begin iterator over the range of points that correspond to vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon_45.  Returns the end iterator over the range of points that correspond to @@ -156,7 +175,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon_45.   Sets the polygon to the point data range [b,e) that corresponds to @@ -164,22 +183,22 @@ specified in its template parameter.

    points is disallowed.
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the polygon.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon_45 into left object that models polygon_45.
    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon_45 and an object that models @@ -189,85 +208,84 @@ specified in its template parameter.

    the polygon.  Linear wrt. vertices.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon_45.  Linear wrt. vertices.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon_45 and returns true.  Returns false and leaves bbox unchanged if polygon is empty.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    area_type area(const T& polygon)
    Returns the area of an object that models polygon_45.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon_45, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity depends upon winding trait.
    template <typename T>
    +
    template <typename T>
    coordinate_distance perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon_45.  Linear wrt. vertices.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up coordinate of an object that models polygon_45 by unsigned factor.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down coordinates of an object that models polygon_45 by unsigned factor.  Linear wrt. vertices.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales coordinates of an object that models polygon_45 by floating point factor.  Linear wrt. vertices.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon_45.  Linear wrt. vertices.
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with vertices of an object that models polygon_45.  Linear wrt. vertices.
    +

    Polygon 45 Data

    -

    The library provides a model of polygon 45 concept declared +

    The library provides a model of polygon 45 concept declared template<typename T> polygon_45_data where T is the coordinate type.

    This data type is used internally when a 45-degree polygon is needed and is @@ -275,8 +293,8 @@ available to the library user who finds it convenient to use a library polygon data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -304,7 +322,7 @@ be convenient to use with the library traits.

    +
    polygon_45_data& operator=(const T2& that) const @@ -324,23 +342,23 @@ be convenient to use with the library traits.

    +
    void set(iT begin_points, iT end_points) -
    geometry_type polygon_45_concept
    template <typename T2>  -
    polygon_45_data& operator=(const T2& that) const
    Assign from an object that is a model of polygon 45.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points.  No check is performed to ensure the points describe corners that are multiples of 45 degrees relative to the coordinate axis.
    -
    +
      - +
    - + - + @@ -353,6 +371,6 @@ be convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_45_set_concept.htm b/doc/gtl_polygon_45_set_concept.htm index a819024..d96b40c 100644 --- a/doc/gtl_polygon_45_set_concept.htm +++ b/doc/gtl_polygon_45_set_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 45 Set Concept - - +-->Boost Polygon Library: Polygon 45 Set Concept + + + +
    - + +
    -
    +

    Polygon 45 Set Concept

    -

    The polygon_45_set concept tag is +

    The polygon_45_set concept tag is polygon_45_set_concept

    The semantic of a polygon_45_set is zero or more @@ -75,7 +94,7 @@ inserting a unit length edge between the two 45 degree edges near the off grid intersection point.  In the case that data represented contains no 45-degree angles and is Manhattan a runtime check will default to the Manhattan algorithm.  The results of which are identical to what the 45-degree -algorithm would do, but obtained more efficiently.

    +algorithm would do, but obtained more efficiently.

    The motivation for providing the polygon_45_set is to extend the special case of Manhattan geometry capability of the library to encompass the slightly less common, but still important special case of geometry @@ -84,7 +103,7 @@ coordinate axis.  This simplifies the implementation of geometry algorithms and affords many opportunities for optimization.  45-degree algorithms can be 50X faster than arbitrary angle algorithms and are required to provide a complete feature set that meets the performance requirements of application -domains in which Manhattan and 45-degree geometry are a common special case.

    Users are recommended to use std::vector and std::list of user defined polygons +domains in which Manhattan and 45-degree geometry are a common special case.

    Users are recommended to use std::vector and std::list of user defined polygons or library provided polygon_45_set_data<coordinate_type> objects.  Lists and vectors of models of polygon_45_concept or polygon_45_with_holes_concept are automatically models of polygon_45_set_concept.

    An object that is a model of @@ -106,10 +125,10 @@ constructor and assignment operator.  The operator template exists to eliminate temp copies of intermediate results when Boolean operators are chained together.

    Operators are declared inside the namespace boost::polygon::operators.

    - - +
    + - -
    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator|(const T1& l, const T2& r)
    Boolean OR operation (polygon set union).  Accepts two objects that model polygon_45_set or one of its refinements.  Returns an @@ -119,7 +138,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator+(const T1& l, const T2& r)
    Same as operator|.  The plus sign is also used for OR operations in Boolean logic expressions.  O( n log n) runtime @@ -127,7 +146,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator&(const T1& l, const T2& r)
    Boolean AND operation (polygon set intersection).  Accepts two objects that model polygon_45_set or one of its refinements.  O( n @@ -135,7 +154,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator*(const T1& l, const T2& r)
    Same as operator&.  The multiplication symbol is also used for AND operations in Boolean logic expressions.  O( n log n) runtime @@ -143,7 +162,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator^(const T1& l, const T2& r)
    Boolean XOR operation (polygon set disjoint-union).  Accepts two objects that model polygon_45_set or one of its refinements.  @@ -152,7 +171,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_45_set_view operator-(const T1& l, const T2& r)
    Boolean SUBTRACT operation (polygon set difference).  Accepts two objects that model polygon_45_set or one of its refinements.  @@ -161,7 +180,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator|=(const T1& l, const T2& r)
    Same as operator|, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) @@ -169,7 +188,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(T1& l, const T2& r)
    Same as operator+, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) @@ -177,7 +196,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator&=(const T1& l, const T2& r)
    Same as operator&, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) @@ -185,7 +204,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator*=(T1& l, const T2& r)
    Same as operator*, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) @@ -193,7 +212,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator^=(const T1& l, const T2& r)
    Same as operator^, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) @@ -201,14 +220,14 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(T1& l, const T2& r)
    Same as operator-, but with self assignment, left operand must model polygon_45_set and not one of it's refinements.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T1>
    +
    template <typename T1>
    T1 operator+(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Note: returns @@ -217,7 +236,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1 operator-(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Note: returns @@ -226,7 +245,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Returns @@ -235,19 +254,19 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Returns reference to modified argument.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    +

    Functions

    - - +
    + + const T& polygon_set,
    +                    +orientation_2d orient) - - - - - + RoundingOption rounding = CLOSEST,
              CornerOption corner = INTERSECTION) - - - - - - -
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& lvalue, const T2& rvalue)
    Eliminates overlaps in geometry and copies from an object that models polygon_45_set or any of its refinements into an object that @@ -256,7 +275,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    bool equivalence(const T1& lvalue, const T2& rvalue)
    Returns true if an object that models polygon_45_set or one of its refinements covers the exact same geometric regions as another object @@ -266,8 +285,8 @@ together.

    template <typename - output_container_type, typename T>
    - void get_trapezoids(output_container_type& output,
    + output_container_type, typename T>
    + void get_trapezoids(output_container_type& output,
                        const T& polygon_set)
    Output container is expected to be a standard container.  @@ -280,10 +299,12 @@ together.

    template <typename - output_container_type, typename T>
    - void get_trapezoids(output_container_type& output,
    + output_container_type, typename T>
    + void get_trapezoids(output_container_type& output,
                        - const T& polygon_set,
                        orientation_2d orient)
    Output container is expected to be a standard container.  Slices geometry of an object that models polygon_45_set or one of its refinements into non overlapping trapezoids along a the specified slicing @@ -294,13 +315,13 @@ together.

    template <typename - polygon_set_type>
    + polygon_set_type>
    void clear(polygon_set_type& polygon_set)
    Makes the object empty of geometry.
    template <typename - polygon_set_type>
    + polygon_set_type>
    bool empty(const polygon_set_type& polygon_set)
    Checks whether the object is empty of geometry.  Polygons that are completely covered by holes will result in empty returning true.   @@ -308,8 +329,8 @@ together.

    template <typename T, typename - rectangle_type>
    - bool extents(rectangle_type& extents_rectangle,
    + rectangle_type>
    + bool extents(rectangle_type& extents_rectangle,
                 const T& polygon_set)
    Computes bounding box of an object that models polygon_45_set and @@ -319,7 +340,7 @@ together.

    log n) runtime complexity and O(n) memory wrt vertices.
    template <typename T>
    +
    template <typename T>
    area_type area(const T& polygon_set)
    Computes the area covered by geometry in an object that models polygon_45_set.   O( n log n) runtime complexity and O(n) @@ -327,7 +348,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& interact(T1& a, const T2& b)
    Given an object that models polygon_45_set and an object that models polygon_45_set or one of its refinements, modifies a to retain only @@ -335,7 +356,7 @@ together.

    runtime complexity and O(n) memory wrt vertices plus intersections.
    template <typename T>
    +
    template <typename T>
    T& self_intersect(T& polygon_set)
    Given an object that models polygon_45_set that has self overlapping regions, modifies the argument to contain only the regions of overlap.  @@ -343,7 +364,7 @@ together.

    intersections.
    template <typename T>
    +
    template <typename T>
    T& self_xor(T& polygon_set)
    Given an object that models polygon_45_set that has self overlapping regions, modifies the argument to contain only the regions that do not @@ -351,14 +372,14 @@ together.

    vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& polygon_set, unsigned_area_type bloating)
    Same as getting all the polygons, bloating them and putting them back.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& polygon_set, unsigned_area_type shrinking)
    Same as getting all the polygons, shrinking them and overwriting the polygon set with the resulting regions.  O( n log n) runtime @@ -366,10 +387,10 @@ together.

    template <typename T, typename - coord_type>
    - T& resize(T& polygon_set, coord_type resizing,
    + coord_type>
    + T& resize(T& polygon_set, coord_type resizing,
              - RoundingOption rounding = CLOSEST,
              CornerOption corner = INTERSECTION)
    Same as bloat if resizing is positive, same as shrink if resizing is negative.  RoundingOption is an enum that controls snapping of non-integer results of resizing 45 degree edges.  CornerOption is @@ -378,7 +399,7 @@ together.

    complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& grow_and(T& polygon_set, unsigned_area_type bloating)
    Same as bloating non-overlapping regions and then applying self intersect to retain only the overlaps introduced by the bloat.  O( @@ -386,13 +407,13 @@ T& grow_and(T& polygon_set, unsigned_area_type bloating)
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon_set, unsigned_area_type factor)
    Scales geometry up by unsigned factor.  O( n log n) runtime complexity and O(n) memory wrt vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon_set, unsigned_area_type factor)
    Scales geometry down by unsigned factor.  Snaps 45 degree edges back to 45 degrees after division truncation leads to small changes in @@ -400,7 +421,7 @@ T& scale_down(T& polygon_set, unsigned_area_type factor)
    template <typename T, typename scaling_type>
    +
    template <typename T, typename scaling_type>
    T& scale(polygon_set_type& polygon_set, double scaling)
    Scales geometry by multiplying by floating point factor.   Snaps 45 degree edges back to 45 degrees after truncation of fractional @@ -408,32 +429,32 @@ T& scale(polygon_set_type& polygon_set, double scaling)
    template <typename T, typename transformation_type>
    -T& transform(T& polygon_set,
    +
    template <typename T, typename transformation_type>
    +T& transform(T& polygon_set,
                 const transformation_type& transformation)
    Applies transformation.transform() on all vertices.  O( n log n) runtime complexity and O(n) memory wrt vertices.
    template <typename T>
    -T& keep(T& polygon_set,
    -        unsigned_area_type min_area,
    -        unsigned_area_type max_area,
    -        unsigned_area_type min_width,
    -        unsigned_area_type max_width,
    -        unsigned_area_type min_height,
    +
    template <typename T>
    +T& keep(T& polygon_set,
    +        unsigned_area_type min_area,
    +        unsigned_area_type max_area,
    +        unsigned_area_type min_width,
    +        unsigned_area_type max_width,
    +        unsigned_area_type min_height,
            unsigned_area_type max_height)
    Retains only regions that satisfy the min/max criteria in the argument list.  Note: useful for visualization to cull too small polygons.  O( n log n) runtime complexity and O(n) memory wrt vertices.
    +

    Polygon 45 Set Data Object

    -

    The polygon 45 set data type encapsulates the internal data format that +

    The polygon 45 set data type encapsulates the internal data format that serves as the input to the sweep-line algorithm that implements polygon-clipping Boolean operations.  It also internally keeps track of whether that data has been sorted or scanned and maintains the invariant that when its flags @@ -444,20 +465,20 @@ above because of the invariants it can enforce which provide the opportunity to maintain the data is sorted form rather than going all the way out to polygons then resorting those vertices for a subsequent operation.

    The declaration of Polygon 45 Set Data is the following:

    -

    template <typename T>
    +

    template <typename T>
    class polygon_45_set_data;

    The class is parameterized on the coordinate data type.  Algorithms that benefit from knowledge of the invariants enforced by the class are implemented as member functions to provide them access to information about those invariants. 

    Member Functions

    - - +
    + - +polygon_45_set_data&
    operator=(const polygon_45_set_data& that)
    - +template <typename iT>
    +void insert(iT input_begin, iT input_end,
                bool is_hole = false) @@ -505,15 +526,15 @@ void insert(iT input_begin, iT input_end,
        &nb -
    polygon_45_set_data() Default constructor.
    template <typename iT>
    +
    template <typename iT>
    polygon_45_set_data(iT input_begin, iT input_end)
    Construct from an iterator range of @@ -470,34 +491,34 @@ invariants. 

    -template <typename l, typename r, typename op>
    +template <typename l, typename r, typename op>
    polygon_45_set_data(const polygon_45_set_view<l,r,op>& t)
    Copy construct from a Boolean operator template.
    -polygon_45_set_data&
    operator=(const polygon_45_set_data& that)
    Assignment from another polygon set, may change scanning orientation.
    -template <typename l, typename r, typename op>
    -polygon_45_set_data&
    operator=(const polygon_45_set_view<l, r, +template <typename l, typename r, typename op>
    +polygon_45_set_data&
    operator=(const polygon_45_set_view<l, r, op>& that)
    Assignment from a Boolean operator template.
    template <typename geometry_object>
    +
    template <typename geometry_object>
    polygon_45_set_data& operator=(const geometry_object& geo)
    Assignment from an insertable object.
    -template <typename iT>
    -void insert(iT input_begin, iT input_end,
                bool is_hole = false)
    Insert objects of an iterator range.  If is_hole is true inserts subtractive regions.  Linear wrt the number of vertices added.
    -void insert(const polygon_45_set_data& polygon_set,
                bool is_hole +void insert(const polygon_45_set_data& polygon_set,
                bool is_hole = false)
    Insert a polygon set.  Linear wrt the number of vertices added.
    -template <typename geometry_type>
    -void insert(const geometry_type& geometry_object,
                bool is_hole +template <typename geometry_type>
    +void insert(const geometry_type& geometry_object,
                bool is_hole = false)
    Insert a geometry object, if is_hole is true then the inserted region is subtractive rather than additive.  Linear wrt the number @@ -521,7 +542,7 @@ void insert(const geometry_type& geometry_object,
      &nb
    -template <typename output_container>
    +template <typename output_container>
    void get(output_container& output) const
    Expects a standard container of geometry objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to objects @@ -534,7 +555,7 @@ void get(output_container& output) const
    -template <typename output_container>
    +template <typename output_container>
    void get_polygons(output_container& output) const
    Expects a standard container of polygon objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to polygons and @@ -544,7 +565,7 @@ void get_polygons(output_container& output) const
    -template <typename output_container>
    +template <typename output_container>
    void get_polygons_with_holes(output_container& o) const
    Expects a standard container of polygon with holes objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to polygons and @@ -553,7 +574,7 @@ void get_polygons_with_holes(output_container& o) const
    -template <typename output_container>
    +template <typename output_container>
    void get_trapezoids(output_container& output) const
    Expects a standard container of polygon objects.  Will scan and eliminate overlaps.  Slices polygon set geometry to trapezoids @@ -563,8 +584,8 @@ void get_trapezoids(output_container& output) const
    -template <typename output_container>
    -void get_trapezoids(output_container& output,
      orientation_2d +template <typename output_container>
    +void get_trapezoids(output_container& output,
      orientation_2d slicing_orientation) const
    Expects a standard container of polygon objects.  Will scan @@ -618,15 +639,15 @@ bool operator!=(const polygon_45_set_data& p) const
    -template <typename input_iterator_type>
    -void set(input_iterator_type input_begin,
             input_iterator_type input_end)
    +template <typename input_iterator_type>
    +void set(input_iterator_type input_begin,
             input_iterator_type input_end)
    Overwrite geometry in polygon set with insertable objects in the iterator range. 
    -template <typename rectangle_type>
    +template <typename rectangle_type>
    bool extents(rectangle_type& extents_rectangle) const
    Given an object that models rectangle, scans and eliminates overlaps in the polygon set because subtractive regions may alter its extents @@ -636,9 +657,9 @@ bool extents(rectangle_type& extents_rectangle) const
    -polygon_45_set_data&
    -resize(coord_type resizing,
    -        RoundingOption rounding = CLOSEST,
           CornerOption +polygon_45_set_data&
    +resize(coord_type resizing,
    +        RoundingOption rounding = CLOSEST,
           CornerOption corner = INTERSECTION)
    Same as bloat if resizing is positive, same as shrink if resizing is negative.  RoundingOption is an enum that controls snapping of @@ -649,8 +670,8 @@ polygon_45_set_data&
    -template <typename transformation_type>
    -polygon_45_set_data&
    transform(const transformation_type& transformation)
    +template <typename transformation_type>
    +polygon_45_set_data&
    transform(const transformation_type& transformation)
    Applies transformation.transform() on vertices stored within the polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + @@ -708,18 +729,18 @@ factor)  Retain only overlapping regions of geometry within a polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + intersections.
    -
    +
      - +
    - + - + @@ -732,6 +753,6 @@ factor)  http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_45_with_holes_concept.htm b/doc/gtl_polygon_45_with_holes_concept.htm index 9469eb2..f0096a2 100644 --- a/doc/gtl_polygon_45_with_holes_concept.htm +++ b/doc/gtl_polygon_45_with_holes_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 45 With Holes Concept - - +-->Boost Polygon Library: Polygon 45 With Holes Concept + + + +
    +
    - + +
    -
    +

    Polygon 45 With Holes Concept

    -

    The polygon_45_with_holes concept tag is +

    The polygon_45_with_holes concept tag is polygon_45_with_holes_concept

    To register a user defined type as a model of polygon_45_with_holes concept, specialize the geometry concept meta-function for that type.  In the example below -CPolygon45WithHoles is registered as a model of polygon_45_with_holes  concept.

    -template <>
    -struct geometry_concept<CPolygon45WithHoles> { typedef polygon_45_with_holes_concept type; };

    +CPolygon45WithHoles is registered as a model of polygon_45_with_holes  concept.

    +template <>
    +struct geometry_concept<CPolygon45WithHoles> { typedef polygon_45_with_holes_concept type; };

    The semantic of a polygon_45_with_holes is a polygon_45 that it can provide iterators over holes that are also polygon_45.  A mutable polygon_45_with_holes must also be able to set its geometry based on an interator range over polygon_45 holes.  There is no convention of -winding of holes enforced within the library.

    +winding of holes enforced within the library.

    Below is shown the default polygon with holes traits.  Specialization of these traits is required for types that don't -conform to the default behavior.

    template <typename -T, typename enable = void>
    -struct polygon_with_holes_traits {
    +conform to the default behavior.

    template <typename +T, typename enable = void>
    +struct polygon_with_holes_traits {
         typedef typename T::iterator_holes_type -iterator_holes_type;
    -     typedef typename T::hole_type hole_type;
    +iterator_holes_type;
    +     typedef typename T::hole_type hole_type;
         static inline iterator_holes_type begin_holes(const T& -t) {
    -          return t.begin_holes();
    -     }
    +t) {
    +          return t.begin_holes();
    +     }
         static inline iterator_holes_type end_holes(const T& t) -{
    -          return t.end_holes();
    -     }
    -     static inline unsigned int size_holes(const T& t) {
    -          return t.size_holes();
    -     }
    +{
    +          return t.end_holes();
    +     }
    +     static inline unsigned int size_holes(const T& t) {
    +          return t.size_holes();
    +     }
    };

    -

    template <typename T, typename enable = void>
    -struct polygon_with_holes_mutable_traits {
    -     template <typename iT>
    +

    template <typename T, typename enable = void>
    +struct polygon_with_holes_mutable_traits {
    +     template <typename iT>
         static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
    +inputEnd) {
              t.set_holes(inputBegin, -inputEnd);
    -          return t;
    -     }
    +inputEnd);
    +          return t;
    +     }
    };

    An object that is a model of polygon_45_with_holes_concept can be viewed as a model of any of its refinements if it is determined at runtime to conform to the restriction of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<rectangle_concept>(polygon_45_with_holes_object)
    -view_as<polygon_90_concept>(polygon_45_with_holes_object)
    -view_as<polygon_90_with_holes_concept>(polygon_45_with_holes_object)
    +

    view_as<rectangle_concept>(polygon_45_with_holes_object)
    +view_as<polygon_90_concept>(polygon_45_with_holes_object)
    +view_as<polygon_90_with_holes_concept>(polygon_45_with_holes_object)
    view_as<polygon_45_concept>(polygon_45_with_holes_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - - - + -
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon_45_with_holes.  @@ -128,7 +147,7 @@ specified in its template parameter.

    vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon_45_with_holes.  @@ -136,7 +155,7 @@ specified in its template parameter.

    vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type begin_holes(const T& polygon)
    Expects a model of polygon_45_with_holes.  @@ -144,7 +163,7 @@ specified in its template parameter.

    to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type end_holes(const T& polygon)
    Expects a model of polygon_45_with_holes.  @@ -153,7 +172,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon_45_with_holes.   @@ -162,14 +181,14 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_holes(T& polygon, iterator b, iterator e)
    Expects a model of polygon_45_with_holes.   Sets the polygon holes to the hole data range [b,e)
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the outer shell of the polygon_45_with_holes.  Does not include sizes @@ -177,7 +196,7 @@ specified in its template parameter.

    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon_45_with_holes or one of its refinements into left object @@ -185,8 +204,8 @@ specified in its template parameter.

    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon_45_with_holes and an object that models @@ -197,86 +216,85 @@ specified in its template parameter.

    the polygon or one of its holes.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon_45_with_holes.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon_45_with_holes and returns true.  Returns false and leaves bbox unchanged if polygon is empty.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& polygon)
    Returns the area of an object that models polygon_45_with_holes including subtracting the area of its holes from the area of the outer shell polygon.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon_45_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
    template <typename T>
    +
    template <typename T>
    coordinate_difference perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon_45, including the perimeters of the holes.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Also applies transform() on the holes of the polygon.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up outer shell and holes of an object that models polygon_45 by unsigned factor.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down outer shell and holes of an object that models polygon_45 by unsigned factor.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales outer shell and holes of an object that models polygon_45 by floating point factor.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon_45 .
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with the outer shell and holes of an object that models polygon_45_with_holes.
    +

    Polygon 45 With Holes Data

    -

    The library provides a model of polygon 45 with holes concept declared +

    The library provides a model of polygon 45 with holes concept declared template<typename T> polygon_45_with_holes_data where T is the coordinate type.

    @@ -285,8 +303,8 @@ needed and is available to the library user who finds it convenient to use a library polygon data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -314,13 +332,13 @@ implemented to be convenient to use with the library traits.

    +
    operator=(const polygon_45_with_holes_data& that) +
    operator=(const T2& that) const @@ -356,30 +374,30 @@ implemented to be convenient to use with the library traits.

    +
    void set(iT begin_points, iT end_points) +
    void set_holes(iT begin_holes, iT end_choless) -
    geometry_type polygon_45_with_holes_concept
    polygon_45_with_holes_data& -
    operator=
    (const polygon_45_with_holes_data& that)
    Assignment operator.
    template <typename T2> polygon_45_with_holes_data&  -
    operator=
    (const T2& that) const
    Assign from an object that is a model of polygon 45 with holes.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points.  No check is performed to ensure the points describe a 45 degree figure.
    template <typename iT>  -
    void set_holes(iT begin_holes, iT end_choless)
    Sets the polygon holes the iterator range of hole polygons.  These polygons in the input range may be either polygon_45_data or polygon_45_with_holes_data or any type that provides begin and end member functions to iterate over point_data<T>.
    -
    +
      - +
    - + - + @@ -392,6 +410,6 @@ implemented to be convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_90_concept.htm b/doc/gtl_polygon_90_concept.htm index 542c660..9247068 100644 --- a/doc/gtl_polygon_90_concept.htm +++ b/doc/gtl_polygon_90_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 90 Concept - - +-->Boost Polygon Library: Polygon 90 Concept + + + +
    +
    - + +
    -
    +

    Polygon 90 Concept

    -

    The polygon_90 concept tag is +

    The polygon_90 concept tag is polygon_90_concept

    To register a user defined type as a model of polygon_90 concept, specialize the geometry concept meta-function for that type.  In the example below CPolygon90 is registered as a model of -polygon_90  concept.

    -template <>
    -struct geometry_concept<CPolygon90> { typedef polygon_90_concept type; };

    +polygon_90  concept.

    +template <>
    +struct geometry_concept<CPolygon90> { typedef polygon_90_concept type; };

    The semantic of a polygon_90 is that it can provide iterators over the x and y coordinates that correspond to its horizontal and vertical sides, starting with an x coordinate.  A mutable polygon_90 must @@ -80,40 +99,40 @@ iterator_points_to_compact.hpp and iterator_compact_to_points.hpp to aid in the specialization of polygon_90_traits.  A std::vector<int> or std::list<int> could be made models of polygon_90_concept by simply providing access to their iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

    +require that those objects provide a default constructor.

    Below is shown the default polygon traits.  Specialization of these traits is required for types that don't conform to the default behavior.  Note that these traits are also used by the -polygon_90_with_holes concept.

    template <typename -T>
    -struct polygon_90_traits {
    -     typedef typename T::coordinate_type coordinate_type;
    +polygon_90_with_holes concept.

    template <typename +T>
    +struct polygon_90_traits {
    +     typedef typename T::coordinate_type coordinate_type;
         typedef typename T::compact_iterator_type -compact_iterator_type;
    +compact_iterator_type;
         static inline compact_iterator_type begin_compact(const -T& t) {
    -          return t.begin_compact();
    -     }
    +T& t) {
    +          return t.begin_compact();
    +     }
         static inline compact_iterator_type end_compact(const -T& t) {
    -          return t.end_compact();
    -     }
    -     static inline unsigned int size(const T& t) {
    -          return t.size();
    -     }
    -     static inline winding_direction winding(const T& t) {
    -          return unknown_winding;
    -     }
    +T& t) {
    +          return t.end_compact();
    +     }
    +     static inline unsigned int size(const T& t) {
    +          return t.size();
    +     }
    +     static inline winding_direction winding(const T& t) {
    +          return unknown_winding;
    +     }
    };

    -

    template <typename T>
    -struct polygon_90_mutable_traits {
    -     template <typename iT>
    +

    template <typename T>
    +struct polygon_90_mutable_traits {
    +     template <typename iT>
         static inline T& set_compact(T& t, iT input_begin, iT -input_end) {
    +input_end) {
              t.set_compact(input_begin, -input_end);
    -          return t;
    -     }

    +input_end);
    +          return t;
    +     }

    };

    An object that is a model of polygon_90_concept can be viewed as a model of any of its @@ -125,30 +144,30 @@ those concepts.  This concept casting is accomplished through the passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - - - + -
    template <typename T>
    compact_iterator_type begin_compact(const T& polygon)
    Expects a model of polygon_90.  Returns the begin iterator over the range of coordinates that correspond to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    compact_iterator_type end_compact(const T& polygon)
    Expects a model of polygon_90.  Returns the end iterator over the range of coordinates that correspond to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon_90.  Returns the begin iterator over the range of points that correspond to vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon_90.  Returns the end iterator over the range of points that correspond to @@ -156,7 +175,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_compact(T& polygon, iterator b, iterator e)
    Expects a model of polygon_90.   Sets the polygon to the coordinate data range [b,e) that corresponds to @@ -164,7 +183,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon_90.   Sets the polygon to the point data range [b,e) that corresponds to @@ -172,22 +191,22 @@ specified in its template parameter.

    successive input points results in undefined behavior.
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the polygon.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon_90 into left object that models polygon_90.
    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon_90 and an object that models @@ -197,85 +216,84 @@ specified in its template parameter.

    the polygon.  Linear wrt. vertices.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon_90.  Linear wrt. vertices.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon_90 and returns true.  Returns false and leaves bbox unchanged if polygon is empty.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& polygon)
    Returns the area of an object that models polygon_90.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon_90, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity depends upon winding trait.
    template <typename T>
    +
    template <typename T>
    coordinate_difference perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon_90.  Linear wrt. vertices.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up coordinate of an object that models polygon_90 by unsigned factor.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down coordinates of an object that models polygon_90 by unsigned factor.  Linear wrt. vertices.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales coordinates of an object that models polygon_90 by floating point factor.  Linear wrt. vertices.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon_90 .  Linear wrt. vertices.
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with vertices of an object that models polygon_90.  Linear wrt. vertices.
    +

    Polygon 90 Data

    -

    The library provides a model of polygon 90 concept declared +

    The library provides a model of polygon 90 concept declared template<typename T> polygon_90_data where T is the coordinate type.

    This data type is used internally when a Manhattan polygon is needed and is @@ -283,8 +301,8 @@ available to the library user who finds it convenient to use a library polygon data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -319,7 +337,7 @@ be convenient to use with the library traits.

    +
    polygon_90_data& operator=(const T2& that) const @@ -351,31 +369,31 @@ be convenient to use with the library traits.

    +
    void set(iT begin_points, iT end_points) +
    void set_compact(iT begin_coords, iT end_coords) -
    geometry_type polygon_90_concept
    template <typename T2>  -
    polygon_90_data& operator=(const T2& that) const
    Assign from an object that is a model of polygon 90.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points.  No check is performed to ensure the points describe a Manhattan figure, every other x and y value of the points is used to initialize the polygon.
    template <typename iT>  -
    void set_compact(iT begin_coords, iT end_coords)
    Sets the polygon to the iterator range of coordinates.  These coordinates correspond to the x values of vertical edges and y values of horizontal edges.  It is expected that the sequence start with an x value and proceed x then y then x then y.
    -
    +
      - +
    - + - + @@ -388,6 +406,6 @@ be convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_90_set_concept.htm b/doc/gtl_polygon_90_set_concept.htm index d4c6daa..156e5ca 100644 --- a/doc/gtl_polygon_90_set_concept.htm +++ b/doc/gtl_polygon_90_set_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 90 Set Concept - - +-->Boost Polygon Library: Polygon 90 Set Concept + + + +
    - + +
    -
    +

    Polygon 90 Set Concept

    -

    The polygon_90_set concept tag is +

    The polygon_90_set concept tag is polygon_90_set_concept

    The semantic of a polygon_90_set is zero or more -Manhattan geometry regions.

    +Manhattan geometry regions.

    The motivation for providing the polygon_90_set_concept is that it is a very common special case of planar geometry which afford the implementation of a variety of optimizations on the @@ -73,7 +92,7 @@ general planar geometry algorithms.  Manhattan geometry processing by the polygon_90_set_concept can be 100X faster than arbitrary angle polygon manipulation.  Because the performance benefits are so large and the special case is important enough, the library provides these performance -benefits for those application domains that require them.

    Users are recommended to use std::vector and std::list of user defined polygons +benefits for those application domains that require them.

    Users are recommended to use std::vector and std::list of user defined polygons or library provided polygon_90_set_data<coordinate_type> objects.  Lists and vectors of models of polygon_90_concept or polygon_90_with_holes_concept or rectangle_concept are automatically models of polygon_90_set_concept.

    @@ -85,10 +104,10 @@ constructor and assignment operator.  The operator template exists to eliminate temp copies of intermediate results when Boolean operators are chained together.

    Operators are declared inside the namespace boost::polygon::operators.

    - - +
    + - -
    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator|(const T1& l, const T2& r)
    Boolean OR operation (polygon set union).  Accepts two objects that model polygon_90_set or one of its refinements.  Returns an @@ -98,7 +117,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator+(const T1& l, const T2& r)
    Same as operator|.  The plus sign is also used for OR operations in Boolean logic expressions.  O( n log n) runtime @@ -106,7 +125,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator&(const T1& l, const T2& r)
    Boolean AND operation (polygon set intersection).  Accepts two objects that model polygon_90_set or one of its refinements.  O( n @@ -114,7 +133,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator*(const T1& l, const T2& r)
    Same as operator&.  The multiplication symbol is also used for AND operations in Boolean logic expressions.  O( n log n) runtime @@ -122,7 +141,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator^(const T1& l, const T2& r)
    Boolean XOR operation (polygon set disjoint-union).  Accepts two objects that model polygon_90_set or one of its refinements.  @@ -132,7 +151,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_90_set_view operator-(const T1& l, const T2& r)
    Boolean SUBTRACT operation (polygon set difference).  Accepts two objects that model polygon_90_set or one of its refinements.  @@ -141,7 +160,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator|=(const T1& l, const T2& r)
    Same as operator|, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) @@ -149,7 +168,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(T1& l, const T2& r)
    Same as operator+, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) @@ -157,7 +176,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator&=(const T1& l, const T2& r)
    Same as operator&, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) @@ -165,7 +184,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator*=(T1& l, const T2& r)
    Same as operator*, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) @@ -173,7 +192,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator^=(const T1& l, const T2& r)
    Same as operator^, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) @@ -181,14 +200,14 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(T1& l, const T2& r)
    Same as operator-, but with self assignment, left operand must model polygon_90_set and not one of it's refinements.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T1>
    +
    template <typename T1>
    T1 operator+(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Note: returns @@ -197,7 +216,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1 operator-(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Note: returns @@ -206,7 +225,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Returns @@ -215,19 +234,19 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Returns reference to modified argument.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    +

    Functions

    - - +
    + + output_container_type, typename T>
    + void get_max_rectangles(output_container_type& output,
                            +const T& polygon_set) - - - - - - - - - - - - - +
              coord_type south, coord_type north) - - intersections. - intersections. - intersections. - intersections. - - - - intersections. - - - -
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& lvalue, const T2& rvalue)
    Eliminates overlaps in geometry and copies from an object that models polygon_90_set or any of its refinements into an object that @@ -236,7 +255,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    bool equivalence(const T1& lvalue, const T2& rvalue)
    Returns true if an object that models polygon_90_set or one of its refinements covers the exact same geometric regions as another object @@ -246,8 +265,8 @@ together.

    template <typename - output_container_type, typename T>
    - void get_rectangles(output_container_type& output,
    + output_container_type, typename T>
    + void get_rectangles(output_container_type& output,
                        const T& polygon_set)
    Output container is expected to be a standard container.  @@ -258,10 +277,9 @@ together.

    template <typename - output_container_type, typename T>
    - void get_max_rectangles(output_container_type& output,
    -                        - const T& polygon_set)
    Output container is expected to be a standard container.  Given an object that models polygon_90_set or one of its refinements finds all overlapping rectangles that are maximal in area and appends them to the @@ -269,13 +287,13 @@ together.

    template <typename - polygon_set_type>
    + polygon_set_type>
    void clear(polygon_set_type& polygon_set)
    Makes the object empty of geometry.
    template <typename - polygon_set_type>
    + polygon_set_type>
    bool empty(const polygon_set_type& polygon_set)
    Checks whether the object is empty of geometry.  Polygons that are completely covered by holes will result in empty returning true.  @@ -284,8 +302,8 @@ together.

    template <typename T, typename - rectangle_type>
    - bool extents(rectangle_type& extents_rectangle,
    + rectangle_type>
    + bool extents(rectangle_type& extents_rectangle,
                 const T& polygon_set)
    Computes bounding box of an object that models polygon_90_set and @@ -295,7 +313,7 @@ together.

    runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& polygon_set)
    Computes the area covered by geometry in an object that models polygon_90_set.  O( n log n) runtime complexity and O(n) memory wrt @@ -303,7 +321,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& interact(T1& a, const T2& b)
    Given an object that models polygon_90_set and an object that models polygon_90_set or one of its refinements, modifies a to retain only @@ -311,7 +329,7 @@ together.

    complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& self_intersect(T& polygon_set)
    Given an object that models polygon_90_set that has self overlapping regions, modifies the argument to contain only the regions of overlap.  @@ -319,7 +337,7 @@ together.

    intersections.
    template <typename T>
    +
    template <typename T>
    T& self_xor(T& polygon_set)
    Given an object that models polygon_90_set that has self overlapping regions, modifies the argument to contain only the regions that do not @@ -327,24 +345,24 @@ together.

    vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& polygon_set, unsigned_area_type bloating)
    Same as getting all the rectangles, bloating them and putting them back.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& bloat(T& polygon_set, orientation_2d orient,
    +
    template <typename T>
    + T& bloat(T& polygon_set, orientation_2d orient,
             unsigned_area_type bloating)
    Same as getting all the rectangles, bloating them and putting them back.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& bloat(T& polygon_set, orientation_2d orient,
    -         unsigned_area_type low_bloating,
    +
    template <typename T>
    + T& bloat(T& polygon_set, orientation_2d orient,
    +         unsigned_area_type low_bloating,
             unsigned_area_type high_bloating)
    Same as getting all the rectangles, bloating them and putting them @@ -352,22 +370,22 @@ together.

    + intersections.
    template <typename T>
    - T& bloat(T& polygon_set, direction_2d dir,
    +
    template <typename T>
    + T& bloat(T& polygon_set, direction_2d dir,
             unsigned_area_type bloating)
    Same as getting all the rectangles, bloating them and putting them back.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& bloat(T& polygon_set,
    +
    template <typename T>
    + T& bloat(T& polygon_set,
             unsigned_area_type - west_bloating,
    + west_bloating,
             unsigned_area_type - east_bloating,
    + east_bloating,
             unsigned_area_type - south_bloating,
    + south_bloating,
             unsigned_area_type north_bloating)
    Same as getting all the rectangles, bloating them and putting them @@ -375,15 +393,15 @@ together.

    + intersections.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& polygon_set, unsigned_area_type shrinking)
    Same as getting all the rectangles of the inverse, bloating them and overwriting the polygon set with the resulting regions then negating.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& shrink(T& polygon_set, orientation_2d orient,
    +
    template <typename T>
    + T& shrink(T& polygon_set, orientation_2d orient,
              unsigned_area_type shrinking)
    Same as getting all the rectangles of the inverse, bloating them and overwriting @@ -391,10 +409,10 @@ together.

    n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& shrink(T& polygon_set, orientation_2d orient,
    +
    template <typename T>
    + T& shrink(T& polygon_set, orientation_2d orient,
              unsigned_area_type - low_shrinking,
    + low_shrinking,
              unsigned_area_type high_shrinking)
    Same as getting all the rectangles of the inverse, bloating them and overwriting @@ -402,8 +420,8 @@ together.

    n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& shrink(T& polygon_set, direction_2d dir,
    +
    template <typename T>
    + T& shrink(T& polygon_set, direction_2d dir,
              unsigned_area_type shrinking)
    Same as getting all the rectangles of the inverse, bloating them and overwriting @@ -411,14 +429,14 @@ together.

    n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    - T& shrink(T& polygon_set,
    +
    template <typename T>
    + T& shrink(T& polygon_set,
              unsigned_area_type - west_shrinking,
    + west_shrinking,
              unsigned_area_type - east_shrinking,
    + east_shrinking,
              unsigned_area_type - south_shrinking,
    + south_shrinking,
              unsigned_area_type north_shrinking)
    Same as getting all the rectangles of the inverse, bloating them and overwriting @@ -427,23 +445,23 @@ together.

    template <typename T, typename - coord_type>
    + coord_type>
    T& resize(T& polygon_set, coord_type resizing)
    Same as bloat if resizing is positive, same as shrink if resizing is negative.
    template <typename T, typename - coord_type>
    - T& resize(polygon_set_type& polygon_set,
    + coord_type>
    + T& resize(polygon_set_type& polygon_set,
              coord_type west, coord_type east, -
              coord_type south, coord_type north)
    Same as bloat if resizing is positive, same as shrink if resizing is negative.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& grow_and(T& polygon_set, unsigned_area_type bloating)
    Same as bloating non-overlapping regions and then applying self intersect to retain only the overlaps introduced by the bloat.  O( @@ -451,8 +469,8 @@ T& grow_and(T& polygon_set, unsigned_area_type bloating)
    template <typename T>
    -T& grow_and(T& polygon_set, orientation_2d orient,
    +
    template <typename T>
    +T& grow_and(T& polygon_set, orientation_2d orient,
                unsigned_area_type bloating)
    Same as bloating non-overlapping regions and then applying self @@ -461,10 +479,10 @@ unsigned_area_type bloating)
    template <typename T>
    -T& grow_and(T& polygon_set, orientation_2d orient,
    +
    template <typename T>
    +T& grow_and(T& polygon_set, orientation_2d orient,
                -unsigned_area_type low_bloating,
    +unsigned_area_type low_bloating,
                unsigned_area_type high_bloating)
    Same as bloating non-overlapping regions and then applying self @@ -473,8 +491,8 @@ unsigned_area_type high_bloating)
    template <typename T>
    -T& grow_and(T& polygon_set, direction_2d dir,
    +
    template <typename T>
    +T& grow_and(T& polygon_set, direction_2d dir,
                unsigned_area_type bloating)
    Same as bloating non-overlapping regions and then applying self @@ -483,14 +501,14 @@ unsigned_area_type bloating)
    template <typename T>
    -T& grow_and(T& polygon_set,
    +
    template <typename T>
    +T& grow_and(T& polygon_set,
                -unsigned_area_type west_bloating,
    +unsigned_area_type west_bloating,
                -unsigned_area_type east_bloating,
    +unsigned_area_type east_bloating,
                -unsigned_area_type south_bloating,
    +unsigned_area_type south_bloating,
                unsigned_area_type north_bloating)
    Same as bloating non-overlapping regions and then applying self @@ -499,28 +517,28 @@ unsigned_area_type north_bloating)
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon_set, unsigned_area_type factor)
    Scales geometry up by unsigned factor.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon_set, unsigned_area_type factor)
    Scales geometry down by unsigned factor.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T, typename scaling_type>
    -T& scale(polygon_set_type& polygon_set,
    +
    template <typename T, typename scaling_type>
    +T& scale(polygon_set_type& polygon_set,
             const scaling_type& scaling)
    Scales geometry by applying scaling.scale() on all vertices.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T, typename coord_type>
    -T& move(T& polygon_set,
    +
    template <typename T, typename coord_type>
    +T& move(T& polygon_set,
            orientation_2d orient, coord_type displacement)
    Moves geometry by displacement amount in the orientation.    @@ -528,40 +546,40 @@ displacement)
    template <typename T, typename coord_type>
    -T& move(T& polygon_set, coord_type x_displacement,
    +
    template <typename T, typename coord_type>
    +T& move(T& polygon_set, coord_type x_displacement,
            coord_type y_displacement)
    Moves the geometry by x_dispacement in x and y_displacement in y.  Note: for consistency should be convolve(polygon_set, point).  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T, typename transformation_type>
    -T& transform(T& polygon_set,
    +
    template <typename T, typename transformation_type>
    +T& transform(T& polygon_set,
                 const transformation_type& transformation)
    Applies transformation.transform() on all vertices.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    template <typename T>
    -T& keep(T& polygon_set,
    -        unsigned_area_type min_area,
    -        unsigned_area_type max_area,
    -        unsigned_area_type min_width,
    -        unsigned_area_type max_width,
    -        unsigned_area_type min_height,
    +
    template <typename T>
    +T& keep(T& polygon_set,
    +        unsigned_area_type min_area,
    +        unsigned_area_type max_area,
    +        unsigned_area_type min_width,
    +        unsigned_area_type max_width,
    +        unsigned_area_type min_height,
            unsigned_area_type max_height)
    Retains only regions that satisfy the min/max criteria in the argument list.  Note: useful for visualization to cull too small polygons.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    +

    Polygon 90 Set Data Object

    -

    The polygon 90 set data type encapsulates the internal data format that +

    The polygon 90 set data type encapsulates the internal data format that serves as the input to the sweep-line algorithm that implements polygon-clipping boolean operations.  It also internally keeps track of whether that data has been sorted or scanned and maintains the invariant that when its flags @@ -572,15 +590,15 @@ above because of the invariants it can enforce which provide the opportunity to maintain the data is sorted form rather than going all the way out to polygons then resorting those vertices for a subsequent operation.

    The declaration of Polygon 90 Set Data is the following:

    -

    template <typename T>
    +

    template <typename T>
    class polygon_90_set_data;

    The class is parameterized on the coordinate data type.  Algorithms that benefit from knowledge of the invariants enforced by the class are implemented as member functions to provide them access to information about those invariants. 

    Member Functions

    - - +
    + @@ -591,9 +609,9 @@ invariants. 

    - + @@ -604,7 +622,7 @@ invariants. 

    @@ -612,33 +630,33 @@ t) +polygon_90_set_data(orientation_2d orient,
                        +const polygon_90_set_data& that) +polygon_90_set_data&
    operator=(const polygon_90_set_data& that)
    - @@ -652,8 +670,8 @@ void insert(const polygon_90_set_data& polygon_set) +polygon_90_set_data&
    +resize(coordinate_type west, coordinate_type east,
           coordinate_type south, coordinate_type north) @@ -835,14 +853,14 @@ polygon_90_set_data& scale_up(unsigned_area_type factor) +factor) 

    @@ -865,23 +883,23 @@ polygon_90_set_data&
    scale(const anisotropic_scale_factor<scal intersections. - + -
    polygon_90_set_data() Default constructor.  Scanning orientation defaults to HORIZONTAL Construct with scanning orientation.
    template <typename iT>
    - polygon_90_set_data(orientation_2d orient,
                        iT input_begin, iT - input_end)
    template <typename iT>
    + polygon_90_set_data(orientation_2d orient,
                        +iT input_begin, iT input_end)
    Construct with scanning orientation from an iterator range of insertable objects.
    -template <typename l, typename r, typename op>
    +template <typename l, typename r, typename op>
    polygon_90_set_data(const polygon_90_set_view<l,r,op>& t)
    Copy construct from a Boolean operator template.
    -polygon_90_set_data(orientation_2d orient,
                        const polygon_90_set_data& -that)
    Construct with scanning orientation and copy from another polygon set.
    -polygon_90_set_data&
    operator=(const polygon_90_set_data& that)
    Assignment from another polygon set, may change scanning orientation.
    -template <typename l, typename r, typename op>
    -polygon_90_set_data&
    operator=(const polygon_90_set_view<l, r, +template <typename l, typename r, typename op>
    +polygon_90_set_data&
    operator=(const polygon_90_set_view<l, r, op>& that)
    Assignment from a Boolean operator template.
    template <typename geometry_object>
    +
    template <typename geometry_object>
    polygon_90_set_data& operator=(const geometry_object& geo)
    Assignment from an insertable object.
    -template <typename iT>
    +template <typename iT>
    void insert(iT input_begin, iT input_end)
    Insert objects of an iterator range.  Linear wrt. inserted vertices.
    -template <typename geometry_type>
    -void insert(const geometry_type& geometry_object,
                bool is_hole +template <typename geometry_type>
    +void insert(const geometry_type& geometry_object,
                bool is_hole = false)
    Insert a geometry object, if is_hole is true then the inserted region is subtractive rather than additive.  Linear wrt. inserted @@ -661,7 +679,7 @@ void insert(const geometry_type& geometry_object,
      &nb
    -template <typename output_container>
    +template <typename output_container>
    void get(output_container& output) const
    Expects a standard container of geometry objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to objects @@ -674,7 +692,7 @@ void get(output_container& output) const
    -template <typename output_container>
    +template <typename output_container>
    void get_polygons(output_container& output) const
    Expects a standard container of polygon objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to polygons and @@ -685,7 +703,7 @@ void get_polygons(output_container& output) const
    -template <typename output_container>
    +template <typename output_container>
    void get_rectangles(output_container& output) const
    Expects a standard container of rectangle objects.  Will scan and eliminate overlaps.  Slices polygon set geometry to rectangles @@ -696,8 +714,8 @@ void get_rectangles(output_container& output) const
    -template <typename output_container>
    -void get_rectangles(output_container& output,
      orientation_2d +template <typename output_container>
    +void get_rectangles(output_container& output,
      orientation_2d slicing_orientation) const
    Expects a standard container of rectangle objects.  Will scan @@ -750,9 +768,9 @@ bool operator!=(const polygon_90_set_data& p) const
    -template <typename input_iterator_type>
    -void set(input_iterator_type input_begin,
             input_iterator_type input_end, -
             orientation_2d orient)
    +template <typename input_iterator_type>
    +void set(input_iterator_type input_begin,
             input_iterator_type input_end, +
             orientation_2d orient)
    Overwrite geometry in polygon set with insertable objects in the iterator range.  Also sets the scanning orientation to that @@ -760,7 +778,7 @@ void set(input_iterator_type input_begin,
        &nb
    -template <typename rectangle_type>
    +template <typename rectangle_type>
    bool extents(rectangle_type& extents_rectangle) const
    Given an object that models rectangle, scans and eliminates overlaps in the polygon set because subtractive regions may alter its extents @@ -770,12 +788,12 @@ bool extents(rectangle_type& extents_rectangle) const
    -polygon_90_set_data&
    -bloat(unsigned_area_type west_bloating,
    +polygon_90_set_data&
    +bloat(unsigned_area_type west_bloating,
          -unsigned_area_type east_bloating,
    +unsigned_area_type east_bloating,
          -unsigned_area_type south_bloating,
    +unsigned_area_type south_bloating,
          unsigned_area_type north_bloating)
    Scans to eliminate overlaps and subtractive regions.  Inserts @@ -786,12 +804,12 @@ unsigned_area_type north_bloating)
    -polygon_90_set_data&
    -shrink(unsigned_area_type west_shrinking,
    +polygon_90_set_data&
    +shrink(unsigned_area_type west_shrinking,
           -unsigned_area_type east_shrinking,
    +unsigned_area_type east_shrinking,
           -unsigned_area_type south_shrinking,
    +unsigned_area_type south_shrinking,
           unsigned_area_type north_shrinking)
    Scans to eliminate overlaps and subtractive regions.  Inserts @@ -804,24 +822,24 @@ unsigned_area_type north_shrinking)
    -polygon_90_set_data&
    -resize(coordinate_type west, coordinate_type east,
           coordinate_type south, coordinate_type north)
    Call bloat or shrink or shrink then bloat depending on whether the resizing values are positive or negative.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    -polygon_90_set_data& move(coordinate_type x_delta,
                              coordinate_type -y_delta)
    +polygon_90_set_data& move(coordinate_type x_delta,
                              +coordinate_type y_delta)
    Add x_delta to x values and y_delta to y values of vertices stored within the polygon set.  Linear wrt. vertices.
    -template <typename transformation_type>
    -polygon_90_set_data&
    transform(const transformation_type& transformation)
    +template <typename transformation_type>
    +polygon_90_set_data&
    transform(const transformation_type& transformation)
    Applies transformation.transform() on vertices stored within the polygon set.  Linear wrt. vertices.

    polygon_90_set_data& scale_down(unsigned_area_type -factor) 

    Scales vertices stored within the polygon set down by factor.  Linear wrt. vertices.
    -template <typename scaling_type>
    -polygon_90_set_data&
    scale(const anisotropic_scale_factor<scaling_type>& +template <typename scaling_type>
    +polygon_90_set_data&
    scale(const anisotropic_scale_factor<scaling_type>& f)
    Scales vertices stored within the polygon set by applying f.scale().  Linear wrt. vertices.
    polygon_90_set_data&
    interact(const polygon_90_set_data& that)
    polygon_90_set_data&
    interact(const polygon_90_set_data& that)
    Retain only regions that touch or overlap regions in argument.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections.
    -
    +
      - +
    - + - + @@ -894,6 +912,6 @@ polygon_90_set_data&
    scale(const anisotropic_scale_factor<scal http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_90_with_holes_concept.htm b/doc/gtl_polygon_90_with_holes_concept.htm index 914d907..5cfb22f 100644 --- a/doc/gtl_polygon_90_with_holes_concept.htm +++ b/doc/gtl_polygon_90_with_holes_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon 90 With Holes Concept - - +-->Boost Polygon Library: Polygon 90 With Holes Concept + + + +
    +
    - + +
    -
    +

    Polygon 90 With Holes Concept

    -

    The polygon_90_with_holes concept tag is +

    The polygon_90_with_holes concept tag is polygon_90_with_holes_concept

    To register a user defined type as a model of polygon_90_with_holes concept, specialize the geometry concept meta-function for that type.  In the example below CPolygon90WithHoles is registered as a model of -polygon_90_with_holes  concept.

    -template <>
    -struct geometry_concept<CPolygon90WithHoles> { typedef polygon_90_with_holes_concept type; };

    +polygon_90_with_holes  concept.

    +template <>
    +struct geometry_concept<CPolygon90WithHoles> { typedef polygon_90_with_holes_concept type; };

    The semantic of a polygon_90_with_holes is a polygon_90 that it can provide iterators over holes that are also polygon_90.  A mutable polygon_90_with_holes must also be able to set its geometry based on an interator range over polygon_90 holes.  There is no convention of -winding of holes enforced within the library.

    +winding of holes enforced within the library.

    Below is shown the default polygon with holes traits.  Specialization of these traits is required for types that don't -conform to the default behavior.

    template <typename -T, typename enable = void>
    -struct polygon_with_holes_traits {
    +conform to the default behavior.

    template <typename +T, typename enable = void>
    +struct polygon_with_holes_traits {
         typedef typename T::iterator_holes_type -iterator_holes_type;
    -     typedef typename T::hole_type hole_type;
    +iterator_holes_type;
    +     typedef typename T::hole_type hole_type;
         static inline iterator_holes_type begin_holes(const T& -t) {
    -          return t.begin_holes();
    -     }
    +t) {
    +          return t.begin_holes();
    +     }
         static inline iterator_holes_type end_holes(const T& t) -{
    -          return t.end_holes();
    -     }
    -     static inline unsigned int size_holes(const T& t) {
    -          return t.size_holes();
    -     }
    +{
    +          return t.end_holes();
    +     }
    +     static inline unsigned int size_holes(const T& t) {
    +          return t.size_holes();
    +     }
    };

    -

    template <typename T, typename enable = void>
    -struct polygon_with_holes_mutable_traits {
    -     template <typename iT>
    +

    template <typename T, typename enable = void>
    +struct polygon_with_holes_mutable_traits {
    +     template <typename iT>
         static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
    +inputEnd) {
              t.set_holes(inputBegin, -inputEnd);
    -          return t;
    -     }
    +inputEnd);
    +          return t;
    +     }
    };

    An object that is a model of polygon_90_with_holes_concept can be viewed as a model of any of its refinements if it is determined at runtime to conform to the restriction of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<rectangle_concept>(polygon_90_with_holes_object)
    +

    view_as<rectangle_concept>(polygon_90_with_holes_object)
    view_as<polygon_90_concept>(polygon_90_with_holes_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - - - - - + -
    template <typename T>
    compact_iterator_type begin_compact(const T& polygon)
    Expects a model of polygon_90.  Returns the begin iterator over the range of coordinates that correspond to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    compact_iterator_type end_compact(const T& polygon)
    Expects a model of polygon_90.  Returns the end iterator over the range of coordinates that correspond to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon_90_with_holes.  @@ -140,7 +159,7 @@ specified in its template parameter.

    vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon_90_with_holes.  @@ -148,7 +167,7 @@ specified in its template parameter.

    vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type begin_holes(const T& polygon)
    Expects a model of polygon_90_with_holes.  @@ -156,7 +175,7 @@ specified in its template parameter.

    to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type end_holes(const T& polygon)
    Expects a model of polygon_90_with_holes.  @@ -165,7 +184,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_compact(T& polygon, iterator b, iterator e)
    Expects a model of polygon_90_with_holes.   @@ -174,7 +193,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon_90_with_holes.   @@ -184,14 +203,14 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_holes(T& polygon, iterator b, iterator e)
    Expects a model of polygon_90_with_holes.   Sets the polygon holes to the hole data range [b,e)
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the outer shell of the polygon_90_with_holes.  Does not include sizes @@ -199,7 +218,7 @@ specified in its template parameter.

    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon_90_with_holes or one of its refinements into left object @@ -207,8 +226,8 @@ specified in its template parameter.

    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon_90_with_holes and an object that models @@ -219,86 +238,85 @@ specified in its template parameter.

    the polygon or one of its holes.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon_90_with_holes.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon_90_with_holes and returns true.  Returns false and leaves bbox unchanged if polygon is empty.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& polygon)
    Returns the area of an object that models polygon_90_with_holes including subtracting the area of its holes from the area of the outer shell polygon.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon_90_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
    template <typename T>
    +
    template <typename T>
    coordinate_difference perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon_90, including the perimeters of the holes.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Also applies transform() on the holes of the polygon.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up outer shell and holes of an object that models polygon_90 by unsigned factor.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down outer shell and holes of an object that models polygon_90 by unsigned factor.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales outer shell and holes of an object that models polygon_90 by floating point factor.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon_90 .
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with the outer shell and holes of an object that models polygon_90_with_holes.
    +

    Polygon 90 With Holes Data

    -

    The library provides a model of polygon 90 with holes concept declared +

    The library provides a model of polygon 90 with holes concept declared template<typename T> polygon_90_with_holes_data where T is the coordinate type.

    @@ -307,8 +325,8 @@ needed and is available to the library user who finds it convenient to use a library polygon data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -343,12 +361,12 @@ implemented to be convenient to use with the library traits.

    +
    operator=(const polygon_90_with_holes_data& that) +
    operator=(const T2& that) const @@ -396,14 +414,14 @@ implemented to be convenient to use with the library traits.

    +
    void set(iT begin_points, iT end_points) +
    void set_compact(iT begin_coords, iT end_coords) +
    void set_holes(iT begin_holes, iT end_choless) -
    geometry_type polygon_90_with_holes_concept
    polygon_90_with_holes_data& -
    operator=
    (const polygon_90_with_holes_data& that)
    Assignment operator.
    template <typename T2> polygon_90_with_holes_data&  -
    operator=
    (const T2& that) const
    Assign from an object that is a model of polygon 90 with holes.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points.  No check is performed to ensure the points describe a Manhattan figure, every other x and y value of the points is used to initialize the polygon.
    template <typename iT>  -
    void set_compact(iT begin_coords, iT end_coords)
    Sets the polygon to the iterator range of coordinates.  These coordinates correspond to the x values of vertical edges and y values of horizontal edges.  It is expected that the sequence start with an x @@ -411,24 +429,24 @@ implemented to be convenient to use with the library traits.

    template <typename iT>  -
    void set_holes(iT begin_holes, iT end_choless)
    Sets the polygon holes the iterator range of hole polygons.  These polygons in the input range may be either polygon_90_data or polygon_90_with_holes_data or any type that provides begin_compact and end_compact member functions.
    -
    +
      - +
    - + - + @@ -441,6 +459,6 @@ implemented to be convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_concept.htm b/doc/gtl_polygon_concept.htm index 11ead5f..57ac5c0 100644 --- a/doc/gtl_polygon_concept.htm +++ b/doc/gtl_polygon_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon Concept - - +-->Boost Polygon Library: Polygon Concept + + + +
    +
    - + +
    -
    +

    Polygon Concept

    -

    The polygon concept tag is +

    The polygon concept tag is polygon_concept

    To register a user defined type as a model of polygon concept, specialize the geometry concept meta-function for that type.  In the example below CPolygon is registered as a model of -polygon  concept.

    -template <>
    -struct geometry_concept<CPolygon> { typedef polygon_concept type; };

    +polygon  concept.

    +template <>
    +struct geometry_concept<CPolygon> { typedef polygon_concept type; };

    The semantic of a polygon is that it can provide iterators over the points that represent its vertices.  It is acceptable to have the last edge explict with the first and last point equal to each other or @@ -79,53 +98,53 @@ range over such points.  A std::vector<point_data<int> > or std > could be made models of polygon_concept by simply providing access to their iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

    +require that those objects provide a default constructor.

    Below is shown the default polygon traits.  Specialization of these traits is required for types that don't conform to the default behavior.  Note that these same traits are also used by several other polygon concepts through SFINE enable template parameter.  The SFINE enable parameter also allows the library to provide default specialization that -work for any object that models the 90 degree polygon concepts.

    -template <typename T, typename enable = gtl_yes>
    -struct polygon_traits {};
    -
    -template <typename T>
    -struct polygon_traits<T,
    -  typename gtl_or_4<
    +work for any object that models the 90 degree polygon concepts.

    +template <typename T, typename enable = gtl_yes>
    +struct polygon_traits {};
    +
    +template <typename T>
    +struct polygon_traits<T,
    +  typename gtl_or_4<
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
    +polygon_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
    +polygon_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type,
    +polygon_with_holes_concept>::type,
        typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type
    -  >::type> {
    -     typedef typename T::coordinate_type coordinate_type;
    -     typedef typename T::iterator_type iterator_type;
    -     typedef typename T::point_type point_type;
    -     static inline iterator_type begin_points(const T& t) {
    -          return t.begin();
    -     }
    -     static inline iterator_type end_points(const T& t) {
    -          return t.end();
    -     }
    -     static inline unsigned int size(const T& t) {
    -          return t.size();
    -     }
    -     static inline winding_direction winding(const T& t) {
    -          return unknown_winding;
    -     }
    +polygon_with_holes_concept>::type
    +  >::type> {
    +     typedef typename T::coordinate_type coordinate_type;
    +     typedef typename T::iterator_type iterator_type;
    +     typedef typename T::point_type point_type;
    +     static inline iterator_type begin_points(const T& t) {
    +          return t.begin();
    +     }
    +     static inline iterator_type end_points(const T& t) {
    +          return t.end();
    +     }
    +     static inline unsigned int size(const T& t) {
    +          return t.size();
    +     }
    +     static inline winding_direction winding(const T& t) {
    +          return unknown_winding;
    +     }
    };

    -

    template <typename T, typename enable = void>
    -struct polygon_mutable_traits {
    -     template <typename iT>
    +

    template <typename T, typename enable = void>
    +struct polygon_mutable_traits {
    +     template <typename iT>
         static inline T& set_points(T& t, iT input_begin, iT -input_end) {
    +input_end) {
              t.set(input_begin, -input_end);
    -          return t;
    -     }
    +input_end);
    +          return t;
    +     }
    };

    Example code custom_polygon.cpp demonstrates mapping a @@ -135,23 +154,23 @@ polygon_concept can be viewed as a model of any of its refinements if it is determined at runtime to conform to the restriction of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<rectangle_concept>(polygon_object)
    -view_as<polygon_90_concept>(polygon_object)
    +

    view_as<rectangle_concept>(polygon_object)
    +view_as<polygon_90_concept>(polygon_object)
    view_as<polygon_45_concept>(polygon_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - + -
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon.  Returns the begin iterator over the range of points that correspond to vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon.  Returns the end iterator over the range of points that correspond to @@ -159,29 +178,29 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon.   Sets the polygon to the point data range [b,e) that corresponds to vertices of a manhattan polygon.
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the polygon.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon into left object that models polygon.
    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon and an object that models @@ -191,84 +210,83 @@ specified in its template parameter.

    the polygon.  Linear wrt. vertices.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon.  Linear wrt. vertices.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon and returns true.  Returns false and leaves bbox unchanged if polygon is empty.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    area_type area(const T& polygon)
    Returns the area of an object that models polygon.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity depends upon winding trait.
    template <typename T>
    +
    template <typename T>
    coordinate_distance perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon.  Linear wrt. vertices.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up coordinate of an object that models polygon by unsigned factor.  Linear wrt. vertices.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down coordinates of an object that models polygon by unsigned factor.  Linear wrt. vertices.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales coordinates of an object that models polygon by floating point factor.  Linear wrt. vertices.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon .  Linear wrt. vertices.
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with vertices of an object that models polygon.  Linear wrt. vertices.
    +

    Polygon Data

    -

    The library provides a model of polygon concept declared +

    The library provides a model of polygon concept declared template<typename T> polygon_data where T is the coordinate type.

    This data type is used internally when a polygon is needed and is available @@ -279,8 +297,8 @@ convenient to use with the library traits.

    demonstrates using the library provided polygon data types and functions

    Members

    - - +
    + @@ -308,7 +326,7 @@ demonstrates using +
    polygon_data& operator=(const T2& that) const @@ -328,21 +346,21 @@ demonstrates using +
    void set(iT begin_points, iT end_points) -
    geometry_type polygon_concept
    template <typename T2>  -
    polygon_data& operator=(const T2& that) const
    Assign from an object that is a model of polygon.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points. 
    -
    +
      - +
    - + - + @@ -355,6 +373,6 @@ demonstrates using http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm index 75ee77e..42a534f 100644 --- a/doc/gtl_polygon_set_concept.htm +++ b/doc/gtl_polygon_set_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon Set Concept - - +-->Boost Polygon Library: Polygon Set Concept + + + +
    - + +
    -
    +

    Polygon Set Concept

    -

    The polygon_set concept tag is +

    The polygon_set concept tag is polygon_set_concept

    The semantic of a polygon_set is zero or more @@ -69,9 +88,14 @@ geometry regions.  A Polygon Set Concept may be defined with floating point coordinates, but a snap rounding distance of one integer unit will still be applied, furthermore, geometry outside the domain where one integer unit is sufficient to provide robustness may lead to undefined behavior in algorithms.  -It is recommended to use 32-bit integer coordinates for robust operations. - -

    Users are recommended to use std::vector and std::list of user defined polygons +It is recommended to use integer coordinates for robust operations.  In the +case that data represented contains only Manhattan geometry a runtime check will +default to the Manhattan algorithm.  The results of which are identical to +what the general algorithm would do, but obtained more efficiently.  In the +case that the data represented contains only Manhattan and 45-degree geometry a +runtime check will default to the faster 45-degree algorithm.  The results +of which may differ slight from what the general algorithm would do because +non-integer intersections will be handled differently.

    Users are recommended to use std::vector and std::list of user defined polygons or library provided polygon_set_data<coordinate_type> objects.  Lists and vectors of models of polygon_concept or polygon_with_holes_concept are automatically models of polygon_set_concept.

    Example code custom_polygon_set.cpp @@ -82,7 +106,7 @@ polygon_90_set_concept or polygon_45_set_concept if it is determined at runtime to conform to the restrictions of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<polygon_90_set_concept>(polygon_set_object)
    +

    view_as<polygon_90_set_concept>(polygon_set_object)
    view_as<polygon_45_set_concept>(polygon_set_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in @@ -97,10 +121,10 @@ constructor and assignment operator.  The operator template exists to eliminate temp copies of intermediate results when Boolean operators are chained together.

    Operators are declared inside the namespace boost::polygon::operators.

    - - +
    + - -
    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator|(const T1& l, const T2& r)
    Boolean OR operation (polygon set union).  Accepts two objects that model polygon_set or one of its refinements.  Returns an @@ -111,7 +135,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator+(const T1& l, const T2& r)
    Same as operator|.  The plus sign is also used for OR operations in Boolean logic expressions.  Expected n log n runtime, @@ -119,7 +143,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator&(const T1& l, const T2& r)
    Boolean AND operation (polygon set intersection).  Accepts two objects that model polygon_set or one of its refinements.  Expected @@ -128,7 +152,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator*(const T1& l, const T2& r)
    Same as operator&.  The multiplication symbol is also used for AND operations in Boolean logic expressions.  Expected n log n @@ -136,7 +160,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator^(const T1& l, const T2& r)
    Boolean XOR operation (polygon set disjoint-union).  Accepts two objects that model polygon_set or one of its refinements.  @@ -145,7 +169,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    polygon_set_view operator-(const T1& l, const T2& r)
    Boolean SUBTRACT operation (polygon set difference).  Accepts two objects that model polygon_set or one of its refinements.  @@ -154,7 +178,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator|=(const T1& l, const T2& r)
    Same as operator|, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n @@ -162,7 +186,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(T1& l, const T2& r)
    Same as operator+, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n @@ -170,7 +194,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator&=(const T1& l, const T2& r)
    Same as operator&, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n @@ -178,7 +202,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator*=(T1& l, const T2& r)
    Same as operator*, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n @@ -186,7 +210,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator^=(const T1& l, const T2& r)
    Same as operator^, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n @@ -194,14 +218,14 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(T1& l, const T2& r)
    Same as operator-, but with self assignment, left operand must model polygon_set and not one of it's refinements.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    template <typename T1>
    +
    template <typename T1>
    T1 operator+(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Note: returns @@ -210,7 +234,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1 operator-(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Note: returns @@ -219,7 +243,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator+=(const T1&, coordinate_type bloating)
    Performs resize operation, inflating by bloating ammount.  If negative the result is a shrink instead of bloat.  Returns @@ -228,19 +252,19 @@ together.

    template <typename T1, typename - T2>
    + T2>
    T1& operator-=(const T1&, coordinate_type shrinking)
    Performs resize operation, deflating by bloating ammount.  If negative the result is a bloat instead of shrink.  Returns reference to modified argument.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    +

    Functions

    - - +
    + + const T& polygon_set,
    +                    +orientation_2d orient) - - - - - - - - - - intersections. - -
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& lvalue, const T2& rvalue)
    Eliminates overlaps in geometry and copies from an object that models polygon_set or any of its refinements into an object that @@ -249,7 +273,7 @@ together.

    template <typename T1, typename - T2>
    + T2>
    bool equivalence(const T1& lvalue, const T2& rvalue)
    Returns true if an object that models polygon_set or one of its refinements covers the exact same geometric regions as another object @@ -259,8 +283,8 @@ together.

    template <typename - output_container_type, typename T>
    - void get_trapezoids(output_container_type& output,
    + output_container_type, typename T>
    + void get_trapezoids(output_container_type& output,
                        const T& polygon_set)
    Output container is expected to be a standard container.  @@ -273,10 +297,12 @@ together.

    template <typename - output_container_type, typename T>
    - void get_trapezoids(output_container_type& output,
    + output_container_type, typename T>
    + void get_trapezoids(output_container_type& output,
                        - const T& polygon_set,
                        orientation_2d orient)
    Output container is expected to be a standard container.  Slices geometry of an object that models polygon_set or one of its refinements into non overlapping trapezoids along a the specified slicing @@ -287,13 +313,13 @@ together.

    template <typename - polygon_set_type>
    + polygon_set_type>
    void clear(polygon_set_type& polygon_set)
    Makes the object empty of geometry.
    template <typename - polygon_set_type>
    + polygon_set_type>
    bool empty(const polygon_set_type& polygon_set)
    Checks whether the object is empty of geometry.  Polygons that are completely covered by holes will result in empty returning true.  @@ -302,8 +328,8 @@ together.

    template <typename T, typename - rectangle_type>
    - bool extents(rectangle_type& extents_rectangle,
    + rectangle_type>
    + bool extents(rectangle_type& extents_rectangle,
                 const T& polygon_set)
    Computes bounding box of an object that models polygon_set and @@ -314,21 +340,21 @@ together.

    intersections.
    template <typename T>
    +
    template <typename T>
    area_type area(const T& polygon_set)
    Computes the area covered by geometry in an object that models polygon_set.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& polygon_set, unsigned_area_type bloating)
    Same as getting all the polygons, bloating them and putting them back.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& polygon_set, unsigned_area_type shrinking)
    Same as getting all the polygons, shrinking them and overwriting the polygon set with the resulting regions.  Expected n log n @@ -336,10 +362,10 @@ together.

    template <typename T, typename - coord_type>
    - T& resize(T& polygon_set, coord_type resizing,
    + coord_type>
    + T& resize(T& polygon_set, coord_type resizing,
              - bool corner_fill_arc = false,
              + bool corner_fill_arc = false,
              unsigned int num_circle_segments = 0)
    Same as bloat if resizing is positive, same as shrink if resizing is negative.  Original topology at acute angle vertices is preserved @@ -350,31 +376,20 @@ together.

    runtime wrt. vertices + intersections.
    template <typename T, typename - coord_type>
    - T& simplify(T& polygon_set, distance_type - threshold)
    Simplify the polygon set by removing vertices that lie - within threshold distance of the line segment that - connects the two adjacent points in the polygon.  - Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon_set, unsigned_area_type factor)
    Scales geometry up by unsigned factor.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon_set, unsigned_area_type factor)
    Scales geometry down by unsigned factor.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    template <typename T, typename transformation_type>
    -T& transform(T& polygon_set,
    +
    template <typename T, typename transformation_type>
    +T& transform(T& polygon_set,
                 const transformation_type& transformation)
    Applies transformation.transform() on all vertices.  Expected n @@ -382,24 +397,24 @@ transformation_type& transformation)
    template <typename T>
    -T& keep(T& polygon_set,
    -        unsigned_area_type min_area,
    -        unsigned_area_type max_area,
    -        unsigned_area_type min_width,
    -        unsigned_area_type max_width,
    -        unsigned_area_type min_height,
    +
    template <typename T>
    +T& keep(T& polygon_set,
    +        unsigned_area_type min_area,
    +        unsigned_area_type max_area,
    +        unsigned_area_type min_width,
    +        unsigned_area_type max_width,
    +        unsigned_area_type min_height,
            unsigned_area_type max_height)
    Retains only regions that satisfy the min/max criteria in the argument list.  Note: useful for visualization to cull too small polygons.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    +

    Polygon Set Data Object

    -

    The polygon set data type encapsulates the internal data format that +

    The polygon set data type encapsulates the internal data format that serves as the input to the sweep-line algorithm that implements polygon-clipping Boolean operations.  It also internally keeps track of whether that data has been sorted or scanned and maintains the invariant that when its flags @@ -410,7 +425,7 @@ above because of the invariants it can enforce which provide the opportunity to maintain the data is sorted form rather than going all the way out to polygons then resorting those vertices for a subsequent operation.

    The declaration of Polygon Set Data is the following:

    -

    template <typename T>
    +

    template <typename T>
    class polygon_set_data;

    The class is parameterized on the coordinate data type.  Algorithms that benefit from knowledge of the invariants enforced by the class are implemented @@ -420,13 +435,13 @@ invariants. 

    demonstrates using the library provided polygon set data types and functions

    Member Functions

    - - +
    + - +polygon_set_data&
    operator=(const polygon_set_data& that)
    - @@ -479,8 +494,8 @@ void insert(const polygon_set_data& polygon_set) -
    polygon_set_data() Default constructor.
    template <typename iT>
    +
    template <typename iT>
    polygon_set_data(iT input_begin, iT input_end)
    Construct with scanning orientation from an iterator range of @@ -439,33 +454,33 @@ demonstrates using
    -template <typename l, typename r, typename op>
    +template <typename l, typename r, typename op>
    polygon_set_data(const polygon_set_view<l,r,op>& t)
    Copy construct from a Boolean operator template.
    -polygon_set_data&
    operator=(const polygon_set_data& that)
    Assignment from another polygon set, may change scanning orientation.
    -template <typename l, typename r, typename op>
    -polygon_set_data&
    operator=(const polygon_set_view<l, r, +template <typename l, typename r, typename op>
    +polygon_set_data&
    operator=(const polygon_set_view<l, r, op>& that)
    Assignment from a Boolean operator template.
    template <typename geometry_object>
    +
    template <typename geometry_object>
    polygon_set_data& operator=(const geometry_object& geo)
    Assignment from an insertable object.
    -template <typename iT>
    +template <typename iT>
    void insert(iT input_begin, iT input_end)
    Insert objects of an iterator range.  Linear wrt vertices inserted.
    -template <typename geometry_type>
    -void insert(const geometry_type& geometry_object,
                bool is_hole +template <typename geometry_type>
    +void insert(const geometry_type& geometry_object,
                bool is_hole = false)
    Insert a geometry object, if is_hole is true then the inserted region is subtractive rather than additive.  Linear wrt vertices @@ -488,7 +503,7 @@ void insert(const geometry_type& geometry_object,
      &nb
    -template <typename output_container>
    +template <typename output_container>
    void get(output_container& output) const
    Expects a standard container of polygons objects.  Will scan and eliminate overlaps.  Converts polygon set geometry to objects @@ -505,7 +520,7 @@ void get(output_container& output) const
    -template <typename output_container>
    +template <typename output_container>
    void get_trapezoids(output_container& output) const
    Expects a standard container of polygon objects.  Will scan and eliminate overlaps.  Slices polygon set geometry to trapezoids @@ -515,8 +530,8 @@ void get_trapezoids(output_container& output) const
    -template <typename output_container>
    -void get_trapezoids(output_container& output,
      orientation_2d +template <typename output_container>
    +void get_trapezoids(output_container& output,
      orientation_2d slicing_orientation) const
    Expects a standard container of polygon objects.  Will scan @@ -563,15 +578,15 @@ bool operator!=(const polygon_set_data& p) const
    -template <typename input_iterator_type>
    -void set(input_iterator_type input_begin,
             input_iterator_type input_end)
    +template <typename input_iterator_type>
    +void set(input_iterator_type input_begin,
             input_iterator_type input_end)
    Overwrite geometry in polygon set with insertable objects in the iterator range.
    -template <typename rectangle_type>
    +template <typename rectangle_type>
    bool extents(rectangle_type& extents_rectangle) const
    Given an object that models rectangle, scans and eliminates overlaps in the polygon set because subtractive regions may alter its extents @@ -581,9 +596,9 @@ bool extents(rectangle_type& extents_rectangle) const
    -polygon_set_data&
    -resize(coord_type resizing,
    -        bool corner_fill_arc = false,
           +polygon_set_data&
    +resize(coord_type resizing,
    +        bool corner_fill_arc = false,
           unsigned int num_circle_segments = 0)
    Inflates if resizing is positive, deflates if resizing is negative.  Original topology at acute angle vertices is preserved @@ -597,8 +612,8 @@ polygon_set_data&
    -template <typename transformation_type>
    -polygon_set_data&
    transform(const transformation_type& transformation)
    +template <typename transformation_type>
    +polygon_set_data&
    transform(const transformation_type& transformation)
    Applies transformation.transform() on vertices stored within the polygon set.  Expected n log n runtime, worst case quadratic @@ -621,25 +636,25 @@ factor) 
    -template <typename scaling_type>
    -polygon_set_data&
    scale(const scaling_type& +template <typename scaling_type>
    +polygon_set_data&
    scale(const scaling_type& f)
    Scales vertices stored within the polygon set by applying f.scale().  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    -
    +
      - +
    - + - + @@ -652,6 +667,6 @@ polygon_set_data&
    scale(const scaling_type& http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - +
    \ No newline at end of file diff --git a/doc/gtl_polygon_with_holes_concept.htm b/doc/gtl_polygon_with_holes_concept.htm index a205648..f723452 100644 --- a/doc/gtl_polygon_with_holes_concept.htm +++ b/doc/gtl_polygon_with_holes_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Polygon With Holes Concept - - +-->Boost Polygon Library: Polygon With Holes Concept + + + +
    +
    - + +
    -
    +

    Polygon With Holes Concept

    -

    The polygon_with_holes concept tag is +

    The polygon_with_holes concept tag is polygon_with_holes_concept

    To register a user defined type as a model of polygon_with_holes concept, specialize the geometry concept meta-function for that type.  In the example below -CPolygonWithHoles is registered as a model of polygon_with_holes  concept.

    -template <>
    -struct geometry_concept<CPolygonWithHoles> { typedef polygon_with_holes_concept type; };

    +CPolygonWithHoles is registered as a model of polygon_with_holes  concept.

    +template <>
    +struct geometry_concept<CPolygonWithHoles> { typedef polygon_with_holes_concept type; };

    The semantic of a polygon_with_holes is a polygon that it can provide iterators over holes that are also polygon.  A mutable polygon_with_holes must also be able to set its geometry based on an interator range over polygon holes.  There is no convention of winding of holes -enforced within the library.

    +enforced within the library.

    Below is shown the default polygon with holes traits.  Specialization of these traits is required for types that don't conform to the default behavior.  Note, these traits are used by all -polygon with holes concepts.

    template <typename -T, typename enable = void>
    -struct polygon_with_holes_traits {
    +polygon with holes concepts.

    template <typename +T, typename enable = void>
    +struct polygon_with_holes_traits {
         typedef typename T::iterator_holes_type -iterator_holes_type;
    -     typedef typename T::hole_type hole_type;
    +iterator_holes_type;
    +     typedef typename T::hole_type hole_type;
         static inline iterator_holes_type begin_holes(const T& -t) {
    -          return t.begin_holes();
    -     }
    +t) {
    +          return t.begin_holes();
    +     }
         static inline iterator_holes_type end_holes(const T& t) -{
    -          return t.end_holes();
    -     }
    -     static inline unsigned int size_holes(const T& t) {
    -          return t.size_holes();
    -     }
    +{
    +          return t.end_holes();
    +     }
    +     static inline unsigned int size_holes(const T& t) {
    +          return t.size_holes();
    +     }
    };

    -

    template <typename T, typename enable = void>
    -struct polygon_with_holes_mutable_traits {
    -     template <typename iT>
    +

    template <typename T, typename enable = void>
    +struct polygon_with_holes_mutable_traits {
    +     template <typename iT>
         static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
    +inputEnd) {
              t.set_holes(inputBegin, -inputEnd);
    -          return t;
    -     }
    +inputEnd);
    +          return t;
    +     }
    };

    An object that is a model of polygon_with_holes_concept can be viewed as a model of any of its refinements if it is determined at runtime to conform to the restriction of those concepts.  This concept casting is accomplished through the view_as<>() function.

    -

    view_as<rectangle_concept>(polygon_with_holes_object)
    -view_as<polygon_90_concept>(polygon_with_holes_object)
    -view_as<polygon_90_with_holes_concept>(polygon_with_holes_object)
    -view_as<polygon_45_concept>(polygon_with_holes_object)
    -view_as<polygon_45_with_holes_concept>(polygon_with_holes_object)
    +

    view_as<rectangle_concept>(polygon_with_holes_object)
    +view_as<polygon_90_concept>(polygon_with_holes_object)
    +view_as<polygon_90_with_holes_concept>(polygon_with_holes_object)
    +view_as<polygon_45_concept>(polygon_with_holes_object)
    +view_as<polygon_45_with_holes_concept>(polygon_with_holes_object)
    view_as<polygon_concept>(polygon_with_holes_object)

    The return value of view_as<>() can be passed into any interface that expects an object of the conceptual type specified in its template parameter.

    Functions

    - - -
    template <typename T>
    + + + - - - - - - - - - - - - - + -
    template <typename T>
    point_iterator_type begin_points(const T& polygon)
    Expects a model of polygon_with_holes.  Returns the begin iterator over the range of points that correspond to vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    point_iterator_type end_points(const T& polygon)
    Expects a model of polygon_with_holes.  Returns the end iterator over the range of points that correspond to vertices of the polygon.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type begin_holes(const T& polygon)
    Expects a model of polygon_with_holes.  Returns the begin iterator over the range of coordinates that correspond to horizontal and vertical edges.
    template <typename T>
    +
    template <typename T>
    hole_iterator_type end_holes(const T& polygon)
    Expects a model of polygon_with_holes.  Returns the end iterator over the range of coordinates that correspond @@ -152,7 +171,7 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_points(T& polygon, iterator b, iterator e)
    Expects a model of polygon_with_holes.   Sets the polygon to the point data range [b,e) that corresponds to @@ -160,13 +179,13 @@ specified in its template parameter.

    template <typename T, typename - iterator>
    + iterator>
    void set_holes(T& polygon, iterator b, iterator e)
    Expects a model of polygon_with_holes.   Sets the polygon holes to the hole data range [b,e)
    template <typename T>
    +
    template <typename T>
    unsigned int size(const T& polygon)
    Returns the number of edges in the outer shell of the polygon_with_holes.  Does not include sizes of @@ -174,7 +193,7 @@ specified in its template parameter.

    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models polygon_with_holes or one of its refinements into left object @@ -182,8 +201,8 @@ specified in its template parameter.

    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models polygon_with_holes and an object that models @@ -194,86 +213,85 @@ specified in its template parameter.

    the polygon or one of its holes.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& polygon)
    Sets object that models point to the center point of the bounding box of an object that models polygon_with_holes.
    template <typename T, - typename rectangle_type>
    + typename rectangle_type>
    bool extents(rectangle_type& bbox, const T& polygon)
    Sets object that models rectangle to the bounding box of an object that models polygon_with_holes and returns true.  Returns false and leaves bbox unchanged if polygon is empty.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& polygon)
    Returns the area of an object that models polygon_with_holes including subtracting the area of its holes from the area of the outer shell polygon.
    template <typename T>
    +
    template <typename T>
    direction_1d winding(const T& polygon)
    Returns the winding direction of an object that models polygon_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
    template <typename T>
    +
    template <typename T>
    coordinate_difference perimeter(const T& polygon)
    Returns the perimeter length of an object that models polygon, including the perimeters of the holes.
    template <typename T, - typename transform_type>
    + typename transform_type>
    T& transform(T& polygon, const transform_type&)
    Applies transform() on the vertices of polygon and sets the polygon to that described by the result of transforming its vertices.  Also applies transform() on the holes of the polygon.
    template <typename T>
    +
    template <typename T>
    T& scale_up(T& polygon, unsigned_area_type factor)
    Scales up outer shell and holes of an object that models polygon by unsigned factor.
    template <typename T>
    +
    template <typename T>
    T& scale_down(T& polygon, unsigned_area_type factor)
    Scales down outer shell and holes of an object that models polygon by unsigned factor.
    template <typename T, scaling_type>
    +
    template <typename T, scaling_type>
    T& scale(T& rectangle, double scaling)
    Scales outer shell and holes of an object that models polygon by floating point factor.
    template <typename T>
    - T& move(T& polygon, orientation_2d,
    +
    template <typename T>
    + T& move(T& polygon, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to coordinate indicated by orientation_2d of vertices of an object that models polygon .
    template <typename polygon_type, typename point_type>
    - polygon_type& convolve(polygon_type& polygon,
    -                       - const point_type& point)
    template <typename polygon_type, typename point_type>
    + polygon_type& convolve(polygon_type& polygon,
                           +const point_type& point)
    Convolves coordinate values of point with the outer shell and holes of an object that models polygon_with_holes.
    +

    Polygon With Holes Data

    -

    The library provides a model of polygon with holes concept declared +

    The library provides a model of polygon with holes concept declared template<typename T> polygon_with_holes_data where T is the coordinate type.

    @@ -282,8 +300,8 @@ needed and is available to the library user who finds it convenient to use a library polygon data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -311,13 +329,13 @@ implemented to be convenient to use with the library traits.

    +
    operator=(const polygon_with_holes_data& that) +
    operator=(const T2& that) const @@ -353,29 +371,29 @@ implemented to be convenient to use with the library traits.

    +
    void set(iT begin_points, iT end_points) +
    void set_holes(iT begin_holes, iT end_choless) -
    geometry_type polygon_with_holes_concept
    polygon_with_holes_data& -
    operator=
    (const polygon_with_holes_data& that)
    Assignment operator.
    template <typename T2> polygon_with_holes_data&  -
    operator=
    (const T2& that) const
    Assign from an object that is a model of polygon with holes.
    template <typename iT>  -
    void set(iT begin_points, iT end_points)
    Sets the polygon to the iterator range of points.
    template <typename iT>  -
    void set_holes(iT begin_holes, iT end_choless)
    Sets the polygon holes the iterator range of hole polygons.  These polygons in the input range may be either polygon_data or polygon_with_holes_data or any type that provides begin and end member functions to iterate over point_data<T>.
    -
    +
      - +
    - + - + @@ -388,6 +406,6 @@ implemented to be convenient to use with the library traits.

    http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file +
    \ No newline at end of file diff --git a/doc/gtl_property_merge.htm b/doc/gtl_property_merge.htm index 51b4717..c1459d2 100644 --- a/doc/gtl_property_merge.htm +++ b/doc/gtl_property_merge.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Property Merge - - +-->Boost Polygon Library: Property Merge + + + +
    +
    - + +
    -
    +

    Property Merge

    -

    The following is the declaration of the property merge algorithm.

    +

    The following is the declaration of the property merge algorithm.

    template <typename coordinate_type, typename -property_type>
    -class property_merge;

    The property algorithm computes the n-layer +property_type>
    +class property_merge;

    The property algorithm computes the n-layer map overlay of input polygon sets.  Each input geometry is inserted along with a property value.  The property type can be anything suitable for use as an element of a std::set.  Multiple geometry objects can be separately @@ -72,13 +91,13 @@ inserted with the same property value.  To store the result of this operation a fairly complex container is required.  Resulting geometries are associated with unique subsets of property values of the input geometry.  Two suitable containers for storing the result of a property merge operation -are:

    std::map<std::set<property_type>, polygon_set_data<coordinate_type> ->
    -std::map<std::vector<property_type>, polygon_set_data<coordinate_type> >

    +are:

    std::map<std::set<property_type>, polygon_set_data<coordinate_type> +>
    +std::map<std::vector<property_type>, polygon_set_data<coordinate_type> >

    Example code property_merge_usage.cpp - demonstrates using the n-layer map-overlay algorithm on polygon data.

    Member Functions

    - - + demonstrates using the n-layer map-overlay algorithm on polygon data.

    Member Functions

    +
    + @@ -89,7 +108,7 @@ Example code property_merge_usage.cpp -
    property_merge() Default constructor.
    -void
    insert(const polygon_set_data<coordinate_type>& ps,
    +void
    insert(const polygon_set_data<coordinate_type>& ps,
           const property_type& property)
    Insert a polygon set with an associated @@ -98,8 +117,8 @@ const property_type& property)
    -template <class GeoObjT>
    -void insert(const GeoObjT& geoObj,
    +template <class GeoObjT>
    +void insert(const GeoObjT& geoObj,
           const property_type& property)
    Insert a geometry object that is a refinement of polygon set with an @@ -108,25 +127,25 @@ const property_type& property)
    -template <typename result_type>
    +template <typename result_type>
    void merge(result_type& result)
    Accepts a container object that conforms to the expectations defined above.  Performs property merge and populates the container object.  Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
    -
    +
      - +
    - + - + @@ -139,6 +158,6 @@ void merge(result_type& result) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    +
    - \ No newline at end of file + \ No newline at end of file diff --git a/doc/gtl_property_merge_45.htm b/doc/gtl_property_merge_45.htm index 851e217..1c0cb69 100644 --- a/doc/gtl_property_merge_45.htm +++ b/doc/gtl_property_merge_45.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Property Merge 90 - - +-->Boost Polygon Library: Property Merge 90 + + + +
    +
    - + +
    -
    +

    Property Merge 45

    -

    The following is the declaration of the property merge algorithm.

    +

    The following is the declaration of the property merge algorithm.

    template <typename coordinate_type, typename -property_type>
    -class property_merge_45;

    The property algorithm computes the n-layer +property_type>
    +class property_merge_45;

    The property algorithm computes the n-layer map overlay of input polygon sets.  Each input geometry is inserted along with a property value.  The property type can be anything suitable for use as an element of a std::set.  Multiple geometry objects can be separately @@ -72,13 +91,13 @@ inserted with the same property value.  To store the result of this operation a fairly complex container is required.  Resulting geometries are associated with unique subsets of property values of the input geometry.  Two suitable containers for storing the result of a property merge operation -are:

    std::map<std::set<property_type>, polygon_45_set_data<coordinate_type> ->
    -std::map<std::vector<property_type>, polygon_45_set_data<coordinate_type> >

    +are:

    std::map<std::set<property_type>, polygon_45_set_data<coordinate_type> +>
    +std::map<std::vector<property_type>, polygon_45_set_data<coordinate_type> >

    Example code property_merge_usage.cpp - demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

    Member Functions

    - - + demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

    Member Functions

    +
    + @@ -89,7 +108,7 @@ Example code property_merge_usage.cpp -
    property_merge_45() Default constructor.
    -void
    insert(const polygon_45_set_data<coordinate_type>& ps,
    +void
    insert(const polygon_45_set_data<coordinate_type>& ps,
           const property_type& property)
    Insert a polygon set with an associated @@ -98,8 +117,8 @@ const property_type& property)
    -template <class GeoObjT>
    -void insert(const GeoObjT& geoObj,
    +template <class GeoObjT>
    +void insert(const GeoObjT& geoObj,
           const property_type& property)
    Insert a geometry object that is a refinement of polygon 45 set with @@ -108,24 +127,24 @@ const property_type& property)
    -template <typename result_type>
    +template <typename result_type>
    void merge(result_type& result)
    Accepts a container object that conforms to the expectations defined above.  Performs property merge and populates the container object.  O(n log n) runtime wrt. vertices + intersections.
    -
    +   - +
    - + - + @@ -138,6 +157,6 @@ void merge(result_type& result) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    + - \ No newline at end of file + \ No newline at end of file diff --git a/doc/gtl_property_merge_90.htm b/doc/gtl_property_merge_90.htm index cd58023..6ada100 100644 --- a/doc/gtl_property_merge_90.htm +++ b/doc/gtl_property_merge_90.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Property Merge 90 - - +-->Boost Polygon Library: Property Merge 90 + + + +
    +
    - + +
    -
    +

    Property Merge 90

    -

    The following is the declaration of the property merge algorithm.

    +

    The following is the declaration of the property merge algorithm.

    template <typename coordinate_type, typename -property_type>
    -class property_merge_90;

    The property algorithm computes the n-layer +property_type>
    +class property_merge_90;

    The property algorithm computes the n-layer map overlay of input polygon sets.  Each input geometry is inserted along with a property value.  The property type can be anything suitable for use as an element of a std::set.  Multiple geometry objects can be separately @@ -72,13 +91,13 @@ inserted with the same property value.  To store the result of this operation a fairly complex container is required.  Resulting geometries are associated with unique subsets of property values of the input geometry.  Two suitable containers for storing the result of a property merge operation -are:

    std::map<std::set<property_type>, polygon_90_set_data<coordinate_type> ->
    -std::map<std::vector<property_type>, polygon_90_set_data<coordinate_type> >

    +are:

    std::map<std::set<property_type>, polygon_90_set_data<coordinate_type> +>
    +std::map<std::vector<property_type>, polygon_90_set_data<coordinate_type> >

    Example code property_merge_usage.cpp - demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

    Member Functions

    - - + demonstrates using the n-layer map-overlay algorithm on polygon 90 data.

    Member Functions

    +
    + @@ -89,7 +108,7 @@ Example code property_merge_usage.cpp -
    property_merge_90() Default constructor.
    -void
    insert(const polygon_90_set_data<coordinate_type>& ps,
    +void
    insert(const polygon_90_set_data<coordinate_type>& ps,
           const property_type& property)
    Insert a polygon set with an associated @@ -98,8 +117,8 @@ const property_type& property)
    -template <class GeoObjT>
    -void insert(const GeoObjT& geoObj,
    +template <class GeoObjT>
    +void insert(const GeoObjT& geoObj,
           const property_type& property)
    Insert a geometry object that is a refinement of polygon 90 set with @@ -108,24 +127,24 @@ const property_type& property)
    -template <typename result_type>
    +template <typename result_type>
    void merge(result_type& result)
    Accepts a container object that conforms to the expectations defined above.  Performs property merge and populates the container object.  O(n log n) runtime wrt. vertices + intersections.
    -
    +   - +
    - + - + @@ -138,6 +157,6 @@ void merge(result_type& result) http://www.boost.org/LICENSE_1_0.txt) -
    Copyright: Copyright © Intel Corporation 2008-2010.
    + - \ No newline at end of file + \ No newline at end of file diff --git a/doc/gtl_rectangle_concept.htm b/doc/gtl_rectangle_concept.htm index 951fddb..1cc27c2 100644 --- a/doc/gtl_rectangle_concept.htm +++ b/doc/gtl_rectangle_concept.htm @@ -1,14 +1,16 @@ - -Boost Polygon Library: Rectangle Concept - - +-->Boost Polygon Library: Rectangle Concept + + + +
    +
    - + +
    -
    +

    Rectangle Concept

    -

    The rectangle concept tag is +

    The rectangle concept tag is rectangle_concept

    To register a user defined type as a model of rectangle concept, specialize the geometry concept meta-function for that type.  In the example below CRectangle is registered as a model of -rectangle  concept.

    -template <>
    -struct geometry_concept<CRectangle> { typedef rectangle_concept type; };

    +rectangle  concept.

    +template <>
    +struct geometry_concept<CRectangle> { typedef rectangle_concept type; };

    The semantic of a rectangle is that it has an x and a y interval and these intervals conform to the semantic of an interval including its invariant.  This invariant on the intervals of a rectangle is enforced by the generic library functions that @@ -77,7 +97,7 @@ operate on rectangles, and is not expected of the data type itself or the concep mapping of that data type to the rectangle concept through its traits.  In this way a boost::tuple<int, int, int, int> or boost::array<int, 4> could be made models of rectangle by simply providing indirect access to their -elements through traits.

    +elements through traits.

    Below is shown the default rectangle traits.  Specialization of these traits is required for types that don't conform to the default behavior.  The interested reader will note SFINAE is used on the @@ -86,103 +106,104 @@ interval_type to work with the default read only traits.  This becomes necessary when refinements of concepts are used and it is undesirable to attempt to match default traits to non-rectangle types at compile time.  Specializing rectangle_traits can be done easily by simply providing gtl_yes as -the enable parameter.

    -template <typename T, typename enable = gtl_yes>
    -struct rectangle_traits {};

    -template <typename T>
    -struct rectangle_traits<T, gtl_no> {};
    -
    -template <typename T>
    +the enable parameter.

    +template <typename T, typename enable = gtl_yes>
    +struct rectangle_traits {};

    +template <typename T>
    +struct rectangle_traits<T, gtl_no> {};
    +
    +template <typename T>
    struct rectangle_traits<T, typename gtl_same_type<typename T::interval_type, -typename T::interval_type>::type> {
    -     typedef typename T::coordinate_type coordinate_type;
    -     typedef typename T::interval_type interval_type;
    +typename T::interval_type>::type> {
    +     typedef typename T::coordinate_type coordinate_type;
    +     typedef typename T::interval_type interval_type;
         static inline interval_type get(const T& rectangle, -orientation_2d orient) {
    +orientation_2d orient) {
              return -rectangle.get(orient); }
    -};
    -
    -template <typename T>
    -struct rectangle_mutable_traits {
    -     template <typename T2>
    +rectangle.get(orient); }
    +};
    +
    +template <typename T>
    +struct rectangle_mutable_traits {
    +     template <typename T2>
         static inline void set(T& rectangle, orientation_2d -orient, const T2& interval) {
    +orient, const T2& interval) {
              rectangle.set(orient, -interval); }
    -     template <typename T2, typename T3>
    +interval); }
    +     template <typename T2, typename T3>
         static inline T construct(const T2& interval_horizontal, -const T3& interval_vertical) {
    +const T3& interval_vertical) {
              return -T(interval_horizontal, interval_vertical); }
    -};

    Functions

    - - -
    template <typename T>
    +T(interval_horizontal, interval_vertical); }
    +};

    Functions

    + + + - - + + coordinate_type>
    + void set(T& rectangle, orientation_2d, direction_1d,
             coordinate_type) +
                     const T2& rectangle2) - - - - - - - - - - - - +
                                +orientation_2d) - - - - + rectangle_type>
    + rectangle_type& transform(rectangle_type& rectangle,
    +                          +coordinate_type axis = 0) + rectangle_type>
    + rectangle_type& scale_up(rectangle_type& rectangle,
    +                         +unsigned_area_type factor) + rectangle_type>
    + rectangle_type& scale_down(rectangle_type& rectangle,
    +                           +unsigned_area_type factor) - + rectangle_type, typename point_type>
    + rectangle_type& convolve(rectangle_type& rectangle,
    +                         +const point_type& point) + rectangle_type, typename point_type>
    + rectangle_type& deconvolve(rectangle_type& rectangle,
    +                           +const point_type& point) + typename T2>
    + coordinate_difference manhattan_distance(const T1& a,
    +                                         +const T2& b) + typename T2>
    + coordinate_distance euclidean_distance(const T1& a,
    +                                         +const T2& b) + T2>
    + bool boundaries_intersect(const T1& a, const T2& b,
    +                          +bool consider_touch = true) - - - - - - +
                   orientation_2d) -
    template <typename T>
    interval_type get(const T& rectangle, orientation_2d)
    Expects a model of rectangle.  Returns the x interval or y interval of the rectangle, depending on the - orientation_2d value.
    + orientation_2d value.

     
    template <typename T, typename - coordinate_type>
    + coordinate_type>
    void set(T& rectangle, orientation_2d, coordinate_type)
    Expects a model of rectangle.   Sets the x interval or y interval of the rectangle to the coordinate, depending on the orientation_2d value.
    template <typename T>
    +
    template <typename T>
    interval_type get(const T& rectangle, orientation_2d, -
                      direction_1d)
    Expects a model of rectangle.  - Returns the coordinate specificed by the direction_1d value of the x interval or y interval of the rectangle, depending on the - orientation_2d value.
    +
                      direction_1d)
    Expects +a model of rectangle.  Returns the coordinate specificed by the +direction_1d value of the x interval or y interval of the rectangle, +depending on the orientation_2d value.
     
    template <typename T, typename - coordinate_type>
    - void set(T& rectangle, orientation_2d, direction_1d,
             coordinate_type)
    Expects a model of rectangle.   Sets the coordinate specified by the direction_1d value of the x interval or y interval of the rectangle to the coordinate, depending on the orientation_2d value.
    template <typename T, typename - T2>
    + T2>
    T construct(const T2& h, const T2& v)
    Construct an object that is a model of rectangle given x interval and y intervals.
    template <typename T, typename - T2>
    - T construct(coordinate_type xl, coordinate_type yl,
                coordinate_type + T2>
    + T construct(coordinate_type xl, coordinate_type yl,
                coordinate_type xh, coordinate_type yh)
    Construct an object that is a model of rectangle given four coordinate values.
    template <typename T1, typename - T2>
    + T2>
    T1& assign(T1& left, const T2& right)
    Copies data from right object that models rectangle into left object that models rectangle.
    template <typename T, typename - T2>
    + T2>
    bool equivalence(const T& rectangle1,
    -
                     const T2& rectangle2)
    Given two objects that model rectangle, compares and returns true if their x and y intervals are respectively equivalent.
    template <typename T, - typename point_type>
    - bool contains(const T&, const point_type& point,
    + typename point_type>
    + bool contains(const T&, const point_type& point,
                  bool consider_touch=true)
    Given an object that models rectangle and an object that models @@ -193,8 +214,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    - bool contains(const T1& a, const T2& b,
    + T2>
    + bool contains(const T1& a, const T2& b,
                  bool consider_touch = true)
    Returns true if model of rectangle a contains both intervals of @@ -202,170 +223,174 @@ T(interval_horizontal, interval_vertical); }
    consider rectangle b contained even if it touches the boundary of a.
    template <typename T>
    +
    template <typename T>
    interval_type horizontal(const T& rectangle)
    Returns the x interval of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    interval_type vertical(const T& rectangle)
    Returns the y interval of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_type xl(const T& rectangle)
    Returns the west coordinate of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_type xh(const T& rectangle)
    Returns the east coordinate of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_type yl(const T& rectangle)
    Returns the south coordinate of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_type yh(const T& rectangle)
    Returns the north coordinate of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    point_type ll(const T& rectangle)
    Returns the lower left corner point of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    point_type lr(const T& rectangle)
    Returns the lower right corner point of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    point_type ul(const T& rectangle)
    Returns the upper left corner point of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    point_type ur(const T& rectangle)
    Returns the upper right corner point of an object that models rectangle.
    // get the center coordinate
    - template <typename T, typename point_type>
    +
    // get the center coordinate
    + template <typename T, typename point_type>
    void center(point_type& p, const T& rectangle)
    Sets object that models point to the center point of an object that models rectangle.
    template <typename T, - typename interval_type>
    + typename interval_type>
    void horizontal(T& rectangle, const interval_type& i)
    Sets the x interval of the object that models rectangle to be equal to the value of an object that models interval.
    template <typename T, - typename interval_type>
    + typename interval_type>
    void vertical(T& rectangle, const interval_type& i )
    Sets the y interval of the object that models rectangle to be equal to the value of an object that models interval.
    template <typename - rectangle_type>
    + rectangle_type>
    void xl(rectangle_type& rectangle, coordinate_type )
    Sets the west coordinate of the object that models rectangle to be equal to the coordinate value.
    template <typename - rectangle_type>
    + rectangle_type>
    void xh(rectangle_type& rectangle, coordinate_type )
    Sets the east coordinate of the object that models rectangle to be equal to the coordinate value.
    template <typename - rectangle_type>
    + rectangle_type>
    void yl(rectangle_type& rectangle, coordinate_type )
    Sets the south coordinate of the object that models rectangle to be equal to the coordinate value.
    template <typename - rectangle_type>
    + rectangle_type>
    void yh(rectangle_type& rectangle, coordinate_type )
    Sets the north coordinate of the object that models rectangle to be equal to the coordinate value.
    template <typename T, - typename T1, typename T2>
    + typename T1, typename T2>
    T& set_points(T& rectangle, const T1& p1, const T2& p2)
    Sets the rectangle to the rectangle fully described by the points p1 and p2.
    template <typename T>
    +
    template <typename T>
    coordinate_difference delta(const T& rectangle, -
                                orientation_2d)
    Returns the delta of the interval specified by orientation_2d of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    manhattan_area_type area(const T& rectangle)
    Returns the area of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_difference half_perimeter(const T& rectangle)
    Returns the length plus width of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    coordinate_difference perimeter(const T& rectangle)
    Returns the perimeter length of an object that models rectangle.
    template <typename T>
    +
    template <typename T>
    orientation_2d quess_orientation(const T& rectangle)
    Returns the orientation in which the rectangle has a longer delta.  Returns HORIZONTAL if the rectangle is a square.
    template <typename - rectangle_type>
    - rectangle_type& transform(rectangle_type& rectangle,
    -                          coordinate_type axis = 0)
    Applies transform() on the two points that fully describe the rectangle and sets the rectangle to that described by the result of transforming those points.
    template <typename - rectangle_type>
    - rectangle_type& scale_up(rectangle_type& rectangle,
    -                         unsigned_area_type factor)
    Scales up x interval and y interval  of an object that models rectangle by unsigned factor.
    template <typename - rectangle_type>
    - rectangle_type& scale_down(rectangle_type& rectangle,
    -                           unsigned_area_type factor)
    Scales down x interval and y interval  of an object that models rectangle by unsigned factor.
    template <typename - rectangle_type, scaling_type>
    - rectangle_type& scale(rectangle_type& rectangle,
    + rectangle_type, scaling_type>
    + rectangle_type& scale(rectangle_type& rectangle,
                          const scaling_type& scaling)
    Applies scale() on the two points that fully describe the rectangle @@ -373,33 +398,33 @@ T(interval_horizontal, interval_vertical); }
    those points.
    template <typename T>
    - T& move(T& rectangle, orientation_2d,
    +
    template <typename T>
    + T& move(T& rectangle, orientation_2d,
            coordinate_difference displacement)
    Adds displacement value to interval indicated by orientation_2d of an object that models rectangle.
    template <typename - rectangle_type, typename point_type>
    - rectangle_type& convolve(rectangle_type& rectangle,
    -                         - const point_type& point)
    Convolves coordinate values of point with x interval and y interval  of an object that models rectangle.
    template <typename - rectangle_type, typename point_type>
    - rectangle_type& deconvolve(rectangle_type& rectangle,
    -                           - const point_type& point)
    Deconvolves coordinate values of point withx interval and y interval  of an object that models rectangle.
    template <typename T1, typename - T2>
    + T2>
    T1& convolve(T1& a, const T2& b)
    Convolves x interval  of b with x interval  of a and convolves y @@ -407,14 +432,14 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    + T2>
    T1& deconvolve(T1& a, const T2& b)
    Deconvolves x interval  of b with x interval  of a and deconvolves y interval  of b with y interval  of a.
    template <typename T1, typename - T2>
    + T2>
    T1& reflected_convolve(T1& a, const T2& b)
    Reflected convolves y interval  of b with x interval  of a and reflected convolves x @@ -422,15 +447,15 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    + T2>
    T1& reflected_deconvolve(T1& a, const T2& b)
    Reflected deconvolves y interval  of b with x interval  of a and reflected deconvolves x interval  of b with y interval  of a.
    template <typename T, - typename point_type>
    - coordinate_difference euclidean_distance(const T&,
    + typename point_type>
    + coordinate_difference euclidean_distance(const T&,
           const point_type& point, orienation_2d)
    Returns the distance from an object that models rectangle to an @@ -439,8 +464,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, - typename T2>
    - coordinate_difference euclidean_distance(const T1& a,
    + typename T2>
    + coordinate_difference euclidean_distance(const T1& a,
           const T2& b, orienation_2d)
    Returns the distance from an object that models rectangle to an object that models rectangle along the given orientation.  Returns @@ -448,8 +473,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T, - typename point_type>
    - coordinate_difference square_euclidean_distance(const T&,
    + typename point_type>
    + coordinate_difference square_euclidean_distance(const T&,
           const point_type& point)
    Returns the square of the Euclidean distance between a point and a rectangle.  Returns zero if the point is contained within the @@ -457,50 +482,50 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, - typename T2>
    - coordinate_difference square_euclidean_distance
    + typename T2>
    + coordinate_difference square_euclidean_distance
           (const T1& a, const T2& b)
    Returns the square of the Euclidean distance between rectangles a and b.  Returns zero if the rectangles intersect.
    template <typename T, - typename point_type>
    - coordinate_difference manhattan_distance(const T&,
    + typename point_type>
    + coordinate_difference manhattan_distance(const T&,
           const point_type& point)
    Returns the Manhattan distance between a point and a rectangle.  Returns zero if the point is contained within the rectangle.
    template <typename T1, - typename T2>
    - coordinate_difference manhattan_distance(const T1& a,
    -                                          - const T2& b)
    Returns the Manhattan distance between rectangles a and b.  Returns zero if the rectangles intersect.
    template <typename T, - typename point_type>
    - coordinate_distance euclidean_distance(const T&,
    + typename point_type>
    + coordinate_distance euclidean_distance(const T&,
           const point_type& point)
    Returns the Euclidean distance between a point and a rectangle.  Returns zero if the point is contained within the rectangle.
    template <typename T1, - typename T2>
    - coordinate_distance euclidean_distance(const T1& a,
    -                                          - const T2& b)
    Returns the Euclidean distance between rectangles a and b.  Returns zero if the rectangles intersect.
    template <typename T1, typename - T2>
    - bool intersects(const T1& a, const T2& b,
    + T2>
    + bool intersects(const T1& a, const T2& b,
                    bool consider_touch = true)
    Returns true if two objects that model rectangle overlap.  If @@ -509,10 +534,10 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    - bool boundaries_intersect(const T1& a, const T2& b,
    -                          - bool consider_touch = true)
    Returns true is two objects that model rectangle partially overlap such that one there is an intersection between the edges of the two rectangles  If the consider_touch flag is true a coordinate is @@ -521,8 +546,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    - bool abuts(const T1& a, const T2& b,
    + T2>
    + bool abuts(const T1& a, const T2& b,
               direction_2d dir)
    Returns true if rectangle b abuts but down not overlap rectangle a @@ -530,8 +555,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    - bool abuts(const T1& a, const T2& b,
    + T2>
    + bool abuts(const T1& a, const T2& b,
               orientation_2d)
    Returns true if rectangle b abuts but down not overlap rectangle a @@ -539,15 +564,15 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    + T2>
    bool abuts(const T1& a, const T2& b)
    Returns true if rectangle b abuts but down not overlap rectangle a on any side.
    template <typename T1, typename - T2>
    - bool intersect(T1& a, const T2& b, orientation_2d
    + T2>
    + bool intersect(T1& a, const T2& b, orientation_2d
                   bool consider_touch = true)
    Sets rectangle a to the intersection of rectangle a and interval b @@ -558,8 +583,8 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    - bool intersect(T1& a, const T2& b,
    + T2>
    + bool intersect(T1& a, const T2& b,
                   bool consider_touch = true)
    Sets rectangle a to the intersection of rectangle a and rectangle b @@ -569,84 +594,84 @@ T(interval_horizontal, interval_vertical); }
    template <typename T1, typename - T2>
    + T2>
    T& generalized_intersect(T1& a, const T2& b)
    Same as intersect, but if they do not intersect set a to the rectangle between a and b by applying generalized_intersect() on the intervals of the rectangles.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& rectangle, coordinate_type)
    Bloats x and y intervals of rectangle by coordinate value.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& rectangle, direction_2d, coordinate_type)
    Bloats side of rectangle specified by direction_2d by coordinate value.
    template <typename T>
    +
    template <typename T>
    T& bloat(T& rectangle, orientation_2d, coordinate_type)
    Bloats interval of rectangle specified by orientation_2d by coordinate value.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& rectangle, coordinate_type)
    Shrinks x and y intervals of rectangle by coordinate value.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& rectangle, direction_2d, coordinate_type)
    Shrinks side of rectangle specified by direction_2d by coordinate value.
    template <typename T>
    +
    template <typename T>
    T& shrink(T& rectangle, orientation_2d, coordinate_type)
    Shrinks interval of rectangle specified by orientation_2d by coordinate value.
    template <typename T1, typename - T2>
    + T2>
    bool encompass(T1& a, const T2& b)
    The x and y intervals of a are set to encompass the x and y intervals of b respectively.
    template <typename T, typename - point_type>
    + point_type>
    bool encompass(T& rectangle, const point_type& point)
    The x and y intervals of rectangle are set to encompass the x and y coordinates of point respectively.
    template <typename T, typename - interval_type>
    + interval_type>
    bool encompass(T& rectangle, const interval_type& i, -
                   orientation_2d)
    The interval of rectangle specified by orientation_2d is set to encompass the interval i.
    template <typename T, typename - point_type>
    + point_type>
    bool get_corner(point_type& point, const T& rectangle,  -
                    +
                    direction_2d, direction_1d)
    Sets point to the corner of the rectangle you reach if you look at its side specified by direction_2d from within the rectangle and turn in the direction_1d direction (low == left, high = right).  Always returns true.
    +

    Rectangle Data

    -

    The library provides a model of rectangle concept declared +

    The library provides a model of rectangle concept declared template<typename T> rectangle_data where T is the coordinate type.

    This data type is used internally when a rectangle is needed and is available @@ -654,8 +679,8 @@ to the library user who finds it convenient to use a library rectangle data type instead of providing their own.  The data type is implemented to be convenient to use with the library traits.

    Members

    - - +
    + @@ -675,8 +700,8 @@ convenient to use with the library traits.

    @@ -716,35 +741,35 @@ convenient to use with the library traits.

    - -
    geometry_type rectangle_concept
    template <typename T1, typename - T2>
    - rectangle_data
    (const T1& horizontal_interval,
    + T2>
    + rectangle_data
    (const T1& horizontal_interval,
                   const T2& vertical_interval)
    Constructs a rectangle with two objects @@ -694,19 +719,19 @@ convenient to use with the library traits.

    template <typename T2> -
    rectangle_data& +
    rectangle_data& operator=(const T2& that) const
    Assign from an object that is a model of rectangle.
    template <typename T2> -
    bool +
    bool operator==(const T2& that) const
    Compare equality to an object that is a model of rectangle.
    template <typename T2> -
    bool +
    bool operator!=(const T2& that) const
    Compare inequality to an object that is a model of rectangle.
    Get the interval in the given orientation.
    template <typename T2>
    +
    template <typename T2>
    void set(orientation_2d orient, const T2& value)
    Sets the interval in the given orientation to the value of an object that models interval.
    -
    +   + + + + + + + + + + + + + +
    Copyright:Copyright © Intel Corporation 2008-2010.
    License:Distributed under the Boost Software License, + Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at + + http://www.boost.org/LICENSE_1_0.txt)
    - - - - - - - - - - - - - -
    Copyright:Copyright © Intel Corporation 2008-2010.
    License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
    - - \ No newline at end of file + + \ No newline at end of file diff --git a/doc/gtl_segment_concept.htm b/doc/gtl_segment_concept.htm new file mode 100644 index 0000000..60349a9 --- /dev/null +++ b/doc/gtl_segment_concept.htm @@ -0,0 +1,572 @@ + + +Boost Polygon Library: Segment Concept + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    + + +

    +

    +

    Segment Concept

    +

    +

    The segment concept tag is segment_concept

    +

    To register a user defined type as a model of the segment +concept, specialize the geometry concept meta-function for that +type.  In the example below CSegment is registered as a model of +the segment concept.

    +

    template <>
    +struct geometry_concept<
    CSegment> +{ typedef segment_concept type; };

    +

    The semantic of a segment is +that it has a low and high point.  A +std::pair<Point, Point>, +boost::tuple<Point, Point> or boost::array<Point, 2> could all be made models of +segment by simply providing indirect access to their elements through +traits, however, these objects cannot be made a model of both segment +and rectangle in the same compilation unit, for obvious reason that +duplicate specialization of the geometry_concept struct is illegal, but +also because it would make overloading generic function by concept +ambiguous if a type modeled more than one concept.

    +

    Below is shown the default +segment traits. Specialization of these traits is required for +types that don't conform to the default behavior.

    + + +

    template <typename Segment>
    + struct segment_traits {
    +   typedef typename Segment::coordinate_type coordinate_type;
    +   typedef typename Segment::point_type point_type;
    +
    +   static inline point_type get(const Segment& segment, direction_1d dir) {
    +     return segment.get(dir);
    +   }
    + };
    +
    template <typename Segment>
    +struct segment_mutable_traits {
    +  typedef typename segment_traits<Segment>::point_type point_type;
    +
    +  static inline void set(Segment& segment, direction_1d dir, const point_type& point) {
    +    segment.set(dir, p);
    +  }
    +
    +  static inline Segment construct(const point_type& low, const point_type& high) {
    +    return Segment(low, high);
    +  }
    +};

    Functions

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    template +<typename Segment>
    point_type get(const Segment& segment, direction_1d dir)
    Returns the low or high endpoint of an object that models segment, depending on +the direction_1d value. 
    template +<typename Segment, typename Point>
    +void set(
    Segment& segment, direction_1d dir,
    +         const Point&
    point)
    Sets +the low or high endpoint of an object that models segment to an object +that models point, depending on the direction_1d value.
    template <typename Segment, typename Point1, typename Point2>
    +Segment construct(const Point1& low, const Point2& high)
    Constructs an object that is a model of segment given the two objects that are models of point.
    template <typename Segment1, typename Segment2>
    Segment1 copy_construct(const Segment2& segment)
    Copy constructs an object that models segment given another segment.
    template +<typename Segment1, typename Segment2>
    + Segment1& assign(Segment1& segment1,
    +                 const
    Segment2& segment2)
    Copies data from the second object that models segment into +the first object that models segment.
    template +<typename Segment1, typename Segment1>
    +bool equivalence(const
    Segment1& segment1,
    +                 const
    Segment1& segment2)
    Given two objects that model segment, compares and +returns true if their low and high values are respectively equal.
    template <typename Segment, typename Point>
    + int orientation(const Segment& segment,
    +                 const Point& point)
    +
    Implements +a robust orientation test of two objects that model segment and point. +Returns 0, if the point is collinear to the segment.
    +Returns 1, if the point lies to the left of the segment.
    +Returns -1, if the point lies to the right of the segment.
    + +
    template <typename Segment1, typename Segment2>
    + + int orientation(const Segment1& segment1,
    + +                 const Segment2& segment2)
    Implements a robust orientation test of two objects +that model segment. Note: segments are treated as math. +vectors.
    +Returns 0, if segments are collinear.
    +Returns 1, if the second segment is CCW oriented to the first segment.
    +Returns -1, if the second segment is CW oriented to the first segment.
    +
    template <typename Segment, typename Point>
    + bool contains(const Segment& segment,
    +     const Point& value, bool consider_touch)
    +
    Returns true if an object that models segment contains an object that models point, else false.
    +
    template <typename Segment1, typename Segment2>
    + + bool contains(const Segment1& segment1,
    + +     const Segment2& segment2, bool consider_touch)
    Returns true if the first object contains the second one, else false. Both objects model segment.
    +
    template <typename Segment>
    +point_type low(const Segment& segment)
    +
    Returns the low endpoint of an object that models segment.
    +
    template <typename Segment>
    +point_type high(const Segment& segment)
    Returns the high endpoint of an object that models segment.
    +
    template <typename Segment>
    +point_type center(const Segment& segment)
    Returns the central point of an object that models segment.
    +
    template <typename Segment, typename Point>
    void low(Segment& segment, const Point& point)
    Sets the low endpoint of an object that models segment.
    +
    template <typename Segment, typename Point>
    +void high(Segment& segment, const Point& point)
    Sets the high endpoint of an object that models of segment.
    +
    template <typename Segment>
    + distance_type length(const Segment& segment)
    +
    Returns length of an object that models segment.
    +
    template +<typename Segment>
    Segment& scale_up(Segment& segment,
        unsigned_area_type factor)
    Multiplies x and y coordinates of both endpoints of an object that models segment by unsigned factor.
    template +<typename Segment>
    +
    Segment& scale_down(Segment& segment,
    +    unsigned_area_type factor)
    Divides x and y coordinates of both endpoints of an object that models segment by unsigned factor.
    template +<typename Segment, typename Scale>
    +
    Segment& scale(Segment& segment, const Scale& sc)
    Calls +the scale member function of the scaling type on the low and high endpoint of +an object that models segment and updates the segment with the +scaled endpoints.
    template +<typename Segment, typename Transform>
    Segment& transform(Segment& segment, const Transform& tr)
    Calls the transform member function of transform type +on the low and high endpoints of an object that models segment and updates the segment with the transformed endpoints.
    template +<typename Segment>
    +
    Segment& move(Segment& segment, orientation_2d
    +    coordinate_difference displacement)
    Adds displacement value to the x or y coordinates of both endpoints of an object +that models segment indicated by the orientation_2d.
    template +<Segment, Point>
    +
    Segment& convolve(Segment& segment, const Point& point)
    Convolves both endpoints of an object that models segment with an object that models a point.
    +
    template +<Segment, Point>
    +
    Segment& deconvolve(Segment& segment, const Point& point)
    Deconvolves both endpoints of an object that models segment with an object that models a point.
    template <typename Segment1, typename Segment2>
    + + +bool abuts(const Segment1& segment1,
    + + +    const Segment2& segment2, direction_1d dir)
    Returns true if two objects that model segment abut, depending on the direction_1d value.
    template <typename Segment1, typename Segment2>
    + +bool abuts(const Segment1& segment1,
    + +           const Segment2& segment2)
    Returns true if two objects that model segment abut: either the first one to the second one or vice versa.
    template <typename Segment1, typename Segment2>
    + bool intersects(const Segment1& segment1,
    +                 const Segment2& segment2,
    +                bool consider_touch)

    +
    Returns true if two objects that model segment intersect, else false.
    +
    template +<typename Segment, typename Point>
    distance_type euclidean_distance(
    +    const
    Segment& segment, const Point& point) +
    Returns distance from an object that models segment +to an object that models point. +
    template +<typename Segment1, typename Segment2>
    distance_type euclidean_distance(
    +    const
    Segment1& segment1, const Segment2& segment2) +
    Returns distance between two objects that model segment. +
    +

    Segment Data

    +

    +

    The library provides a model of the segment concept declared template<typename T> segment_data, where +T is the coordinate type.

    +

    This data type is used internally when a segment is needed and +is available to the library user, who finds it convenient to use a +library segment data type instead of providing their own.  The data +type is implemented to be convenient to use with the library traits.

    Members

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    geometry_typesegment_concept
    coordinate_typeT
    point_typepoint_data<T>
    +
    segment_data()Default constructor.
    segment_data(const point_type& low,
    +             const point_type& high)
    Constructs a segment from the given endpoints.
    segment_data(const segment_data& that)Copy constructor.
    segment_data& operator=(const segment_data& that)Assignment operator.
    template +<typename Segment>
    +
    segment_data& operator=(const Segment& that) +const
    Assign from an object that is a model of segment.
    bool operator==(const segment_data& that) constEquality operator overload.
    bool operator!=(const segment_data& that) constInequality operator overload.
    bool operator<(const segment_data& that) constLess operator overload. Compares low endpoints then high endpoints to break ties.
    +
    bool operator<=(const segment_data& that) constLess or equal operator overload. Compares low endpoints then high endpoints to break ties.
    +
    bool operator>(const segment_data& that) constGreater operator overload. Compares low endpoints then high endpoints to break ties.
    +
    bool operator>=(const segment_data& that) constGreater or equal operator overload. Compares low endpoints then high endpoints to break ties.
    +
    point_type get(direction_1d dir) constRetrieves the low/high endpoint considering direction value.
    point_type low() constRetrieves the low endpoint.
    point_type high() constRetrieves the high endpoint.
    void set(direction_1d dir, const point_type& point)Sets the endpoint in the given direction.
    segment_data& low(const point_type& point)Sets the low endpoint.
    segment_data& high(const point_type& point)Sets the high endpoint.
    + +

    Segment Utils

    +

    +

    The library provides several algorithms for the manipulation of + sets of segment data. In particular, the generalize line segment + intersection algorithm used for polygon set operations is exposed + through several interfaces to allow it to be used with any + collection or sequence of objects that model the segment_concept. +

    Functions

    + + + + + + + + + + + + + + + + + + + + + + +
    template +<typename SegmentContainer,
    +          typename SegmentIterator
    >
    +
    void intersect_segments(
    +   
    SegmentContainer* result,
    + +    SegmentIterator first,
    +    SegmentIterator last) +
    Accumulates +the result of splitting the segments in the iterator range at their +intersection points into the result container. Preconditions: segment +type used by all the input structures should model segment concept.Postconditions: no segments intersect except at their end + points. Useful to satisfy the precondition of voronoi diagram + construction. + Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections. +
    template +<typename Segment,
    +         
    typename SegmentIterator>
    +
    void intersect_segments(
    +   
    vector<pair<size_t, Segment>* result,
    + +    SegmentIterator first,
    +    SegmentIterator last)
    Accumulates +the result of splitting the segments in the iterator range at their +intersection points into the result container. Preconditions: segment +type used by all the input structures should model segment concept. +Postconditions: no segments intersect except at their end points. The +index of the input segment is paired with each resultant segment that +was split to produce it to associate the result segments with the +inputs segments. Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections.
    template +<typename Rectangle,
    +         
    typename SegmentIterator>
    +
    void envelope_segments(
    +   
    Rectangle* rect,
    + +    SegmentIterator first,
        SegmentIterator last
    ) +
    Computes +the bounding rectangle of the iterator range of line segments. +Preconditions: segment type and rectangle type used by the input +structures should model segment concept and rectangle concept +respectively. Linear runtime.
    + +
      + + + + + + + + + + + +
    Copyright:Copyright © Intel Corporation 2008-2010.
    License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
    +
    + + + \ No newline at end of file diff --git a/doc/images/benchmark_points_10.png b/doc/images/benchmark_points_10.png new file mode 100644 index 0000000000000000000000000000000000000000..98d4eafaae14facb09f006b2ee3575ae790246f4 GIT binary patch literal 15729 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_points_100.png b/doc/images/benchmark_points_100.png new file mode 100644 index 0000000000000000000000000000000000000000..b876cbaecd40dd1c153aa708bd132873fc41dc7b GIT binary patch literal 16377 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

    FBNOl9xx-1NG;;~8jlLd#<&$! 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 gkPksc^*lrj3=9lxN#5=*4F5rJ!QSPQ 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_points_1000000.png b/doc/images/benchmark_points_1000000.png new file mode 100644 index 0000000000000000000000000000000000000000..470962695be86ef2aaa950d855b7abdeb36fc427 GIT binary patch literal 16201 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_points_all.png b/doc/images/benchmark_points_all.png new file mode 100644 index 0000000000000000000000000000000000000000..68f89ca1571e09918b8af03fe01b273ea1d29f06 GIT binary patch literal 22818 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%0AlP2}s|NHUk>gspz z-W@%9v~P~QnzeQH+gn?8rhQH?E39MjznT;OVXJ;f+WM_o*1cP+XYO^AuYP~ew!FOD z+}xbu!-o$U4+6L6-=Ak$tY%yNTRgtz;M1bzzO%1&aFvh z&j}0+40TUFe&k3+MFk5BOOK>++P6116&0^~*Ic;Vb@6o8)?aJ4-^*&6FqcQQoW(JU zVQ<|3ljieT+}N-ES@EInVNyiQS5-Bh!~cFf?mu(p%>BCGx@Kl&kB{{}KHk5+ilhDT z!t{Sk4Odr(PoFl;Eb)b36DZB&uMS`T z^YioPPe9rVLk=X}9vL&@_# z1&{3Htx@87F+Uz0WZoEIlW?HH{C>^mMt0B)h@4f4#_Y4p)Wx$~7A;!T$}K+6zW(0n z)2laZ*bu+J4m1|#qn3T=<~(*#_j(J1Mc-#1o1>hrXZt;rU;e!G|I3z=cXwvWeF@SQ z>kcg~c=G%G{`}~9MyaQ!Xa=u(=hL5CURaoULZO`D#;(%U{r&z?QM0Pvx_%8PTdjsi#W;_Cl?Jvmu@`I03rE-oo)X>t2%DzC4L z_3LB-#pf)|+W}wFRxDby$a{K}SG$Y5d;Fe?k3T*>Ub%8*^0A(qI|`NmE?V>0)U!xm zTYI)mWl>pKnVVZ%gbrK7lqpl5JbCit$B)d*%MvBR{$~ZZv?zF-ZhHKqfsuKRtn1tt zS|VE~c`ZHM&j0<}x4y2fMZyb$O+4pY$Cj=ye}C`Gs3cw1B%! z#;PRa-k!=5$-IRD7Wwz~FthW46seSlr13jWxR(3k!org$PcmFs?mvIAd;hI%^0rl5 z{O8;Gah?=}lut`atKV+D9=0aJFyn%PT>tipkB<@$x9P_0D7dj9v0Gd}FLZJ01ItzK zuG)l3YX-KRdb2ewclpL|x|^?`iPRC3Ii9;Zc6Zs{!pCk^Rli!f#dCsh@<N3@n!z=-)&G>oyE8q)E1QKRl0f0d(Wr)oOLVwzF9G3 z)Yt|5*4tdf#Bf08RrmCF>%Z>sxBojO?tp=gg~bictHGI|mP1p>@zB37tKRc=Xh*n4zK{!cv<*=|~{Y zJL9?PMn;>S9qZ}g`R(#k2i$sGdsw6UO;vnbsOJYKNf*|WMN19(E|!)k`)#fMo>$eV za`MZUFL!sB@BebiyNq|+La-j)L#3H}KJBf#DbjSi@le6k|I=BvGauxxJ$JdSrRB!7 z!-o#B@kkgXALChW6I^;EW9Ft!n|}QGao~W%)+pb6Pft%zA0HntuSFWGo@q5HcuW?0 zu3Nm{c2fK%-s|CIGbCc&?d#LlpFDp2c!r4(OX7E9`>D#4ejA70Eq1U0HP>f^p4Rq$ zHub;TdZ}3V)qkgnyDyWzbIkPZ_oN#yFE3wx^+_?0drj)!(C;Zmkyo!qrT=vmV97Lz znXh?Pu6rWe<`w*N&z?P$vDsjk=00t!UDGZvTeeJ1U44Dj)~i_E1$&^h{Bf^g9rgOQMG8rs8soM9TY>7e4)9*`@_wD&J zDHOIAVAr#N6RO_RT-@BemIkp;Usm8$)ZfwZmUY!`}q9E?M&A#6)EV2Y=OP z27F%cc-QX=|9rzNXe;;Bo7rn``6bT{P4i!H=Y80ZdY?r;sBT!viyn{=Q4f17#?5f{p_YF1wl%k=xps?Ls!oD5 z!Eb6zT5QQK!pWfG-4(f2YCUVJB0EENnPkqVCnv9N^O<3AP;=sz2J3Pb$6H2;7uD)6 ziY;5ZU`_C*$SdLoVUZ^o)7e9pN2&8|E_}k11j<*J-WcepN(hAAk!Fy1#>8zO^Y-7) zrI~TooAhrVNo1HXZ{EJz-`_x0?yDAKzGhIX;4H_w^FmtJ3a+Yuz2q|We>lT}yzlkr z_+CkdoPDgQsCe+;LGS5$wlzOCJXX#uvkl{D+F~nm`AbLKArISi=dVV8*hj=Yl4*s09%D1&EpR|*GXa*)LA_+8Bp*fN)P`ak=9EGjRJy`iaz>Gr1S)2}b{ zoxNz$qB%mGpz_gzFS@ufepByio1lwz-JV7g25z3uFN-Yxy64H)r_=dn9eK7gV7_&e zf-j#k?-!=<(w@bZ>!9`8L3 zkDlYX;y1-D)i2XeJaYOh`B2&C^JdQcd0KzJ&rGAEjSK%C<~%uf-7fR&YdTd|!_x8( zHnCb-TCNZhZrWmTs44%&89s&?p>NCbqY|%Mi!|p8x`?*NZz%dRS9)HpZHS#s*?$So ziCfjaXFa|HT3vB=wt3y33U;=Llbp5hzJ}i|uCd{0vXSpvZ25hEw8xzQOXDQ%({C6G zA`53OIl=ZW$3&{Tt813Yyj>Ri&+m=8YMb8PtZ>3uKx^N#>2DKeiT>X#njE#`pkLRD zOxrN~FsZ3u-xw4>vwt5qb=tJFl$1Tc-|hC557(VD|IX^ryTxS|98ET?c{@CfTEhC| z84T8@vgn8C&(;cAb5uilZ}YjwzFnFHSv_UR8zkhi<%|v7CS(gRywKV8>wAA^=SJQ1 zv@{_W!_rq*mho=nJLmuI>Z*5^)-o)Pua1Pu2|leqW@LNeWL)^~T0VwVWv5^E_vk5C zxY`F!<63=Np!s&h^0rL#pRfKLF6U=%h*4QSxte`DpI*%L!{z+5*FKBlpJ`WHb@giU z@xHTjt;=6uTg%t6P3pPI_o`LzuHM<%J4M4e^;^{HY4;+weN;O=XSp~(GeeJ1(Tzs0 zn>l+kIDYQ$HA>tUbv||K)EPco)%T^HbBfBFdROa;=&ZHR0^hnbHnga|e04KaZ;JQM zpxg3`T2w1{K0f{P)t|OG#wI2vwzhjYo7c@Qp7eX3ZS|^kYG7ccD#YUW>d+<)o8sk< zmdR+pTPn`adZ6czoZElhbA6}hT}dn5xNb*tHakN?LeH8>I-KrG;-@sb4jJ^EO>sY= zlqGjGvG9*e-PU;px3}ePdpc>-q{Z(2R;ep^Oxp8iF3(a{Jq0ePQccCo?>y4z&)R#B zwTCmuUfbT~{m-_GsTS4FpK^2a;wiH=pSBe-d?@`mwLq2OL)4LMi_b6hBVsQ< z{I7d>dPV4!KQG?g+`KK7pTB=+@$+NHj@{CIlzx#3RHF1L?lqpbb|-_xX%)$whvket zk%C{EH#cvRZgrcu`b=ns2=gEI3Jx0vg$Su0~K{0vNWc zeV4EQb8%myxs=yCj!R`5efW2Xw)-sFC*~N=V6dytWJiz5uDuzv?H9NzYi@E0KXkY< zsZWC8-L(6A!|VL@CfzQ3@hI|iw1@v!--Q#Ze#M;wwUo959y-*!=(sjRa>M!kFQ2TN z>|6gTQ1|HBNwdX2>kFv}z7&;wEX>ScXlMBM?=Rzd>z94gWqv(xtkTi%%B_eJ?1>IDb09 z&?dw-Btt}L+luA>{tN|=ce3tgujbyHyZu$nwafC-A;}9Leh3((X}9W`7o@jddHpprGxP4Q(#IdQ)J>*&Ee%@fY`q&~^R>>* zQ%^Pd3$H9cZT-h9aYw88s;upIo){fD^{o`-O%I9wd)85Fw9|}l1}iORXz0hoW7(&x>3TorZJF!)C6he-^42h#&I=bmz|6jS^>KkwT)o6|o(JmMDJdVi1h)KmO+ zKOX$}_&8|gmOXoFUR+qH9kynIhst@$2<0uEjpZDd*gW6+i9B6@z=Qd)lYdO>OWS2z zFPw?X(>Skl%BJW&hi$U>^rKHV?TFpG>lo|NKoM33o}P;xXXY(Cd|jjE@q3T;ueI4v zvJ|epZ2Kkp_VnsUVO8G#3wLIvE&nJPQonHFwc>ZTwsIfdQ2hK{?5+~fEEtR9k|j%Q zvJ=W0-`x>hVww=ewL`Rhrzrc@d&MvN#HaqxYP!4bso$v;W-EVM%s-mIcwl4o@esAC z+UG;FuU&GEZ`&q+tD`tdL&vwh`oT4ZK2e4`EwMLiAG8+fu2QdkA^&^TeB(E=)@7hI zMe}$r-o9N88e>m8JIgTnSn<4Vf}n7p)}zFb%*e3+g?i$}?P7H*0aLfnQ46$R?slz0 zvQ=`sSN=-hSBY=ifA0Rld|<)?#hN+i56@q%aNl3G>FG};=FYv(m;OEA&debHBjewB z|F?&7Ui{h18yFS!>iz%o_A4428@XB+&HFo>50t?^8LZLDyZL@kS8bRdL+n1k_dna> z%#NPQeE#ObyqQxsiDhwpHvM_eDc`t(05@ypMfHZ5(ow2`i^uASYzclR#| zob!KYy84|WN04^Um0%t_1_NJy)k<&9xD6AdE$x;h0a)X3NpyenxQS%ZS|2OTI;>K(N|&9pFDZl*Ve4u zB_%8zTq=~{UQ}1KKCG1Aal$JNr+{6((RCA2cSOp}bWD`twqK<3N9JH=JmrAfPIIeTdvoX(KSneG6cl~K+;o=v%GmmvuKDxGrLz%&a`>dp(tI?f# zv3k1QpC?yuT~*D|bU`9a^yq_N2|kJL_${mk)6RX)RXBU#34=rN={Hi7)pqMdr(a=> zVE&`}zr;$KbFtIn3(;R5$~|N_aAd~OU5^~5A7GfyP{nTO?qjcpa+|6YMmj3T{XoqdFwQFF_9C zU-Dp^;Qj@P`<1S8&k*5m)>UOvJK(U<)7vO!h6;1@`M>kZ7kF!f8jL2~Jd0#DuUb2Y zf#CqJ`HX4Dqt=(}`rlK?JvUR9!KlmV#hJLBQ8O+^UW+^-Rup+>-`iiOSd7Z&{oX9L zXd%NIkqrh64Ij&wh;Pkd;CLulvj6AD3qpat51)I4zED+TDKxrMa9B6JD?Kgz<73e; zV!hY*Oxh4E^;5~}x_Pncu1T{}JHLq8?iEnup8PTO{FIyh8awmvmG_?bU=tB&`K_?a zXTP4q%v(!ud~?~tn)*%Edz!`5>e)x^s`{Xx>S9S`e|SgQS5 z)F*vF?H4C6!-SO&V=r%FOV8RC9 z6<4|nd1mUl#v7mQ*ZI@Ib-rG3hYW*3(EEwzvsc^lOK9sq;X3)i+WJiTViV2(vp>go zEmDy==`9<-$b1&Z<%xHcMUQbYBp62gt@-`4d;X`iHPcc!Bvlx4^o46f6j&QN*Ug%0 zm&)M4aIEQBU9zA0_gSgSkM&3zm%X`h;)F+Z=+?~3%l`iPeEvg*KNy%(ylTx-2T(Bd~bkI*_He8v}K*QZRbTxnR7ojd}N)))EoEs{k!<{Pj>P9 zthvhdkd@bZhWndW5qu2JOT+Y{uezu3JrZD$S@8dUQfhj-|7^3huf$}I%g(%(8|6^s zK4Dr%^uFom-k7ijDrwwYG_jt6;i+u7mHxWr#t}UIrv1z@Oc6X{%*ipKF{ztxFzPXi zT{@Ju$&lyuyV%p-ZqrNWo_d~`}q%)akyXy3iWwb@yxr|GWVmU?lKt6%35){@gEw?Dk`UVZh`&p&2G&(~ed za8a7Ld2xnQ(<9xcL%nBCy_C=n-SWTxVrt7~r>q6S{C;<|_p>u7TlIYq{ms;HG^_H} zYuD#j-gH_9eew+V+SC1U`8QF91>20Q(kr4gKO8yf9ov;FxnFdFJe$ewc!y}W?L18; z^%ALR*?JL{|5(%o7z$#ojy`FAI$u^}*#(^!FSq=7wZJe_Zl(Ow)t{a3I=>A6zqciB zT}*iVM*Ub8W~ngas_K;uYbI^~A5yfrx5D7MQre`~%u^C=yw&9{s?AedXjIK{Y1Rkt zZJqM}<fHHXTe7svd_w=SUHg%;;e5pQThDFt*9OeAWyw4k(U!CB zmBdkz3!+Oo^W68AEb^4e7W=yL4s$YN!@1-(KQrIuS|U4sSQti0x4ISDy{~CqsC2?K z!{Y*|bMRV5jr;NA^JYou^{nsL%&PS~Z6^|>l@^qwc6Fk6%FF*d4}L$gHulG~s&f~* zu6}(ZGWDkOglBzgE%o;rGa4*ASjux^8FNGAmD@V6Vt?P0n4DsjyY6z4bLBj({skPr z1U04~efs#1-zC4dN2VGxn-{cwN#cH-ue*Hy36<1|3>$U^d^m8VOK|2?7Uwftm=64V zuxaM^*uGUe7!=Z@_w$Ar-SW`);oYkCy{CugxI1Xz{R;bHojYC3F;@epJuLIQ;mL4D zsV9sr&!m%m;+kg`69V%uUM_zmHCgRx8W%$ahs}#8?~WBq-zZf-86G_66Md(nz1i#6GouyrtwS_?A|_rFd3WsC?W{ERhP%7VZ%;EeHm?8qbh>8n zG7D89P!pA{>qu#)n4?O94wuBEJ^dQXE@*TfUQ^YjxxnDggKwKQJFn?mw1WGm_@|J{ zsLf?wPejZn>ptpeE0uV5@O#BFCb#g?H}_9hikrN-p7QH@sue?r=bTcN#Q_R%&TuQ*&=m<>TZ1n-YqWjIXScL ze(#cm1v@^iUDWxm?W9p{^tp(*f_x;W_WrR=g>CXcTq6+RZO;>x#IvG&M(o z;N^a$UMhXw@4S|NI?%{$UH&d+LxQ89pWpF5*_UruoRNEEAd#7}`g~F7agS-MkEL@m z%y6wW`BXnM=8?{xbh-O?mw0sPT$~!6gl52Al@`HC>GDIE6vrFc`53 zF-7OkoOyF|vwHKvj?T`LXU=R<1&!ioX3Yq7H)M4*#}<^E#qf0>vDs1TS8F zH2Le}LmgMnjWTg$HYTWYUXwO{M{C@I3stj&5cQcg>o`S^SnvLd+cRD<&5YUEWX&q8mDXPO$EI&*D~dH1g%iP?v4{MnS!^fvp$y#7Eju4Kkz zCZ2HxDK=4?w?)MFeEyJS`?zF%_woyqwf*MCBYN34 z#ZBG_u5+uJ@F-WAPvmRg@~|^&ba>_}WYdpbFIzI%&uupw9wn> z?&9+2&*$?ho^iWMUd}DQw=rsM*4A5Bw_5IFYuXa-HShS38-&ux7_+ z$tpF5B`TbA+E4XRnHzu>K$7;zt5=g=DnqRV>FJhk*JmZ!L#pX&bsG0&$r(B zdQ|Tv+c}r;v&%mfF?fh*vwtwT$TYdZ(QNX5B@tIamWyux4qXdP>tA;L_2o;Ks=mB< zc*L?X`asRQ6=&jJCr>x3)>D;^?Yb6lAf!q!7X2!!G9=BYy9HX?lQY7DB?B?;_Xpt{@`p=0|9~W;In4{2q`?SjD$ezWv zQ>(M8pM9GWt?71%gTZEw`I^HUR!!bj!DVa9BDYm;_12{P`{li7zQ~juzU#%v;POG& z^R4zecd^{p0q-V!5ZrxpbNcz+@ArB0zn|u{^#8Bx`?uxae>cS=>cCvOGLF=>Zesy#F-+73P0-cOi#r_glgD_a}Z_a{leSiKUK*_pL}>|1JEZ#FPo1nw)Q3#hv9h z&SXhoGBA{QcFE^=+=O4Y6(1A~3@&V26`)~bJJ-0D)$3iyV#5xuKEv53zixkYFLb-{ zS+2fUGY;m;92E(YkT$<##+}?V$>KKOxwCJ?R<|;BolRjraFShJex=;TnQy+Wd;9W< zokc;x*1yHRYfkd-DG94*U|^Qnmu)K(<#oRO-?7^3In1kt`zvzN${q+YY}hTl%Q;`w zs^rCl$&)Xy3|8+x`sr$T{L&>$bmI5j(VV#8NuPzt{*vVu`I>H04+WQfu5iBlF1Tv< z>E_5ipK2K#Htp@5w2&b{>Q}ol^V&xXUnPbGhArH-Vfmi)CE+RzU#5J2qxt^jvEtRw z8GrmMT6gZ(`Q?>q&+5BayPrxi+z?ps<;Ys2IVBDsI+}H(ws~?2Oi_qQ^T~cd=diylcbEH|ONG`uxvcxS%KD($~&9?Z;>9UobIDzVo%DX#T^6 zvmY*8U3P+p|E|c)e~zvDnzh%T73*=E!>U?-Bu`>mP~WpH7gJS^J_wRHr~hwe%FdUm z!3LK+3|kuvc`kLjO%FV@$alssDK(BuRr|aj8L_kPe11%BX&@&$UFwR=c*SeNu_6+$m+gwkb>p5;`-BCv4h&;meiwMHX(Ak6BK=>3F>GN#Bk3(|>2~ z>0)LGsdP7=Tp_?PrDg7-^uYC9NnEC%>N8zH3(y)?e7gFRe+vJnt3UNw_Brf#7I`Fh zD6y#K=su>h)SRnEyIY&Qqt3DNT3b-dkOsmG$cG?s9G}u0MbNSe3oGvA_QR#^mGIjKzI}Gj5rO1P28P2@6l2G)bdt zRd#h`WMoZEO+o@_&GDrK0qZ1z)IFc}>g_DHT($p&Zdzb|@ApHO9x$t2WT^5!d*&U3 zimO-__tj;m<}a-l{a$pc_)bOMHd!Sb<)*vMxijZ3+nn^=H0M|P6s9*@cdwJ?YTcwh!x` z`o94EV!wqaR^^G@-|^*#kfYGVxQT{#h71Cag)iS+_NcFb5YOXCyIm8`7}3ZTV2tInm!iH1f#U%g<#frFm~OcIOMuU;2-_U(!@ zamMY^c^smvEoXgp`vXAeCyPXaDtbBEGP3gV~x^EQUGcx4WY!~=0 z5WjJKu0z$?M;D)8d6TU5j+M81>Hb~q2Y46^or-%d+zC(NdlKfy=acU~A^p+2cX8)^ zS8d<^egD6&`tHXrx10p|dBwfB&+UO}+nzC9p0WD-3^oQ4gTmTr2TQjE3i-cJIBLsS zeyB$>ZFOX7(8(W03>wB${(gO+FL&Y}8wP7c9TA_SmN*|8{?^ z3B!gf;hQhTpFJ2bo%@o?qQ#4|^L%`Lef|96wq}K9Wvx1_lnJ(SZ`SSEdJIb%Eml32 zx$4>XttRsWW0$5c`tHm{g2oPA}g^r_ERf3n_c+Ofcb?brhYOP-#KM;CXm zzcF2I!np$ySB-w_GQVD)bdZ(T+AZUsl>;jSvx{1s^{W08GN;zoZ10%2i`#LQM{Mdh zHh#G~D}&YD-7dA%m%d)LIy~2Ufl)QXgAYd4Il*QJKdH@3VkkHrf7I-*A=e_#TE>HE z%nc{M>M}4GGu-(9NLVFsnf~G#BJGiTS2a&G*fcZe*U#q@=O{~Ub~__BJ^Qq4jv&L4 zpW){OGFN*{&px*Pm8F}|>^I988;X>_-7m`XZ`{c4@BjZs%O;X7=4LBYsq)3v`#gH|?opIT^CeYW-RsW+Xc>%^wV-|$?(z#y?7bS^+{;>^$9wc**Z z#~2w-|G9AL(-MiR^KH#qV?y8E@7jMh%$O}=iF?Wt_ow$;q?ei(O|kS^T(sf;gR(_s z3;}EOpKbo}rDa#BXhg(43q}S@HJf+q_!(M?&bC`?Ff=S_U`jCCY~J=JD0qXbL+ZB$ zeNX01ocM6Uf`5&t-k2);hNbl%;@xiXDwt)vvaPw5@N=OwM$oB%izE`HEzzigO*=Zc8R!k-dGe6xnlc~*?p^Im&aaB))g@`5C62i zZSkh0?Tfo^NQfS5-1_fS#zfT#&L+1{6<=5}t4UWxYco5;?(+BBbnox0{e3;YUe>Z` zNw88T<4M`f9`(zmAHD0R+WZku;F)`Tc1h9o)61-~eSZD@^t&W&d*y-}2lemoKE1nI zwr}0>;L1&6@s*Az|Ar z{b%9wKc$}hI$xlv&1%lGL;m=yLn@33p7Wlp5_^9@Rc`i7AvsQl>gLl7j!`0f?a2lf z&&60&zl-%dPI>%`r^-s4!6#zNNu>^xPObUg(S`YYO)hFSri!FJSykj+qAGk?o$IEP z*<@Rdf(!F2U*;^@v}BIt<6k>N_OWesQ~a|rV!<|}Ypfc=OV}8GT=G{L#$*S$# zqSN6|PrDWgy0b8F^)@MVa-8S5efxh}+zWG;?~DbvWW7oiY`njo*A!U89l+FJK3nE# z)*EFbeu2=wts8uM`V@3M932~TZ=OD#{q@z=ZIT=^JgVQPwPaQu37r3Eh5yRiwP~rp znT{E8C-6f$>-pK?r-J|7=i1+Tzx1#$R0+k#Pt2eCYf+Ch+n=VkyTJ*4LJ8e5KjS?h@B8MH~0cm{)(%%y|0zBl?$&FZJqQjnY0ovwo$( z(Yq!8E&TsXUsaTIr{7Vuq~1z*QvOT@*Tb;_OFS1?mp?DwYtC$bhk-#YP)RG|tiq`) zb*C8{GBs0Xeg3jZQ!O#S%Aec*j;3IkgjU}j>qTZOV=LDQA5vp*Xi!P;dNO6z`Wg3( z9?b4$Nxw2DVq;-$0~f=w9g??;JNGGV=HFfPLz%m|l<^d2(BG?Eo0?~sh9sq!ZWiwo zSaQ|jZ^?gfDIf!>HI>nP(`D#y*^G|R`zeBm`>CUogrQbw< zhqawem=^hgTdQx{k+{<9%nf}<&Sl^Ddvuw_^!j-n*M0?TS${%?k#E(J7KL0fuXpF1 zBUx0VcRu~SD%Xs=+Co)kuj~2bj|M!88>}jxFSwai_IT&aHEMj54<~JC+bYk-Af@g0 zUFxp+#$U1185``6d#QhyWBNQ*@2Fp=jN`2S?Ca||S(+X^NMO*=(o*ugbbI$NlPi6R z&+WdqUAfx4EjFz`^VDGtZU%;9LL&c9D4bfmBmAmt&$`7jGC@^|Rj1BQi8rd(G@io9 zz?{sJYyahHNBHsf-sRSD99+}vg!p%9cAxoT5-7pIQqwK9Tr>x_@j|bW1 zGfboyetbS}pPZcR-Xk$_%9JNlJl@Q_ll%3vk&#hRQPHbgak-&7V()KlU0weEURlqQ z%16`R7VS5^^SFv9x>kyTVZ)^d&8iQ@PdWWJ*wL#z!>H+Y;M?yz9cNv*GEt-V)a#?y zPxC(A7RopIa`3&$?cshupJ;v9nNsjqC4S8oBZh|7gQ2pwg}0ykd~KE|0|Un>)BwbY*|=W$w$23dhXb*2&09 z3ve@}b?GHIG9EaxJ8$~d9KGhQa>H*zvlt(ozi??8ACF@cqrboZ-njKwv)SJO3P^PTR@V%&%Xqy!vWeKwAG|OZ9Wn$Ba^>mk3W`ywA{Z>^bvse(!LpsW($^ z_FwJa+Y(oM>nmf!w{>r0cj(zE$umYfyx+XP>3cROsE^V*ze{e_juX*`lN`(&TYI&{ z6i;k^aee*$IhMsdY|c(jOnr|lD=Up=p3$6miCDKNIAY~IQ($W zzhAGb_S)&{u66I1i;IgZac_Nm(|D)(hIMjniE9_0k#jBja-C(?Vo|xznr!?I84t=# zz2mQUwnd#yQC@Y~blsV_h3f(qhKjuIYG>s=%#a+Yvoqk`!S55epMEK=PDxvOTar|n9rS-uFbhvJ1KKWkrPuOhFnR&<7JbYZEc8sNA${P{e zh2_t89{+XpQ)CUp3FFOruXgaC{qcLAC_{jgf&0@FzqxpuUE2bM?tVU=DUM|Ageg;| z%$)i2<8k?ZIoqoH`)cRcev5Q*InpC(EF&YQwfTC2$ia*M&aSn{m~v#MiZjE37ltQY z`pkFnERM)4>s+sx`t1_;<^1XQ!e(DNY|WFep2^N|*osHE_{h?*dD^$R7^;M-AGR%T zJ+wrpXy5wA^9yP$C&*<=cirPzr^2vh>8aui)14K%1#==RnE^r<`v-M6((RJ@zGh>W+Cg0mq znSHorW}5-$TgS>w&(DXJShlILp4-^0_`o4aM(1XcPUJPOO>tqjekb=XjB%Q<_UgK_ z{qy&$uwM9l^uvP}H~-r1|Nr;%d3*gB#)z1hJ;}%W*ySn|zMq|2(Edtx)2}$4FK-@6 zGN-Q)ob`K0v9nnH-+vqbt^T)KZ1U2TJ3K9T=5|!flke=~X<>^Ao4)&kuS?9V;u$iZ zPe1dYx97*4{r}z?2G_^@{`co$RPw1c59hCzo}KzAOXQj!Q0I zCZB&>&ml6y^beDF(X>wGMe$eJj;`QhSoUn=ak*|6C6_CA?&KIqe0zJl{PU?dF;2zm zN=B@GqAdN=H-Zm;_WvBEou0*Urb;(4_o=Dc#{0X{cRZg~T(M%j49qX60(4O1%@) zdt6dvtNdn5bXdQ;yhK@Z?bMD(+p3RLTsE2iPw7|d^siRjb4)Rj1Z1^@^v-X?2yv=#{$$<|)E}iJ@t}ko* z+S1yR!8Zas?|JD8%Wc1%d_2AXkGtq^UvH(?p^Oa@d@>dX49=_! zUhX&FuJ+Rt&%VceayA;Cs#!nJ#U5rgS!sAK!rkT9$L?Pq-z!f3jX8LPF;4R_kKsKN z5&pSf=gCS)7l>J0H(RT^D9U|pV0Ot2?YU~gf~u8OFT4V0%n4t)tjosGD0cCyuV!mR zSxy}i|~yMwf~w6^8n-&guNEQU*y>+g@_t=H@Fc)nBl4Z}19ThJvEj@I0#?Iwuo~`rcd#QZa z@VJ+fSN57+KdyS*bDQV>Jy`dD z$Nzto-?_`>YR!JlJp4p}&r^NT{U191)j2Z$_NzGF7i@Mp^6^XPZQY`>dAnsctm!IS zu}VG1YHpv~;;_}Bubhe;Eu7r9ZGT*~_uk8GlQiF4U7WN2=H+ASqiXfDb_6Otl1x4o zAX%3C`Mlk{yXWRTyL@=!!*>hc1=K9^tG}}T@{4_e|9IEBdAl5(vTXMJ@5S+d_1V<_ zsp)T0sSi2#FZ0`p{b3spY2S!uS&$=N_aiYsfBlCW&p-3>@p*-w+%oI;m2a<7%g@gH z`>Ox+IelH3AO6hMS�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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_10.png b/doc/images/benchmark_segments_10.png new file mode 100644 index 0000000000000000000000000000000000000000..cee2c5419c35827640f0f69468071c0344e25bad GIT binary patch literal 13036 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 B`)2?E literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_1000.png b/doc/images/benchmark_segments_1000.png new file mode 100644 index 0000000000000000000000000000000000000000..01b61638439f62ca3550c14fc300a1e12c0d0ba7 GIT binary patch literal 13067 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_10000.png b/doc/images/benchmark_segments_10000.png new file mode 100644 index 0000000000000000000000000000000000000000..4f0e840cba6f65ad5e2aa695fff7e576431c86ad GIT binary patch literal 13387 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_100000.png b/doc/images/benchmark_segments_100000.png new file mode 100644 index 0000000000000000000000000000000000000000..126bd9f07920fafd853c3592e8ed0ec418a41bdf GIT binary patch literal 13245 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_1000000.png b/doc/images/benchmark_segments_1000000.png new file mode 100644 index 0000000000000000000000000000000000000000..a484504809a55132bfbdf29f33255d3cbce83e6f GIT binary patch literal 13223 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_all.png b/doc/images/benchmark_segments_all.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c77a130226b2926bcd6b2e914627c5cc49d302 GIT binary patch literal 19244 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 literal 0 HcmV?d00001 diff --git a/doc/images/benchmark_segments_memory.png b/doc/images/benchmark_segments_memory.png new file mode 100644 index 0000000000000000000000000000000000000000..fe25346368b331835a90448c2bfdba9e4d76950d GIT binary patch literal 24333 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 z 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

      P09K4?sa0Rw#KsGR#Tg1&v>o9 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 QIN#-#_O!;i-TnVf0OcR=_5c6? literal 0 HcmV?d00001 diff --git a/doc/images/voronoi.png b/doc/images/voronoi.png new file mode 100644 index 0000000000000000000000000000000000000000..c785f185c749a0ca70117154381bbd6e1c06aae2 GIT binary patch literal 53336 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�drs=qFQKar zr|934`WCP5XVAN1hC%`p(<6ad47={du8ZE@=QUMJG&RLwRpF6tasR6_dH46tHOsrR zLgtK`@2r4(dn!YtG=qHKCRtQE*E+Uxc^nWIW@!>;v}j(x=Mz_B=5_sI!K05&mfqVh zbaj?P$d~B-Q5T=8Swvav*tF@OqRZOFp*m^$*ED8(UnzN&e5rlR@# zITF@?ez*I*)+U?PGnDE$6H}|ITtpwpRAnmsp3Jdudcw)nS)eOkpG}x``@yZP*`ilJ z{r&yjRMz9qkB=);Pfy#De4Nkei=fkr#JSFY%C)6Ej1_k2s&TMrGrc>p;Ql!U=JNSR zdpnI6E?Di_*|BX?Q*ZZN7i|f%Ad4fLHYvv5)w(2{o@WqL{ffJQU4tigCLWro z?9O&=!W~_XicW?ni`T{OPP1%#lA@5)*FF8IbC%Kh(EJYtueIJF9$iMMQ3B zijAA%gEF@2@9$&-rvE?m^Kj&4=6@gRo-0n@%@ZRZFnQKp86lxZ#a(;S=2qVn2>Nlb zC5v_SZ{>caYm>J=F-h3EjB(cPWdZlLGBRmyckg7dVBGibSN5%)#pzS7OI0>5>TS|- zQA(RusVV$6sc**CxM^nl{(igN#Ss9yJCL!EK8*SWu1USrCwiK~7M$eg{Q+B2*eEm{ot%EBA zPEHoAHJZKR*7t*Lt7@NjpLp;(#%pimYqsJ~R$}Q)JvK2_rpu<86*E2kzkdHeE%t(2 z2Q=5ZG%##p3^-Kuhl|awP7tbT-5=m;wbFUI`H$*ny`W9|XFXr@=;!~Mmd(Og z$WdCu7O)|{$mstAzp6=DOM~NAhpk=o>gsCkZ@VN6lU`i$zH;`EB@5%(dwZ)nd6pOO z2^zLcVdco&mUC06RM{%Vu;N3)EUT&ADNT3$V$`#CHh8$Q9cf}>)Sc^So{+3nyecEx z?rWZ3$v*9i)<-+UaumEi*)Q6^CRk2f{+Hw=L>X*PC9P z-}dH(_@}L==dbUc>ooDlMZVz7m-Z|Ua?Q2

      Li17u}Ij(3vnR!%z0U+f3W)ve0SD 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 K=d#Wzp$PyU0aB0v literal 0 HcmV?d00001 diff --git a/doc/images/voronoi3.png b/doc/images/voronoi3.png new file mode 100644 index 0000000000000000000000000000000000000000..15ab7a9a5330b8024f02f5b58401ed4b3f490ba9 GIT binary patch literal 32558 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 b&v;?SpWn<@A$J%U7#KWV{an^LB{Ts5QFEus literal 0 HcmV?d00001 diff --git a/doc/images/voronoi4.png b/doc/images/voronoi4.png new file mode 100644 index 0000000000000000000000000000000000000000..bffb72fd96f5d70d19aeecd415a0ade193bfcd72 GIT binary patch literal 9406 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 d=J) - -Boost Polygon Library: Main Page - - +-->Boost Polygon Library: Main Page + + + + + + + + + + + + + + + +
      +
      - + +
      -
      +

      THE BOOST.POLYGON LIBRARY

      The Boost.Polygon library provides algorithms focused on manipulating planar @@ -67,21 +100,38 @@ algorithms such as polygon connectivity graph extraction, offsetting and map-ove An example of the disjoint-union (XOR) of figure a and figure b is shown below in figure c.  These so-called Boolean algorithms are of significant interest in GIS (Geospatial Information -Systems), VLSI CAD as well al other fields of CAD, and many more application +Systems), VLSI CAD as well all other fields of CAD, and many more application areas, and providing them is the primary focus of this library.  The Boost.Polygon library is not intended to cover all of computational geometry in its scope, and provides a set of capabilities for working with coordinates, points, intervals and rectangles that are needed to support -implementing and interacting with polygon data structures and algorithms. 

      -The coordinate data type is a template parameter of all data types and -algorithms provided by the library, and is expected to be integral.  -Floating point coordinate data types are not supported by the algorithms -implemented in the library due to the fact that the achieving floating point -robustness implies a different set of algorithms and generally platform specific -assumptions about floating point representations.  -For additional detailed discussion of the library and its implementation -including benchmark comparisons with other open source alternatives please see -the paper and +implementing and interacting with polygon data structures and algorithms. 

      +One of the important features of the library is the implementation of +the generic sweepline algorithm to construct Voronoi diagrams of points and linear segments in 2D (developed +as part of the GSoC 2010 program). Voronoi diagram data structure has +applications in image segmentation, optical character recognition, +nearest neighbor queries execution. It is closely related with the other +computational geometry concepts: Delaunay triangulation, medial axis, +straight skeleton, the largest empty circle. The Boost.Polygon library +provides interface to construct Voronoi diagram of points figure a and +line segments figure b (the last could be used to discretize any +two-dimensional curve). Figure c contains the example of the medial axis of the +non-convex polygon. The implementation outperforms most of the known +commercial and non-commercial libraries in both efficiency and +numerical robustness aspects. You may find more details on the topic at the Voronoi main page.
      + +

      +

      +

      The coordinate data type is a template parameter of all data types +and algorithms provided by the library, and is expected to be integral. +Floating point coordinate data types are not supported by the +algorithms implemented in the library due to the fact that the +achieving floating point robustness implies a different set of +algorithms and generally platform specific assumptions about floating +point representations.  +For additional detailed discussion of the library and its +implementation including benchmark comparisons with other open source +alternatives please see the paper and presentation from boostcon 2009 as well as a detailed analysis of the runtime complexity of @@ -95,40 +145,39 @@ runtime or memory efficiency of the underlying algorithms.  The API is intended to demonstrate what could be achieved with ease by a C++-concepts based library interface, but is implemented based on current language features.  This API makes the following code snippet that operates on non-library geometry types possible:

      - + -
      -
      +
      +
      - - void foo(list<CPolygon>& result, const list<CPolygon>& a,
      -          + + void foo(list<CPolygon>& result, const list<CPolygon>& a,
      +          - + const list<CPolygon>& b, int deflateValue) {
      -
      +
      -     +     CBoundingBox domainExtent;
      -
      +
      - -      using namespace boost::polygon::operators;
      -
      + +      using namespace boost::polygon::operators;
      +
      - -      + +      boost::polygon::extents(domainExtent, a);
      -
      +
      - -      result += (b & + +      result += (b & domainExtent) ^ (a - deflateValue);
      -
      +
      - + }

      In the code snippet above the hypothetical polygon type CPolygon has been @@ -139,10 +188,11 @@ The end result is accumulated into a list of polygons with a union operation.&nb It is considerably more typing to describe this usage of the API than to code it, and the description is not much clearer than the code itself.  A picture is worth a thousand words.

      -

      -

      In Boost.Polygon operations such as those shown above are free functions named for what they do, or are overloads of C++ operators that make it -easy to infer from reading the code what to expect.  Operators are -contained in the namespace boost::polygon::operators +

      +

      In Boost.Polygon operations such as those shown above are free +functions named for what they do, or are overloads of C++ operators +that make it easy to infer from reading the code what to expect.  +Operators are contained in the namespace boost::polygon::operators so that they can be used outside the boost::polygon namespace without bringing in the entire boost::polygon namespace.  Following the @@ -179,20 +229,27 @@ performing these programming tasks.

    1. connectivity_extraction_usage.cpp Using the connectivity extraction algorithm to build a connectivity graph on polygons
    2. -
    3. property_merge_usage.cpp + +
    4. property_merge_usage.cpp Using the n-layer map-overlay algorithm on polygon data
    5. + -
    6. Tutorials: +
    7. Tutorials:
      • Layout Versus Schematic Learn how to apply Boost.Polygon capabilities to implement a simplified circuit extraction application
      • Minkowski Sum Learn how to apply Boost.Polygon capabilities to implement Minkowski sum of polygon sets
      • +
      • Voronoi Basic Tutorial Learn how + to construct, traverse, visualize, associate data with Voronoi diagrams without digging into the library details.
      • +
      • Voronoi Advanced Tutorial + Learn how to configure the Voronoi builder and Voronoi diagram + data structure with the user provided coordinate types.
      - +
    8. We would like to thank: Thomas Klimpel, Frank Mori Hess, Barend Gehrels, @@ -206,17 +263,17 @@ feedback and or formal review of the library as part of the boost submission process and Fernando Cacciola for graciously serving as review manager.

      -
        - +
      - + - + @@ -229,6 +286,6 @@ process and Fernando Cacciola for graciously serving as review manager.

      http://www.boost.org/LICENSE_1_0.txt) -
      Copyright: Copyright © Intel Corporation 2008-2010.
      +
      - \ No newline at end of file + \ No newline at end of file diff --git a/doc/voronoi_advanced_tutorial.htm b/doc/voronoi_advanced_tutorial.htm new file mode 100644 index 0000000..ad002c0 --- /dev/null +++ b/doc/voronoi_advanced_tutorial.htm @@ -0,0 +1,462 @@ + + + + + + Voronoi Advanced Tutorial +

      Voronoi Advanced Tutorial
      +

      + +This tutorial consists of two parts. The first one provides two +examples of a real world problems that default configuration of Voronoi +library is capable to solve. By default configuration we mean the one +that accepts +signed 32-bit integer and outputs floating-point (64-bit +double) coordinates. We provide those examples to convince even the +most skeptical users that they probably don't need to configure library +for higher-precision input or output coordinate types. However if the +posed problem really requires those, fully featured configuration of +both input and output coordinate types is provided in the second part +of this tutorial.
      + +

      Red Planet

      + +

      Problem Statement

      + +
      + +
      Lets imagine that NASA is +planning to send a new robot to Mars. Each day the center situated on Earth +will send a destination point coordinates the robot needs to reach by +the end of the day. Of course we'd like to save as much energy as +possible thus choosing the shortest possible path. This would be a +straight line in a perfect world (we don't consider curvature of +surface), but situation becomes more complicated as there are some +rocks and wells on Mars our robot can't go through. Behind of those our +robot has some dimensions that might not allow it to pass narrow places.
      + +

      Application of Voronoi diagram

      + +The problem above could be solved using Voronoi diagram. The first +stage would be to discretize obstacles (rocks and wells) with +polylines. Afterwards we will compute Voronoi diagram of the input set +of segments. As each Voronoi edge is equidistant from the two closest +sites we are able to filter edges the robot won't be able to pass due +to it's dimensions. The last step would be to run a bit optimized A* +algorithm to find +the shortest or at least suboptimal path and we are done.
      + +

      Discretization of input geometries

      + +To show how good is the default input coordinate type provided by the +Voronoi library +we will discretize the whole area of Mars. That will be approximately +1.44 *  10^8  square kilometres that is equal to 1.44 *  +10^18  square centimetres, which could be snapped to the integer +grid with a side of 1.2 * 10^9 centimetres.  To make the Voronoi +graph +precise on the boundaries of that grid we will replicate input map 9 +times (3x3), thus Voronoi diagram within a central piece will +provide us with a correct connectivity graph. This step will increase +the size of our grid to 3.6 * 10^9 centimetres that is less than 2^32. +So we are able to discretize the Red Planet's surface within a 1 +centimetre +precision using the default input coordinate type (signed 32-bit +integer). That would imply maximum absolute error to be +equal up to 0.5 centimetres per coordinate. Considering the radius of +our robot to be +0.3 metres and for security reasons avoiding any large enough obstacles +that are within 1 metre distance from it that error would be irrelevant.
      + + +

      Output analysis

      + +Estimates of the resulting Voronoi diagram precision were already +explained here. +So to avoid those computations again we will simply state that the +maximum absolute error of the output geometries will be on the grid +boundaries and will be equal to 2^-16 centimetres, which is +approximately equal to 150 nanometres and is 100 times larger than +a radius of a complex molecule. We would like to notice that the +absolute error of the discretization step is much higher than the one +produced by the Voronoi diagram construction algorithm. +

      VLSI Design

      + +

      Problem Statement

      + +
      + +
      + +Very-large-scale integration (VLSI) is the +process of creating +integrated circuits by combining thousands of transistors into a single +chip. Considering the fact that it may take weeks or months to get an +integrated circuit manufactured, designers often spend large amounts of +time analyzing their layouts to avoid costly mistakes. One of the +common static analysis checks is minimum distance requirement between +the components of an integrated circuit (distance should be greater +than +specified value).
      + +

      Application of Voronoi diagram

      + +It appears that the minimum distance between components of the input +set of points and segments corresponds to the one of the Voronoi +diagram edges. This means that we can iterate through each edge of +the Voronoi graph, extract the pair of input geometries that form it +and find +the distance between those. As the total amount of such edges is O(N) +value +(N - is the number of input geometries) the minimum distance could be +efficiently find in a linear time once we construct the diagram.
      + +

      Discretization of input geometries

      + +The average size of the modern CPUs is around 2.5 x 2.5 centimetres. +Snapping this to the 32-bit integer grid will give discretization +precision of 2.5 / 2^33 centimetres or 3 picometres that is 10 times +smaller value than radius of an atom. That would be probably good +enough precision even for a few next generations of processors.
      + +

      Output analysis

      + +The maximum absolute error of the output geometries will be 2.5 / 2^47 +centimetres or 0.2 femtometres that is 10 times smaller value than +the radius of an electron. However in this particular case we are not +interested in the precision of the output, rather in its topology. As +it was noticed on +the Voronoi main page very small edges +are removed from the Voronoi diagram. However user should not worry +because the edge that correspond to the minimal distance won't be among +those. That means that we would be able to 100% correctly identify a +pair of closest objects within the discretization precision.
      + +

      Conclusions

      + +The above two examples show usage of the default Voronoi coordinate +types +in the macro and micro world. The main point of those was to give the user +understanding of a scale that the default coordinate types provide. There +are +two main points we didn't mention before, but that would be relevant to +the most real world problems:
      + +
        + +
      • The absolute error of the coordinates of the output Voronoi +diagram +inside the 32-bit integer discretization grid is slightly smaller than +the absolute error of discretization itself, thus could be neglected at +all.
      • +
      • In both problems above we didn't consider error of measurement. +For example: is it possible to construct a map of the Mars within the +0.5 +centimetres precision, or to get coordinates of the circuit parts +withing the subatomic precision? I guess the answer for both questions +would be "No". And that actually means that the error of the +discretization +step could be neglected comparing to the error produced by the +measuring +devices.
        +
      • +
      +The second statement means that there is actually no point to provide +implementation that operates with floating-point input coordinates, +because those always could be snapped to the integer grid. In case the +user is not satisfied with the precision that the 32-bit integer grid +provides or would like to retrieve coordinates of the output geometries +within a smaller +relative error, follow the next paragraph.
      + +

      Voronoi Coordinate Types Configuration

      + +In the following chapter we are going to extend input coordinate type +to the 48-bit signed +integer and output coordinate type to the 80-bit IEEE floating-point +type +(long double). The code for this chapter is available in voroni_advanced_tutorial.cpp. +While it won't be possible to compile it using the MSVC compiler (it +doesn't +support 80-bit long double type; ieee754.h header is required), it +should give a clear understanding of how the library supports the user +provided coordinate types.
      + +
      + +So the main step would be to declare the voronoi coordinate type traits +that satisfy set of restrictions explained here:
      + +
      + +struct +my_voronoi_ctype_traits {
      + +  +typedef boost::int64_t int_type;
      + +  +typedef detail::extended_int<3> int_x2_type;
      + +  +typedef detail::extended_int<3> uint_x2_type;
      + +  +typedef detail::extended_int<128> big_int_type;
      + +  +typedef fpt80 fpt_type;
      + +  +typedef fpt80 efpt_type;
      + +  +typedef my_ulp_comparison ulp_cmp_type;
      + +  +typedef my_fpt_converter to_fpt_converter_type;
      + +  +typedef my_fpt_converter to_efpt_converter_type;
      + +};
      +
      +
      It is always better to use C++ built-in types wherever it's +possible. That's why we use the 64-bit signed integer type to handle +our +input coordinates. int_x2_type +and uint_x2_type +is required to handle 96-bit signed/unsigned integers. As there is no +such built-in type we use library provided efficient fixed integer +type. +The big integer type should be capable to handle 48 * 64 bit integers, +that is +less than 32 * 128, and so far we are good with extended_int<128> +type. We use the same floating point type for both fpt_type +and efpt_type +as it has enough exponent bits to represent both 48 * 32 bit and 48 * +64 bit integers (that is also the reason we don't need two +floating-point converter structures). The ulp_cmp_type +structure checks weather two IEEE floating-point values are within the +given signed integer ulp range (we won't analyze corresponding code +here as it requires deep understanding of the floating-point +architecture and its usage to compare +floating-point values), but just to mention the declaration is +following:
      + +
      + +struct +my_ulp_comparison {
      + +  enum +Result {
      +    LESS = -1,

      + +    +EQUAL = 0,
      + +    +MORE = 1
      + +  };
      + +  Result +operator()(fpt80 a, fpt80 b, unsigned int maxUlps) const;
      + +};
      +
      +
      The last step would be to declare the my_fpt_converter +structure (converts the integer types to the floating-point type):
      + +
      + +struct +my_fpt_converter {
      + +  +template <typename T>
      + +  fpt80 +operator()(const T& that) const {
      + +    +return static_cast<fpt80>(that);
      + +  }
      + +
      + +  +template <size_t N>
      + +  fpt80 +operator()(const typename detail::extended_int<N>& that) +const {
      + +    +fpt80 result = 0.0;
      + +    +for (size_t i = 1; i <= (std::min)((size_t)3, that.size()); ++i) {
      + +      +if (i != 1)
      + +        +result *= static_cast<fpt80>(0x100000000ULL);
      + +      +result += that.chunks()[that.size() - i];
      + +    +}
      + +    +return (that.count() < 0) ? -result : result;
      + +  }
      + +};
      +
      +
      At this point we are done with declaration of the Voronoi +coordinate type traits. The next step is to declare the Voronoi diagram +traits:
      + +
      + +struct +my_voronoi_diagram_traits {
      + +  +typedef fpt80 coordinate_type;
      + +  +typedef voronoi_cell<coordinate_type> cell_type;
      + +  +typedef voronoi_vertex<coordinate_type> vertex_type;
      + +  +typedef voronoi_edge<coordinate_type> edge_type;
      + +  +typedef struct {
      + +  public:
      + +    +enum { ULPS = 128 };
      + +    +bool operator()(const point_type &v1, const point_type &v2) +const {
      + +      +return (ulp_cmp(v1.x(), v2.x(), ULPS) == my_ulp_comparison::EQUAL +&&
      + +              +ulp_cmp(v1.y(), v2.y(), ULPS) == my_ulp_comparison::EQUAL);
      + +    +}
      + +  +private:
      + +    +my_ulp_comparison ulp_cmp;
      + +  } +vertex_equality_predicate_type;
      + +};
      + +
      + +Above we simply declared the Voronoi primitive types +and vertex +equality predicate using the new coordinate type and corresponding ulp +comparison structure. As we are done with the declaration of the +coordinate +type specific structures we are ready to proceed to the construction +step itself. The first step would be to initialize voronoi_builder +structure with a set of random points:
      + +
      + +// Random +generator and distribution. MAX is equal to 2^48.
      + +boost::mt19937_64 +gen(std::time(0));
      + +boost::random::uniform_int_distribution<boost::int64_t> +distr(-MAX, MAX-1);
      +
      +
      +// Declaring and configuring Voronoi builder with the new coordinate +type traits.
      +voronoi_builder<boost::int64_t, my_voronoi_ctype_traits> vb;

      +
      + +// Voronoi +builder initialization step.
      +for (size_t i = 0; i < GENERATED_POINTS; ++i) {

      + +  +boost::int64_t x = distr(gen);
      + +  +boost::int64_t y = distr(gen);
      + +  +vb.insert_point(x, y);
      + +}
      +
      +
      The second step would be to generate the Voronoi diagram and +this is done as before with the two lines of code:
      + +
      + +// Declaring +and configuring Voronoi diagram structure with the new coordinate type +traits.
      +voronoi_diagram<fpt80, my_voronoi_diagram_traits> vd;

      + +vb.construct(&vd);
      +
      +
      From this point the user can operate with the Voronoi diagram +data structure +and in our tutorial we output some simple stats of the resulting +Voronoi graph. Probably the hardest part of this tutorial is +the declaration of the ulp comparison structure. The library provides +efficient well-commented cross-platform implementation for 64-bit +floating-point type (double). So the best advice would be to follow +that implementation, but before doing that really consider thoughtfully if the +default +coordinate types are not capable to deal with your problem.
      + +
      + + + + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      + + + \ No newline at end of file diff --git a/doc/voronoi_basic_tutorial.htm b/doc/voronoi_basic_tutorial.htm new file mode 100644 index 0000000..be4b0a4 --- /dev/null +++ b/doc/voronoi_basic_tutorial.htm @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + Voronoi Basic Tutorial +

      Voronoi Basic Tutorial
      +

      + +

      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:
      +

      + +
        + +
      • preparing input geometries
        +
      • +
      • Voronoi diagram construction
      • + +
      • Voronoi graph traversal
        +
      • + +
      • associating the user data with the Voronoi primitives
      • +
      • accessing input site inside the Voronoi cell
      • +
      • Voronoi diagram rendering
        +
      • + + +
      + +In the example that goes through this tutorial (voronoi_basic_tutorial.cpp) +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. We split each input segment onto three sites (segment +itself and both endpoints), edges that go between the sites corresponding to the same segment are +considered to be non-primary.
      + +
      + +
      + +
      + +And before you proceed don't forget to:
      +

      +#include "boost/polygon/voronoi.hpp"
      +using boost::polygon::voronoi_builder;
      +using boost::polygon::voronoi_diagram;
      +
      + +

      Preparing Input Geometries

      Below is the example of how the user provided point and segment classes might look like:
      +
      struct Point {
        int a;
      +  int b;
      +  Point (int x, int y) : a(x), b(y) {}
      + +};

      +
      struct Segment {

      + +  Point p0;
      +  Point p1;
      +  Segment (int x1, int y1, int x2, int y2) : p0(x1, y1), p1(x2, y2) {}
      +
      + +};
      +
      +
      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:
      +
      +template <>
      +struct geometry_concept<Point> { typedef point_concept type; };

        
      template <>
      struct point_traits<Point> {
        typedef int coordinate_type;
      +   

        static inline coordinate_type get(const Point& point, orientation_2d orient) {
      +    return
      (orient == HORIZONTAL) ? point.a : point.b;
        }
      +};

      + +
      +template <>
      +
      struct geometry_concept<Segment> { typedef segment_concept type; };
      +
      +
      template <>
      +struct point_traits<Segment> {
      +  typedef int coordinate_type;
      +  typedef Point point_type;
      +
      +    
      +  static inline coordinate_type get(const Segment& segment, direction_1d dir) {
      +    return
      dir.to_int() ? segment.p1() : segment.p0();
      +  }
      };

      +
      +It's also possible to use the native Boost.Polygon types as point_data and segment_data, that won't require the above mapping.
      +
      +So once we are done we can create the sample input:
      + +
      + +std::vector<Point> +points;
      +points.push_back(Point(0, 0));
      +points.push_back(Point(1, 6));
      +std::vector<Segment> segments;
      +segments.push_back(Segment(-4, 5, 5, -1));
      +segments.push_back(Segment(3, -11, 13, -1));

      +
      +

      Construction of the Voronoi Diagram
      +

      At this point we are ready to construct the Voronoi diagram:
      +
      +
      +voronoi_diagram<double> vd;
      +construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &vd);

      + +

      Traversing Voronoi Graph

      + +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:
      + +
        + +
      • simply iterating over the Voronoi edges (counts each edge twice):
        +
        +int iterate_primary_edges1(const voronoi_diagram<double> &vd) +{
        +  int result = 0;
        +  for (voronoi_diagram<double>::const_edge_iterator it = +vd.edges().begin();
        +       it != vd.edges().end(); ++it) {
        +    if (it->is_primary())
        +      ++result;
        +  }
        +  return result;
        +}

        +  
        +
      • +
      • iterating over the Voronoi cells and then traversing edges around +each cell (counts each edge twice):
        +
        + int +iterate_primary_edges2(const voronoi_diagram<double> &vd) {
        +  int result = 0;
        +  for (voronoi_diagram<double>::const_cell_iterator it = +vd.cells().begin();
        +       it != vd.cells().end(); ++it) {
        +    const voronoi_diagram<double>::cell_type +&cell = *it;
        +    const voronoi_diagram<double>::edge_type *edge += cell.incident_edge();
        +    // This is convenient way to iterate edges around +Voronoi cell.
        +    do {
        +      if (edge->is_primary())
        +        ++result;
        +      edge = edge->next();
        +    } while (edge != cell.incident_edge());
        +  }
        +  return result;
        +}

        +
        +
      • +
      • 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):
        + int +iterate_primary_edges3(const voronoi_diagram<double> &vd) {
        +  int result = 0;
        +  for (voronoi_diagram<double>::const_vertex_iterator it = +vd.vertices().begin();
        +       it != vd.vertices().end(); ++it) {
        +    const voronoi_diagram<double>::vertex_type +&vertex = *it;
        +    const voronoi_diagram<double>::edge_type *edge += vertex.incident_edge();
        +    // This is convenient way to iterate edges around +Voronoi vertex.
        +    do {
        +      if (edge->is_primary())
        +        ++result;
        +      edge = edge->rot_next();
        +    } while (edge != vertex.incident_edge());
        +  }
        +  return result;
        +}
      • +
      + +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.
      + +

      Associating User Data with Voronoi Primitives

      + +A few simple cases of associating the user data with the Voronoi primitives are +following:
      + +
        + +
      • associating number of incident edges with each cell, vertex;
      • +
      • associating color information with each edge;
      • +
      • using DFS or BFS on the Voronoi graph requires to mark visited +edges/vertices/cells.
      • +
      + +We will consider the first example and will associate the total number +of incident edges with each cell.
      + +Note: Each Voronoi primitive contains mutable color member, +that allows to use it for the graph algorithms or associate user data via array indices.
      + +
      + +// Using color member of the Voronoi primitives to store the average number
      +// of edges around each cell (including secondary edges).
      +{
      +  printf("Number of edges (including secondary) around the Voronoi cells:\n");
      +  for (voronoi_diagram<double>::const_edge_iterator it = vd.edges().begin();
      +       it != vd.edges().end(); ++it) {
      +    std::size_t cnt = it->cell()->color();
      +    it->cell()->color(cnt + 1);
      +  }
      +  for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
      +       it != vd.cells().end(); ++it) {
      +    printf("%lu ", it->color());
      +  }
      +  printf("\n");
      +  printf("\n");
      +}

      + +

      Accessing Input Site inside the Voronoi Cell

      +As explained in the Voronoi diagram +section, Voronoi cells don't contain coordinates of the input +geometries directly. Instead they contains source index and source +category that uniquely identify input site. The below routines +traverses over the all Voronoi cells, fetches input geometry +corresponding to the Voronoi cell and prints coordinates of the input +site.
      +
      +unsigned int cell_index = 0;
      +for (voronoi_diagram<double>::const_cell_iterator it = vd.cells().begin();
      +     it != vd.cells().end(); ++it) {
      +  if (it->contains_point()) {
      +    std::size_t index = it->source_index();
      +    Point p = points[index];
      +    printf("Cell #%ud contains a point: (%d, %d).\n",
      +           cell_index, x(p), y(p));
      +  } else {
      +    std::size_t index = it->source_index() - points.size();
      +    Point p0 = low(segments[index]);
      +    Point p1 = high(segments[index]);
      +    if (it->source_category() ==
      +        boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) {
      +      printf("Cell #%ud contains segment start point: (%d, %d).\n",
      +             cell_index, x(p0), y(p0));
      +    } else if (it->source_category() ==
      +               +boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT) {
      +      printf("Cell #%ud contains segment end point: (%d, %d).\n",
      +             cell_index, x(p0), y(p0));
      +    } else {
      +      printf("Cell #%ud contains a segment: ((%d, %d), (%d, %d)). \n",
      +             cell_index, x(p0), y(p0), x(p1), y(p1));
      +    }
      +  }
      +  ++cell_index;
      +}
      +

      Voronoi Diagram Rendering
      +

      + + +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:
      + +
        + +
      • Some of the Voronoi edges are infinite, so should be clipped;
      • +
      • Some of the Voronoi edge are parabolic arcs, so should be +discretized.
      • +
      + +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. voronoi_visualizer.cpp +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 boost/libs/polygon/example directory.
      +
      +

      Summary
      +

      + +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. 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 advanced Voronoi tutorial we +explain why this is enough for the 95% of cases and how to expand the +algorithm coordinate types for the other 5%.
      + +
      + + + + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      + + + \ No newline at end of file diff --git a/doc/voronoi_benchmark.htm b/doc/voronoi_benchmark.htm new file mode 100644 index 0000000..cb1aacc --- /dev/null +++ b/doc/voronoi_benchmark.htm @@ -0,0 +1,534 @@ + + + + + + + + + + + + + + + + Voronoi Benchmark + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      + +

      Voronoi Benchmark

      +There are not many known Voronoi libraries that are capable to satisfy the +following set of conditions:
      +
        +
      • could handle input data sets of points and segments
        +
      • +
      • give exact warranties about the algorithm robustness and +output topology
        +
      • +
      • compute coordinates of the output geometries within the fixed relative precision
        +
      • +
      Below is the list of libraries included in this benchmark sorted by the number of conditions each of them satisfies:
      +
        +
      • Boost.Polygon Voronoi - satisfies all the conditions above, implements sweep-line algorithm.
        +
      • +
      • CGAL - satisfies the first two conditions, implements incremental algorithm. CGAL is a well-known +library in the computational geometry area, especially for its +robustness.
        +
      • +
      • S-Hull +- doesn't satisfy any of the above conditions. S-Hull is a non-robust +implementation of the sweep-hull algorithm used to construct Delaunay +triangulation of a set of points.
        +
      • +
      At the moment this benchmark includes only two robust implementations: +Boost.Polygon Voronoi and CGAL. Thus we are considering comparison of +those two to be of the most interest.
      +
      +Other libraries (OpenVoronoi, Triangle) would be added to this benchmark +incrementally (we are open for suggestions).
      +

      Important
      +

      While results of this benchmark show complete dominance of +the Boost.Polygon Voronoi over the CGAL Delaunay Graph implementation, +we would like to make it clear +that both libraries use different approach to construct Voronoi +diagram. Thus there are problems where the CGAL's incremental approach would +be still more vital than the sweep-line algorithm (e.g. input sites are +inserted as a live stream +data).
      +

      Voronoi Benchmark Details
      +

      +The benchmark consists of the two parts:
      + +Below we list important benchmark details that should be considered while reviewing its results:
      +
        +
      • We ensure that input data sets are the same for all +libraries by initializing random generator with the same seed
      • +
      • We ensure that input data sets that consist of segments +don't contain intersections using Boost.Polygon functionality
      • +
      • S-Hull's implementation doesn't process duplicate points +properly, thus those are eliminated before the algorithm execution +explicitly (Boost.Polygon Voronoi and CGAL do that  implicitly)
        +
      • + +
      • There is no Voronoi diagram data structure in CGAL/S-Hull. That's why we use the segment Delaunay graph which is topologically +dual to the Voronoi diagram
      • +
      • CGAL's and S-Hull's output Delaunay triangulation doesn't contain information +about coordinates of the Voronoi vertices. We didn't include time to compute Voronoi vertices and memory +storage required for those in this benchmark.
        +
      • +
      • Both Boost.Polygon Voronoi and CGAL process each input +segment +as 3 input objects (segment itself and its endpoints), thus the running +time and memory usage for Voronoi of segments would be at +least 3 times +slower than for Voronoi of points
      • + + +
      + +The benchmark was executed on the following two system configurations:
      +
      +Hardware: Intel i5-7600 2.8 GHz, 4GiB RAM.
      +OS: Windows 7 Professional 32-bit.
      +Libraries: Boost 1.48.0, CGAL-4.0.
      +
      +Hardware: Intel i5-7600 2.8 GHz, 4GiB RAM.
      +OS: Ubuntu 11.10 64-bit.
      +Libraries: Boost 1.48.0, CGAL-4.0, GMP 5.0.4, MPFR 3.1.0 + cumulative +patch.
      +

      Voronoi Benchmark Results

      +

      Random Points Benchmark

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Test specification
      +
      Average construction +time (in secs)
      +
      Number +of Points
      +
      Number +of Runs
      +
      Boost +Win-32
      +
      CGAL +Win-32
      +
      S-Hull Win-32
      +
      Boost +Linux-64
      +
      CGAL +Linux-64
      +
      S-Hull Linux-64
      +
      10
      +
      100000
      +
      0.000027
      +
      0.000116
      +
      0.000043
      +
      0.000013
      +
      0.000052
      +
      0.000012
      +
      100
      +
      10000
      +
      0.000392
      +
      0.002649
      +
      0.000521
      +
      0.000192
      +
       0.001150
      +
      0.000139
      +
      1000
      +
      1000
      +
      0.004541
      +
      0.039140
      +
      0.007125
      +
      0.002130
      +
      0.016680
      +
      0.002010
      +
      10000
      +
      100
      +
      0.047540
      +
      0.684090
      +
      0.091640
      +
      0.022900
      +
      0.297900
      +
      0.028300
      +
      100000
      +
      10
      +
      0.530200
      +
       16.904600
      +
      1.218000
      +
      0.274000
      +
      8.047000
      +
      0.432000
      +
      1000000
      +
      1
      +
      5.882000
      +
      566.056000
      +
      15.394000
      +
      3.290000
      +
      315.740000
      +
      6.350000
      +
      +
      + + + + + + + + + + + + + + + + + + + +

      +

      +
      +

      Random Segments Benchmark

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Test specification
      +
      Average construction +time (in secs)
      Number +of Segments
      +
      Number +of Runs
      +
      Boost +Win-32
      +
      CGAL +Win-32
      +
      Boost +Linux-64
      +
      CGAL +Linux-64
      +
      10
      +
      100000
      +
      0.000290
      +
      0.001047
      +
      0.000165
      +
      0.000483
      +
      100
      +
      10000
      +
      0.003655
      +
      0.014812
      +
      0.002006
      +
      0.007006
      +
      1000
      +
      1000
      +
      0.038158
      +
      0.177315
      +
      0.020440
      +
      0.084000
      +
      10000
      +
      100
      +
      0.389470
      +
      2.561340
      +
       0.209700
      +
      1.191900
      +
      100000
      +
      10
      +
      4.031300
      +
      49.314600
      +
      2.228000
      +
      23.538000
      +
      1000000
      +
      1
      +
      40.912000
      +
      1640.830000
      +
      22.250000
      +
      856.650000
      +
      +
      + + + + + + + + + + + + + + + + + + + +

      +

      +
      + +

      Voronoi Benchmark Summary

      +The main conclusions for the benchmark results above are following:
      +
        +
      • There is no input size range were CGAL would outperform +Boost.Polygon Voronoi. Even considering the fact that we didn't include +time it would take CGAL to compute coordinates of the Voronoi vertices.
      • +
      • The more interesting fact is that robust implementation of +the Boost.Polygon Voronoi is faster than non-robust of +S-Hull (except small input sets of around 100 points on Linux-64).
        +
      • + +
      • Logarithmic execution time shows that Boost.Polygon Voronoi and S-Hull +have clear N*log(N) complexity, while this doesn't seem to be true for +CGAL (at least for large input data sets).
        +
      • +
      • Boost.Polygon Voronoi computes coordinates of the output +Voronoi vertices within 64 machine epsilon precision. There are no such +warranties for the CGAL library.
        +
      • +
      • Boost.Polygon Voronoi of points is 4 times faster for small +input data sets (10 points) and this factor grows up to 100 for large +input data sets (1000000 points).
      • +
      • Boost.Polygon Voronoi of segments is 3 times faster for +small input data sets (10 segments) and this factor grows up to 40 for +large input data sets (1000000 segments).
      • +
      • Boost.Polygon +Voronoi is capable to construct Voronoi of 10000 points or 1000 +segments in 0.02 seconds. This allows to produce real time frame rate +for those quantities.
      • +
      +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + + \ No newline at end of file diff --git a/doc/voronoi_builder.htm b/doc/voronoi_builder.htm new file mode 100644 index 0000000..94e0355 --- /dev/null +++ b/doc/voronoi_builder.htm @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + Voronoi Builder + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      +

      Voronoi Builder
      +

      + +Voronoi builder is the event generator structure. It implements the sweepline +algorithm +that scans a 2D space and generates two types of events: +site events and circle events (we won't go into details what those are +exactly). Each event is reported to the output data structure builder. +The structure shares Voronoi name as the events generated by it +correspond to the Voronoi diagram edges and vertices, thus giving +enough information to construct the Voronoi diagram of a set of points +and linear segments. The requirements for the input/output +coordinate type of +the builder geometries are not the same as for the rest of the +Boost.Polygon library. The main differences are in the following:
      +
        +
      • The input coordinate type is not required to be integral (while it +still should be an integer type)
      • +
      • The output coordinate type (for +Voronoi vertices) is required to be IEEE-754 floating point type
      • +
      +

      Important

      + + +We encourage users to use default static methods defined in the voronoi.hpp +header to construct Voronoi diagram, however it's always possible to +use Voronoi builder explicitly, especially if the user wants to drop +the external dependencies such as MPL (metaprogramming library). So the +following include set woudn't depend on any heavy external headers (except STL and boost/cstdint.hpp), even +Boost.Polygon itself:
      + +
      + + #include <voronoi_builder.hpp>
      + + #include <voronoi_diagram.hpp>
      +
      +
      This +also gives a way to build Voronoi construction API on top of the +Voronoi builder data structure for the other Boost libraries.
      +

      Declaration
      +

      + + + + + template +<typename T,
      +           +typename CTT = detail::voronoi_ctype_traits<T>,
      +           +typename VP = detail::voronoi_predicates<CTT> >
      + class +voronoi_builder;
      +
      + T
      +- specifies the coordinate type of the input geometries (points and +segments).
      + + CTT +- defines input/output coordinate type traits used by Voronoi predicates (VP).
      + + VP +- predicate kernel, that provides builder with robust and +efficient predicates and functors.
      + +The Voronoi builder data structure is ready to use from the box with +32-bit signed integer input coordinate type. The user may extend the +input coordinate range to the other integer types (e.g. 64-bit +integer), however this will also require manual set up of the +coordinate type traits. Default voronoi_predicates<CTT> +structure provides correct and efficient predicates as soon as types defined by CTT +satisfy the requirements explained at the end of this page. In case those +requirements are not satisfied for the user provided coordinate type traits, +the proper predicates kernel +implementation is required.
      +

      Member Functions

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +voronoi_builder()Default +constructor.
      size_t insert_point(const int_type& x,
      +                    +const int_type& y)

      +
      Inserts a point object with +the specified coordinates into the Voronoi builder.
      +Returns index number of the inserted site.
      + +
      size_t insert_segment(const int_type& x1,
                            +const int_type& y1,
                            +const int_type& x2,
      +                      +const int_type& y2)

      +
      Inserts a segment object +with the specified coordinates into the Voronoi builder.
      +Returns index number of the inserted site.
      + +
      +template <typename OUTPUT>
      +void construct(OUTPUT* output)
      +
      Runs sweepline +algorithm over the set of the inserted geometries, outputs site and +circle events to the OUTPUT data structure. It's responsibility of the +output data structure to process them.
      +
      +void clear()
      +
      Clears the +list of the inserted geometries. Sets index counter to zero.
      +
      +

      Voronoi Coordinate Type Traits

      + + +

      The library provides the default coordinate type traits specialization for the +32-bit signed integer type:

      + + +

      template <typename T>
      +struct voronoi_ctype_traits;
      +
      +template <>
      +struct voronoi_ctype_traits<int32> {
      +    typedef int32 int_type;
      +    typedef int64 int_x2_type;
      +    typedef uint64 uint_x2_type;
      +    typedef extended_int<128> big_int_type;
      +    typedef fpt64 fpt_type;
      +    typedef extended_exponent_fpt<fpt_type> +efpt_type;
      +    typedef ulp_comparison<fpt_type> ulp_cmp_type;
      +    typedef type_converter_fpt to_fpt_converter_type;
      +    typedef type_converter_efpt to_efpt_converter_type;
      +};

      +
      + One +of the most important features of the library is that Voronoi builder +output geometries are constructed within defined relative error (64 +machine epsilons). That means the more mantissa bits the user provided +fpt_type has the better precision of the output geometries will be. In +order for the user defined traits to be consistent with the default +Voronoi builder predicates user should define following set of +coordinate types (the assumption is made that input geometries have +X-bit signed integer coordinate type):
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      int_type
      +
      At least X-bit signed +integer type.
      +
      +int_x2_type
      +
      At least 2X-bit signed +integer type.
      +
      +uint_x2_type
      +
      At least 2X-bit unsigned +integer type.
      +
      +big_int_type
      +
      At least 8X-bit signed +integer type for voronoi of points.
      +At least 64X-bit signed integer type for voronoi of segments.
      +
      +fpt_type
      +
      IEEE-754 floating point +type, with mantissa at least (X+16) bits and exponent able to handle +32X-bit unsigned integer type.
      +
      +efpt_type
      +
      IEEE-754 floating point +type, with mantissa at least (X+16) bits and exponent able to handle +64X-bit unsigned integer type.
      +
      +ulp_cmp_type
      +
      Ulp comparison structure +that checks if two fpt_type values are within the given ulp range +(relative error range).
      +
      +to_fpt_converter_type
      +
      Type converter structure +that converts any of the integer types above plus efpt_type to the +fpt_type using operator().
      +
      +to_efpt_converter_type
      +
      Type converter structure +that converts any of the integer types above to the efpt_type using +operator().
      +
      +

      Notes:

      +
        +
      • +Four different integer types are used (instead of a single +big_int_type) to slightly improve algorithm performance and memory +usage.
      • +
      • As the maximum required size of the big_int_type is known in advance +(based on the size of the integer type), library provided +implementation of a fixed integer could be used (it is much faster than +heap-allocated big integers).
      • +
      • +Two separate floating-point types are defined because for the input +with +32-bit signed integer coordinates double won't be able to handle +2048-bit (64 * 32) integers as they will overflow its exponent. On the +gcc compiler it's possible to use 80-bit long doubles for both fpt +types, however this is not supported by MSVC compiler.
      • +
      • efpt_type and to_efpt_converter_type are not used to construct Voronoi diagram of points (mocks will work fine).
      • +
      • +For an example of the user defined coordinate type traits +see advanced Voronoi tutorial.
      • +
      + +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + + diff --git a/doc/voronoi_diagram.htm b/doc/voronoi_diagram.htm new file mode 100644 index 0000000..e344da6 --- /dev/null +++ b/doc/voronoi_diagram.htm @@ -0,0 +1,994 @@ + + + + + + + + + + + + + + + + + + + Voronoi Diagram + + + + + + + + + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      + +

      Voronoi Diagram

      +Voronoi +diagram is the computational geometry concept that represents partition +of the given space onto regions, with bounds determined by distances to a +specified family of objects. The application area of this concept vary from +Archaeology to Zoology. The Boost.Polygon library provides implementation of +the Voronoi diagram data structure in 2D space. The internal representation +consists of the three arrays, that respectively contain: Voronoi cells +(represent the area around the input sites bounded by the Voronoi edges), Voronoi vertices +(points where three or more Voronoi edges intersect), Voronoi edges +(the one dimensional curves containing points equidistant from the two +closest input sites). Each of the primitives (cell, vertex, edge) +contains pointers to the other linked primitives, so that it's always +possible to efficiently traverse Voronoi graph. The picture below shows +the Voronoi vertices in red, Voronoi edges in black, input sites that +correspond to the Voronoi cells in blue. It is considered that each +input segment consists of the three sites: segment itself and its +endpoints. As the result two additional +Voronoi edges are constructed per each input segment. This is made to +simplify the representation of the Voronoi diagram.
      +
      + + +
      +

      Important

      All +the Voronoi primitive data structures (edge, vertex, cell) contain +mutable color member. Color type is equivalent to the std::size_t type, +except that the upper five bits are reserved for the internal usage. +That would mean that the maximum supported value by color member is 32 +times less than the one supported by std::size_t.
      +

      Declaration
      +

      + + + + + + template +<typename T, typename TRAITS = voronoi_diagram_traits<T> >
      + class +voronoi_diagram;
      +
      +
      T +- specifies the coordinate type of the Voronoi vertices.
      + TRAITS +- Voronoi diagram traits (explained in the end of this chapter).
      +

      Member Functions

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      voronoi_diagram()
      +
      Default constructor.
      +
      void + clear()
      +
      Clears diagram.
      +
      const +cell_container_type& cells() const
      +
      Returns the const +reference to the cell container.
      +
      const +vertex_container_type& vertices() const
      +
      Returns the const +reference to the vertex container.
      +
      const +edge_container_type& edges() const
      +
      Returns the const +reference to the edge container.
      +
      size_t num_cells() const
      +
      Returns the number of the +cells in the Voronoi diagram.
      +This value should be the same as the size of the cell container.
      +
      size_t num_edges() const
      +
      Returns the number of the +edges (half-edges) in the Voronoi diagram.
      This value should be the same as the size of the edge container.
      +
      size_t num_vertices() const
      +
      Returns the number of the +vertices in the Voronoi diagram.
      +This value should be the same as the size of the vertex container.
      +
      + +

      Member Types

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      coordinate_type
      +
      Coordinate type.
      +
      cell_type
      +
      Voronoi cell.
      +
      vertex_type
      +
      Voronoi vertex.
      +
      edge_type
      +
      Voronoi edge.
      +
      cell_container_type
      +
      Container of Voronoi cells.
      +
      const_cell_iterator
      +
      Const cell container iterator.
      +
      vertex_container_type
      +
      Container of Voronoi vertices.
      +
      const_vertex_iterator
      +
      Const vertex container iterator.
      +
      edge_container_type
      +
      Container of Voronoi edges.
      +
      const_edge_iterator
      +
      Const edge container iterator.
      +
      + + + +

      Voronoi Geometry Type
      +

      +

      GeometryCategory
      +

      +Defines geometry type of the input objects.
      +
      + enum GeometryCategory {
      +   GEOMETRY_CATEGORY_POINT = 0x0,
      +   GEOMETRY_CATEGORY_SEGMENT = 0x1
      + };
      +

      SourceCategory

      + +Defines category of the input site that forms Voronoi cell.
      +
      + enum SourceCategory {
      +   // Point subtypes.
      +   SOURCE_CATEGORY_SINGLE_POINT = 0x0,
      +   SOURCE_CATEGORY_SEGMENT_START_POINT = 0x1,
      +   SOURCE_CATEGORY_SEGMENT_END_POINT = 0x2,
      +
      +   // Segment subtypes.
      +   SOURCE_CATEGORY_INITIAL_SEGMENT = 0x8,
      +   SOURCE_CATEGORY_REVERSE_SEGMENT = 0x9,
      +
      +   SOURCE_CATEGORY_GEOMETRY_SHIFT = 0x3,
      +   SOURCE_CATEGORY_BITMASK = 0x1F
      + };
      +
      +Voronoi +diagram data structure doesn't store coordinates of the input +geometries. +Instead it links with those via source index and source category method +of the Voronoi cell primitive. Source index is incrementally given +(starting from zero) to each input site inserted into Voronoi builder. +Considering the fact that each input segment is splitted onto three +separate sites with the same index, we distinguish between them using +SourceCategory. For the example see Voronoi basic tutorial.
      +

      Member Functions

      + + + + + + + +
      bool belongs(
      +     SourceCategory source_category,
      +     GeometryCategory geometry_category)
      +
      Returns true if source category belongs to the given geometry category.
      +Returns false else.
      +
      +

      Voronoi Edge

      + + +Voronoi edge is represented as enhanced classical half-edge +data structure.
      +

      Declaration

      + + + + template +<typename T>
      + class +voronoi_edge;
      +
      +T
      - coordinate type.
      +

      Member Functions

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      voronoi_edge(bool is_linear, bool is_primary)
      +
      Voronoi edge constructor.
      +
      voronoi_cell_type* cell()
      +
      Returns the pointer to the +Voronoi cell +that edge belongs to.
      +
      const +voronoi_cell_type* cell() const
      +
      Returns the const pointer +to the Voronoi cell that edge belongs to.
      +
      void + cell(voronoi_cell_type* c)
      +
      Sets the Voronoi cell +pointer for the cell current edge belongs to.
      +
      voronoi_vertex_type* vertex0()
      +
      Returns the pointer to the +start point of the edge.
      +If the edge is infinite in that direction returns NULL.
      +
      const +voronoi_vertex_type* vertex0() const
      +
      Returns the const pointer +to the point vertex of the edge.
      +If the edge is infinite in that direction returns NULL.
      +
      void + vertex0(voronoi_vertex_type* v)
      +
      Sets the start point +pointer of the edge.
      +
      voronoi_vertex_type* vertex1()
      +
      Returns the pointer to the +end point of the edge.
      +If the edge is infinite in that direction returns NULL.
      +
      const +voronoi_vertex_type* vertex1() const
      +
      Returns the const pointer +to the end point of the edge.
      +If the edge is infinite in that direction returns NULL.
      +
      voronoi_edge_type* twin()
      +
      Returns the pointer to the +twin edge.
      +
      const +voronoi_edge_type* twin() const
      +
      Returns the const pointer +to the twin edge.
      +
      void + twin(voronoi_edge_type* e)
      +
      Sets the twin edge pointer +of the edge.
      +
      voronoi_edge_type* next()
      +
      Returns the pointer to the +CCW next edge within the corresponding Voronoi cell.
      +Edges not necessarily share a common vertex (e.g. infinite edges).
      +
      const +voronoi_edge_type* next() const
      +
      Returns the const pointer +to the CCW next edge within the corresponding Voronoi cell.
      +Edges not necessarily share a common vertex (e.g. infinite edges).
      +
      void + next(voronoi_edge_type* e)
      +
      Sets the CCW next edge +pointer of the edge.
      +
      voronoi_edge_type* prev()
      +
      Returns the pointer to the +CCW prev edge within the corresponding Voronoi cell.
      +Edges not necessarily share a common vertex (e.g. infinite edges).
      +
      const +voronoi_edge_type* prev() const
      +
      Returns the const pointer +to the CCW prev edge within the corresponding Voronoi cell.
      +Edges not necessarily share a common vertex (e.g. infinite edges).
      +
      void + prev(voronoi_edge_type* e)
      +
      Sets the CCW prev edge +pointer of the edge.
      +
      color_type color() const
      +
      Returns the color value.
      +
      void color(color_type color) const
      +
      Sets the color of +the edge.
      +Allows to execute graph algorithms and associate data.
      +
      voronoi_edge_type* rot_next()
      +
      Returns the pointer to the +CCW next edge rotated around the edge start point.
      Works for infinite + edges as well.
      +
      const +voronoi_edge_type* rot_next() const
      +
      Returns the const pointer +to the CCW next edge rotated around the edge start point.
      Works for infinite edges as well.
      voronoi_edge_type* rot_prev()
      +
      Returns the pointer to the +CCW prev edge rotated around the edge start point.
      Works for infinite edges as well.
      +
      const +voronoi_edge_type* rot_prev() const
      +
      Returns the const pointer +to the CCW prev edge rotated around the edge start point.
      Works for infinite edges as well.
      bool + is_finite() const
      +
      Returns true if the both +end points of the edge are finite, else false.
      +
      bool + is_infinite() constReturns true if one of the +end points of the edge is infinite, else false.
      bool + is_linear() const
      +
      Returns true if the edge +is linear (segment, ray, line), else false.
      +
      bool + is_curved() const
      +
      Returns true if the edge +is curved (parabolic arc), else false.
      +
      bool + is_primary() const
      +
      Returns false if the edge +goes through the endpoint of the segment site, else true.
      +
      bool + is_secondary() constReturns true if the edge +goes through the endpoint of the segment site, else false.
      +
      +
      All +the above methods have O(1) complexity. The size of +the Voronoi edge structure is equal to: 5 * sizeof(void *) + sizeof(size_t).
      +

      Member Types

      + + + + + + + + + + + + + + + + + + + + + + + + +
      coordinate_type
      +
      Coordinate type.
      +
      voronoi_cell_type
      +
      Voronoi cell type.
      +
      voronoi_vertex_type
      +
      Voronoi vertex type.
      +
      voronoi_edge_type
      +
      Voronoi edge type.
      +
      color_type
      +
      Color type (check the Important section).
      +
      +

      Voronoi Cell

      + +Voronoi cell is represented by a site the cell contains and a pointer +to the incident edge.
      +

      Declaration

      + + + + template +<typename T>
      +class voronoi_cell;
      +
      +
      T - coordinate type.
      +

      Member Functions

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      voronoi_cell(source_index_type source_index,
      +             source_category_type source_category)

      +
      Voronoi cell constructor.
      +
      source_index_type source_index() const
      +
      Returns input site index among the other sites.
      +Both segment endpoints and segment itself will have the same index.
      +
      source_category_type source_category() const
      +
      Returns input site category among the other sites.
      +Allows to distinguish between segment site and its endpoints.
      + +
      voronoi_edge_type* incident_edge()
      +
      Returns the pointer to the +one of the boundary edges.
      +
      const +voronoi_edge_type* incident_edge() const
      +
      Returns the const pointer +to the one of the boundary edges.
      +
      void + incident_edge(voronoi_edge_type* e)
      +
      Sets the incident boundary +edge pointer of the cell.
      +
      color_type color() const
      +
      Returns the color associated with the cell.
      void color(color_type color) const
      +
      Sets the color of +the cell.
      + +Allows to execute graph algorithms and associate data.
      +
      bool + contains_point() constReturns true if the cell +contains a point site, else false.
      bool + contains_segment() constReturns true if the cell +contains a segment site, else false.
      bool + is_degenerate() const Returns true if the cell +doesn't have an incident edge.
      +Could happen if a few input segments share a common endpoint.
      +
      +
      All the above methods have O(1) complexity. The size of +the Voronoi cell structure is equal to: sizeof(void *) + 2 * sizeof(size_t). +

      Member Types

      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      coordinate_type
      +
      Coordinate type.
      +
      source_index_typeSource index type.
      +
      source_category_type
      +
      Source category type.
      +
      voronoi_edge_type + Voronoi edge type. +
      color_type + Color type (check the Important section). +
      +

      Miscellaneous

      + +The following code snippet effectively traverses the Voronoi edges around the +Voronoi cell:
      +
      + const +voronoi_edge<double>* edge = cell->incident_edge();
      + do {
      +   +edge = edge->next();
      +   +// Do smth. with edge.
      + } while +(edge != cell->incident_edge());
      +

      Voronoi Vertex

      +Voronoi vertex is represented by a point that corresponds to the vertex +and a pointer to the incident edge.
      +

      Declaration

      + + + + template +<typename T>
      + class +voronoi_vertex;
      +
      +
      T - coordinate type.
      +

      Member Functions

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      voronoi_vertex(const coordinate_type& x,
      +               const coordinate_type& y)

      +
      Voronoi vertex constructor.
      +
      const +point_type& x() const
      +
      Returns the x-coordinate of the point that represents the vertex.
      +
      const +point_type& y() constReturns the y-coordinate of the point that represents the vertex.
      +
      voronoi_edge_type* incident_edge()
      +
      Returns the incident edge +pointer.
      +
      const +voronoi_edge_type* incident_edge() const
      +
      Returns the const pointer +to the incident edge.
      +
      void + incident_edge(voronoi_edge_type* e)
      +
      Sets the incident edge +pointer.
      +
      color_type color() const
      +
      Returns the color associated with the vertex.
      void color(color_type color) const
      +
      Sets the color of +the vertex.
      +Allows to executegraph algorithms and associate data.
      +
      +
      All the above methods have O(1) complexity. The size of +the Voronoi vertex structure is equal to: sizeof(void *) + sizeof(size_t) + 2 * +sizeof(coordinate_type). +

      Member Types

      + + + + + + + + + + + + + + + + +
      coordinate_type
      +
      Coordainte type.
      +
      voronoi_edge_type
      +
      Voronoi edge type.
      +
      color_type + Color type (check the Important section). +
      + +

      Miscellaneous

      The following code snippet effectively traverses the Voronoi edges around the +Voronoi vertex:
      +
      + const +voronoi_edge<double>* edge = vertex->incident_edge();
      + do {
      +   +edge = edge->next();
      +   +// Do smth. with edge.
      + } while +(edge != vertex->incident_edge());
      +
      +

      Voronoi Diagram Traits
      +

      +Voronoi diagram traits are used to configure Voronoi diagram data +structure.
      +

      Declaration

      + + + + template +<typename T>
      + struct +voronoi_diagram_traits;
      +
      +
      T - coordinate type.
      +

      Member Types

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      coordinate_type
      +
      The main coordinate type +of the Voronoi diagram primitives.
      +
      cell_type
      +
      Voronoi cell type.
      +
      vertex_type
      +
      Voronoi vertex_type.
      +
      edge_type
      +
      Voronoi edge_type.
      +
      vertex_equality_predicate_type
      +
      Predicate that returns +true if two points are considered to be equal.
      +This is used to unite nearby Voronoi vertices.
      +
      +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + + \ No newline at end of file diff --git a/doc/voronoi_main.htm b/doc/voronoi_main.htm new file mode 100644 index 0000000..3aa40ce --- /dev/null +++ b/doc/voronoi_main.htm @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + Voronoi Main + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      + +

      THE BOOST.POLYGON VORONOI LIBRARY
      +

      +
      +The Boost.Polygon Voronoi library provides functionality to construct the Voronoi diagram +of a set of points and linear segments in 2D space with the following +set of +limitations:
      +
        +
      • coordinates of the input points and endpoints of the +segments +should be of the integer type;
      • +
      • input segments should not overlap +except their endpoints.
      • +
      +While the first restriction is permanent (it +allows to give the exact warranties about the output precision and +algorithm execution), +the second one may be resolved using the Boost.Polygon functionality. +The strong sides of the +library and main benefits comparing to the other implementations are +discussed in the following paragraphs.
      +

      Robustness and Efficiency

      +Let's explain a bit those terms. The efficiency is simply measured by +the time it takes the algorithm to execute. The robustness is a bit +more harder to explain. But those of you who had the experience with +the following situations would understand what it doesn't mean: application segfaults randomly, algorithm output contains +degeneracies or is completely invalid (e.g. a point is considered to be outside of the polygon, +while should be inside). In other words robust implementation doesn't +fail and produces expected output in 100% of cases, thus user can rely +on +it. Robustness is a weak place of the most non-commercial +implementations of any complex geometric algorithm. The main issues could be divided onto two main categories: memory management +issues, numeric stability issues. Our implementation avoids the +first type of issues using pure STL data structures, thus you won't find +any operator new in the code. The second category of problems is +resolved using multiprecision geometric +predicates. +Even for commercial implementations usage of such predicates usually +results in a huge performance slowdown. Here is another strong side of +the Boost.Polygon +Voronoi library: we avoid multiprecision computations in 95% of cases +using +extremely fast floating-point predicates. Yes, those are not always +exact, but we developed the relative +error arithmetic apparatus to identify them and switch to the +higher precision predicates when required.
      +

      Precision of the Output Structures
      +

      +One of the extremely important results of using two types of predicates +is that library efficiently computes relatively precise coordinates of +the output geometries. Here we will explain a bit what exactly +"relatively precise" means and how the received output may differ from +the theoretically correct one (here and after we assume that output +coordinate type is the IEEE-754 floating-point type).
      +
      +Voronoi implementation guaranties that the relative error of the +coordinates of the output +geometries is always not higher than 64 machine epsilons (6 +bits of mantissa), while in many cases it is slightly less. That also +means that using floating-point type with the larger mantissa will +produce more precise output. Let's consider +the following example: the output Voronoi +vertex has double (53-bit mantissa) x-coordinate equal to 1.0, then the +absolute error is at most 2^-53 * 2^6 = 2^-47 and the exact value of +x-coordinate lies in the range [1.0 - 2^-47, 1.0 + 2^-47]. For +x-coordinate equal to 2^31, the absolute error will be at most 2^-53 * +2^31 * 2^6 = 2^-16 and the exact value of x-coordinate lies in the +range +[2^31 - 2^-16, 2^31 + 2^16]. For the output Voronoi vertex with long +double +(64-bit mantissa) x-coordinate equal to 2^31, the absolute error will +be at most 2^-64 * 2 ^31 * 2^6 = 2^-27 and the exact value of +x-coordinate +lies in the range [2^31-2^-27, 2^31+2^-27]. If you'd like to become +master of the absolute and relative error try this article.
      +
      +During the finalization step the implementation unites Voronoi vertices whose both +coordinates are situated within the relative error range equal to 128 +machine epsilons and removes any Voronoi edges between them. That is +the only case that might cause differences between the algorithm output +topology and theoretically precise one.  Now let's see what is the practical +impact of this. Consider the following example: we are going to construct the +Voronoi diagram of our Solar System. The radius of our Solar System is +approximately 2^42 metres, and we are going to snap it to the integer +grid of [-2^42; 2^42] x [-2^42; 2^42].  Let's choose the long double +(64 bit mantissa) output coordinate type, then the maximum absolute error +for the output geometries within our Solar System will be on its boundaries +and equal to 2^-64 * 2^42 * 2^6 = 2^-18 metres. In the output we are going to +consider vertices with both coordinates that are within 2^-17 metres (8 +micrometres) distance to be equal. That distance is equal to +the size of a bacteria and is relative to the Solar System size.
      +

      Fully Functional with Segments

      +There are not many implementations of the Voronoi diagram construction +algorithm that could +handle linear segment inputs, even considering the commercial libraries. +Support of the +segments allows to discretize any input geometry (circle, ellipse, +parabola). Of course as the result those might have floating-point +coordinates, but that is resolved using scaling and snapping to the +integer grid. This functionality is very handy as it allows to compute +the medial axis transform of the arbitrary set of input geometries. So +one may start +using it for the next generation pattern recognition or computer vision +project.
      +

      Basic and Advanced Usage Cases

      +The main library header voronoi.hpp +defines the following static functions to integrate the Voronoi library functionality with the Boost.Polygon interfaces:
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      template <typename Point, typename VB>
      +size_t insert(const Point &point, VB *vb)
      +
      Inserts a point into the Voronoi builder data structure.
      +Point type should model the point concept.
      + +Returns index number of the inserted site.
      +
      template <typename PointIterator, typename VB>
      +void insert(PointIterator first,
      +            PointIterator last,
      +            VB *vb)
      +
      Inserts an iterator range of points into the Voronoi builder data structure.
      +Corresponding point type should model the point concept.
      +
      template <typename Segment, typename VB>
      +size_t insert(const Segment &segment, VB *vb)
      +
      Inserts a segment into the Voronoi builder data structure.
      +Segment type should model the segment concept.
      + +Returns index number of the inserted site.
      +
      template <typename SegmentIterator, typename VB>
      +void insert(SegmentIterator first,
      +            SegmentIterator last,
      +            VB *vb)
      +
      Inserts an iterator range of segments into the Voronoi builder data structure.
      +Corresponding segment type should model the segment concept.
      +
      template <typename PointIterator, typename VD>
      +void construct_voronoi(PointIterator first,
                             +PointIterator last,
      +                       +VD *vd)
      +
      Constructs Voronoi diagram of a set of points.
      Corresponding point type should model the point concept.
      +
      template <typename SegmentIterator, typename VD>
      +void construct_voronoi(SegmentIterator first,
      +                       +SegmentIterator last,
      +                       +VD *vd)
      +
      Constructs Voronoi diagram of a set of segments.
      Corresponding segment type should model the segment concept.
      +
      template <typename PointIterator,
      +          typename SegmentIterator,
      +          typename VD>
      void construct_voronoi(PointIterator p_first,
      +                       +PointIterator p_last,
                             +SegmentIterator s_first,
      +                       +SegmentIterator s_last,
                             +VD *vd)
      +
      Constructs Voronoi +diagram of a set of points and segments.
      Corresponding point type should model the point concept.
      +Corresponding segment type should model the segment concept.
      +
      +
      This +means that it's possible to construct the Voronoi diagram with the +following two lines of code (if corresponding input types satisfy the Boost.Polygon concept model):
      +
      + voronoi_diagram<double> +vd;
      + construct_voronoi(points.begin(), points.end(), &vd);
      +
      The library also provides the clear interfaces to + associate user data with the output geometries and efficiently traverse Voronoi graph. +More details on those are covered in the basic Voronoi tutorial. Advanced usage of the library with the configuration of the coordinate +types is explained in the advanced +Voronoi tutorial. +The library also allows users to implement their own Voronoi diagram / +Delaunay triangulation construction routines based on the Voronoi builder API.
      +

      No Third Party Dependencies
      +

      Yes, +the library doesn't depend on any 3rd party code. Even more than that +there is only one dependency on the Boost libraries: boost/cstdint.hpp. +All the required multiprecision types functionality is implemented as +part of the library and is not exposed to the user. Considering the +fact that Voronoi implementation consists of just 7 headers (3 public +and 4 private) it is easy to compile it within a minute after download. +On the other hand voronoi.hpp header provides integration routines with +the Boost.Polygon concepts and models with a drawback of additional +dependencies.

      Extensible for the User Provided Coordinate Types

      +Our implementation is coordinate type agnostic. That means that as soon +as user provided types satisfy the set of restrictions of the Voronoi builder coordinate type traits +and implement methods required by the library, no changes are required +neither to the algorithm, nor to the implementation of the predicates. So it's +possible to +construct Voronoi diagram for the 256-bit integer input coordinate type +and +512-bit output floating-point type without making any changes to the +internal code.
      +

      Bright Future
      +

      +Below one may find the list of the main directions for the future +development of the library.
      +High-priority tasks that already have approximate implementation plan +are the following (some of those may be proposed as future GSoC projects):
      +
        +
      • Implementing Delaunay triangulation data structure.
        +Note: only data structure needs to be implemented that properly +processes events provided by the Voronoi builder.
      • +
      • Implementing medial axis transform data structure.
        +Note: in general case the Voronoi diagram has completely the same +geometry +as the medial axis (they are 100% equal), however for many applications +user is not interested in the Voronoi edges inside the hole regions. +The main point +of this data structure is to automatically filter Voronoi edges that +belong to those areas.
      • +
      • Voronoi +diagram data structure could be used to find K nearest neighbors of N +sites in O(N*K*log(K) + N*log(N)) time. The return value would be a +list of the k nearest neighbors for each site.
        +
      • +
      • Using the r-tree data structure built on top of the +bounding rectangles around the Voronoi cells to answer the nearest +neighbor queries in log(N) time, where N is the number of the Voronoi cells.
        +Note: there should be r-tree data structure available soon as part of +the Boost libraries.
      • + +
      • Providing interface to retrieve the convex hull of a set of +points and segments from the Voronoi builder once the Voronoi diagram is +constructed in O(N) time.
      • +
      • Providing serialization utilities for the Voronoi diagram data structure.
        +
      • + + +
      +High-priority tasks to be considered:
      +
        +
      • Dropping the restriction on the non-intersecting input +geometries.
      • +
      • Integration of the Voronoi diagram data structure with the BGL (Boost +Graph Library).
      • +
      • Support of the other types of distance metrics.
      • +
      • Construction of the constrained Delaunay triangulation.
      • +
      • Support of the circular input geometries.
      • +
      +Based on the community suggestions priorities may be changed.
      +

      Theoretical Research
      +

      Voronoi +was developed as part of the Google Summer of Code 2010. The +library was actively maintained for the last two years and involved +strong mathematical research in the field of algorithms, data +structures, +relative error arithmetic and numerical robustness. Nowadays one can +often read a scientific article that contains non-practical theoretical +results or implementation with +benchmarks nobody else can reproduce. The opposite story is with +the Boost.Polygon Voronoi library. We provide pure implementation and +benchmarks one may run on +his PC. In case community finds it useful we will incrementally +add more documentation on the theoretical side of our implementation. The +authors would like to acknowledge the Steven Fortune's article "A Sweepline algorithm +for Voronoi diagrams", that contains the fundamental ideas of the +current implementation.
      +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + + \ No newline at end of file diff --git a/doc/voronoi_predicates.htm b/doc/voronoi_predicates.htm new file mode 100644 index 0000000..467dca2 --- /dev/null +++ b/doc/voronoi_predicates.htm @@ -0,0 +1,251 @@ + + + + + + + + + + + + + Voronoi Predicates + + + + + + + + + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      + + +

      Voronoi Predicates
      +

      + +In mathematical theory predicate is an operator which returns true +or false (e.g. it may answer a question: "is it sunny today?").
      + +Voronoi predicates contain implementation of a set of the geometric +predicates used by the Voronoi builder. +Except of those they also provide +functors that allow to compute the coordinates of the centers of the +inscribed +circles (those correspond to the Voronoi vertices) within the given +relative error precision range (64 machine epsilons). This means that +the more mantissa bits +your floating point type has the better precision of the output +geometries you'll get. This +is a very handy functionality as it allows to improve output precision +simply providing 3rd party IEEE-754 like floating-point types.
      + + +

      Geometric Predicates

      + +The main issues with the implementation of any complex geometric +algorithm arise when dealing with the robustness of the geometric +predicates. +Usually this +is also the point where the commercial projects stand strong against +noncommercial implementations (it's not the case with our +implementation). +For the short example let's consider the following code snippet, that +could +be used to compute orientation of the three points:
      + +
      + + double +cross_product(double dx1, double dy1, double dx2, double dy2) {
      + +   +return dx1 * dy2 - dx2 * dy1;
      + + }
      +
      +int main() {
      +  int v = 1 << 30;  // 2 ^ 30
      +  double result =
      cross_product(v, v - 1, v + 1, +v);
      +  printf("%.3f", result);
      +  return 0;
      +}
      +
      +
      The +output of this simple program will be "0.000", while +the correct one is "1.000". In terms of the orientation test this means +that points are collinear instead of being CCW oriented. This is one of +the basic predicates used in any geometric algorithm and taking wrong +output from it may influence the further algorithm execution: +corrupting algorithm underlying structures or producing completely +invalid output. Voronoi uses +slightly more complex predicates. To insure that they are robust and +efficient the approach that combines two known techniques (lazy +arithmetic and multiple +precision computations) is used.
      + + +

      Lazy Arithmetic

      + +Lazy +arithmetic is based on the usage of IEEE-754 floating-point types to +quickly evaluate the result of the expression. While this approach has +a good speed +performance it doesn't produce reliable results all the time (as in the +example above). The way to solve the issue is apart from computing +result of the expression compute the relative error of it as well. This +will +give us the range of values the evaluated result belongs to and based +on that we can +come up with two decisions: 1) output the value; 2) recompute the +expression using multiprecision type. The way relative errors are +evaluated is explained in the Voronoi +Robust FPT section.
      + + +

      Multiple Precision Arithmetic

      + +In the vast majority of cases +the lazy arithmetic approach produces correct result thus further +processing is not required. In other cases the Voronoi library defined +or user +provided multiple precision types are used to produce correct result. +However even that doesn't solve all the cases. Multiprecision geometric +predicates could be divided onto two categories:
      + +
      + +1) mathematical transformation of the predicate exists that evaluates +the exact result:
      +
      +Predicate: A/B + C/D ?< 0;
      +After math. transform: (A*D + B*C) / (B * D) ?< 0;
      +
      +Predicate: sqrt(A) ?< 1.2;
      +After math. transform: A ?< 1.44;
      +
      +
      2) the correct result could be produced only by increasing +precision of the multiprecision type and with defined relative error +for the output type:
      + +
      + + Predicate: +sqrt(A) + sqrt(B) + sqrt(C) + sqrt(D) + sqrt(E) ?< 1.2;
      +Imagine that value of the expression to the left is very close to 1.2;
      +

      + + Predicate: +sin(x) ?< 0.57;
      +Relative error of sin function should be known;
      +
      +
      The Voronoi of points could be completely +implemented using predicates of the first type, however the Voronoi of +segments could not. +The predicate that doesn't fall into the first category is responsible +for comparison of the Voronoi circle events. However it appears that +properly used +this predicate can't corrupt algorithm internal structures and produces +output technically the same as produced in case this predicate fell in +the first category.  The main reasons for this are: 1) algorithm +operates with integer coordinate type of the input geometries; 2) +closely +situated Voronoi vertices are considered to be the same in the output +data structure (this won't influence main targets algorithm is used +for).
      +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + + \ No newline at end of file diff --git a/doc/voronoi_robust_fpt.htm b/doc/voronoi_robust_fpt.htm new file mode 100644 index 0000000..7f6ad0a --- /dev/null +++ b/doc/voronoi_robust_fpt.htm @@ -0,0 +1,212 @@ + + + + + + + + + + + + Voronoi Robust FPT + + + + + + + + + + + + +
      + +
      + + + + +
      + + +

      + +

      Voronoi Robust FPT

      +The Voronoi +robust floating-point types are the set of classes and tools that +allow to estimate relative error of the arithmetic expressions. It is +assumed that the other Boost libraries may find this unit functionality +extremely useful, as it can be used to implement robust and efficient +arithmetic predicates or functors that compute values within known +relative error.
      +

      Robust Fpt Type

      +The robust +fpt type (robust floating-point type) +- represents the IEEE-754 floating-point type wrapper that also +contains +information about the relative error of the underlying value. The +implementation overloads 5 standard operations: +, -, *, /, sqrt and +apart from the evaluating value of the expression also computes its +relative +error. Let's consider two values A and B; C - rounding error, re(X) +- relative error of the X expression, then following rules apply:
      +
      + re(A+B) +<= max(re(A), re(B)) + C, if A * B >= 0;
      + re(A-B) +<= (B * re(A) + A * re(B)) / |A - B| + C, if A * B < 0;
      + re(A*B) +<= re(A) + re(B) + C;
      + re(A/B) +<= re(A) + re(B) + C;
      + re(sqrt(A)) +<= re(A) * 0.5 + C;
      +
      +
      The constant C is equal to the rounding error, +which for the above set of arithmetic operations in the IEEE-754 +floating-point implementation should be equal to 1 machine epsilon.
      +

      Robust Difference Type

      +The robust +difference type - +represents expression wrapper that holds the positive and negative +partial +sums of the expression in a separate values in order to avoid +the cancellation errors before evaluating the final difference. +Following +arithmetic operators are overloaded for the robust difference type: +, +-, *, / (division operator is not overloaded for the case were both +arguments have robust difference type).
      +Looking at the relative error formulas above one may notice a few facts:
      +1) all of the formulas evaluate upper bound of the relative error, the +actual value could be a lot smaller;
      +2) relative error estimate for the expression depends on the order +operations are evaluated;
      +3) relative error of  the difference of two positive numbers may +be +extremely large in case their values are close to each other (this is +also known as the cancellation error).
      +To explain this a bit, consider the following expression (~ - stands for +almost equal, << - many times larger than):
      +
      + A - B + +C, where A ~ B and C << B;
      +
      +Computing the relative error of this expression from left to right will +produce extremely large relative error:
      +
      + re(A-B+C) += max(re(A-B), re(C)) = re(A-B) = (B * re(A) + A * re(B)) / 0 = INF;
      +
      +
      While doing this from right to left will keep the relative +error value small:
      +
      + re(A-B+C) += re(C-B+A) = max(re(C-B), re(A)) = max(re(A), re(B));
      +
      +
      While both estimates are valid (they define upper bound of +the relative error), of course the second one is preferable.
      +Here is the place where robust difference type comes useful. Basically +it splits expression onto positive and negative partial sums and +evaluates the +difference only when the result is required. And did I mention that +positive and negative values might be of the robust fpt type, that's +why +the relative error is always known for the expression result.
      +

      Robust Sqrt Expression Structure

      +The robust square root expression structure allows to compute the +result of +the expression that contains square roots within defined relative +error. +As an example, consider the following expression:
      +
      + A * +sqrt(a) - B * sqrt(b), A * B > 0, a >= 0, b >= 0;
      +
      +Computing this expressions directly may apply huge cancellation error, +however it may be transformed to the next equivalent expression:
      +
      +(A * A * a - B * B * b) / (A * sqrt(a) + B * sqrt(b));

      +
      +The numerator and denominator of this expression could be computed +directly as those won't lead to the cancellation errors.
      +
      +In general case the robust sqrt expression structure allows to evaluate +the following set of expressions:
      +
      +sum(A[i] * sqrt(a[i]), i = 1 .. N), N <= 4;

      +
      +This appears to be enough for the Boost.Polygon Voronoi.
      +
        + + + + + + + + + + + +
      Copyright:Copyright © Andrii Sydorchuk 2010-2012
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + \ No newline at end of file diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..9549dad --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,37 @@ +# Copyright Andrii Sydorchuk 2010-2012. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import cast ; +import testing ; + +lib opengl : : opengl32 ; + +project voronoi_example + : + requirements + . + msvc:on + $(BOOST_ROOT)/libs/timer/build//boost_timer + ; + +exe voronoi-visualizer + : + voronoi_visualizer.cpp + [ cast _ moccable-cpp : voronoi_visualizer.cpp ] + /qt//QtOpenGL + : + windows:opengl + ; + +alias "basic-tutorial" + : + [ run voronoi_basic_tutorial.cpp ] + ; + +alias "advanced-tutorial" + : + [ run voronoi_advanced_tutorial.cpp ] + ; + diff --git a/example/input_data/polygon/polygon_001.txt b/example/input_data/polygon/polygon_001.txt new file mode 100644 index 0000000..5bbb057 --- /dev/null +++ b/example/input_data/polygon/polygon_001.txt @@ -0,0 +1,10 @@ +0 +8 +0 0 -3 5 +-3 5 2 10 +2 10 4 6 +4 6 10 12 +10 12 13 6 +13 6 11 1 +11 1 5 1 +5 1 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_002.txt b/example/input_data/polygon/polygon_002.txt new file mode 100644 index 0000000..486bd91 --- /dev/null +++ b/example/input_data/polygon/polygon_002.txt @@ -0,0 +1,16 @@ +0 +14 +0 0 -3 5 +-3 5 2 10 +2 10 4 6 +4 6 10 12 +10 12 13 6 +13 6 11 1 +11 1 5 1 +5 1 0 0 +1 2 0 5 +0 5 5 2 +5 2 1 2 +10 3 8 6 +8 6 10 8 +10 8 10 3 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_003.txt b/example/input_data/polygon/polygon_003.txt new file mode 100644 index 0000000..4292460 --- /dev/null +++ b/example/input_data/polygon/polygon_003.txt @@ -0,0 +1,10 @@ +0 +8 +0 0 0 8 +0 8 4 12 +4 12 9 13 +9 13 13 13 +13 13 13 4 +13 4 10 0 +10 0 5 -1 +5 -1 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_004.txt b/example/input_data/polygon/polygon_004.txt new file mode 100644 index 0000000..bb5a50b --- /dev/null +++ b/example/input_data/polygon/polygon_004.txt @@ -0,0 +1,10 @@ +0 +8 +0 0 0 8 +0 8 4 12 +4 12 9 13 +9 13 7 7 +7 7 13 4 +13 4 10 0 +10 0 5 -1 +5 -1 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_005.txt b/example/input_data/polygon/polygon_005.txt new file mode 100644 index 0000000..7825f92 --- /dev/null +++ b/example/input_data/polygon/polygon_005.txt @@ -0,0 +1,8 @@ +0 +6 +0 0 10 0 +10 0 16 -6 +16 -6 22 0 +22 0 22 -12 +22 -12 10 -12 +10 -12 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_006.txt b/example/input_data/polygon/polygon_006.txt new file mode 100644 index 0000000..064dded --- /dev/null +++ b/example/input_data/polygon/polygon_006.txt @@ -0,0 +1,9 @@ +0 +7 +0 0 0 10 +0 10 6 10 +6 10 10 7 +10 7 14 10 +14 10 20 10 +20 10 20 0 +20 0 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_007.txt b/example/input_data/polygon/polygon_007.txt new file mode 100644 index 0000000..af811fe --- /dev/null +++ b/example/input_data/polygon/polygon_007.txt @@ -0,0 +1,14 @@ +0 +12 +0 0 8 3 +8 3 10 13 +10 13 16 6 +16 6 16 15 +16 15 25 10 +25 10 15 1 +15 1 27 -1 +27 -1 14 -4 +14 -4 13 3 +13 3 11 -5 +11 -5 10 0 +10 0 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_008.txt b/example/input_data/polygon/polygon_008.txt new file mode 100644 index 0000000..6598541 --- /dev/null +++ b/example/input_data/polygon/polygon_008.txt @@ -0,0 +1,12 @@ +0 +10 +0 0 1 8 +1 8 10 7 +10 7 20 10 +20 10 25 9 +25 9 28 5 +28 5 23 -2 +23 -2 24 -7 +24 -7 13 -9 +13 -9 10 -3 +10 -3 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_009.txt b/example/input_data/polygon/polygon_009.txt new file mode 100644 index 0000000..863e93f --- /dev/null +++ b/example/input_data/polygon/polygon_009.txt @@ -0,0 +1,6 @@ +0 +4 +0 0 0 10 +0 10 30 10 +30 10 30 0 +30 0 0 0 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_010.txt b/example/input_data/polygon/polygon_010.txt new file mode 100644 index 0000000..3dc6cf9 --- /dev/null +++ b/example/input_data/polygon/polygon_010.txt @@ -0,0 +1,25 @@ +0 +23 +-12 4 -12 -4 +-12 -4 -8 -4 +-8 -4 -8 -1 +-8 -1 -9 0 +-9 0 -8 1 +-8 1 -8 4 +-8 4 -12 4 +-4 4 -4 -4 +-4 -4 0 -4 +0 -4 0 4 +0 4 -4 4 +4 4 4 -4 +4 -4 8 -4 +8 -4 8 4 +8 4 4 4 +-4 -8 -8 -8 +-8 -8 -8 -12 +-8 -12 -4 -12 +-4 -12 -4 -16 +-4 -16 -8 -16 +0 -8 2 -8 +2 -8 4 -8 +2 -8 2 -16 diff --git a/example/input_data/polygon/polygon_011.txt b/example/input_data/polygon/polygon_011.txt new file mode 100644 index 0000000..34ec6a5 --- /dev/null +++ b/example/input_data/polygon/polygon_011.txt @@ -0,0 +1,11 @@ +0 +9 +0 0 1 10 +1 10 4 9 +4 9 4 2 +4 2 0 0 +5 5 6 8 +6 8 10 10 +10 10 9 1 +9 1 6 2 +6 2 5 5 \ No newline at end of file diff --git a/example/input_data/polygon/polygon_012.txt b/example/input_data/polygon/polygon_012.txt new file mode 100644 index 0000000..c338d97 --- /dev/null +++ b/example/input_data/polygon/polygon_012.txt @@ -0,0 +1,14 @@ +0 +12 +0 0 100 0 +100 0 100 100 +100 100 0 100 +0 100 0 0 +15 15 60 20 +60 20 87 23 +60 20 57 47 +15 85 30 80 +30 80 25 65 +30 80 60 70 +60 70 75 65 +60 70 65 85 \ No newline at end of file diff --git a/example/input_data/primary/primary_001.txt b/example/input_data/primary/primary_001.txt new file mode 100644 index 0000000..5b553c0 --- /dev/null +++ b/example/input_data/primary/primary_001.txt @@ -0,0 +1,2 @@ +1 +0 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_002.txt b/example/input_data/primary/primary_002.txt new file mode 100644 index 0000000..0b45514 --- /dev/null +++ b/example/input_data/primary/primary_002.txt @@ -0,0 +1,3 @@ +2 +0 0 +1 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_003.txt b/example/input_data/primary/primary_003.txt new file mode 100644 index 0000000..fdbbf7a --- /dev/null +++ b/example/input_data/primary/primary_003.txt @@ -0,0 +1,3 @@ +2 +0 0 +0 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_004.txt b/example/input_data/primary/primary_004.txt new file mode 100644 index 0000000..c64ab21 --- /dev/null +++ b/example/input_data/primary/primary_004.txt @@ -0,0 +1,3 @@ +2 +0 0 +1 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_005.txt b/example/input_data/primary/primary_005.txt new file mode 100644 index 0000000..bbadf55 --- /dev/null +++ b/example/input_data/primary/primary_005.txt @@ -0,0 +1,11 @@ +10 +0 0 +0 1 +0 2 +0 3 +0 4 +0 -1 +0 -2 +0 -3 +0 -4 +0 -5 \ No newline at end of file diff --git a/example/input_data/primary/primary_006.txt b/example/input_data/primary/primary_006.txt new file mode 100644 index 0000000..eb7aea4 --- /dev/null +++ b/example/input_data/primary/primary_006.txt @@ -0,0 +1,11 @@ +10 +0 0 +1 0 +2 0 +3 0 +4 0 +5 0 +-1 0 +-2 0 +-3 0 +-4 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_007.txt b/example/input_data/primary/primary_007.txt new file mode 100644 index 0000000..88ac779 --- /dev/null +++ b/example/input_data/primary/primary_007.txt @@ -0,0 +1,12 @@ +11 +0 0 +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +7 7 +8 8 +9 9 +10 10 \ No newline at end of file diff --git a/example/input_data/primary/primary_008.txt b/example/input_data/primary/primary_008.txt new file mode 100644 index 0000000..9f4b6f0 --- /dev/null +++ b/example/input_data/primary/primary_008.txt @@ -0,0 +1,11 @@ +10 +-46 -37 +-40 -30 +-34 -23 +-28 -16 +-22 -09 +-16 -02 +-10 05 +-04 12 +02 19 +08 26 \ No newline at end of file diff --git a/example/input_data/primary/primary_009.txt b/example/input_data/primary/primary_009.txt new file mode 100644 index 0000000..99f5f0c --- /dev/null +++ b/example/input_data/primary/primary_009.txt @@ -0,0 +1,11 @@ +10 +33333 11111 +66666 0 +99999 -11111 +133332 -22222 +166665 -33333 +199998 -44444 +233331 -55555 +266664 -66666 +299997 -77777 +333330 -88888 \ No newline at end of file diff --git a/example/input_data/primary/primary_010.txt b/example/input_data/primary/primary_010.txt new file mode 100644 index 0000000..4dbbd93 --- /dev/null +++ b/example/input_data/primary/primary_010.txt @@ -0,0 +1,4 @@ +3 +0 0 +2005 2005 +10025 10025 \ No newline at end of file diff --git a/example/input_data/primary/primary_011.txt b/example/input_data/primary/primary_011.txt new file mode 100644 index 0000000..2573f61 --- /dev/null +++ b/example/input_data/primary/primary_011.txt @@ -0,0 +1,4 @@ +3 +0 0 +0 4 +1 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_012.txt b/example/input_data/primary/primary_012.txt new file mode 100644 index 0000000..a14a3f9 --- /dev/null +++ b/example/input_data/primary/primary_012.txt @@ -0,0 +1,5 @@ +4 +0 0 +0 1 +1 0 +1 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_013.txt b/example/input_data/primary/primary_013.txt new file mode 100644 index 0000000..494c527 --- /dev/null +++ b/example/input_data/primary/primary_013.txt @@ -0,0 +1,14 @@ +13 +0 5 +0 -5 +-4 -3 +4 -3 +4 3 +-4 3 +3 -4 +-3 4 +-3 -4 +3 4 +-5 0 +5 0 +0 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_014.txt b/example/input_data/primary/primary_014.txt new file mode 100644 index 0000000..72b1acc --- /dev/null +++ b/example/input_data/primary/primary_014.txt @@ -0,0 +1,13 @@ +12 +0 5 +0 -5 +-4 -3 +4 -3 +4 3 +-4 3 +3 -4 +-3 4 +-3 -4 +3 4 +-5 0 +5 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_015.txt b/example/input_data/primary/primary_015.txt new file mode 100644 index 0000000..f228af2 --- /dev/null +++ b/example/input_data/primary/primary_015.txt @@ -0,0 +1,5 @@ +4 +4 3 +4 8 +9 2 +9 9 \ No newline at end of file diff --git a/example/input_data/primary/primary_016.txt b/example/input_data/primary/primary_016.txt new file mode 100644 index 0000000..4deb886 --- /dev/null +++ b/example/input_data/primary/primary_016.txt @@ -0,0 +1,101 @@ +100 +100 0 +99 6 +99 12 +98 18 +96 24 +95 30 +92 36 +90 42 +87 48 +84 53 +80 58 +77 63 +72 68 +68 72 +63 77 +58 80 +53 84 +48 87 +42 90 +36 92 +30 95 +24 96 +18 98 +12 99 +6 99 +0 99 +-6 99 +-12 99 +-18 98 +-24 96 +-30 95 +-36 93 +-42 90 +-48 87 +-53 84 +-58 80 +-63 77 +-68 72 +-72 68 +-76 63 +-80 58 +-84 53 +-87 48 +-90 42 +-92 36 +-95 31 +-96 25 +-98 18 +-99 12 +-99 6 +-99 0 +-99 -6 +-99 -12 +-98 -18 +-96 -24 +-95 -30 +-93 -36 +-90 -42 +-87 -48 +-84 -53 +-81 -58 +-77 -63 +-73 -68 +-68 -72 +-63 -76 +-58 -80 +-53 -84 +-48 -87 +-42 -90 +-37 -92 +-31 -95 +-25 -96 +-18 -98 +-12 -99 +-6 -99 +0 -99 +6 -99 +12 -99 +18 -98 +24 -96 +30 -95 +36 -93 +42 -90 +47 -87 +53 -84 +58 -81 +63 -77 +68 -73 +72 -68 +76 -63 +80 -59 +84 -53 +87 -48 +90 -42 +92 -37 +95 -31 +96 -25 +98 -19 +99 -12 +99 -6 \ No newline at end of file diff --git a/example/input_data/primary/primary_017.txt b/example/input_data/primary/primary_017.txt new file mode 100644 index 0000000..57e3ccc --- /dev/null +++ b/example/input_data/primary/primary_017.txt @@ -0,0 +1,3 @@ +0 +1 +0 0 1 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_018.txt b/example/input_data/primary/primary_018.txt new file mode 100644 index 0000000..013611c --- /dev/null +++ b/example/input_data/primary/primary_018.txt @@ -0,0 +1,6 @@ +2 +3 1 +1 3 +1 +0 0 +4 4 \ No newline at end of file diff --git a/example/input_data/primary/primary_019.txt b/example/input_data/primary/primary_019.txt new file mode 100644 index 0000000..4068a32 --- /dev/null +++ b/example/input_data/primary/primary_019.txt @@ -0,0 +1,5 @@ +2 +3 2 +2 3 +1 +4 0 0 4 \ No newline at end of file diff --git a/example/input_data/primary/primary_020.txt b/example/input_data/primary/primary_020.txt new file mode 100644 index 0000000..c1e81b4 --- /dev/null +++ b/example/input_data/primary/primary_020.txt @@ -0,0 +1,7 @@ +3 +-2 -2 +-2 4 +-2 10 +1 +0 0 +0 8 \ No newline at end of file diff --git a/example/input_data/primary/primary_021.txt b/example/input_data/primary/primary_021.txt new file mode 100644 index 0000000..c421253 --- /dev/null +++ b/example/input_data/primary/primary_021.txt @@ -0,0 +1,4 @@ +1 +-1 1 +1 +1 0 1 2 \ No newline at end of file diff --git a/example/input_data/primary/primary_022.txt b/example/input_data/primary/primary_022.txt new file mode 100644 index 0000000..0784942 --- /dev/null +++ b/example/input_data/primary/primary_022.txt @@ -0,0 +1,5 @@ +0 +3 +0 0 4 0 +4 0 0 4 +0 4 4 4 \ No newline at end of file diff --git a/example/input_data/primary/primary_023.txt b/example/input_data/primary/primary_023.txt new file mode 100644 index 0000000..75cb14a --- /dev/null +++ b/example/input_data/primary/primary_023.txt @@ -0,0 +1,6 @@ +0 +4 +0 0 4 0 +4 0 4 4 +4 4 0 4 +0 4 0 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_024.txt b/example/input_data/primary/primary_024.txt new file mode 100644 index 0000000..66ac2d8 --- /dev/null +++ b/example/input_data/primary/primary_024.txt @@ -0,0 +1,4 @@ +0 +2 +0 0 4 0 +2 2 2 4 \ No newline at end of file diff --git a/example/input_data/primary/primary_025.txt b/example/input_data/primary/primary_025.txt new file mode 100644 index 0000000..a6eeea2 --- /dev/null +++ b/example/input_data/primary/primary_025.txt @@ -0,0 +1,5 @@ +1 +5 6 +2 +0 0 4 0 +2 2 2 4 \ No newline at end of file diff --git a/example/input_data/primary/primary_026.txt b/example/input_data/primary/primary_026.txt new file mode 100644 index 0000000..834264e --- /dev/null +++ b/example/input_data/primary/primary_026.txt @@ -0,0 +1,6 @@ +2 +0 0 +1 6 +2 +-4 5 5 -1 +3 -11 13 -1 \ No newline at end of file diff --git a/example/input_data/primary/primary_027.txt b/example/input_data/primary/primary_027.txt new file mode 100644 index 0000000..710e8a8 --- /dev/null +++ b/example/input_data/primary/primary_027.txt @@ -0,0 +1,12 @@ +2 +0 0 +1 6 +8 +-6 5 2 -7 +3 -11 13 -1 +-4 5 5 -1 +4 4 11 4 +4 4 8 10 +11 4 8 10 +8 10 5 13 +8 10 11 13 \ No newline at end of file diff --git a/example/input_data/primary/primary_028.txt b/example/input_data/primary/primary_028.txt new file mode 100644 index 0000000..1ed194d --- /dev/null +++ b/example/input_data/primary/primary_028.txt @@ -0,0 +1,5 @@ +0 +3 +0 0 4 2 +4 2 4 -2 +4 -2 0 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_029.txt b/example/input_data/primary/primary_029.txt new file mode 100644 index 0000000..3ca79ed --- /dev/null +++ b/example/input_data/primary/primary_029.txt @@ -0,0 +1,10 @@ +0 +8 +0 0 0 1 +0 0 1 0 +0 0 -1 0 +0 0 0 -1 +0 0 1 1 +0 0 1 -1 +0 0 -1 1 +0 0 -1 -1 \ No newline at end of file diff --git a/example/input_data/primary/primary_030.txt b/example/input_data/primary/primary_030.txt new file mode 100644 index 0000000..fde6cac --- /dev/null +++ b/example/input_data/primary/primary_030.txt @@ -0,0 +1,14 @@ +0 +12 +-1 10 1 10 +10 -1 10 1 +-1 -10 1 -10 +-10 -1 -10 1 +-6 8 -2 11 +-8 6 -11 2 +6 8 2 11 +8 6 11 2 +6 -8 2 -11 +8 -6 11 -2 +-6 -8 -2 -11 +-8 -6 -11 -2 \ No newline at end of file diff --git a/example/input_data/primary/primary_031.txt b/example/input_data/primary/primary_031.txt new file mode 100644 index 0000000..d60d5ce --- /dev/null +++ b/example/input_data/primary/primary_031.txt @@ -0,0 +1,15 @@ +1 +0 0 +12 +-1 10 1 10 +10 -1 10 1 +-1 -10 1 -10 +-10 -1 -10 1 +-6 8 -2 11 +-8 6 -11 2 +6 8 2 11 +8 6 11 2 +6 -8 2 -11 +8 -6 11 -2 +-6 -8 -2 -11 +-8 -6 -11 -2 \ No newline at end of file diff --git a/example/input_data/primary/primary_032.txt b/example/input_data/primary/primary_032.txt new file mode 100644 index 0000000..40617fa --- /dev/null +++ b/example/input_data/primary/primary_032.txt @@ -0,0 +1,6 @@ +3 +0 -4 +2 8 +-16 15 +1 +7 20 7 -20 diff --git a/example/input_data/primary/primary_033.txt b/example/input_data/primary/primary_033.txt new file mode 100644 index 0000000..65514ee --- /dev/null +++ b/example/input_data/primary/primary_033.txt @@ -0,0 +1,7 @@ +4 +-6 6 +-5 6 +-4 6 +-3 6 +1 +0 0 0 7 \ No newline at end of file diff --git a/example/input_data/primary/primary_034.txt b/example/input_data/primary/primary_034.txt new file mode 100644 index 0000000..d4e0b97 --- /dev/null +++ b/example/input_data/primary/primary_034.txt @@ -0,0 +1,6 @@ +0 +4 +0 -4 2 8 +2 8 -16 15 +0 -4 -16 15 +7 20 7 -20 diff --git a/example/input_data/primary/primary_035.txt b/example/input_data/primary/primary_035.txt new file mode 100644 index 0000000..dce66e7 --- /dev/null +++ b/example/input_data/primary/primary_035.txt @@ -0,0 +1,22 @@ +0 +20 +100 0 95 30 +95 30 80 58 +80 58 58 80 +58 80 30 95 +30 95 0 99 +0 99 -30 95 +-30 95 -58 80 +-58 80 -80 58 +-80 58 -95 30 +-95 30 -99 0 +-99 0 -95 -30 +-95 -30 -80 -58 +-80 -58 -58 -80 +-58 -80 -30 -95 +-30 -95 0 -99 +0 -99 30 -95 +30 -95 58 -80 +58 -80 80 -58 +80 -58 95 -30 +95 -30 100 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_036.txt b/example/input_data/primary/primary_036.txt new file mode 100644 index 0000000..c73b72c --- /dev/null +++ b/example/input_data/primary/primary_036.txt @@ -0,0 +1,102 @@ +0 +100 +100 0 99 6 +99 6 99 12 +99 12 98 18 +98 18 96 24 +96 24 95 30 +95 30 92 36 +92 36 90 42 +90 42 87 48 +87 48 84 53 +84 53 80 58 +80 58 77 63 +77 63 72 68 +72 68 68 72 +68 72 63 77 +63 77 58 80 +58 80 53 84 +53 84 48 87 +48 87 42 90 +42 90 36 92 +36 92 30 95 +30 95 24 96 +24 96 18 98 +18 98 12 99 +12 99 6 99 +6 99 0 99 +0 99 -6 99 +-6 99 -12 99 +-12 99 -18 98 +-18 98 -24 96 +-24 96 -30 95 +-30 95 -36 92 +-36 92 -42 90 +-42 90 -48 87 +-48 87 -53 84 +-53 84 -58 80 +-58 80 -63 77 +-63 77 -68 72 +-68 72 -72 68 +-72 68 -77 63 +-77 63 -80 58 +-80 58 -84 53 +-84 53 -87 48 +-87 48 -90 42 +-90 42 -92 36 +-92 36 -95 30 +-95 30 -96 24 +-96 24 -98 18 +-98 18 -99 12 +-99 12 -99 6 +-99 6 -99 0 +-99 0 -99 -6 +-99 -6 -99 -12 +-99 -12 -98 -18 +-98 -18 -96 -24 +-96 -24 -95 -30 +-95 -30 -92 -36 +-92 -36 -90 -42 +-90 -42 -87 -48 +-87 -48 -84 -53 +-84 -53 -80 -58 +-80 -58 -77 -63 +-77 -63 -72 -68 +-72 -68 -68 -72 +-68 -72 -63 -77 +-63 -77 -58 -80 +-58 -80 -53 -84 +-53 -84 -48 -87 +-48 -87 -42 -90 +-42 -90 -36 -92 +-36 -92 -30 -95 +-30 -95 -24 -96 +-24 -96 -18 -98 +-18 -98 -12 -99 +-12 -99 -6 -99 +-6 -99 0 -99 +0 -99 6 -99 +6 -99 12 -99 +12 -99 18 -98 +18 -98 24 -96 +24 -96 30 -95 +30 -95 36 -92 +36 -92 42 -90 +42 -90 48 -87 +48 -87 53 -84 +53 -84 58 -80 +58 -80 63 -77 +63 -77 68 -72 +68 -72 72 -68 +72 -68 77 -63 +77 -63 80 -58 +80 -58 84 -53 +84 -53 87 -48 +87 -48 90 -42 +90 -42 92 -36 +92 -36 95 -30 +95 -30 96 -24 +96 -24 98 -18 +98 -18 99 -12 +99 -12 99 -6 +99 -6 100 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_037.txt b/example/input_data/primary/primary_037.txt new file mode 100644 index 0000000..552fee8 --- /dev/null +++ b/example/input_data/primary/primary_037.txt @@ -0,0 +1,102 @@ +80 +99 6 +99 12 +98 18 +96 24 +92 36 +90 42 +87 48 +84 53 +77 63 +72 68 +68 72 +63 77 +53 84 +48 87 +42 90 +36 92 +24 96 +18 98 +12 99 +6 99 +-6 99 +-12 99 +-18 98 +-24 96 +-36 92 +-42 90 +-48 87 +-53 84 +-63 77 +-68 72 +-72 68 +-77 63 +-84 53 +-87 48 +-90 42 +-92 36 +-96 24 +-98 18 +-99 12 +-99 6 +-99 -6 +-99 -12 +-98 -18 +-96 -24 +-92 -36 +-90 -42 +-87 -48 +-84 -53 +-77 -63 +-72 -68 +-68 -72 +-63 -77 +-53 -84 +-48 -87 +-42 -90 +-36 -92 +-24 -96 +-18 -98 +-12 -99 +-6 -99 +6 -99 +12 -99 +18 -98 +24 -96 +36 -92 +42 -90 +48 -87 +53 -84 +63 -77 +68 -72 +72 -68 +77 -63 +84 -53 +87 -48 +90 -42 +92 -36 +96 -24 +98 -18 +99 -12 +99 -6 +20 +100 0 99 6 +95 30 92 36 +80 58 77 63 +58 80 53 84 +30 95 24 96 +0 99 -6 99 +-30 95 -36 92 +-58 80 -63 77 +-80 58 -84 53 +-95 30 -96 24 +-99 0 -99 -6 +-95 -30 -92 -36 +-80 -58 -77 -63 +-58 -80 -53 -84 +-30 -95 -24 -96 +0 -99 6 -99 +30 -95 36 -92 +58 -80 63 -77 +80 -58 84 -53 +95 -30 96 -24 \ No newline at end of file diff --git a/example/input_data/primary/primary_038.txt b/example/input_data/primary/primary_038.txt new file mode 100644 index 0000000..66a50f7 --- /dev/null +++ b/example/input_data/primary/primary_038.txt @@ -0,0 +1,222 @@ +0 +220 +0 0 0 10 +0 0 10 0 +0 10 0 20 +0 10 10 10 +0 20 0 30 +0 20 10 20 +0 30 0 40 +0 30 10 30 +0 40 0 50 +0 40 10 40 +0 50 0 60 +0 50 10 50 +0 60 0 70 +0 60 10 60 +0 70 0 80 +0 70 10 70 +0 80 0 90 +0 80 10 80 +0 90 0 100 +0 90 10 90 +0 100 10 100 +10 0 10 10 +10 0 20 0 +10 10 10 20 +10 10 20 10 +10 20 10 30 +10 20 20 20 +10 30 10 40 +10 30 20 30 +10 40 10 50 +10 40 20 40 +10 50 10 60 +10 50 20 50 +10 60 10 70 +10 60 20 60 +10 70 10 80 +10 70 20 70 +10 80 10 90 +10 80 20 80 +10 90 10 100 +10 90 20 90 +10 100 20 100 +20 0 20 10 +20 0 30 0 +20 10 20 20 +20 10 30 10 +20 20 20 30 +20 20 30 20 +20 30 20 40 +20 30 30 30 +20 40 20 50 +20 40 30 40 +20 50 20 60 +20 50 30 50 +20 60 20 70 +20 60 30 60 +20 70 20 80 +20 70 30 70 +20 80 20 90 +20 80 30 80 +20 90 20 100 +20 90 30 90 +20 100 30 100 +30 0 30 10 +30 0 40 0 +30 10 30 20 +30 10 40 10 +30 20 30 30 +30 20 40 20 +30 30 30 40 +30 30 40 30 +30 40 30 50 +30 40 40 40 +30 50 30 60 +30 50 40 50 +30 60 30 70 +30 60 40 60 +30 70 30 80 +30 70 40 70 +30 80 30 90 +30 80 40 80 +30 90 30 100 +30 90 40 90 +30 100 40 100 +40 0 40 10 +40 0 50 0 +40 10 40 20 +40 10 50 10 +40 20 40 30 +40 20 50 20 +40 30 40 40 +40 30 50 30 +40 40 40 50 +40 40 50 40 +40 50 40 60 +40 50 50 50 +40 60 40 70 +40 60 50 60 +40 70 40 80 +40 70 50 70 +40 80 40 90 +40 80 50 80 +40 90 40 100 +40 90 50 90 +40 100 50 100 +50 0 50 10 +50 0 60 0 +50 10 50 20 +50 10 60 10 +50 20 50 30 +50 20 60 20 +50 30 50 40 +50 30 60 30 +50 40 50 50 +50 40 60 40 +50 50 50 60 +50 50 60 50 +50 60 50 70 +50 60 60 60 +50 70 50 80 +50 70 60 70 +50 80 50 90 +50 80 60 80 +50 90 50 100 +50 90 60 90 +50 100 60 100 +60 0 60 10 +60 0 70 0 +60 10 60 20 +60 10 70 10 +60 20 60 30 +60 20 70 20 +60 30 60 40 +60 30 70 30 +60 40 60 50 +60 40 70 40 +60 50 60 60 +60 50 70 50 +60 60 60 70 +60 60 70 60 +60 70 60 80 +60 70 70 70 +60 80 60 90 +60 80 70 80 +60 90 60 100 +60 90 70 90 +60 100 70 100 +70 0 70 10 +70 0 80 0 +70 10 70 20 +70 10 80 10 +70 20 70 30 +70 20 80 20 +70 30 70 40 +70 30 80 30 +70 40 70 50 +70 40 80 40 +70 50 70 60 +70 50 80 50 +70 60 70 70 +70 60 80 60 +70 70 70 80 +70 70 80 70 +70 80 70 90 +70 80 80 80 +70 90 70 100 +70 90 80 90 +70 100 80 100 +80 0 80 10 +80 0 90 0 +80 10 80 20 +80 10 90 10 +80 20 80 30 +80 20 90 20 +80 30 80 40 +80 30 90 30 +80 40 80 50 +80 40 90 40 +80 50 80 60 +80 50 90 50 +80 60 80 70 +80 60 90 60 +80 70 80 80 +80 70 90 70 +80 80 80 90 +80 80 90 80 +80 90 80 100 +80 90 90 90 +80 100 90 100 +90 0 90 10 +90 0 100 0 +90 10 90 20 +90 10 100 10 +90 20 90 30 +90 20 100 20 +90 30 90 40 +90 30 100 30 +90 40 90 50 +90 40 100 40 +90 50 90 60 +90 50 100 50 +90 60 90 70 +90 60 100 60 +90 70 90 80 +90 70 100 70 +90 80 90 90 +90 80 100 80 +90 90 90 100 +90 90 100 90 +90 100 100 100 +100 0 100 10 +100 10 100 20 +100 20 100 30 +100 30 100 40 +100 40 100 50 +100 50 100 60 +100 60 100 70 +100 70 100 80 +100 80 100 90 +100 90 100 100 \ No newline at end of file diff --git a/example/input_data/primary/primary_039.txt b/example/input_data/primary/primary_039.txt new file mode 100644 index 0000000..ed18731 --- /dev/null +++ b/example/input_data/primary/primary_039.txt @@ -0,0 +1,322 @@ +100 +5 5 +5 15 +5 25 +5 35 +5 45 +5 55 +5 65 +5 75 +5 85 +5 95 +15 5 +15 15 +15 25 +15 35 +15 45 +15 55 +15 65 +15 75 +15 85 +15 95 +25 5 +25 15 +25 25 +25 35 +25 45 +25 55 +25 65 +25 75 +25 85 +25 95 +35 5 +35 15 +35 25 +35 35 +35 45 +35 55 +35 65 +35 75 +35 85 +35 95 +45 5 +45 15 +45 25 +45 35 +45 45 +45 55 +45 65 +45 75 +45 85 +45 95 +55 5 +55 15 +55 25 +55 35 +55 45 +55 55 +55 65 +55 75 +55 85 +55 95 +65 5 +65 15 +65 25 +65 35 +65 45 +65 55 +65 65 +65 75 +65 85 +65 95 +75 5 +75 15 +75 25 +75 35 +75 45 +75 55 +75 65 +75 75 +75 85 +75 95 +85 5 +85 15 +85 25 +85 35 +85 45 +85 55 +85 65 +85 75 +85 85 +85 95 +95 5 +95 15 +95 25 +95 35 +95 45 +95 55 +95 65 +95 75 +95 85 +95 95 +220 +0 0 0 10 +0 0 10 0 +0 10 0 20 +0 10 10 10 +0 20 0 30 +0 20 10 20 +0 30 0 40 +0 30 10 30 +0 40 0 50 +0 40 10 40 +0 50 0 60 +0 50 10 50 +0 60 0 70 +0 60 10 60 +0 70 0 80 +0 70 10 70 +0 80 0 90 +0 80 10 80 +0 90 0 100 +0 90 10 90 +0 100 10 100 +10 0 10 10 +10 0 20 0 +10 10 10 20 +10 10 20 10 +10 20 10 30 +10 20 20 20 +10 30 10 40 +10 30 20 30 +10 40 10 50 +10 40 20 40 +10 50 10 60 +10 50 20 50 +10 60 10 70 +10 60 20 60 +10 70 10 80 +10 70 20 70 +10 80 10 90 +10 80 20 80 +10 90 10 100 +10 90 20 90 +10 100 20 100 +20 0 20 10 +20 0 30 0 +20 10 20 20 +20 10 30 10 +20 20 20 30 +20 20 30 20 +20 30 20 40 +20 30 30 30 +20 40 20 50 +20 40 30 40 +20 50 20 60 +20 50 30 50 +20 60 20 70 +20 60 30 60 +20 70 20 80 +20 70 30 70 +20 80 20 90 +20 80 30 80 +20 90 20 100 +20 90 30 90 +20 100 30 100 +30 0 30 10 +30 0 40 0 +30 10 30 20 +30 10 40 10 +30 20 30 30 +30 20 40 20 +30 30 30 40 +30 30 40 30 +30 40 30 50 +30 40 40 40 +30 50 30 60 +30 50 40 50 +30 60 30 70 +30 60 40 60 +30 70 30 80 +30 70 40 70 +30 80 30 90 +30 80 40 80 +30 90 30 100 +30 90 40 90 +30 100 40 100 +40 0 40 10 +40 0 50 0 +40 10 40 20 +40 10 50 10 +40 20 40 30 +40 20 50 20 +40 30 40 40 +40 30 50 30 +40 40 40 50 +40 40 50 40 +40 50 40 60 +40 50 50 50 +40 60 40 70 +40 60 50 60 +40 70 40 80 +40 70 50 70 +40 80 40 90 +40 80 50 80 +40 90 40 100 +40 90 50 90 +40 100 50 100 +50 0 50 10 +50 0 60 0 +50 10 50 20 +50 10 60 10 +50 20 50 30 +50 20 60 20 +50 30 50 40 +50 30 60 30 +50 40 50 50 +50 40 60 40 +50 50 50 60 +50 50 60 50 +50 60 50 70 +50 60 60 60 +50 70 50 80 +50 70 60 70 +50 80 50 90 +50 80 60 80 +50 90 50 100 +50 90 60 90 +50 100 60 100 +60 0 60 10 +60 0 70 0 +60 10 60 20 +60 10 70 10 +60 20 60 30 +60 20 70 20 +60 30 60 40 +60 30 70 30 +60 40 60 50 +60 40 70 40 +60 50 60 60 +60 50 70 50 +60 60 60 70 +60 60 70 60 +60 70 60 80 +60 70 70 70 +60 80 60 90 +60 80 70 80 +60 90 60 100 +60 90 70 90 +60 100 70 100 +70 0 70 10 +70 0 80 0 +70 10 70 20 +70 10 80 10 +70 20 70 30 +70 20 80 20 +70 30 70 40 +70 30 80 30 +70 40 70 50 +70 40 80 40 +70 50 70 60 +70 50 80 50 +70 60 70 70 +70 60 80 60 +70 70 70 80 +70 70 80 70 +70 80 70 90 +70 80 80 80 +70 90 70 100 +70 90 80 90 +70 100 80 100 +80 0 80 10 +80 0 90 0 +80 10 80 20 +80 10 90 10 +80 20 80 30 +80 20 90 20 +80 30 80 40 +80 30 90 30 +80 40 80 50 +80 40 90 40 +80 50 80 60 +80 50 90 50 +80 60 80 70 +80 60 90 60 +80 70 80 80 +80 70 90 70 +80 80 80 90 +80 80 90 80 +80 90 80 100 +80 90 90 90 +80 100 90 100 +90 0 90 10 +90 0 100 0 +90 10 90 20 +90 10 100 10 +90 20 90 30 +90 20 100 20 +90 30 90 40 +90 30 100 30 +90 40 90 50 +90 40 100 40 +90 50 90 60 +90 50 100 50 +90 60 90 70 +90 60 100 60 +90 70 90 80 +90 70 100 70 +90 80 90 90 +90 80 100 80 +90 90 90 100 +90 90 100 90 +90 100 100 100 +100 0 100 10 +100 10 100 20 +100 20 100 30 +100 30 100 40 +100 40 100 50 +100 50 100 60 +100 60 100 70 +100 70 100 80 +100 80 100 90 +100 90 100 100 \ No newline at end of file diff --git a/example/input_data/primary/primary_040.txt b/example/input_data/primary/primary_040.txt new file mode 100644 index 0000000..bf55be4 --- /dev/null +++ b/example/input_data/primary/primary_040.txt @@ -0,0 +1,11 @@ +10 +858993458 1717986916 +-429496729 1288490187 +-2147483645 -1288490187 +-2147483645 -858993458 +-1717986916 858993458 +-2147483645 -429496729 +429496729 -2147483645 +858993458 -429496729 +-429496729 1717986916 +1717986916 -858993458 \ No newline at end of file diff --git a/example/input_data/primary/primary_041.txt b/example/input_data/primary/primary_041.txt new file mode 100644 index 0000000..76ef90d --- /dev/null +++ b/example/input_data/primary/primary_041.txt @@ -0,0 +1,8 @@ +0 +6 +0 0 0 10 +-5 0 -1 0 +-6 2 -1 2 +-4 5 -2 5 +-8 8 -1 8 +-7 -2 -7 7 \ No newline at end of file diff --git a/example/input_data/primary/primary_042.txt b/example/input_data/primary/primary_042.txt new file mode 100644 index 0000000..57d7726 --- /dev/null +++ b/example/input_data/primary/primary_042.txt @@ -0,0 +1,5 @@ +0 +3 +-6 -1 -5 3 +-1 0 4 -1 +3 0 4 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_043.txt b/example/input_data/primary/primary_043.txt new file mode 100644 index 0000000..ccddfcb --- /dev/null +++ b/example/input_data/primary/primary_043.txt @@ -0,0 +1,5 @@ +0 +3 +-5 -2 -4 2 +-5 3 -2 2 +-5 5 -2 2 \ No newline at end of file diff --git a/example/input_data/primary/primary_044.txt b/example/input_data/primary/primary_044.txt new file mode 100644 index 0000000..b4cf7e0 --- /dev/null +++ b/example/input_data/primary/primary_044.txt @@ -0,0 +1,5 @@ +0 +3 +-9 -8 -4 -3 +-8 -3 -4 -3 +-2 7 -1 3 \ No newline at end of file diff --git a/example/input_data/primary/primary_045.txt b/example/input_data/primary/primary_045.txt new file mode 100644 index 0000000..74c4d69 --- /dev/null +++ b/example/input_data/primary/primary_045.txt @@ -0,0 +1,5 @@ +0 +3 +14 76 38 29 +37 47 61 50 +39 37 41 35 diff --git a/example/input_data/primary/primary_046.txt b/example/input_data/primary/primary_046.txt new file mode 100644 index 0000000..5ff83eb --- /dev/null +++ b/example/input_data/primary/primary_046.txt @@ -0,0 +1,5 @@ +2 +2 -5 +3 -3 +1 +0 0 2 -7 \ No newline at end of file diff --git a/example/input_data/primary/primary_047.txt b/example/input_data/primary/primary_047.txt new file mode 100644 index 0000000..bd8f67c --- /dev/null +++ b/example/input_data/primary/primary_047.txt @@ -0,0 +1,5 @@ +1 +-35 -49 +2 +-48 -29 -46 -78 +-46 -46 -45 -42 \ No newline at end of file diff --git a/example/input_data/primary/primary_048.txt b/example/input_data/primary/primary_048.txt new file mode 100644 index 0000000..d93dfb4 --- /dev/null +++ b/example/input_data/primary/primary_048.txt @@ -0,0 +1,11 @@ +0 +9 +-50 -29 -49 -73 +-48 -29 -46 -78 +-46 -46 -45 -42 +-35 -49 -34 -49 +-30 -2 -29 3 +-43 16 -40 6 +-36 38 -34 49 +-35 39 -31 37 +-28 34 -27 -9 \ No newline at end of file diff --git a/example/input_data/primary/primary_049.txt b/example/input_data/primary/primary_049.txt new file mode 100644 index 0000000..a8b8536 --- /dev/null +++ b/example/input_data/primary/primary_049.txt @@ -0,0 +1,11 @@ +0 +9 +-5 4 -7 8 +-5 4 -5 2 +-5 4 -2 7 +-1 -6 -5 -2 +-1 -6 -3 -10 +-1 -6 5 -6 +5 -1 5 -4 +5 -1 3 4 +5 -1 8 6 \ No newline at end of file diff --git a/example/input_data/primary/primary_050.txt b/example/input_data/primary/primary_050.txt new file mode 100644 index 0000000..7de80de --- /dev/null +++ b/example/input_data/primary/primary_050.txt @@ -0,0 +1,5 @@ +0 4 +2134582590 2134582590 2134582590 2141031480 +2134582590 2134582590 2141031480 2134582590 +2141031480 2134582590 2141031480 2141031480 +2134582590 2141031480 2141031480 2141031480 \ No newline at end of file diff --git a/example/input_data/primary/primary_051.txt b/example/input_data/primary/primary_051.txt new file mode 100644 index 0000000..61eb7d5 --- /dev/null +++ b/example/input_data/primary/primary_051.txt @@ -0,0 +1,5 @@ +0 4 +-1073741800 -1073741800 -687194752 -1159641144 +-1073741800 -1073741800 -408021884 -923417948 +-1073741800 -1073741800 -343597376 -2061584256 +-2147483600 -837518604 -1073741800 -1073741800 \ No newline at end of file diff --git a/example/input_data/primary/primary_052.txt b/example/input_data/primary/primary_052.txt new file mode 100644 index 0000000..877def6 --- /dev/null +++ b/example/input_data/primary/primary_052.txt @@ -0,0 +1,5 @@ +0 +3 +0 0 0 -1 +0 0 1 1 +0 0 1 -1 \ No newline at end of file diff --git a/example/input_data/primary/primary_053.txt b/example/input_data/primary/primary_053.txt new file mode 100644 index 0000000..8beb1d5 --- /dev/null +++ b/example/input_data/primary/primary_053.txt @@ -0,0 +1,5 @@ +2 +1 0 +0 10 +1 +-2 10 -1 0 \ No newline at end of file diff --git a/example/input_data/primary/primary_054.txt b/example/input_data/primary/primary_054.txt new file mode 100644 index 0000000..4ef0f59 --- /dev/null +++ b/example/input_data/primary/primary_054.txt @@ -0,0 +1,4 @@ +0 3 +-1073741800 -1073741800 -687194752 -1159641144 +-1073741800 -1073741800 -408021884 -923417948 +-1073741800 -1073741800 -343597376 -2061584256 \ No newline at end of file diff --git a/example/input_data/primary/primary_055.txt b/example/input_data/primary/primary_055.txt new file mode 100644 index 0000000..9f01d2f --- /dev/null +++ b/example/input_data/primary/primary_055.txt @@ -0,0 +1,5 @@ +0 +3 +-3 -4 -1 -2 +-2 4 4 -1 +0 -2 0 1 \ No newline at end of file diff --git a/example/input_data/primary/primary_056.txt b/example/input_data/primary/primary_056.txt new file mode 100644 index 0000000..886f56d --- /dev/null +++ b/example/input_data/primary/primary_056.txt @@ -0,0 +1,5 @@ +1 +9 72 +2 +-2 0 -1 -50 +-1 -50 0 -99 \ No newline at end of file diff --git a/example/input_data/primary/primary_057.txt b/example/input_data/primary/primary_057.txt new file mode 100644 index 0000000..75aa2ab --- /dev/null +++ b/example/input_data/primary/primary_057.txt @@ -0,0 +1,6 @@ +5 +-4 -4 +-6 0 +-2 2 +0 4 +-10 2 \ No newline at end of file diff --git a/example/input_data/primary/primary_058.txt b/example/input_data/primary/primary_058.txt new file mode 100644 index 0000000..6b4eda5 --- /dev/null +++ b/example/input_data/primary/primary_058.txt @@ -0,0 +1,9 @@ +0 8 +644245092 214748364 858993456 214748364 +-644245092 -214748364 0 644245092 +-858993456 -214748364 -429496728 -644245092 +0 644245092 -214748364 644245092 +644245092 644245092 0 644245092 +858993456 858993456 644245092 644245092 +644245092 214748364 644245092 644245092 +858993456 214748364 644245092 214748364 diff --git a/example/input_data/primary/primary_059.txt b/example/input_data/primary/primary_059.txt new file mode 100644 index 0000000..df514ff --- /dev/null +++ b/example/input_data/primary/primary_059.txt @@ -0,0 +1,12 @@ +0 11 +214748364 -214748364 1073741820 -1073741820 +-858993456 -214748364 -858993456 0 +-214748364 -644245092 -858993456 -214748364 +0 -644245092 -214748364 -644245092 +214748364 -644245092 0 -644245092 +-858993456 0 -858993456 -214748364 +-644245092 214748364 -858993456 0 +-214748364 214748364 -214748364 0 +-214748364 0 429496728 0 +-214748364 0 -214748364 -644245092 +-214748364 -644245092 0 -644245092 diff --git a/example/input_data/primary/primary_060.txt b/example/input_data/primary/primary_060.txt new file mode 100644 index 0000000..0838949 --- /dev/null +++ b/example/input_data/primary/primary_060.txt @@ -0,0 +1,12 @@ +0 11 +1 -1 5 -5 +-4 -1 -4 0 +-1 -3 -4 -1 +0 -3 -1 -3 +1 -3 0 -3 +-4 0 -4 -1 +-3 1 -4 0 +-1 1 -1 0 +-1 0 2 0 +-1 0 -1 -3 +-1 -3 0 -3 diff --git a/example/input_data/primary/primary_061.txt b/example/input_data/primary/primary_061.txt new file mode 100644 index 0000000..eda3d14 --- /dev/null +++ b/example/input_data/primary/primary_061.txt @@ -0,0 +1,9 @@ +0 8 +-858993456 644245092 0 -429496728 +644245092 214748364 -214748364 214748364 +0 429496728 214748364 644245092 +214748364 644245092 429496728 644245092 +429496728 644245092 644245092 858993456 +-858993456 644245092 -429496728 214748364 +-429496728 644245092 214748364 644245092 +214748364 644245092 429496728 644245092 diff --git a/example/input_data/primary/primary_062.txt b/example/input_data/primary/primary_062.txt new file mode 100644 index 0000000..5e30486 --- /dev/null +++ b/example/input_data/primary/primary_062.txt @@ -0,0 +1,4 @@ +0 3 +644245092 214748364 -214748364 214748364 +0 429496728 214748364 644245092 +-429496728 644245092 214748364 644245092 diff --git a/example/input_data/primary/primary_063.txt b/example/input_data/primary/primary_063.txt new file mode 100644 index 0000000..724c6d0 --- /dev/null +++ b/example/input_data/primary/primary_063.txt @@ -0,0 +1,4 @@ +0 +2 +-5 0 -1 -1 +-4 0 -6 3 diff --git a/example/input_data/primary/primary_064.txt b/example/input_data/primary/primary_064.txt new file mode 100644 index 0000000..29d933a --- /dev/null +++ b/example/input_data/primary/primary_064.txt @@ -0,0 +1,4 @@ +0 3 +-8 15 24 28 +-37 4 -39 36 +12 -30 44 8 diff --git a/example/input_data/primary/primary_065.txt b/example/input_data/primary/primary_065.txt new file mode 100644 index 0000000..1614082 --- /dev/null +++ b/example/input_data/primary/primary_065.txt @@ -0,0 +1,89 @@ +0 +87 +-50061 -49176 -49997 -49195 +-50024 -49880 -49980 -49904 +-50001 -49559 -49983 -49632 +-49990 -49437 -49931 -49440 +-49971 -49300 -49894 -49240 +-49938 -49762 -49923 -49826 +-49938 -49133 -49864 -49064 +-49923 -49874 -49852 -49836 +-49897 -49640 -49866 -49683 +-49895 -49859 -49840 -49829 +-49889 -49210 -49828 -49159 +-49857 -49380 -49795 -49428 +-49841 -49551 -49836 -49502 +-49833 -49320 -49791 -49333 +-49828 -49707 -49779 -49627 +-49821 -49526 -49800 -49565 +-49817 -49714 -49729 -49752 +-49806 -49111 -49733 -49060 +-49796 -49803 -49787 -49787 +-49761 -49652 -49679 -49721 +-49756 -49266 -49727 -49249 +-49754 -49465 -49656 -49532 +-49740 -49146 -49706 -49152 +-49726 -49236 -49710 -49163 +-49717 -49215 -49617 -49303 +-49702 -49809 -49680 -49735 +-49702 -49370 -49678 -49415 +-49677 -49849 -49636 -49917 +-49641 -49057 -49560 -49083 +-49632 -49692 -49548 -49776 +-49627 -49640 -49627 -49572 +-49626 -49932 -49565 -49834 +-49605 -49426 -49547 -49466 +-49597 -49185 -49526 -49250 +-49542 -49652 -49454 -49751 +-49540 -49283 -49471 -49298 +-49537 -49845 -49500 -49927 +-49527 -49420 -49473 -49518 +-49519 -49092 -49483 -49162 +-49517 -49235 -49442 -49292 +-49511 -49972 -49504 -49938 +-49504 -49827 -49458 -49784 +-49494 -49323 -49485 -49413 +-49481 -49509 -49443 -49578 +-49461 -49606 -49427 -49598 +-49435 -49153 -49403 -49183 +-49419 -49762 -49376 -49792 +-49417 -49832 -49334 -49899 +-49408 -49887 -49398 -49973 +-49388 -49221 -49365 -49277 +-49381 -49444 -49374 -49522 +-49379 -49434 -49336 -49457 +-49373 -49220 -49367 -49171 +-49369 -49140 -49317 -49239 +-49367 -49538 -49291 -49562 +-49364 -49102 -49293 -49109 +-49346 -49652 -49332 -49605 +-49343 -49810 -49295 -49850 +-49337 -49198 -49292 -49238 +-49322 -49092 -49309 -49041 +-49317 -49349 -49315 -49396 +-49312 -49203 -49294 -49126 +-49297 -49988 -49256 -49977 +-49295 -49580 -49213 -49491 +-49291 -49641 -49278 -49656 +-49286 -49601 -49250 -49672 +-49283 -49914 -49281 -49847 +-49281 -49590 -49250 -49601 +-49273 -49379 -49232 -49312 +-49257 -49616 -49231 -49621 +-49245 -49884 -49202 -49841 +-49234 -49059 -49156 -49135 +-49225 -49336 -49164 -49360 +-49207 -49354 -49204 -49372 +-49188 -49136 -49160 -49168 +-49171 -49946 -49108 -49855 +-49169 -49415 -49101 -49453 +-49158 -49164 -49136 -49122 +-49130 -49925 -49097 -49841 +-49127 -49675 -49047 -49676 +-49109 -49435 -49011 -49528 +-49104 -49909 -49084 -49859 +-49082 -49602 -48992 -49566 +-49073 -49130 -49002 -49081 +-49064 -49936 -49025 -49978 +-49044 -49020 -49028 -49012 +-49010 -49234 -48949 -49210 diff --git a/example/input_data/primary/primary_066.txt b/example/input_data/primary/primary_066.txt new file mode 100644 index 0000000..45f9dd3 --- /dev/null +++ b/example/input_data/primary/primary_066.txt @@ -0,0 +1,195 @@ +0 +193 +-50004 -49132 -49976 -49143 +-50000 -49669 -49975 -49629 +-49998 -49048 -49946 -49035 +-49992 -49789 -49931 -49697 +-49987 -49783 -49900 -49859 +-49986 -49922 -49973 -49927 +-49986 -49478 -49972 -49515 +-49984 -49089 -49938 -49107 +-49983 -49675 -49963 -49734 +-49975 -49538 -49940 -49498 +-49971 -49867 -49918 -49886 +-49964 -49980 -49952 -50034 +-49952 -49566 -49904 -49592 +-49952 -49236 -49859 -49215 +-49945 -49509 -49921 -49460 +-49941 -49836 -49865 -49921 +-49940 -49321 -49932 -49403 +-49933 -49797 -49837 -49806 +-49929 -49381 -49858 -49388 +-49928 -49608 -49872 -49696 +-49927 -49805 -49902 -49825 +-49909 -49026 -49858 -48938 +-49898 -49229 -49851 -49251 +-49895 -49633 -49808 -49721 +-49886 -49687 -49837 -49759 +-49878 -49348 -49846 -49395 +-49875 -49084 -49837 -49109 +-49861 -49927 -49842 -49904 +-49857 -49151 -49830 -49181 +-49856 -49372 -49846 -49393 +-49855 -49515 -49784 -49607 +-49851 -49037 -49844 -49073 +-49845 -49220 -49790 -49301 +-49838 -49482 -49826 -49430 +-49836 -49490 -49770 -49397 +-49829 -49370 -49738 -49326 +-49805 -49616 -49781 -49647 +-49802 -49947 -49754 -49975 +-49802 -49824 -49782 -49751 +-49800 -49734 -49712 -49767 +-49795 -49462 -49730 -49430 +-49788 -49139 -49728 -49156 +-49786 -49538 -49747 -49514 +-49783 -49261 -49742 -49187 +-49775 -49133 -49752 -49051 +-49772 -49826 -49770 -49755 +-49770 -49737 -49715 -49701 +-49768 -49969 -49737 -49988 +-49768 -49289 -49708 -49270 +-49756 -49890 -49745 -49906 +-49732 -50045 -49659 -49957 +-49726 -49961 -49689 -49933 +-49725 -49584 -49701 -49520 +-49717 -49454 -49665 -49408 +-49713 -49620 -49696 -49597 +-49705 -49300 -49688 -49280 +-49702 -48946 -49619 -49011 +-49701 -49797 -49672 -49733 +-49699 -49730 -49640 -49673 +-49696 -49538 -49668 -49562 +-49695 -49454 -49644 -49509 +-49683 -49845 -49613 -49847 +-49676 -49455 -49614 -49455 +-49676 -49165 -49665 -49131 +-49669 -49436 -49618 -49397 +-49667 -49273 -49611 -49341 +-49664 -49941 -49644 -49853 +-49655 -49426 -49593 -49405 +-49650 -49039 -49592 -48996 +-49645 -49762 -49558 -49819 +-49642 -49918 -49629 -49925 +-49638 -49409 -49582 -49328 +-49636 -49743 -49559 -49805 +-49629 -49529 -49549 -49487 +-49627 -49096 -49577 -49054 +-49626 -49940 -49562 -50025 +-49612 -49466 -49574 -49398 +-49606 -49583 -49532 -49633 +-49606 -49288 -49556 -49356 +-49600 -49856 -49556 -49907 +-49594 -49166 -49546 -49148 +-49593 -49160 -49557 -49119 +-49586 -49533 -49534 -49534 +-49576 -49655 -49527 -49733 +-49571 -49468 -49564 -49410 +-49555 -49534 -49505 -49544 +-49555 -49314 -49503 -49289 +-49547 -49413 -49535 -49473 +-49543 -49984 -49462 -49886 +-49537 -49835 -49489 -49866 +-49536 -49256 -49515 -49237 +-49530 -49940 -49503 -49875 +-49510 -49342 -49485 -49366 +-49505 -49287 -49455 -49308 +-49499 -49909 -49475 -49880 +-49499 -49648 -49486 -49612 +-49489 -49785 -49482 -49851 +-49488 -49690 -49469 -49624 +-49484 -49727 -49441 -49650 +-49477 -49146 -49461 -49149 +-49474 -49433 -49401 -49411 +-49471 -49873 -49451 -49780 +-49471 -49725 -49415 -49775 +-49460 -49998 -49361 -49980 +-49458 -49621 -49448 -49561 +-49448 -49432 -49420 -49438 +-49443 -49942 -49353 -49975 +-49441 -49662 -49360 -49721 +-49439 -49313 -49375 -49361 +-49438 -49826 -49378 -49771 +-49437 -49884 -49427 -49849 +-49432 -49713 -49416 -49748 +-49423 -49035 -49363 -48938 +-49411 -49201 -49312 -49232 +-49410 -49095 -49399 -49034 +-49399 -49547 -49342 -49497 +-49399 -49230 -49390 -49259 +-49394 -49445 -49361 -49429 +-49393 -49615 -49360 -49660 +-49392 -49185 -49371 -49185 +-49392 -49020 -49390 -49005 +-49369 -49816 -49324 -49864 +-49368 -49828 -49342 -49845 +-49355 -50082 -49274 -49996 +-49354 -49414 -49270 -49512 +-49350 -49378 -49324 -49448 +-49349 -49027 -49317 -49012 +-49345 -49337 -49315 -49263 +-49344 -49983 -49278 -49977 +-49341 -49596 -49321 -49518 +-49338 -49054 -49329 -49121 +-49337 -49788 -49267 -49727 +-49333 -49258 -49320 -49275 +-49329 -49596 -49276 -49520 +-49325 -49228 -49232 -49257 +-49316 -49037 -49266 -49136 +-49313 -49612 -49267 -49604 +-49310 -49276 -49305 -49362 +-49306 -49704 -49294 -49652 +-49302 -49872 -49216 -49849 +-49286 -49089 -49225 -49139 +-49284 -49119 -49278 -49117 +-49276 -49306 -49209 -49406 +-49271 -49927 -49196 -49833 +-49264 -49696 -49176 -49674 +-49253 -49909 -49245 -49992 +-49252 -49804 -49161 -49822 +-49251 -49757 -49177 -49747 +-49249 -49603 -49150 -49595 +-49239 -49989 -49200 -49929 +-49239 -49202 -49205 -49178 +-49233 -49713 -49169 -49751 +-49225 -49327 -49210 -49359 +-49223 -49037 -49158 -48993 +-49219 -49243 -49181 -49336 +-49212 -49235 -49199 -49267 +-49211 -49912 -49138 -49959 +-49210 -49462 -49123 -49497 +-49206 -49814 -49151 -49905 +-49201 -49527 -49188 -49481 +-49190 -49120 -49173 -49206 +-49178 -49656 -49174 -49598 +-49172 -49616 -49110 -49600 +-49164 -49673 -49157 -49768 +-49161 -49414 -49096 -49406 +-49159 -49013 -49077 -49078 +-49154 -49000 -49086 -49047 +-49151 -49787 -49151 -49693 +-49143 -49651 -49123 -49683 +-49141 -49982 -49100 -49949 +-49138 -49607 -49117 -49583 +-49128 -49565 -49115 -49499 +-49123 -49412 -49040 -49426 +-49121 -49732 -49103 -49690 +-49117 -49724 -49102 -49688 +-49114 -49206 -49075 -49124 +-49110 -49937 -49030 -49889 +-49109 -49215 -49071 -49305 +-49092 -49527 -49056 -49604 +-49091 -49133 -49057 -49070 +-49089 -49036 -49022 -49076 +-49079 -49254 -49019 -49331 +-49077 -49768 -49042 -49804 +-49060 -49611 -49029 -49677 +-49060 -49083 -49052 -49170 +-49054 -49751 -49041 -49789 +-49047 -49846 -48991 -49882 +-49045 -49567 -48976 -49528 +-49043 -49787 -49000 -49864 +-49038 -49415 -49028 -49463 +-49033 -49721 -48973 -49756 +-49009 -49823 -48919 -49827 +-49008 -49022 -48959 -49051 diff --git a/example/input_data/primary/primary_067.txt b/example/input_data/primary/primary_067.txt new file mode 100644 index 0000000..0278f75 --- /dev/null +++ b/example/input_data/primary/primary_067.txt @@ -0,0 +1,193 @@ +0 +191 +-50042 -49987 -49958 -49945 +-50038 -49880 -49984 -49840 +-50037 -49252 -49945 -49166 +-50037 -49056 -49996 -49148 +-50032 -49217 -49997 -49201 +-50026 -49270 -49960 -49312 +-50015 -49525 -49981 -49615 +-49999 -49338 -49906 -49318 +-49987 -49179 -49967 -49165 +-49979 -49752 -49915 -49671 +-49969 -49530 -49933 -49592 +-49951 -49784 -49879 -49749 +-49951 -49221 -49901 -49194 +-49946 -49228 -49884 -49303 +-49945 -49017 -49892 -49044 +-49942 -49455 -49940 -49549 +-49935 -49727 -49867 -49646 +-49935 -49357 -49857 -49444 +-49929 -49561 -49868 -49576 +-49927 -49909 -49877 -49866 +-49917 -49237 -49913 -49230 +-49914 -49291 -49888 -49357 +-49911 -49876 -49902 -49845 +-49898 -49977 -49854 -49895 +-49898 -49495 -49817 -49490 +-49894 -50000 -49824 -50069 +-49893 -49680 -49865 -49692 +-49882 -49217 -49795 -49150 +-49873 -49323 -49831 -49278 +-49865 -49067 -49777 -49100 +-49859 -49115 -49822 -49170 +-49856 -49764 -49847 -49787 +-49855 -49475 -49796 -49446 +-49847 -49503 -49826 -49601 +-49847 -49227 -49774 -49288 +-49838 -49679 -49810 -49646 +-49821 -49704 -49807 -49760 +-49818 -49528 -49797 -49532 +-49812 -49585 -49753 -49537 +-49805 -49866 -49749 -49911 +-49803 -49243 -49742 -49282 +-49795 -49351 -49763 -49446 +-49790 -49322 -49768 -49409 +-49788 -49759 -49766 -49695 +-49780 -49048 -49765 -49147 +-49773 -49459 -49741 -49530 +-49764 -49068 -49746 -49104 +-49762 -49163 -49758 -49119 +-49760 -49208 -49715 -49126 +-49756 -49583 -49713 -49539 +-49754 -49728 -49690 -49715 +-49752 -49643 -49686 -49622 +-49748 -49983 -49653 -49989 +-49735 -49490 -49710 -49475 +-49733 -49426 -49649 -49404 +-49730 -49073 -49701 -49052 +-49727 -49005 -49681 -48996 +-49722 -49757 -49687 -49773 +-49702 -49179 -49668 -49222 +-49701 -49141 -49666 -49086 +-49698 -49353 -49683 -49290 +-49696 -49526 -49669 -49525 +-49692 -49988 -49637 -50061 +-49691 -49859 -49676 -49844 +-49690 -49445 -49637 -49414 +-49682 -49552 -49675 -49610 +-49679 -49853 -49671 -49918 +-49677 -49383 -49616 -49389 +-49673 -49827 -49666 -49784 +-49663 -49990 -49626 -50052 +-49661 -49742 -49639 -49842 +-49655 -49070 -49627 -48996 +-49650 -49495 -49585 -49491 +-49649 -49907 -49584 -49945 +-49645 -49253 -49640 -49189 +-49644 -49285 -49555 -49253 +-49643 -49740 -49592 -49686 +-49640 -49281 -49602 -49182 +-49630 -49389 -49536 -49479 +-49622 -49335 -49554 -49292 +-49619 -49538 -49606 -49522 +-49606 -49039 -49535 -49096 +-49602 -49383 -49599 -49328 +-49600 -49700 -49596 -49691 +-49599 -49612 -49531 -49514 +-49599 -49560 -49546 -49483 +-49592 -49206 -49563 -49198 +-49588 -49783 -49564 -49811 +-49575 -49789 -49486 -49772 +-49570 -49179 -49482 -49278 +-49557 -49225 -49506 -49269 +-49552 -49621 -49524 -49654 +-49540 -49058 -49532 -49085 +-49534 -49873 -49522 -49964 +-49532 -49626 -49502 -49607 +-49530 -49638 -49432 -49539 +-49527 -49420 -49478 -49505 +-49526 -49716 -49439 -49744 +-49508 -49372 -49498 -49454 +-49508 -49301 -49468 -49382 +-49507 -49275 -49459 -49371 +-49497 -49840 -49422 -49895 +-49494 -49252 -49451 -49251 +-49480 -49732 -49452 -49803 +-49472 -49036 -49460 -49129 +-49459 -49831 -49391 -49775 +-49456 -49427 -49390 -49409 +-49453 -49001 -49452 -48918 +-49441 -48971 -49380 -49025 +-49438 -49914 -49388 -49964 +-49430 -49525 -49342 -49457 +-49427 -49116 -49393 -49180 +-49424 -49378 -49339 -49293 +-49420 -49667 -49378 -49577 +-49419 -49208 -49392 -49286 +-49417 -49885 -49407 -49797 +-49417 -49327 -49345 -49285 +-49404 -49689 -49389 -49637 +-49399 -49430 -49320 -49375 +-49399 -49238 -49370 -49259 +-49394 -49946 -49367 -49866 +-49388 -49703 -49362 -49664 +-49385 -49785 -49311 -49789 +-49382 -49166 -49378 -49154 +-49375 -49211 -49344 -49286 +-49374 -49997 -49313 -50051 +-49367 -49941 -49348 -49969 +-49364 -49787 -49340 -49887 +-49359 -49232 -49315 -49203 +-49351 -49957 -49323 -49869 +-49349 -48969 -49303 -49026 +-49344 -49030 -49342 -49116 +-49333 -49248 -49326 -49316 +-49304 -49695 -49210 -49737 +-49301 -49643 -49244 -49656 +-49300 -49907 -49242 -49908 +-49295 -49272 -49231 -49194 +-49293 -49026 -49291 -48987 +-49290 -49992 -49244 -49950 +-49287 -49539 -49265 -49542 +-49278 -49142 -49261 -49117 +-49277 -49304 -49216 -49313 +-49272 -49800 -49251 -49769 +-49270 -49894 -49239 -49809 +-49269 -49397 -49196 -49319 +-49268 -49911 -49171 -49902 +-49257 -49050 -49208 -49086 +-49250 -49780 -49178 -49731 +-49239 -49113 -49166 -49120 +-49237 -49247 -49203 -49166 +-49230 -49019 -49194 -49061 +-49217 -49465 -49215 -49528 +-49213 -49605 -49116 -49548 +-49212 -49846 -49211 -49815 +-49209 -49912 -49171 -49955 +-49203 -49685 -49188 -49672 +-49203 -49234 -49147 -49333 +-49201 -49854 -49116 -49916 +-49200 -49087 -49190 -49045 +-49188 -49258 -49133 -49220 +-49179 -49615 -49150 -49581 +-49179 -49568 -49137 -49507 +-49168 -49326 -49114 -49385 +-49164 -50078 -49090 -49990 +-49164 -49498 -49157 -49409 +-49160 -49807 -49085 -49875 +-49158 -49601 -49136 -49624 +-49156 -49015 -49063 -49081 +-49155 -49894 -49135 -49907 +-49150 -49949 -49107 -49930 +-49150 -49143 -49147 -49210 +-49149 -49896 -49076 -49946 +-49147 -49219 -49094 -49155 +-49132 -49474 -49113 -49509 +-49129 -49400 -49052 -49347 +-49114 -49721 -49082 -49630 +-49113 -49663 -49106 -49585 +-49109 -49241 -49091 -49330 +-49107 -49230 -49067 -49179 +-49106 -49585 -49097 -49487 +-49104 -49006 -49077 -49043 +-49083 -49910 -49080 -49941 +-49069 -49028 -49010 -48971 +-49068 -49800 -49050 -49796 +-49045 -49223 -49029 -49273 +-49043 -49598 -48998 -49619 +-49037 -49738 -49031 -49678 +-49037 -49062 -49024 -49129 +-49033 -49407 -49023 -49483 +-49008 -49795 -48973 -49798 +-49003 -49428 -48993 -49376 diff --git a/example/input_data/primary/primary_068.txt b/example/input_data/primary/primary_068.txt new file mode 100644 index 0000000..0684c81 --- /dev/null +++ b/example/input_data/primary/primary_068.txt @@ -0,0 +1,98 @@ +0 +87 +-50021 -49808 -49940 -49833 +-50019 -49363 -49964 -49351 +-49963 -49703 -49912 -49721 +-49948 -49289 -49940 -49212 +-49916 -49137 -49870 -49141 +-49906 -49419 -49873 -49349 +-49903 -49328 -49899 -49307 +-49897 -49741 -49852 -49675 +-49895 -49638 -49828 -49568 +-49893 -49251 -49855 -49313 +-49871 -49502 -49801 -49551 +-49866 -49431 -49834 -49524 +-49861 -49122 -49812 -49030 +-49852 -49901 -49814 -49872 +-49815 -49601 -49716 -49652 +-49799 -49916 -49785 -49916 +-49766 -49501 -49745 -49523 +-49765 -49266 -49672 -49282 +-49763 -49207 -49681 -49170 +-49756 -49650 -49744 -49699 +-49748 -49703 -49663 -49657 +-49736 -49581 -49683 -49534 +-49736 -49463 -49700 -49534 +-49732 -49049 -49674 -49119 +-49722 -49992 -49694 -49963 +-49710 -49415 -49648 -49378 +-49710 -49298 -49670 -49339 +-49688 -49985 -49652 -50004 +-49684 -49416 -49634 -49459 +-49659 -49561 -49573 -49550 +-49654 -49211 -49613 -49161 +-49638 -49058 -49576 -49104 +-49624 -49012 -49543 -49051 +-49621 -49341 -49619 -49317 +-49608 -49406 -49593 -49379 +-49599 -49228 -49538 -49293 +-49598 -49634 -49527 -49534 +-49594 -49713 -49523 -49729 +-49586 -49735 -49580 -49724 +-49564 -49184 -49531 -49109 +-49560 -49651 -49528 -49579 +-49552 -49739 -49457 -49829 +-49549 -49938 -49543 -49953 +-49517 -49670 -49480 -49763 +-49508 -49076 -49493 -49008 +-49507 -49467 -49451 -49459 +-49478 -49308 -49439 -49383 +-49477 -48995 -49393 -49025 +-49468 -49237 -49401 -49183 +-49464 -49517 -49393 -49532 +-49453 -49670 -49395 -49751 +-49448 -49430 -49367 -49380 +-49434 -49371 -49403 -49302 +-49422 -49836 -49384 -49882 +-49408 -49095 -49396 -49110 +-49387 -49237 -49366 -49277 +-49368 -49766 -49365 -49777 +-49366 -49860 -49280 -49911 +-49359 -49526 -49355 -49554 +-49352 -49281 -49275 -49187 +-49346 -49424 -49327 -49370 +-49346 -48957 -49257 -49045 +-49344 -49529 -49311 -49595 +-49344 -49131 -49270 -49077 +-49331 -49505 -49276 -49470 +-49275 -49446 -49269 -49529 +-49274 -48994 -49239 -49083 +-49269 -49530 -49266 -49579 +-49268 -49916 -49229 -49923 +-49254 -49830 -49233 -49777 +-49214 -49820 -49168 -49806 +-49214 -49246 -49207 -49200 +-49209 -49470 -49159 -49503 +-49203 -49239 -49121 -49256 +-49186 -49302 -49156 -49306 +-49185 -49612 -49130 -49664 +-49158 -49718 -49100 -49653 +-49155 -49271 -49056 -49347 +-49138 -49437 -49061 -49374 +-49137 -49475 -49136 -49540 +-49126 -49059 -49069 -49056 +-49113 -49751 -49072 -49794 +-49102 -49977 -49024 -49998 +-49070 -49161 -49052 -49212 +-49053 -49902 -49030 -49948 +-49048 -49413 -49004 -49497 +-49021 -49751 -49015 -49668 +-49478.582149386399 -49780.216848801821 +-49394.596858638746 -49830.083115183246 +-49404.712650811380 -49872.695164891658 +-49392.218561523550 -49808.669479018703 +../../SOC_2010/sweepline/libs/sweepline/test/sweepline_test.cpp(703): error in "segment_random_test2": check verify_output(test_output_small, NO_HALF_EDGE_INTERSECTIONS) == true failed [false != true] +-49478.582149386399 -49780.216848801821 +-49394.596858638746 -49830.083115183246 +-49404.712650811380 -49872.695164891658 +-49392.218561523550 -49808.669479018703 diff --git a/example/input_data/primary/primary_069.txt b/example/input_data/primary/primary_069.txt new file mode 100644 index 0000000..0fbf4bc --- /dev/null +++ b/example/input_data/primary/primary_069.txt @@ -0,0 +1,83 @@ +0 +81 +-50026 -49688 -49978 -49701 +-49998 -49860 -49969 -49782 +-49974 -49744 -49897 -49748 +-49972 -49661 -49971 -49727 +-49971 -49845 -49902 -49789 +-49967 -49338 -49934 -49244 +-49947 -49670 -49896 -49744 +-49939 -49502 -49885 -49564 +-49937 -49150 -49874 -49115 +-49930 -49608 -49885 -49665 +-49925 -48976 -49888 -49019 +-49919 -49430 -49851 -49399 +-49909 -49052 -49908 -49015 +-49902 -49341 -49895 -49344 +-49899 -49717 -49827 -49792 +-49878 -49284 -49790 -49223 +-49844 -49250 -49784 -49171 +-49792 -49805 -49708 -49872 +-49781 -49381 -49727 -49379 +-49772 -49162 -49702 -49126 +-49768 -49290 -49696 -49324 +-49764 -49266 -49705 -49194 +-49737 -49279 -49659 -49200 +-49701 -49846 -49640 -49812 +-49699 -49415 -49670 -49409 +-49694 -49710 -49670 -49623 +-49688 -49732 -49653 -49759 +-49682 -49014 -49675 -49030 +-49679 -49421 -49641 -49428 +-49671 -49124 -49659 -49117 +-49642 -49113 -49599 -49063 +-49639 -49409 -49547 -49439 +-49629 -49070 -49595 -49043 +-49616 -49830 -49532 -49887 +-49616 -49438 -49544 -49519 +-49615 -49093 -49574 -49097 +-49610 -49583 -49587 -49491 +-49608 -49736 -49550 -49812 +-49599 -49403 -49520 -49408 +-49588 -49924 -49576 -49918 +-49579 -50064 -49483 -49994 +-49559 -49800 -49506 -49870 +-49552 -49543 -49534 -49570 +-49541 -49937 -49469 -49920 +-49513 -49782 -49494 -49816 +-49509 -49996 -49472 -49955 +-49509 -49892 -49452 -49796 +-49482 -50051 -49468 -49972 +-49419 -49411 -49371 -49424 +-49411 -49494 -49328 -49567 +-49407 -49584 -49358 -49547 +-49399 -49236 -49341 -49168 +-49370 -49205 -49284 -49121 +-49364 -49032 -49355 -49119 +-49363 -49029 -49302 -49048 +-49340 -49544 -49242 -49472 +-49335 -49800 -49325 -49866 +-49334 -49786 -49282 -49798 +-49323 -49685 -49229 -49765 +-49311 -49777 -49247 -49789 +-49305 -49633 -49283 -49631 +-49300 -49574 -49261 -49601 +-49295 -49245 -49286 -49278 +-49275 -49861 -49223 -49778 +-49261 -49054 -49235 -49029 +-49260 -49355 -49228 -49436 +-49248 -49991 -49198 -49926 +-49236 -49618 -49152 -49637 +-49225 -50042 -49179 -49961 +-49190 -49250 -49108 -49308 +-49189 -49609 -49168 -49578 +-49164 -49936 -49133 -49922 +-49124 -49640 -49057 -49695 +-49117 -49169 -49041 -49213 +-49111 -49802 -49099 -49894 +-49105 -49697 -49053 -49738 +-49082 -49532 -49031 -49559 +-49063 -49321 -49007 -49234 +-49032 -49130 -48987 -49200 +-49025 -49437 -48988 -49427 +-49008 -49119 -48968 -49214 diff --git a/example/input_data/primary/primary_070.txt b/example/input_data/primary/primary_070.txt new file mode 100644 index 0000000..df3e8f9 --- /dev/null +++ b/example/input_data/primary/primary_070.txt @@ -0,0 +1,5 @@ +1 +-49400 -49572 +2 +-49431 -49703 -49427 -49798 +-49427 -49798 -49423 -49892 \ No newline at end of file diff --git a/example/input_data/primary/primary_071.txt b/example/input_data/primary/primary_071.txt new file mode 100644 index 0000000..a09a125 --- /dev/null +++ b/example/input_data/primary/primary_071.txt @@ -0,0 +1,94 @@ +0 +90 +-50051 -49552 -49991 -49625 +-50042 -49515 -49976 -49442 +-50024 -49188 -49996 -49221 +-50007 -49191 -49933 -49159 +-50000 -49509 -49989 -49549 +-49991 -49047 -49950 -49120 +-49984 -49938 -49909 -49904 +-49959 -49631 -49908 -49568 +-49954 -49626 -49887 -49595 +-49949 -49320 -49859 -49414 +-49916 -49188 -49859 -49241 +-49906 -49611 -49830 -49675 +-49905 -49754 -49847 -49843 +-49892 -49327 -49848 -49239 +-49882 -49416 -49872 -49486 +-49871 -49640 -49797 -49703 +-49846 -49283 -49821 -49368 +-49767 -49927 -49707 -49928 +-49765 -49619 -49762 -49671 +-49764 -49476 -49721 -49531 +-49753 -49486 -49691 -49491 +-49738 -49590 -49712 -49679 +-49736 -49108 -49686 -49138 +-49736 -49008 -49671 -48932 +-49724 -49802 -49627 -49770 +-49717 -49691 -49694 -49699 +-49714 -49152 -49708 -49200 +-49707 -49875 -49621 -49790 +-49700 -49062 -49648 -49109 +-49684 -49680 -49611 -49740 +-49654 -49456 -49562 -49400 +-49611 -49270 -49584 -49339 +-49585 -49234 -49567 -49210 +-49578 -49012 -49527 -49080 +-49561 -49658 -49538 -49670 +-49536 -49144 -49445 -49082 +-49523 -49784 -49500 -49868 +-49509 -49742 -49424 -49733 +-49508 -49070 -49472 -49092 +-49490 -49176 -49439 -49082 +-49477 -49856 -49475 -49779 +-49467 -49051 -49446 -49014 +-49462 -49793 -49457 -49818 +-49460 -49642 -49381 -49620 +-49444 -49977 -49349 -50073 +-49444 -49973 -49396 -49915 +-49425 -49114 -49363 -49182 +-49424 -49002 -49351 -49096 +-49400 -49470 -49311 -49557 +-49392 -49631 -49324 -49704 +-49375 -49195 -49281 -49123 +-49361 -49096 -49314 -49143 +-49345 -49402 -49256 -49437 +-49339 -49476 -49298 -49437 +-49324 -49287 -49242 -49273 +-49290 -49579 -49252 -49548 +-49280 -49601 -49217 -49612 +-49268 -49108 -49169 -49112 +-49257 -49481 -49241 -49480 +-49248 -49521 -49233 -49580 +-49246 -49802 -49245 -49893 +-49236 -49292 -49205 -49336 +-49220 -49157 -49210 -49143 +-49209 -49367 -49171 -49405 +-49205 -49883 -49176 -49926 +-49204 -49128 -49131 -49099 +-49200 -49252 -49128 -49166 +-49194 -49507 -49189 -49496 +-49185 -49344 -49140 -49354 +-49183 -49895 -49144 -49867 +-49183 -49289 -49135 -49213 +-49177 -49192 -49168 -49158 +-49140 -49876 -49120 -49924 +-49140 -49855 -49116 -49874 +-49138 -49132 -49081 -49142 +-49127 -49293 -49090 -49363 +-49096 -49761 -49037 -49744 +-49096 -49101 -49081 -49093 +-49090 -49308 -49083 -49401 +-49086 -49605 -49074 -49539 +-49084 -49865 -49059 -49795 +-49084 -49124 -48989 -49171 +-49077 -49034 -49067 -49009 +-49069 -49979 -49067 -49965 +-49063 -49317 -49050 -49248 +-49036 -49851 -49002 -49942 +-49032 -49126 -49003 -49097 +-49025 -49181 -48951 -49179 +-49022 -49065 -48973 -49118 +-49018 -49876 -48988 -49875 +../../SOC_2010/sweepline/libs/sweepline/test/sweepline_test.cpp(723): error in "segment_random_test2": check test_output_small.num_vertex_records() == test_output_large.num_vertex_records() failed [476 != 526] +../../SOC_2010/sweepline/libs/sweepline/test/sweepline_test.cpp(725): error in "segment_random_test2": check test_output_small.num_edge_records() == test_output_large.num_edge_records() failed [734 != 795] diff --git a/example/input_data/random/random_001.txt b/example/input_data/random/random_001.txt new file mode 100644 index 0000000..04742bb --- /dev/null +++ b/example/input_data/random/random_001.txt @@ -0,0 +1,11 @@ +10 +9 1 +4 3 +9 6 +9 8 +3 9 +6 8 +0 5 +9 5 +3 0 +2 1 \ No newline at end of file diff --git a/example/input_data/random/random_002.txt b/example/input_data/random/random_002.txt new file mode 100644 index 0000000..72905d1 --- /dev/null +++ b/example/input_data/random/random_002.txt @@ -0,0 +1,11 @@ +10 +9 9 +2 6 +3 1 +6 4 +9 1 +9 7 +6 2 +2 4 +3 7 +6 7 \ No newline at end of file diff --git a/example/input_data/random/random_003.txt b/example/input_data/random/random_003.txt new file mode 100644 index 0000000..395e24d --- /dev/null +++ b/example/input_data/random/random_003.txt @@ -0,0 +1,11 @@ +10 +4 1 +5 4 +5 5 +2 6 +3 4 +0 7 +2 5 +8 9 +0 4 +2 7 \ No newline at end of file diff --git a/example/input_data/random/random_004.txt b/example/input_data/random/random_004.txt new file mode 100644 index 0000000..b287e93 --- /dev/null +++ b/example/input_data/random/random_004.txt @@ -0,0 +1,101 @@ +100 +29 76 +99 94 +74 20 +53 26 +95 55 +94 21 +50 70 +19 93 +31 30 +73 61 +87 23 +60 66 +51 29 +82 51 +74 40 +31 77 +1 82 +43 0 +58 67 +63 32 +19 90 +68 31 +49 63 +76 83 +72 20 +70 11 +80 23 +4 90 +32 56 +63 75 +51 71 +62 10 +80 57 +71 47 +2 8 +67 85 +64 72 +85 6 +53 91 +92 25 +95 79 +24 6 +1 10 +10 85 +11 30 +22 14 +48 55 +82 8 +14 54 +84 60 +33 91 +85 60 +65 81 +60 23 +10 44 +29 32 +21 11 +90 15 +73 71 +41 62 +9 36 +44 80 +27 39 +41 38 +25 23 +86 15 +4 76 +52 6 +39 97 +42 25 +93 93 +97 24 +13 16 +58 62 +48 78 +43 74 +99 85 +13 42 +8 82 +13 9 +51 50 +85 83 +30 11 +58 42 +44 32 +88 74 +37 21 +65 28 +79 94 +50 94 +38 83 +82 13 +30 88 +16 92 +73 66 +24 0 +40 82 +57 25 +55 88 +13 33 \ No newline at end of file diff --git a/example/input_data/random/random_005.txt b/example/input_data/random/random_005.txt new file mode 100644 index 0000000..427ee9c --- /dev/null +++ b/example/input_data/random/random_005.txt @@ -0,0 +1,101 @@ +100 +-901943112 1116691472 +2104533928 1889785568 +1030792128 -1288490160 +128849016 -1030792128 +1932735240 214748360 +1889785568 -1245540488 +0 858993440 +-1331439832 1846835896 +-816043768 -858993440 +987842456 472446392 +1589137864 -1159641144 +429496720 687194752 +42949672 -901943112 +1374389504 42949672 +1030792128 -429496720 +-816043768 1159641144 +-2104533928 1374389504 +-300647704 -2147483600 +343597376 730144424 +558345736 -773094096 +-1331439832 1717986880 +773094096 -816043768 +-42949672 558345736 +1116691472 1417339176 +944892784 -1288490160 +858993440 -1675037208 +1288490160 -1159641144 +-1975684912 1717986880 +-773094096 257698032 +558345736 1073741800 +42949672 901943112 +515396064 -1717986880 +1288490160 300647704 +901943112 -128849016 +-2061584256 -1803886224 +730144424 1503238520 +601295408 944892784 +1503238520 -1889785568 +128849016 1760936552 +1803886224 -1073741800 +1932735240 1245540488 +-1116691472 -1889785568 +-2104533928 -1717986880 +-1717986880 1503238520 +-1675037208 -858993440 +-1202590816 -1546188192 +-85899344 214748360 +1374389504 -1803886224 +-1546188192 171798688 +1460288848 429496720 +-730144424 1760936552 +1503238520 429496720 +644245080 1331439832 +429496720 -1159641144 +-1717986880 -257698032 +-901943112 -773094096 +-1245540488 -1675037208 +1717986880 -1503238520 +987842456 901943112 +-386547048 515396064 +-1760936552 -601295408 +-257698032 1288490160 +-987842456 -472446392 +-386547048 -515396064 +-1073741800 -1159641144 +1546188192 -1503238520 +-1975684912 1116691472 +85899344 -1889785568 +-472446392 2018634584 +-343597376 -1073741800 +1846835896 1846835896 +2018634584 -1116691472 +-1589137864 -1460288848 +343597376 515396064 +-85899344 1202590816 +-300647704 1030792128 +2104533928 1503238520 +-1589137864 -343597376 +-1803886224 1374389504 +-1589137864 -1760936552 +42949672 0 +1503238520 1417339176 +-858993440 -1675037208 +343597376 -343597376 +-257698032 -773094096 +1632087536 1030792128 +-558345736 -1245540488 +644245080 -944892784 +1245540488 1889785568 +0 1889785568 +-515396064 1417339176 +1374389504 -1589137864 +-858993440 1632087536 +-1460288848 1803886224 +987842456 687194752 +-1116691472 -2147483600 +-429496720 1374389504 +300647704 -1073741800 +214748360 1632087536 +-1589137864 -730144424 \ No newline at end of file diff --git a/example/input_data/random/random_006.txt b/example/input_data/random/random_006.txt new file mode 100644 index 0000000..700f222 --- /dev/null +++ b/example/input_data/random/random_006.txt @@ -0,0 +1,6 @@ +0 +4 +-27 -32 5 -21 +-18 41 27 9 +-17 -25 12 9 +27 0 40 -20 diff --git a/example/input_data/random/random_007.txt b/example/input_data/random/random_007.txt new file mode 100644 index 0000000..f4270e3 --- /dev/null +++ b/example/input_data/random/random_007.txt @@ -0,0 +1,6 @@ +0 +4 +-48 10 -17 19 +-35 -30 -33 -2 +13 -45 18 46 +31 -14 47 18 diff --git a/example/input_data/random/random_008.txt b/example/input_data/random/random_008.txt new file mode 100644 index 0000000..5263a53 --- /dev/null +++ b/example/input_data/random/random_008.txt @@ -0,0 +1,6 @@ +0 +4 +-34 7 -21 13 +-9 37 39 10 +7 21 26 -18 +8 45 47 22 diff --git a/example/input_data/random/random_009.txt b/example/input_data/random/random_009.txt new file mode 100644 index 0000000..b49d69d --- /dev/null +++ b/example/input_data/random/random_009.txt @@ -0,0 +1,7 @@ +0 +5 +-21 -9 -9 -34 +-20 1 11 43 +-3 -1 21 18 +34 -18 40 15 +47 43 48 -7 diff --git a/example/input_data/random/random_010.txt b/example/input_data/random/random_010.txt new file mode 100644 index 0000000..73e87f8 --- /dev/null +++ b/example/input_data/random/random_010.txt @@ -0,0 +1,5 @@ +0 +3 +-39 -43 -6 -22 +13 -21 33 38 +24 -42 42 43 diff --git a/example/input_data/random/random_011.txt b/example/input_data/random/random_011.txt new file mode 100644 index 0000000..178dfba --- /dev/null +++ b/example/input_data/random/random_011.txt @@ -0,0 +1,7 @@ +0 +5 +-22 -18 -13 -26 +-16 -36 23 -28 +-12 -11 6 19 +-4 -3 44 -30 +15 -5 47 17 diff --git a/example/input_data/random/random_012.txt b/example/input_data/random/random_012.txt new file mode 100644 index 0000000..c1959b7 --- /dev/null +++ b/example/input_data/random/random_012.txt @@ -0,0 +1,6 @@ +0 +4 +-27 -24 -20 -45 +-15 29 28 20 +-12 -36 19 -21 +1 -21 3 -1 diff --git a/example/input_data/random/random_013.txt b/example/input_data/random/random_013.txt new file mode 100644 index 0000000..e379ead --- /dev/null +++ b/example/input_data/random/random_013.txt @@ -0,0 +1,6 @@ +0 +4 +-47 11 -25 -20 +-17 2 3 -46 +-13 29 32 -35 +25 -3 42 37 diff --git a/example/input_data/random/random_014.txt b/example/input_data/random/random_014.txt new file mode 100644 index 0000000..bb01d6d --- /dev/null +++ b/example/input_data/random/random_014.txt @@ -0,0 +1,7 @@ +0 +5 +-36 -8 -18 24 +-17 44 -2 18 +-16 -7 -9 -28 +-14 5 -2 -20 +31 42 33 36 diff --git a/example/input_data/random/random_015.txt b/example/input_data/random/random_015.txt new file mode 100644 index 0000000..0ae016b --- /dev/null +++ b/example/input_data/random/random_015.txt @@ -0,0 +1,5 @@ +0 +3 +-24 17 -19 -12 +-21 -40 3 -17 +28 1 38 -38 diff --git a/example/input_data/random/random_016.txt b/example/input_data/random/random_016.txt new file mode 100644 index 0000000..7c04741 --- /dev/null +++ b/example/input_data/random/random_016.txt @@ -0,0 +1,8 @@ +0 +6 +-44 -29 -36 -40 +-40 0 -5 -43 +-7 37 -3 -23 +-4 18 14 30 +6 39 38 32 +12 -20 27 -15 diff --git a/example/input_data/random/random_017.txt b/example/input_data/random/random_017.txt new file mode 100644 index 0000000..267e541 --- /dev/null +++ b/example/input_data/random/random_017.txt @@ -0,0 +1,5 @@ +0 +3 +-46 -50 -36 -14 +-5 46 -4 -40 +21 45 49 -45 diff --git a/example/input_data/random/random_018.txt b/example/input_data/random/random_018.txt new file mode 100644 index 0000000..980c7f6 --- /dev/null +++ b/example/input_data/random/random_018.txt @@ -0,0 +1,7 @@ +0 +5 +-45 44 -36 -29 +-36 41 -32 -14 +-16 44 23 9 +13 -4 19 -29 +18 -3 48 39 diff --git a/example/input_data/random/random_019.txt b/example/input_data/random/random_019.txt new file mode 100644 index 0000000..011dbae --- /dev/null +++ b/example/input_data/random/random_019.txt @@ -0,0 +1,7 @@ +0 +5 +-29 22 -6 18 +-6 -20 18 19 +-5 28 44 22 +9 -48 22 -15 +11 32 11 39 diff --git a/example/input_data/random/random_020.txt b/example/input_data/random/random_020.txt new file mode 100644 index 0000000..77b6947 --- /dev/null +++ b/example/input_data/random/random_020.txt @@ -0,0 +1,7 @@ +0 +5 +-14 -43 37 -49 +-12 41 -10 -43 +-7 -20 18 -38 +7 34 47 -38 +23 26 42 -3 diff --git a/example/input_data/random/random_021.txt b/example/input_data/random/random_021.txt new file mode 100644 index 0000000..f959ec6 --- /dev/null +++ b/example/input_data/random/random_021.txt @@ -0,0 +1,7 @@ +0 +5 +-47 32 0 28 +-20 -22 9 -13 +-13 37 21 30 +-7 47 2 47 +26 47 32 1 diff --git a/example/input_data/random/random_022.txt b/example/input_data/random/random_022.txt new file mode 100644 index 0000000..e8fa87c --- /dev/null +++ b/example/input_data/random/random_022.txt @@ -0,0 +1,5 @@ +0 +3 +-19 17 -10 9 +-1 -50 25 40 +26 15 48 -3 diff --git a/example/input_data/random/random_023.txt b/example/input_data/random/random_023.txt new file mode 100644 index 0000000..1d27d98 --- /dev/null +++ b/example/input_data/random/random_023.txt @@ -0,0 +1,8 @@ +0 +6 +-41 -46 -20 -48 +-41 -22 10 -46 +-27 36 28 19 +-10 -10 28 -15 +13 -28 48 -19 +41 -20 47 1 diff --git a/example/input_data/random/random_024.txt b/example/input_data/random/random_024.txt new file mode 100644 index 0000000..401f125 --- /dev/null +++ b/example/input_data/random/random_024.txt @@ -0,0 +1,7 @@ +0 +5 +-29 26 24 -46 +-24 -48 -15 -19 +-15 -20 -2 -23 +-9 -30 0 -42 +3 21 24 43 diff --git a/example/input_data/random/random_025.txt b/example/input_data/random/random_025.txt new file mode 100644 index 0000000..4d3ca29 --- /dev/null +++ b/example/input_data/random/random_025.txt @@ -0,0 +1,4 @@ +0 +2 +-8 -34 29 22 +37 10 48 7 diff --git a/example/input_data/random/random_026.txt b/example/input_data/random/random_026.txt new file mode 100644 index 0000000..c35bfd7 --- /dev/null +++ b/example/input_data/random/random_026.txt @@ -0,0 +1,6 @@ +0 +4 +-35 -28 19 26 +-21 16 -19 -4 +9 -34 27 3 +25 48 47 -31 diff --git a/example/input_data/random/random_027.txt b/example/input_data/random/random_027.txt new file mode 100644 index 0000000..ce38d7a --- /dev/null +++ b/example/input_data/random/random_027.txt @@ -0,0 +1,8 @@ +0 +6 +-45 46 -24 24 +-37 30 -36 -7 +-18 -47 -4 -14 +-3 -34 40 -33 +5 17 44 -26 +35 -16 45 9 diff --git a/example/input_data/random/random_028.txt b/example/input_data/random/random_028.txt new file mode 100644 index 0000000..46952bd --- /dev/null +++ b/example/input_data/random/random_028.txt @@ -0,0 +1,7 @@ +0 +5 +-30 -27 -18 16 +-14 47 0 -46 +-13 42 13 20 +-10 26 7 -42 +-2 22 22 -42 diff --git a/example/output_data/polygon/polygon_001.png b/example/output_data/polygon/polygon_001.png new file mode 100644 index 0000000000000000000000000000000000000000..abb16facabf69a3c4581ad21c14426234f2710fb GIT binary patch literal 9500 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+eO>z4Ym(lDfO2W0*heRf^g8iCj z5*hCt{vvU~&U1L%@s%R+}^~knoIyOmZM??p6^89-m2M{Nr(e zi9y5X0F#_~tEEnZ{EUN4^OE_vA85(yJg|JWfnlA{1_lN$;SCMXeG>V&A8;8*9Qb@D zkuhdTGpo&c8L5);;HB#14qVwC@6GKQrSX(D0_aGGY!h4l;Qex3ey2W)(@}<8}ba`5s_8HS3U!*oNw~ z4Go{pBr;krZ)Tm6&c}Vjl98KXfdM18Mm|?@#DR4)4>Da#owC> zOPz%BGYO2ZjoVq@^zeyouq%!@aE>E_fuWT%;=r$E2JNhGx+HZHq(Qb`Jjk>SuwwqdA6b9u0bfb1c!A>EUz}oiy3Ih>MWS2sTB0Im?5IEf%VE~YZjdZ4<@mI^CEH6 z1tca(>MYPJjyTXzvY}zuvJE~QJnjdWUKzEs@^~CzdUa~6Kf?kW;|Pb^XB!$0zJU7T z>tESvT#XB%Vd795e4{`_qD!%S0WaI##>N*3jJY!o)kPdIV9{B?YbL|WrUcTL#>Sn| zZmE+XUFkXjtXk0aH^L^;$w7?pg1}~UZ zCo;;yGU_(pM138o+_!^Fx6<`>78par2%P2|elOb)%6vf-n#3~ZpLJ`5rAM#=FyZif z*@q%ahj4J{>+K0!*p43+11;NKU_N56kW1`VTNUm%(RDEN{>Ed-wtl< za*3}Au?f&uZ?IDNX>kof>&Nx?SL&LYd?W;M=3p@JD9-dt9d}NBxXUaoqvzlul3{F zrIx_>=GN2#(aLQmv&H|{R?0^RZD`oGbc4-~S@MUjn(vDE(6Rl)Ep~_1dqnPaz2gYK zZ|C++5vFcwu z+7t~+oBJOv?pBJ~``~23)JN@a4X6G8cI$oy$2|3k*W zf{{BxB3qw3Zc#VubdCsz*+DPjY?mbL@cMWldH637l8p*Z z2biL!K04?4dhhCuIy<)fiHWYu%b482y5;3N$Je&eiZM$ojBdP2Iyk3+^}^DrR^k5a zx1T<*{b;kGm`UuyG7+nY@U0tkDmwMV=5R(hR0nZ{hp&}c7qsWY4gK?pmGa-54=}xO zJN@vLk2tpyi_QX9%^1fYzN=3+dH+0CdxM>kJELElL)?rjT$776I#x$u1H-IsiO*L> zY&dKF?(h#5odvdYZt+jQmQ+s#$mUu$!?bA_kxig+`*fpu?m z+ba9-*6)(u20bnK8eVhO>F5*b?}2F}& zqTE^_Dj0ewv`Z9XyZeEryuSvV|6aGh6XVTPiOF>m@2(Zxu)y2$pN;2U-L$p;?z}H} zV0*N0okEUA%+ebRif82CY2U~Zabd2^eJh6je1gHhl9*6nZG+6vF>fqiYZyEJ{dmRvEuOYdg~*G zmwx_z_J8j;OZ$l9Z08cMTE+a3diLx2*QdYJ-=6CJ|NmCJ@X~9VvN|uE`nuRx9EDb;|N7zgB)STvxj8+}E|AFDJGu9CcS;`mJ(JP;c3~ zb6YE)8|ce*v&k_p<(keXW}zTw% zw2%Ki-8B8*+nb+~Opn^h6tnfByB6YeV0&n6_O_8$QllU71_O`f$^yM}}DsJ_f7`c$wfB zTx7Ffr@~V`c8v(LF2CHO?sK8SpL%~^*#1h>UsLpWyLI^UT{nNeT;Mz*X@WL~^{be< ztE)hsSbyvJ;*gn_4mPPh(YU>H*6StRSNA%XT;J(+(c!tl{T=*&SIzr0` zR{J9O>y+hJ?6l<{-#mA9r`)SQCU+E9*s*`fDZRDRDm-}Z;XM^H+4K8@)=%XV3z?Wa z``pzzdSQ|6FSZq5T~hPd?#uG3Q^8sBQ~N(=J%1I$UtTBmMqo)s3g3%~ul5v|u6t(H zUiopxH9PsG^YmqPZiMu`1t-w;)<*>9t`^~qaojN_|4#e95dTWAw~Id+dX=tIihJ?L zr&(qgCe=+g`-XU7GQP>kugK zd~rO`boFV3YRuA#Pn<^Q^YqVmpJw9@7ZiMd@qy68n}7Nl?l1o0d7vruX~f#%ua|^V zoMYFB@Y-K==aF1DYkK~jcDs=HoDCNFJfU43HXuQQ=t;@0-Or5k6JbR=4bYf8PBa(j_<(VCIF>-5FC9bFko zV%n~Yo3AmquU7bOL$H?7va%1EU zufP`|_rDf+qZH$6B9*iL;?YI^OkyGvlP{kOy{LYo3*>Iwi|Q1kV0oOmo{XABi(ci%8f7;M(N7o9Y?x~9!9beCFUA=DR(M9@9Vm7Mo z@!{O}k{|0`s}6a$gd@E6r1?AN>Q(E5wXTLgP0q0`HeFw{D%9>@Te05J=O^S=&OIAr z`gzCxsLGF~t84ANV)bQpDm?mL&0YOHV&mt{iQ?L>OZl!TmaMCqnt!K#8z}m}2L6;V zwGMwCwU>FLW4nUuQf-d%J3Fny%fSJ^uWsvk_m!uYHnWzW4BT5>IxXqxx$`T+MdX~G zXR&}B4=NKvZcpvM==5AG>F~Mpr(~OCw9ie9)tbAyBO~Yi#&9kDebYc@ykFYPYJcjY z&-1Kc?edNHk`Mn}?ffF9SMB}|{@fMwK26Em{K+utWz1ad<85>2i(0eHjy<`oIP`hp z{Y9T1y^i`_Gv!y5RYXBxpPF^}`;Cdu(~s(fb@BeQ=UZ58x~b-|-4)e@gXWgAc*19& z-hBJ?@yD#1E!tcgcU$MKzULOaYVN7y8M%=KakJx-?CWicX7cx+#41Z(S+9 zsp~gqZCf?JA*eUR&h0d)q|rXWb$;iQh{8Uf9lN45*>-{>^Xs}=JFnU)s!kmor&`g3$oJ~) z46m!JYkHGH)H(NJ!OEJyq0vj5kM=!%v8ecJi_Px6 zHD}}|Ec)>2fnv$J9}Bu&t5+?zS-Nd~O;4Ov`14hDtT+A`o<3jOBf`qQwsf7`s#o{z zqo=%Qy&4i~&$!fVT}{uuL!n)6>lms(X04TJU8f+jPHvS*Z_WQTu|Fl&X@vAnQFSU) zYfn8GzNfULX55I(F5TEdNYqMk_CBV zZTwG(y}I1zR3m|=6P%x~S^_d5=6Vsw zTx#m2XE!TEd?VR=d-_1oe`&YaQ{mU{X zYUL+GH;!<@UOPv-imhQ?>P*uLz82Yj-O(QacE9LpA;soXhG#Yzt6ze=QU32|?fbZATXZ6}%=!m%hx|&brOihjieALz>YmTjm;aqE&j zRcEIj41M+N@xJM&ju*HtytSib!;6@{h1TJkRxj=DyhvL5Bk{s70juye+V^+xKjn-l z(K&wM;VNxVN;2(~k9!iiBPz5@HXiK!T+WCRt>b!!Lc99rDahXu_udh8|7yZ+_n*gV zHP-*KS{l?JYIp2}aroy~?}UD97wg@BcH&G-ZqVIYaO9_LyyCXB*)_fB&7$I~Yq?|B zh;-|nQY=|#Hpz+ob$88UyD6czPc=*9pC-RqT3otLZ=FKSwMEVolFC$PpSzm&^=V=F z{Hgs5yO)}2$m&>4OfH|hT4ZjSyjbiSk>!?~oL|HQ#_ubXKP9l?g+t%n*468t-h8`X z>0a;=m6%*TS9fuboZL#+hkHIUr0!{buQ6*{^7e;X`hBsMf1@n-)$V(l`){?|j;One zc5=^FeyTKidFXrkkvG*PAImD5_{4ZmZ@gU~dhw&`xA1v;{@oE@mvP|J@6WexKk)p& zs+OrBvM;uM^*!0TUsikb%cOQsJJj!ejKi7dMSlJYu~k6=RMbpL{g_;>-Wvrm7z5xZKm7I^$~0@7#Z4E=wD46dU(lFPf9-+S}zTZePp4Zq3)bmmW0pY!7Z1uUgp@Zq;tloJB4 z-8Otw@JsvS^{MIYFHgPQyk$piKEv*B9~)%75_im<#iGMyS-zt0dh^x2%e1$jzx3$a zpZ+V(U!)J5n|{x^@BI7rkgq;g)6%x{Zr^On*nQ}kcgyF86J?IB)1JTXj-7Y+?Zqqx z$ENuoFWyi!dvC4flXJ2>+k>YomWNGw{F}#RU6ES+lA~|GbN|n^lHJag@Oi!y^O@h1 z9%p|yx?l1C^E&m*S?MMXB5k)<`W{G1wX}1-CUW=BBJa(Q*D{#xw?FzgMs=J0&k`H< z)iqyj_5a`g{^FVY%0B0se;d3OUr|ihxJe{lzcp(~_t#ZhEcWTY^Is0qS1&h1c*C(N zk2mIB^_PD>wcdV<$gc1$4hNE$E%)h(zEiMWa`a;qgZ2IRTL+!DNNd`qGkX84OeR`Y`IVqM)XKT-OSHASJ;%$>R@@9ImN51CgMF0r-T$F_R=&D&WsoDBLothZm5GL8sIc<^^w za)efnZ(sk^xA!;y*0nrhb@bL(RN)w}$$F0-nd^62x*oUXZc942lD7By+^Yg^ONpRV_B#-rjTDXS{v zs;55w+_dHX$D0B_{nrZbI$WQ0{NSJaf*<3T-~KP0TfguIw{b*>(b>G^6F%#oNc73o zJ?=X9=?eQT|GH%4PtVx-E;C2F^5p9@8SUS@&+Ysya6Nwig!e@;^H$$#j?Hn%dR}&GX|pSHP>nC| zu88|FzclZ92ULXE$)4AbHm<*Y=Vx@@lV$F4GVPO`zIRP~nQ*Z|lV^{8qJO->e%efD$n=BKwTzxn%o{{Byv&yRP^-yQV) z{O+1_e^yo>|NH6Djioa4_sjobblc6MBbEB#Z}(Pf{+}gt@|~yY?YaNu@bMon|DI>m z)Bm^ot@^g<;>X`b$SvV#66-yc*#3R8h&=z%721lQRSyLImyf>uHYkznbn_Rd1B((Z zdG;JX{`utnhy10dPIf1om#lx$o-37c!({i|MTgUyuP?n^xT=D$M_s=!)*~^Stx753 z;s(vK{fB@5c^bE1iH!XH_?7Q6@93Y+yS;PnH_iwXz56@tHE$H+c{C-qzmx;+&z>d`a^=e)T$nmpU`ctdD-^y)N_5Bi-6pUv!zl9lw4S z9V^45>)7tyKm3{F_Q{Wi=JQ_9JC>SRcDum(ufT>E9{URG1zv(GDdyjk7hhb>#k>8o zI%D@aNNQMf;u_DDOLrh4;&ot=vE{yH{ol3UUtbCF#otpGZv;L3^mNk#c_uO0S!vsY zO}^xOu)3?Ab^4-5u|?}UQCr~+FD{5U^X*v<4l99+CxQ}Z-8H-8SI?qjH8uav`w8zv z*Pi(Jaqo=mc`Xmiex)rAw3_z#caPh;A~n|=5mTx#C<8F@5nSzoHFCzL9 z+3p4ZP@elOBwEYlj^BS49V_#*dCOmHYfi14Am$sm&~VP70&8V~4KMD9+~tQ_T;SW+ z|E%ENE8%4~a}U4$;(Z{A;pefx$6m%=+~qr+i+8&*8)LU)$*#lIRmH{ANdlI;WGb%jT_kR47NKQw=bQzL4jZTl$=KID)$jPqN0tYa!(z337FHki0Li$9 zGr!*z{w1wTbUN2%P+{>)J;88B&Eq=fpdZR}|2;XnQR4919@hg&4zfIZmVc0O+FvA+ zC$M~j&54YElD>Ao4`?s@QE_&rN%igjVV09u|C5!s{9r%zJoCKLe}c2UYBtonAE}?4 z_uv1=!2}ko2%fB2cl|D2xi1Kb#64R2eg57HtB-cD=&+f(Zf1Vpc3aZ5kI6nN6BOl- z1vW@T>?_>g1dcyOud1J`oDRS3@jQ@J(965$b)4a>Jr;H|!~=(jxZ<>kYx`aXW_`82_~hHXu}VuGQNtWH_Nth;`JYrCf&>fn4_Rk6~b z^_{4)@P-?WnzJM-@)KHx!X}F!pMB}gw*58|{S8O`o=ATWpLR(8MUVdR7NouSMJ@s33n&0uv+5YUIPk%&wJZ-=C zvQ6X9)6IrEyC%%_{8;$((#_Mef7~gvsGXI0*Pq$f^4L^v=HQxtJbn*1MY%0)K6=h) z5SOWihsYBUap^Wh@V~gclcZ32CGjmE8-4EBtEch6`i0oEqT%N-~9Q~e!TV1 zJN7T@(A52R_>*1F(FxYp(~_<>eqSDE)w14i|Gd6#_D{YiUL7}7`Y-!2{9n!F_43vV z2^)(o_xU{%`_(%C&}%-i!as8B&fV)v>|9y;@^Qh-Y>gB{3r6mJe>g;5CEc9$ko9Lt zO@Bv;a>7Mc#%@`oX4d$1>h|)VKg;XQ?YsP0KFR*m%L=YwhGu~c3%(rKy;gGFiRF)* z6JNbOWVG;|yLyS_O?~ec0l}ke_kw5a?do`b=!(ev>9KyxXZ@|R`qSlcIVm&XK-T@2 zuS;kA4ftdAf6dQdhI)+L|4w}Tbl|sM`ua~Ve`L-0b@ENtA@k|!-=1H(+_PRWS$M;P zZgKW|?e*`@FMm8M@fG`F`+WyA&LkWZ*XP;uTq5V2*8IMyheRBXv*`R#n&0Qov**94 zYxlOHE?El5t=@L-V) zKkpuM>pS!Ok2@X;iIZWJTH4Gi{`7~`hN76-F#qL`x7<2;M{|B(bBks}A7@0t)w#^? zL(Rl&=eHZMUQlA>UUzEwV}9oMFH7cZv*1sBb-F^v;V_HNkBcJqe0#*-$IZ3hX25#E z*!f*SaNla?_xiatGyUBYU*&1;5fQw=%EgE_sWaUD zQTpTGHhbfUL!u1xOEx^vTmIVdUW_o)fn2MIg6-b3_4meBTCbk@=+SC1#w{-F+;U1j zj0Ll6H#GdaaaJ~Cj_TG`ucR3mSPp^K0yse?s_ldC>@T!)V1-T1&HtSDj-eMiHwT-g z65i18&nMBmd_g8ySy>VLuN3q01&PpEI*0koHi(N|(1A|Sfv4GCOrCz4QA!PYf~|Je zp}cnvo52%wZ=UddIi2^;VKH=u5NuOJ9e66x6Kn~S*aiLFJDE|O0#aaJz5t>C~?WvO#CV;0k72Uw|mE-pTwI6n7G`kZF5Jkkkj?;O5Tg zg3g|PIiL5=AsOswD6ybE7!;fk1#|B-8iIHoe2`@g;I$0~ZJKXdSxuZlGx|OUn2sfw zmoHF+`UZ>tM8>O7-yeto*#TZ;-~)4)QS041jjzDodh>*@ z=Xl;bhg9UyJWv4&&48&e1HlSV{4r1S%`?6b*c>o}$g`zI4ThCFWfmwwgEYYh6q+kw z%PNk6(v1?bKOmmDEE1>34p9XPj~yUW7ePJKlMV7mD0H^{09Xz@qmGig9)nYtDA;vn zMeN5wNrMUIh#Zh3ZonqQd(P&)gQs|Ke1HjqZ6MF&_<=$PxwKERoy*rQwHu239zBlc6?=<$pRvv)on136#?%mMf3k#6C8)s#2bbzgd5^un1 z!%PvBctB|*9^?}TWS`ua4oabGz<%{P!1V2C-n#>AU@M_SLi{q2+pWOvwBE`5JK4NE z0X1>_^GVd#NeBgpIFr~0`?6y8FqA0yZ463Zq2L5~^Q7zz_1!y}wJ#lntlt4I;`x>d zirUqJkR=@rwVP&JZ$L>MH>On7+yKgz`(%Z>FVdQ I&MBb@0Lg4DTmS$7 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_002.png b/example/output_data/polygon/polygon_002.png new file mode 100644 index 0000000000000000000000000000000000000000..3e707daf7f8be6870426e993e74fe2be526fbd4c GIT binary patch literal 12207 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 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_003.png b/example/output_data/polygon/polygon_003.png new file mode 100644 index 0000000000000000000000000000000000000000..de62fd7db7f950a590ce3bb68d746659b234f8a7 GIT binary patch literal 7968 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 RW?*1o@O1TaS?83{1OOp{16lw8 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_004.png b/example/output_data/polygon/polygon_004.png new file mode 100644 index 0000000000000000000000000000000000000000..a89a45245c164a2405e8669a75f94d1f5d21bf65 GIT binary patch literal 8940 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 AjQ{`u literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_005.png b/example/output_data/polygon/polygon_005.png new file mode 100644 index 0000000000000000000000000000000000000000..2b26dcc37d5758b2ea353a0b7dcde9ec3086804b GIT binary patch literal 7298 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 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_006.png b/example/output_data/polygon/polygon_006.png new file mode 100644 index 0000000000000000000000000000000000000000..2fbdcb7371c7b7afc1c91d82b79c0b44a1c2369f GIT binary patch literal 6019 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=HC?o-U3d6?5L+%`K8TxvlMDxcRv~epM+;+@IMfKmO;Cl_;emF#A`GwvzL^O^bFP zasN1B_O|#N!6NQOIS`NTHlT))Ru70sbD2R)reY|EC<_^w!<@Q_7pLrwns z*X2h9dj#f8(rs~?!J0_`MCP*z0-E>+Q^oJU-o5*+03*)4zNEtDo6lzCZnIz07jy+U&=_3g_=%G(k|& z^WITz1lb1GIsL0`S$g;{ddk?v5X44`|9|UANy{-j5uw0{QLUN^Y6P|`?&k|zvQn! z&u=aI$~wpS=C05Gc2&hk+ehh&Utje3_ky$ab=Q_nlhujKfAZzxMEi}CLl-_hwq(U~ z6DgbW4(YngD!=RZ4y9p&>dB$A%us35Dw$93`+m8f-yiQ7 z)x$G=(eq#OTNf;fTjd&K*nM;R#WlKX>&}EnztcU|dVbw*cem%?kGi?F)iOT+@c8SI zzllCSK41NG)b#luyUfq?S8rXJ%HEyXd*fu4+iB+a2daB`rZ0G2ve!07ras~NDYon9 zx7^s7WX9C}vbST+e5)tjA0L?7y0sO*G8CHQ*}WsFY;*qN$mpoQGpe`WiSFT+kM-~E zI`@9|)IOfyOy?5U-M&5J!@sLV&$mAPW0&=L{&ui!KYMPRta3R$`TddV9-ieFig)dk z)9bU}nVow1wViI+x(JrWqkG(3uI=TkEU>BY?VtEi`>O=!xfQN48#Q3I&Cl7nT|&HW z`zd#q=ije-fqiH2{B5RBMfKJ{52T9f=5PI3&z2p0nosPsL6Z7wZC(8e_j}1H5euJ} z*n<3aaNX424X>l##B8)+>V7IA7`a_0$Utt-vg0Q{NZPtJ8D|TI>s)(tJLB54F#BgW zb-#-}K6KjjWX6j>`=Vc**r5MF=GnfzJ)HL8rzc88nclL=CxB` z%Wk?kJ^%jH$*ryS-0vjE?Z@XGZ_#bN-tzhPmb3piM}n=|HnH}7%GNVK`1T$@VKB2+ zrQ&Ry`5BOpq?o#&O5e;+ku`c)@nP1y+J2tu9v1OMt}z>}V3vgE?%e(+KW4{@zzaWX ztuJ@1dH?45-z?o%8$Uj}`f1Vge?M#QJo|6C)>qd$V$Jar`^q*&iGB0in=Y?>c;4l& z9}5a=5_gAjThE=Ixv}`D7N^d&)D-)Pr6^_o3O*_?`24$SkzmyQ8|Od2iTacLr1PrL!QwxE?D9YVKLgGY*D_OXTSw|@ zR~)~$xp!jX`Il7{J1q7!#jX~e^Qa$`7QeEHy*Ax+_k>kSBgndIwqWaKh!q}9I|H-s zUQzzddpioIE}sAS_di$VZTmKTo}0Ax)5fCYtv-KZ?CN>8{H(77r;gX=o7T=CjRBRt6u)U<3WL`$<&=IanmnFcGDzK(myRH`AvdTFQ9uz(&V)J zZkxAl`DIv~w{!cN`j{OvC;Ho0>xlF|_;u)9x@Pv-{+ZJx=WqV|X5)ot`*qiV!ZPRd ziCyKJqRhVV?Ms&ghvmD1!W!q@VcCBJL6$`_b-$I2%ukWs^ay0x=RR=Et#XaoSP6@{ zr8zsdugQ z_3HPH&w_kbYaJtV|HrzkQFVL7ti#_l9Z0(Ec1<|4JtxPe!uNc(dz-CW6ZbWxbvLHM z$`GOLccR6NCjCfSn|UO7(=WsRz7JI&_vdG4pX^^ajn$6*x1sl*xX9TNWgBj^PfUHE zvh~de*;;?FWws#89J&qd$(!Qk?n61K$aCNAC^--*qSXE{sxxG(q2Zt z(>*O6s#Cee_~xtQHRg|A^Vj{CyFN+ITlaMJy1!e08G7%Ji(DOBw&BM7iK%Z>wpOIi zfAa0bhd;Bfp0BIj@gr_`nCG-&V^9*g&LZ~PWYe4zRw>ItNo3tVCHeb)uP^w=|4-En zbrdRO6^wXu^MsMo>Z9Ek;@$kp&s3Mjaj&ZH`|I~ftgv+1^Iyj=ExV+&PJyX=uk=jw zO;LL|?q2EMm)`#D)`e`r@DF|o2T#;YOtm=?wxvVcLV1J2O#Mw!dn5war{6M6?B3DD z&BSfj<0BoZ8`tyhW7(ef67{pQd~PVMd%)Gm`rK_rz<9G%@PbRU~goNm#p+n*;-Nf=xbFLSl>I94G*l9w@$qJ=xFE5kY3K{Bce7A z2?uT6UV*h`3Wk4BXk`5^wGw1ykk9hxJHalO7l`=KG4VMlU_>teemP@y^NFmFNk_j_$w>=u>(H*4bf9UzRHe?Qs67#e^Q*y5;NsA! zICkPMD4Z^B?a^u+V$8;^+YX%ST1b7;nImIr>x?}Qt2g(5z1{XO{jL)PDej}HX1 zi0yHz|6s8vs{Vt;2a!frhJZ8ecOHhGv%hffxfQ3y=a25KUo8EZzBwiw6shw2&mKPi zyUC56&VS~wF%VRCnsI7x{Y||+PW|?8#MDyQxtCo^7VrLfV{elur_PK^KlQ@)|IH0p zw!eOBHS1)d2!o}Er^eq7eIVKw-uHE-Khw9<>5$&k46phR7JowOKUf6#B^(U-)%&=8 z&cCD=W;bVU2>n|tyYEMBf)Eq;vP*d~^`~DlpJ<OTw=w-N{e%*6z&to^=ck1rDTx`3_uCM;j=byhs`_*SmIM5WH{j+Cv;qmYN z9lHP4KL5Sq*Qt&ZO`M!M6-%cbfAs27$BkQ?=RIHa>QcvvrcMr>imB6{LqwbB-CD8B zL}^n36BBpb!lh>G^m;qi>b|VZ4T+T!jQo(q#Jy_k9*C&vtC?o2^m;pVDij-8r$#O7 zUG1%$lzp=5S??-uWhL%7mjuVD(<&c>EQ@NIm+E?Tso+FbeT5ARoK9~7TQ)1`{HDcV zCnPa(&%3(m&5m6rMe#YZ`eN$a^QO-$h3IGnr-)Ts*J!WP>#dnre){?S?uxU9+y8S- z+q*+-mi+O${q?b*b4@-;MrPOg9CqT+`LS|Z?p}f3ntw87YveXR1N&z|gP`Icm(zCf z4R*)ebMIZA5pp{7NO^X8ez#i>_e0OJ4G#i!Z}+d>{-;{}weI}nBXes1O7!+lpMSOF z*YE4je)iY@7yYuVfBNg~CRgRMO%FJkxaBTxnlCggtapws{d|2ojb8xYni&%`}1_i*>%5 z^G?_(r~8QO8^{VTrtVUZ72(QC-B$%8bU;?@l@^R#({&)}X4DbU0wbkO5xk8@i?()X zKgd^B>JAl%&3Cf{{AY4kTHEBxVRs zJgUU0Gi{-345PiV(xwQR#-o2g5_1G69$mzt^X#h9x&|p_rS78w5oeaW#xQPma}n!S z*f7Jrdk0fovP+7gb>q=5APrH~tvdLCP!>CgUP+PCLlj=jHh`}paFCmvNYbt@fzT{v}5{FXZZ zDl>-dvio+%aq7%d-=Og+Hi1#6?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+eOvn2X0pPCPiLf0_^I^vrIaZfT1~Q)?z}j2k96lZ_LJ^gd}=4N zc-*_q&Yl&yNa3WIcc{V-LBZt=uTG2GGR*!ezm=WgiYl>MXy(ht9ks-VV?!pBPDUVSs#61Ruu@ByrZ7{^G#;@nUNZ#}HnT)rSS56-g+Y3$ z3x{s78p{n8Nu7+DMv4d2I5#XvRRx*i(J2tM+=pX>rBTEMt5m0kvw{hZue~&cnR0rB z6muGl6b~#rk#JB9B+$jcy=?)=32hpJhr&Q2Z9HN*twxFm(l|CGXoEGi2r1@tf-E?Z zaBvz(NfQJ2wk04w1HgT6BZdSTbhuh~-Q) zQgpb?60yM*TpP2#+JdGkYq@HSF z@D)lpIBjZx8cW6mA;p}zMv4x_DH{@APvK;orF@`it@c76jtdg1PB)lSof<$sk^?!# zwSl!dz-gwy0!6Qu4dSO-7|u>O*t8d9NE-w9w?!>RiVn(CI1>FqrYJPCRxk45xWK|F z_Qn$w+#nC#(-39~QEz6gUhKmWFqeV*8z_n#QoUL>xSwia2tAo_P)<{rDMa-^ldaZ5 zAC7>DLW*yu8Yw!M8bxdfKh?r;m19G~dXRrY7P)X#FZ1CDXyp-mGt)@XL6k}7#%56H zh-wHPx~D13w8oE(`<-FvEWK|YPia=;eiIoo;5C=0(~ws1rkJ!A_`PawJ@v}NH{og3dod3Aw`*9 zBgF%cQZ_uun8L{@rhcGlu_nkA163yrrBtT|*OLhc1vQ14bi5i^-9tdh)X}S@AmmgF zL-)jkO^bunSR#5DxcgRtqT6W-$HNmKQxuz7-Iw`rY~WxNlZga{8>@!kp^KWrOlSPq zxcfjJDr3^I*ah;Caj+806i&u8wPscgVWu-a4G^kR;01{5#>Ney8(2#~UOD5^DPR$- z#xkRoN339(4~GFaqgX*0$W?4!EeFa^wJ_vQKFG8$SdFD(HUsyMbs$&Gp2E>Me+nn# zJ*8&WKTCW#K8P`jeFz4*%3MQ`>GBj##yGWRRv(a_nGD=BK&Cx#^=dg#da8v%f8s%= zbs(8e2JRhT)3~Q_G~S-V$v97~nf1;xAC3%1C&_g7W;5~Fp$)FV0fy9fnPX*u^$x79~4xb9u$H^CLUyxTkga0L4Z;0 z!w!%p{vRE|a~_qK$j@Q;t|82H=j;5B=0!EG-y0*f`q?t>ySps;P{~+uxZb7n9rNdK zmzt}xJR2B63E|z3I+4V_cg>&uf0S{>Ecf9kxLkki$BYF+g8%iMP73VsoGI{N*?f1w zX&pagW7V|RTT3J;gTnSsLG{9mGG1*5Oj4a1R_~k6p+B|b$NG*R^E-Y>3;vHwbU9$A zAAW6>C8pesQ8D?qJ7|SY|tYZN+*Qi)o9ZPd&{4VaDwa3e2MDO)mET$s)gbH z8Sw<(q8Za!-GdKZY++FTJe5O#X@F6Sa-bT^kK;v**A4{n74ZCA#BQv#Rrr^)(lnWv+ZuJ>(r$-~Jbrl?6$w6)yD|Jwecv|&!`V$R0qtnDrpD_xHK=T>#TA(ZO$V8Jat!8ol#yHf_?vYa0} zK-v^@m%CJGwod|={RIxUH3j3eF6w&xvcD*s`{VtrX2x|vYAk#i(W-~MEq6_Nn4V+m z)AAQoy2_j@^KO~mmMT+se~)NDvyozf!R>Piy^()qZ+%rync3)k)4xHqP*1Y1mA^Ox zRDeDR_!g|RXGsc2ZlD?qUrM~>nvDxneu&;>|Gk6pbudV1KV#UDul&W1Vr$lef=DFqB%1rkg;3AU$N4miHCKd{T}r0rTu4h5wtoQ;QXybo-de#~8T*^99H|I+(> z58smU<&Zg0$h1atT2aH-r`>W1?cd^+_8finegh~!9(X5f-E8V{F?F-gf!0zDVJ7SE z^A(qL{3tJ(xdxQpy532fZJ5*lV&9D^yACr%oZ9H!lB{~Jc;h~&lLFH~Mc@rn)kB(= zyB71*x98v3Ad>2oaC{2K@+lVckAF~RiQK>f5m>Kz@hwALtANNfP%^ur%XrQ9ab@Iz z8m}3zIo?cTcr9qTW;(0)58=Dhr^i&vFc=%3{41%sW;$!}u0LNgvo2Ndd%-BDexNFh z>$zczWz6p%HB( z+UGurAN3x{F zFP<^Qq-_Z*xxZq`y2d^R?g#T^#ND~3zi3)>dRH1(qnLo=0j8))k7H(LpPk?FqqH)$ z?k<=7D9~Iq}tBk>G&)jdzE>|I+xuWPu%5+<`jO&$QZ_} zy6gPCc*PSBw}#XwN5&$}Vio6}J&X7b{@Mu{%s#!KDv=Nxvau#jU6 z%k^8&d^u|F8@WQc@O_1|Pg>99;CEL%kmblX`F>)y*PaQf+KEawGR+LDMJ-t(4W=!A zYn0e&z9~o5r=`7CIAN`F=dRmw%4^H~11Ak1-_PO`ewZlF5}{k%qPSXuHE4N%@$Ns7 zx@)I%D)0I^dGlFuknK718CI8C?&5zR{KF?T@;^&x_`i7XzHREe-Aj_^*b3+*D%s>r zXUOI*nxnpd`6}ha^?7W;m1_fIwzukp^|dk`6jD2M_#4NDZHrvKOa7L8`#$5r3Nc=m z;u#$Lw~KPiR$t5d-4*S-p+kJ;wM=kBSWRklE_d26ZVoVfPNsrG^^kDNbw zC0>-RI8i(GP={CY*+eCqEsLwBEI)f8XvUv)doO;{JSI6?=I{GUKYl3+2UV_FozkWk z*I#~YR@UCImnlknmR-#@il`1e^s=<#@cN5Sjdsm>{QSsyxIs&8Ar=y!K9q3{JC$+ z?tJ@SxXYjS|33Zitgnl-TjZTH<;8mGbrMVd?b`I>g<7rjZK0q!^I!k(-TtrPpR9Jz zcS+S0*oE-H6$Lr9tWLjCVt+N}s`#_LASn z!<%QwT%De;vGI`Q|Fm!BQaYl2Q(xF=tkVtAy3pj#xuH+3y;!2?=u^M1^G=;MpR&*Y zwe6GJML8;;rycJ4@L}JpQm?g6-VbHkZoOQ%)6M+3)zXW9wRP@KNM2a!%fCnO{g!3Z za(7(6bh7KitZzZ9?HJaEc_)7Q{qS}#=R4=!(mYQtnrXeM5a$d#c3$)B{=YKPe|CGT z3qLe{yE3enA?mH#39EwY2Qtl;azFl_Se&aXF=LO-zVzEae(HR&@$>Gf?w#hxr0cu; z{+WY^o_s&-Wt^w&F6=IrcXIxXdn$iB3~MNrl3(o&(ngIhYOb+&ySMZTiK^|+C1mc zi9MW_Qt{g!3Rn}bn`n|0Fac9MvL!Wq6&7$(U-?FvepE4tE zg~_7o|FzkVXMpkxTQt|?`{noNX*^!~qE24!UYS&G{nAMn*Q6e@kt&b+xA(@~Nt&Rf zUG_z-`REoQzxA85U+$beJ^g)9(yt>Ie(pS8du*DqV|`LO=R6^`L&YUbI(fw{4;gKC zG*x%1fA6eJx;_7V-jki}zhlxacb^vjoA+dcl8w9Sfk*pf)b_vktNN$sfA+A{lZeuv zZMx|jy>iSQ_Gq_vevs*9=sx~LAm#0;^%tLhx)JNO$6}&QyXhvmfTY`uk78AQTApXD z@@Khhb|omMf;H>yow%6guhw=xnLc^mXQT7E(@wstGBUG?UbpGEdvzI4*1BKN#6 zTle!R20v>*UwU0$t9^LWrBA%k=b3VA|L|*n{NeKBbglRn|AwQVy*M_NJwC|!Zu80w zZr83ovAA(Rtnaq)!`}^B{q=e$7S%H8#69OY-0QXe{?;S2xvQo{)ckCdxjkR!pZT`` zGV`V-7u8*Rxj1|N&zhaT56)_CUe39p!k=&Qee-k~#i`HVMJ2U;w>dBjwjUvvx*WR@$ah(mH+7b(P!~B%A zw6kksu1!zx()#53|I1wI6A7**>q}oZhV6Qx{Oir-7yp;O{~s3=th|118ZAzSbBl#wNTi!WRE(K$L%NG|5jR?O*+^W@h+zI<)Z!yoeC}Szd1#J=1dQN^jw_zpy=Dl2a_x<&qcPd zeG7E?b0>S-A{X(1-tu+Eshhqj96xXA)qg}nGw!sFYsinJDalqlKJoVEPCA%Wsk!Tk z%j?e`W%@@gy+al{o^wpJ)Qe*!^|(QBBZwN^tl?rbx^cg{XkN!<(#>*#j!+_C0ypH=jByfWR_bT)eK@zzFF(N zyd(JjzGt`JUBC4He#IT<)9Z6ze>wB^^NWu`f4}E{yk5E1tSr)obu5YV%l|P-~S7}x-MNP+{!8KNO*ZJ%58}H7& zueK!BEIO$*^jNVEdt~NI_B`h<*(36n%dYSE)gfzRxnot8l<#GwMcU0z*p6*H{jIdC z{*<9{{_mBSZd>d2&pX_G{^`Swee&8@Yu}s2%gw2}pQaO>9ktk(t-H+PP=Vvh_ox5N z*4r3lqb)vO}m+jLRJ^o>u%;oHu++PA76&(!S+nyA(JbZI$)9m=K9D8N* zb?*l(de=F5{#VJ(elw%P`M5iZO0HhcnDuS((t?(UIl6O`P8NlCt?SwPs<`U$i9_wD zS}Jc|Uvu+%={hq#&;6BOmM_cQax&rKGNC?$IlfV4pHqLf|9IJJx@p@am!CbnY3qX` z9&?>r>iw?KKkxeF$Vs~+*L>V|`Pci%F5a~DmyY~aEM6+R z{ba&LyUF+OPx-YkMCPzi(Vjgu&aXMAp1%?CP3!m<`4{gqez&$g<=AkeP3HN@_cn@a zKO3lO`O2OD_-$gVuGhwe6&CHRE)Ufi#coer%)QC)A;;nAIx~bc13%iH{8%z!YVyO+ z8v7KFw`~fy)KTEN%o35~%{Te}{7KiUSFB3iF5|C%|3cQx58*i~W+x40Vfgs?dNHy zT2{XIK5BU9t7uqy`|;5JPbP2QPD@t4|L=OvOOfpK#3GYPfoB#!uX}Df<4n@i-`{8N zHvRj1wqIEK^)1h5@reDNaM+Tk-eW6!Kww{czm87e|D{rL`$J?7hia}l$G3i^+|$fk zIl8XXC!XN#Sy~mH$ohR{SgqW(9ZxT27o_S%^>yB#{_*dnPmgoVs!Mh+v$un0{E;i{+N!>Tf9=kMhnu!ct-troJz$3WcK_4;8&@tUd1WdPlX+{iZ|8)+ znu(I_vrO0TFO~ndoPApUipaO8ERgizz4^F1 z4haX9)SFrE`s+LYuu#Ird`mv7pSD-4U&!#zYg=~Y>{IEYE0V>peg{3=sQz?AgT|c+ z?ztLleg9MbxlDiY_r<^Hy?!e*ySIznwV8h9Ktx#PR5g$@D^lc`n5=d3F8t^7qwBK$|00_`GH3TQ^({E^Q>LxmVwcU=+LfO_9JX2G z#a|!$?)UkNrSXCvFZO=@{OKFFS8aS)&6(Bv4jJ*tgvrIq*)e;S%ug27S1+8(Vc91X zd+S^Ho0|O-v-lTOudTl-cf{0E?fMC=zel%RGO$x`+qg@lNt;jk=#!Y0`E8%>y}y`y zI-6g;`RGTUnQPWt9Jn&ctNMdbuYAme#oY|S|Nmc!{cgT~a;3Cf*~{ZQHIIIot+FGD z{nLw2J&`NZIW|}9Oa6@{6uXKH9tN`{SMO z^_$ilJYKNlVz=Y9)HU0FWlv15V!XKLn}fwFk=-Y}Y@HielV{KWGcSw(K@Nx3r5FEw z>l?lmU-vWSFIwfc;Z^oT=YpfFKE3$F_RLGywSjed(VXTrT1)4Yn;0Fe&EHq&{wJ^M zZm0H|!lO+=GJ4uyc^JifPJXnV9IDm#R1=aLCnR4k*4n1*I^D`c{5to#ia@zoyMnM+ zl4?5->uQ>nRLvDR>szot#BKV2pO|p)(82kZ?=znz?A^HXcTj}Gl<7-%%%6H{b#K~b zmWTrXu3nkM8IOMVdOdT%oF^Uan92hc1zZ)Ui7N@|3JC zatd3e$fQ#d)~9zOOOHX~-xTkVyBp6HzFH{qn`6r-*Znt|Io9#1x9$w;6;3#)9b{70 zlGvrDwxj;&p5m)PIp!C^E!K-U~r<9*HbJ!P}#HN%PT_ z?IG{K{;)cf{WszFtK)lbBtN-WZMP-ne`WUNx1a7`$qg#m|JZWZ{rL~$<+k2B?_9lO z<`cg4S{I)->|fM)^8LzZ&E@-&cINnYzT0|kV=rsM{za$trl`s*#Kx!>UtM$gNNHus z&&}_>Bf_)Xr*I_l9p*E=F5~b@KYYf6dHTOpmu6Jo?5VkUUaOVW#a!*^mrW_E=MIL% zW$LV12dZkzE*9y8EA77BCUo)oul~7Ow(lQ)_2b?1ef1x{B^Q6M(TRBbxAuwI;r9nM z_f7xxZYsyt*scFL667p*CW$rKR%k+J)}E{v&z+ zyu9SbcYV6?UpD9eDSq@TjW5x5nc@toe^2s4pS91w`s41BRj)Eld~e5kU!2PJNveOk zf8cA5L({xUww^NR-go}-_iag%KVIa%ir@N@;a1ozAw`{qF5h*(hOY@Y__Orm0qxZv zCh-4`D!6UAtN-FrwcF1(G-Rl1E<0WKfrU{_C-a85-pCF4PF}HW$+UNFud8$NOe&v@qzT)RW%#SaX-Avh#pli7+|5&_XvXRo+ ztqY&aZ@W_YV)n94JU@HiK7C=Q)tSfxkN;g-v*oEpx~`n%u7aB1k@pr?>-OGrp1C^metx9Z+N9!DGAo{Hr&%!N{`joB z@z$E#>ofkxG)!M+_f*d~W`6DdtV+l$>>8_Q#ck*+um>B^SS5o z)OOucxvH?k-_OMV{olSRDK4AAk|kW<%W!Ycp%4F_Ze?e&k31=xb*gZl@~5z{jH6$L zPF3-5T_GgOzx8}#?`rj@`~LTQ?wllh*8OnGh6USX^z|NpxYGOFkfo_wVMkVU*YjzC z4aa6Qv##|hHxp>xUZ~x7p(> z^Y6Yobo_(*o(J=CKVE+P<$U71=i95;w2!X?S&`plbw{S7yT z>$20!U+SE=u+Q&#&xx(Kbqv;>%(*maZN1*h*CO#R|306dbnr~{tNYV=Q`Z&E*&GtD z=)E+P+gws-h1&5i5C1f;^f}>P6Thd(UpRT$rilEMX1nBtuJ3|#k{BG_teENP1hCO|BGUhe$>+@Ibv6-M_1!$(Y&k3PvDWv!I-(}N4Xm3_eXQf$(DdqH=#d=NLy5+z^Uj(I#ys68 z&)&BwQf6sY0bRQFbdG7qF;@PuuBRge6#RPm4C0TD+FpBNbIlj!RVZB7z z3(Iq=D_xgdd@7`$zPYG`^GM{WX3H?%b!}(+yz7~?Zftp#?V53`EXvMzeZ5H>yQaCp zIriwj&$B$fU)ytPj9y>D8U>Am$8 z^Mx&L(RN3#E?9Ljboc&8-(EenJa==_mqXu*bta^G-jBare@@5P9(OSZT3*quH6y=ZtgT-%eWe^ik2Q*N%B7 zK9&_s{aweAr0f&G{%ZL}leK=Qm*0ruEVvU?Gyn4DXD4T--~HyQ`C)!;|NZ$T_16EV zh~57yTd_dJa?iKNMJaJV|6Vs)`%=)os9QaBBcR-QQg!TZdPdzUAtolaVM@u~TI zpDy*&1(x%o98A9dO^F{dZ>ad6@(=`Fu2<(Dg&k$M@{>lNW2#rEVWN zXWy$g-Fo}(ub+S0|NF@lyDQ?cR_o_KjQK0)xn16p8fE8tTJ?a)^GlZsrrf;#VpquT zue&d&X$tpEciC|#uj<|2T~%M6ys$lgy-xktTmJQXQ$JrG6`q$DYVxP zO*$BQNqmz2ujxGU_NxCpPtQ%7qB`rxPt*A8c}1`6U+LA%Q3`tLr}tO8{(R8W>c?z5 zd^;z|o~Zp_`SiJJm^S0G9k$`89{y6!EcyBV=c=Oj+s^;k^>6WIcNfoTfed1b2a*mK zg;?|P7OzoJ&D-M zGQ%nC)hr?Yv-b19y-sot{&(!>(fywtUjFJ=`@8QIagTi|*^k zF!?BIe_f;aPjmep%ddaE%j+(@-(i2Yq~cG>)90C2xc4+1=h%=D(Rb9VK{I9PDzC+- z``6V^ee{&!+2g1QrItT!dw<1?U-#`zf594epqxoZYI5>5p#-kTm8w&B$TG)I)iX2N z^(%VM*CWg^v42W97U?ywS;@Ngl&ihmjSJj+8h-0sc3>{Lzdw@6r_fqE^w7T?&im6s zE3SmkxxeP(+|RE6&ojH&YzaB+om}ZI_4PZ``fRWJ+}=F`2Bwn0w2 z3qQAScF!#NIq_$>svMu+y;&vp%Zo1ZUs@5K)nY50V7Pc?$_veNj+c9d5`IZfEczZ_ zyi{w)w|lmc`KLb~__D)fSIoZuFT&^4$Nu|xB#77Yod45z7FinNe-(PG8pYoTQldZ*^?PPA$t4g=^FjldbD(_LQzSw_QuOI7RG#OHhGo0 zXMq}{*y+>yx>Jsb@i<;P9D2lLSB%`A^FPY`ul%b!e!kdt{jL^g-lvP?mjvp6Xfo9h zG@2a!xk8C=L;CFv!QuPF73`|$ zGY6B>zQxU+bo{S-4S!S6nca`Q7oRT9``&f`;p@k5PPy89EWRhB-yx82u<+@NZ>{&W zN>dNA&&mF~`pb{M_K#%r|Mh)locOc1J>6;N3wBUKw-8fxvREV%`@k?Vx4Ovb=V8@D z)}Pl0mHfVX(lsskj;_9)R{WQc32wD#gC0LkToz`LW@i*pV4|7F5-u3a@cF?dsh79R zmgQMgl>A-2@niFzoj%okGuONVyQJ=A&vl>W?M>P&5d|jm3sW^)G+$nnw%aiG;O^Vr z<@tr-eR?O(D4xjj0=wnBV8z$#>&vP%`aBv~-6t)!Px^4J*K1C>kLEMZ4bNuOhbB#X zkY%9bGRt|w)ji-uTd($^>*ZzVxpr=^_aCfgi6{`UR8!mPugPswF)Q(Q{o~($pXTO% zWr@5!aoIYZ=l^b>zwCPdcPP^}r2|dM9v>45N?#h^>$kb|;*<90^jw*q(knE7!OG(%W3y zY>rJ)vFhe~e}3+`&3I1vyS{ndw-dj=JwJE;zFmX<_rL2aUU1gV$(wVF`=0uNroGbB z>@?QrDeNtNJ|q9{YN5}pwZfNqs*ekO_AT*WoVzc%=D+#$tcs8>z15+4 zcb0X&IeTxZ#r2(+nYYWweGs~Se@~s{iF&5h53OdjGjM;?I?n9Q6BnE&Gb^KY&!W(m=8Z(yyS^7yFd+u(aMU(9oxe){d~e_g+4&f7UX zOG5ftVr<;;LqU7u-!*^Z*pQGPbjRZ98RKU&Uf5m#v-%*Dw<*uPd8>~l2c3Z`@DI9U z$$QRPdfttMF6*iLuYBLkmsV#PH)r*++MVyG>wR~OW{KFK?mw69`8=WbAU~b;|E-npt*WAaz{VmBN$>99fgP)%Lz1(wKDnI?%QmM8DQ^c19ylc+`GZivM!I=4j>e-v=&6@y|~#mk93MKEGh!i=E2f_ZG?DQEq09o}PSA z=(@G=-QfGvBi)K>f9Kzc&HT_Na;o-&6{A>AWY^3-iJC75PYG|AJ!AWS)sfo=Lt8FA z;Mbh;JHd`g=fWmv(eEcOb1%L4B=kCd>g&flpKGVZsIO7o`F`r}1)zm}lSE>30^iDP)qLl!o>}tq zUT(bMy=UvQ&3|def0;eiX(#_J^#e_7Jpxzm34OG)^Ii72{a*d|bG9zleLl@;C;vA0 z2G(f9*O>+LKE7dICjS0=j}Sk5xS(kK?(ir3!rwLP3MU*CJ5wh$C;aYgQ0&j2Q9pIw z?w`Tlrcb)}X@bIFK1;-fT{RcOKfdUCmszq?$7s^>B`a*w-v)6#wXTjKKbwJlD`{Qo!@<`cKsc8cjW_3VM{X<93-YxM;?LNJvy>G4_3F6g^tN9zG@tv_)D8W%X$Yk4+151UjtAor} zJ!k)8LA!S|DD)drIW{a{)zq5H_FVGmvGbRjx9=|ezI^`g9VOpIC;oT&b5@vtzSBP z?KSxSD*MX*Xr;6DN}qP{L^wIHUQsyE6jhY-q~qX5A$#>*%e&{>C(bGG`slRs!>qKh z3|2m`PJt|si#NR9o|mvQ`sXsI=*aQz&+CtsOYh#@>F(8XR<4UvriFn!%i^e8^XiU# zdCBGdfdRpfR+ij3&3G+?=dpr!0jtRq`z(G2zU413Kd^ap%PH9Z-2ST7Cb!rF<(C&r z$MXlww2auWOh(!&=|kkxzrHr2@|?>W%1$O6j4CRbe5?3w;-2+AddptEmj5dF+`@AY z%bN}c?rRg0nn8t<+#bFMJEm|XW@?%hNX;oZPfGYz4IAm+8MZ~ zO-Od1d@DR)QT1MivO`|)47Q6%+wq>W{q7eW{OIY5qHUiAn69WFXxf?k%f#Y)4CjVt z5uUXj=ao|aHJlYrI5?-wd}Zyat^Gab&8sEN*#l;$N+sx7@(IMa&QYFUb8-KRv%8tM zcr>sUpC~-w`F7_w28LNnT{zx*UDQ>pTJaz&&8y|Wxf2Not%GD9m{@4<__IoV2b0-3 ztB4PMip8N?{mJ}xP6@1U+8DUwOl1rswEC0t|Fyh~J@AZk!vj%EzM>-v4C@U}%E~1Q zecQF>6<^LA9NHZ^;Mk|s;{7a^@q?PGlf-W>^}@V~Mv5B@y;=-T zh}*smP-8K3YhV?87RzX$t?JaVLFF)L&9}5tGppsU%J8M{40brr6u2SaE?AVKIfadJ z##|xA<7HiXJG7=AKbQ=1Q-IQw9cOmm0{KjtB|;{6-wVbBH?I~M|1Q1irB}B2o@zP3 zb|RtBW`1JO?`a?(DjaweQFMQLS29Dw_bD8feIj1X)eC(%O#Ilo9|uU?;ZJp1P{^dy zr}({gr3D)UpL6Ggzo4-`U5#D(r&=5ivqZePA71iY>de&R2lsq(<-Z`H>hw+bYwbFa zVt2Og+TwKwYlGETq*R-a)>&SE@XvCVK*kh??pm+f`PzMq4Tpo2Qs$?u?{l6hkTHQr z?Dyo~`$A-xUk9qONPSs5H(O=@%ImD5*MqJ31@;_!1uu6SvL@e?36@8$t1K zjAO%%{_`)&wlDLHSX5Nq1L~v%XO@VZ_^!NnQ|G?k__SLNWXLxEOo4`D zClWU1YVKn2&YZxJ>a;-8C?aR}8`0!GH5Mtw14+9f;nBe9)sk~vbJwMWl{S307Wr_P zIIwl+78#|l1G!G&KvFfhT4HFBp2Bfc?xyy;Ks6Sv$p@37gFwN#p!QUYLn@QbwxgSP z7;+kf6mL&Fv}loy-%NoO9&FujC+vMBd8)<1l}TrtqWh8i2H&|Fd;^qHq^DF@wBDCq zAS9`CYr1phgzFl@OjG}?{>JcNnTX*2Lr2OO%v?JsY>Nz;Qm!e?B&s2JY26jjjNc8r zRHp?@jACy$=`e%#8F=j8cj%7xvxPn!Ykb(c&3KE~C-9wWIdF<4VvG7$a7>|Tiq|vTFjRHAHvQ1V<}Hph1tL0l#9mL{yGZm@%K;~rh&9>}Uq#FiQhfc3 zYpEkBzH}Vey1y>D#oWMos^tI^OT?PvceEM!oH{3zE-84T@HR+|B~7jQs8z~(&}Iw+ zV@9#l-XKdE8N!yhocJ`Sc!F+#8cUi=^U+OUpEkH_2s0TAC2Z6wUe92mpz1Vj>6=5- ze$=w2DK#H0DmoFjQTJ5K0iS=N)eLWLq@Q48DDd!VIrI9{cF%^Rpe+~10ZJ)$!3%eN zmV2Ng-3IQ8nIff~Y0{z3^KXMqzP!-7DsmOaNNHiI@S zd|;8(nFopbHNGeOhPTu6bO_`@!4)8MRe%;L5HHDeNIX29g22QaIIa7obFYD-V^#`i4sGUgo7z_^6 z4WJ~(!YF1RIg63u-XfP1<(fJ=T<3$-SoBULe4P76)W(0Nzz&52k95GUVgTiub2643 z>x0!;+*l&!+;ltuvR7u7km6jKXK{=Nd{Q>N(BMDxJEgI49*>yX_QNqUz8qgzA|hrn zGNdhYsVD)NUmT>y;>5;%Q+vjABSitGHObJVS?1CC;e?DO$LRpImcx?|TCD=dM8f(h zoDV;+M7XEE6J^kG>-?}{ia|o;zhe(Bq-^NZXn!NB<2zG;&$pq}1sviL6NDaKT(V(< z#v0d|0({ZG@%9wX#OeR+J$4&cZ?$*)z`(%3;OXk;vd$@?2>>6`i^Ko` literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_008.png b/example/output_data/polygon/polygon_008.png new file mode 100644 index 0000000000000000000000000000000000000000..17105a1fc4462550ba0d680f2f8c1a5561130fcb GIT binary patch literal 10448 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 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_009.png b/example/output_data/polygon/polygon_009.png new file mode 100644 index 0000000000000000000000000000000000000000..b5423620f820935294d613f05cd8e9f5f0764739 GIT binary patch literal 3888 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=DjaJY5_^D(1Ys<6R_sT+rcSi!-{oyyVA z{Wc|B4g1sLKkkfs_INkXzsCIS7jN^Qe))9!?bDZ-`VQ@T^trOh_4)DCueY~O-#+u_ z*Nc}KYTo#N7yV=7zoBE#-u)ZWbaWn6{40sCY&v?r_=GHj!ZT4t{!hQ&Ff#1>39^N; z(e?S$=Ibrl=imH&k;!mx`?ufMWz!X&h$>FZPyG7n+wt|+^^N1>(ys-#GyljsdwuSg zUr+15Up-?{@9LT$ST%Fz|C;abuh0DZ>+9PG(*+|B6tDfct2^%b>%3ou@txXEOx@?V zyQeUo-}-F#j;dEGcUlfSGW^z|^T6_2hqjzw!bgj07qJf!*+)eE6*p9@u~p)(=rMiN zwOla5=APU{)|z!7j!=ZnaS*2u#1W3LIWISnb<4F5Z9d0@k1^FQVizKm*IDp19{v1Q zF!I3pNab}FB8^84-v~w?_@Cap<52;N*zt|-DUAQmNEIGc@z@4H9gjY+h#lYRp2Aqa#Vw|gi>W*Lw(_Qi_18MI{hSjD zYpPwu?%b6sJi3xY=Uig{iKg9A%Ihp-8;@4L5sWM_&psl$TxEmBbXz6vcS*fF9&KR} zd%oE{<>1w|g5h&!9e6b7TZhh$Ri=-+E(=G@xh^-6HGH#MOd%&zckylIO%JrLb!h83 zCluCIyNJyJS+bNvXC26r%~8thcE~gyEd^O(mVHEYy2^$f(`=Qv&w(u2#3FVbWXZ*~ zg5fc<4m_ImtwYBGWXWmah!~J1?jTFJnYyzvqUC9<6;N82KS1`-tdvl?^*UK9Ni9-SKD}i`aLNCF#-1>votn9<_Zd82KR* zWR`zIVSKfV*p+J?+7gXN@4gj`42V=-_dvRlwc17O&l=N5T>F$aB)Fv?5LoKnZT2@`fGTO&@V-RlA7Q zC~w%Y-t-YyR<(;*&w)qlu61bt(5ZG2+pfN0$9&UATz0qRCLUeOsq-$icSn=^P328H zbQ_P>t`Q9XkO5MqvSCNN=_9Ursr@G&m9dCj-|iN3aPwQi$U9vJ9^Jaup>5G+tJHm4 zAR^|vR3WSTX7`jrP=rJ&uY0iKTZfLGe?p;c_7PE;yK)ncF6Go&2eM@I4dqQcbQ+JA zt`Q6`FspVE1I2oq=_9UlS^Xy-6|smt2U&9StzcwK*MUcOu61bd09kTcAYu;4l5mhE zpri$|WYxD09Y6nsLc8oEqA?&#R&wf`16i{BhVmv0-NvJpAWO`vUBp1?7vz(7AWKSE z#Eye30mbT^t^<#5T85sZ{+JMgITT8H+6t?ns>98BHMBb3)QoZsl4^09=e`*<{nv(-K2V+d3C z@hIhW4aaXNZ>o@LJo+OI1eeraAe!Eile05MkD<5urf7-QrIV;`+$N&8m|Lv9V@iU9q#Qj`44a|ZOHAd}s z7#Wg4$^P9TNu388`)sNi@(yS_Dap$em1l@p$o%d)ufBn!wnRHJ?7+nv;Wc`VtPBF+ y@>*>J149xMH-o|`V>A#(Q^II2AUhX)i{GZai|<#=1w94^1_n=8KbLh*2~7aJLk)!h literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_010.png b/example/output_data/polygon/polygon_010.png new file mode 100644 index 0000000000000000000000000000000000000000..a1d1984e644b61ec15c62cdc51d607c886269ffc GIT binary patch literal 8950 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 literal 0 HcmV?d00001 diff --git a/example/output_data/polygon/polygon_011.png b/example/output_data/polygon/polygon_011.png new file mode 100644 index 0000000000000000000000000000000000000000..3b689b46646e52e2a5b217ca84ce9fea5712f53c GIT binary patch literal 14867 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

      asb7-Zx6V0Ow9!OEw);#(Y<2zKqWho! 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_001.png b/example/output_data/primary/primary_001.png new file mode 100644 index 0000000000000000000000000000000000000000..e84069fc8345938b6eefc62fd4f2726eb357eaaa GIT binary patch literal 2842 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=CXnJY5_^D(1Yszqko4t!k%&O0S%jkv=#xxhI){VZzTfatsU) z?sMocG|V`_#L&Sx$`}oV(UdTn3r2GRj$BY1&d*Treuu^U^?r;Wxb-6r99#G3)l0qv z-9}ah0pSP+217K)fn)E&3?nWxyvgRPpUcP)6t{taA&H5bK|yVlF&YS?DPc4hjOGG- bxj;R(hjaa1Td7M73=9mOu6{1-oD!M?l3Sga29w(7BevL9RXp+soH$f z3=CZNJzX3_D(1YsW6jrWAmHFA{Pe+2%gjqcv(oEkP0UzuGwW;0NuA`LQieMRpMPhF zx%2uBBLl-cw**FpBP?PJ4nCud(LfkY38T4SG#B8=1#fDT@D06mSl3gP!gMe@Z1A`$N!{uLWZrNMO9YVjme*R(ao^X`qPHXMa7{3h+ w3`tDf3<_$ajL|?CO$np9U^Ext%LVb*Yk0Pv5{z|ZU|?YIboFyt=akR{03*C1ng9R* literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_003.png b/example/output_data/primary/primary_003.png new file mode 100644 index 0000000000000000000000000000000000000000..66dc11ef06610bee672ed5763647f57687e6aa18 GIT binary patch literal 2877 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=CZFJzX3_D(1YsW5{*bK!Cwf^T)%VJ3lj7vrO}tF*7J{UCcR;;+{f21_q<`SD6_Y zYy68><)^s-GYI`RBC=!~P8inas*W!|(57T%)>yfgy>B zn?XShjdA0~-C&-1nGD}d+jpO1V9=BvO~j))c@UIhvXA#xu`o2G&rI$q{wl!0;QvTm zk-@`bF)!_gD literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_004.png b/example/output_data/primary/primary_004.png new file mode 100644 index 0000000000000000000000000000000000000000..7d134e28ceff9f8290d88812351a863e45d97e72 GIT binary patch literal 5182 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_005.png b/example/output_data/primary/primary_005.png new file mode 100644 index 0000000000000000000000000000000000000000..9715acbcde488a0a86f9d0541b17c81cd5a24453 GIT binary patch literal 3211 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=BNBo-U3d6?5L+b?kfOA>a^L{iM5a^RAiw*EYK+IQ&v_ez8~f?(B%E`{ouM+n0NL zKQBYWnflf23=BU^nYbAg)HX0MB#kmg17QGD!tqy(4D0?@e|rBrd^y997W0S$3FjZZ zy854SjVi9xDe>l&7Ta|bhT^xg^XD=$1l>zuWH`bi#^B&XETivjj4czxf&7hcBpDQ* zbqJ7{70TAgF+AA%d+N&HlQbFbJ>?ZMxU;zSOW76X&73+38&*#ciaZd5En7*vd1b{G zZVGa^e__MNbGz?vR}E&^;|+4Qj35*7o_KTPUsyi_!-wcMN-PW=mLP&thoND{0VakH zVi>Zk*%>O{?)hCCZNz$Dw@x)%TlF{ftpBe>80HtaaPX9U{qy{$zzndv(8IMkwpR0n zwo`&$BP-8$jU`7!4Q5w^B5GhF;nwETm578BzWc@7mF&-iA{ZD98(A3ygwYs0Wu>Cc z*-{NVzn$HFj)6flALMXs5rs2794}iZ$H?$td&D;$27zK14oo}nidcv7Gkm!9_tcfz zlOhc7Ke2I3yt`;uW&Nu0CX1NCjZlwH9Z@Ku$Z8*4YpU4+cMT6-FnA)mEf*x_rIBN@vp8<)4g10w!UHQ8@ zn4#v7G$_l)e))EVxfo~GVcWf{>!2y`ftcUVqSF}~rkH~qjxB{@Mjb?CW3qKPIK%2x zvyq=+>r!9sOW|rLuWV-J`JN%aSN7|H942mwH(E!f9F#HkQ4N7h#r8#gb160h%S--ElKh1~ngWlP9k+9=i zPVB3HS2Y>z9`cGA+_?l3Sga29w(7BevL9RXp+soH$f z3=G`io-U3d6?5L+ar8PIAmMgVBk#=IotyR6@);Y}O2$0$ui{I2B>hFXu|V@m?(J>M zPn*80;<>RQ_x#)R18tn&lMb<+Prk->{_xYP%Gx{zh9xXw3=TdCj0{Ic8KZ$Pni58H z!DuePl?(R$t7a(wWb@vhm&7hzL zW^_wO{{8j*cN6dG^A*eEH7eycSI8BpHo88!+Wqm=^k)~-Zx*~;WA-!7=f(!B)xP`0 zh0WHSdtmdQz5Bux@yji;W^dHqY)CXuZ0Ef*KObx$+~iRPayXBM#%O3ja@=T27)=S_ cl(7Hm)~;HO2kXlj7#J8lUHx3vIVCg!0M#^No&W#< literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_007.png b/example/output_data/primary/primary_007.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2b31b258989b5cd0e4956ce8e73b1841667d3e GIT binary patch literal 9544 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_010.png b/example/output_data/primary/primary_010.png new file mode 100644 index 0000000000000000000000000000000000000000..305bade56cf76b69dd7b0bcb7a1b036052a248ab GIT binary patch literal 6278 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_011.png b/example/output_data/primary/primary_011.png new file mode 100644 index 0000000000000000000000000000000000000000..625ef724d1db13bca949b56a07f56ab1694af887 GIT binary patch literal 4652 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 DO-nY@ literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_012.png b/example/output_data/primary/primary_012.png new file mode 100644 index 0000000000000000000000000000000000000000..8bd486442b31f546d404186e1fc38c24f45268f7 GIT binary patch literal 2953 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 j%H!X&LS_G?|NIv%-L=2gTe~DWM4fDrCw2 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_014.png b/example/output_data/primary/primary_014.png new file mode 100644 index 0000000000000000000000000000000000000000..7c281b7ce401d66126a41a3fd1fd62910ac276b2 GIT binary patch literal 13061 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+jhrNXeOAsx)tj<2uAk64cjBDA@jZ5>E)Ro77vZyc*V5ITuL{oO z-5~hzrC#U%58d&9_yat4ZH@Ui>C4sn#{UoYI`0yFu>S-9L-GHt&eOj1#viaxuNMqz zuF3bP=Uy}ORs5^({}0yd*E?U5|9_Cpdza{+#+Y5AJM`B4YrX%!UD12emnr|Be&?5; zRL6a1UE}``yI<`6&AsHMWvfU0&v_I6aokT^Ucdj(qC;xlyPo=J{1yDe7!%dH`{nmAc??Ho?k=Z>87 z^cK8h*D*-(ob<0i?#i1(mtWue+xg)vzXtE=Oqb1{Z5PaJoxbV9W47$j8!4XWT4qIl zV9z(1yOMM0c=p}b!VizdH(ZfjE_C*o@%ou9zMIZg^IluE;pC;7 zIh>}GAMjt8<$hz0#V?(NMn&&QZqIC1M7H>b?>w(|DEr{ffX@X+7jy7ZZ<)j-HmPK)oNJbfy^&jcJ5Onk*c@(CyXC^Y=Zx1) zY>nM~Y8%A5A9FZOH$C7#Ar*dOFUKu)uys|>Y*qxeI)`nmg;@8v$m!w=o7+->7CMvP zTnAg%dwOPoGS@$cH6L4?x#$0723faK{amw@uSJdT?RtoHa?3?}j~TC>*b=6*SO-1%(Wx!re-*)YcLZv-ov+9|a?zh;w!hBxj zSCx{9yti^Tgthuk`}Npo#k`hf`9YV&7j_r0t_7#GOY`QiU+uo&yQArv`l0NFtJT9M z7Z(NU+pK=&_(G3)3&f*e56=v+<+yuijmgFfu{)aPft{P_eXcnx_JvW5qd&;GZ-v)& zTI^j>IxldmPD$*9EM5*+8lLlKLF>tE(>5?r4fr zKa`!=A@0;%)D*bdW_DJf#It$#@*y78OLy9;QBwc;Qo|vGhg@zP5eX+IEeW^aUuBxO zqJUM|r{(&g0{sbW4@4GUt5CZ-$>7P}>K}P zN;L6C0qbJlmg|Qu=+Ciwtg<+)LhNdj!5`bIJrJF;=UTEHCBCIC>uY&OD z_R?(zt~;70f?PXGJcPG+*2SAP%~ruPUd7pzfn8f-m+mxI)2A>vc=4f-hg@l#AlI6h zKX;s~>Lb1`VOr;hs2QJH!<6S_l!%?5cTQm0-sk5ogA>u*<1+)&IWFJ5bEUx`cSn;X zIMJRxS{dNZ9o()x0~DXj>=~>YgM0g)&AdFZ>3djOE;u^-p8Kp&Ze5vQWEEi$6MIG$ z1~IWStCjYM*+^LRP44Y`6nR;&>H7s~vxwD))Vz-us$CImGPi!KFR^Z4 z;(=XZ5}Q(8~^3jVNc z`Cpd9SNVA&zKgW!c>XPtyAs#*@D-V-4!PyJ##CgJ{4H9Y>8Kih-wSQh4U?oVn6F& zQ_?-=bKE;^meRbn^^ltP{9?5$>P_aZd-WyOnWY`L<&}71Qi&hOu?AZFi z@#^n66<_qu_uUiRlm7MyTXuG<@3ec*eO8pSpAYJeBG0WTZJHJ)Y`%>K; z_OELac34diei+!q9(}&})5Xm;+Es2Ji>#Vwyl|f2p2%0}2MbD>n6FLb za-O#2tp)!p^@9baLh6T%S@`$VJ^QkFeudi?j}LLhO44hLMa&|9%`{#p$9d1BG~OU) z?wN+tX&^_|o@?HvF0oGPflI}<2hxt;Eg4_Rop0MGyl1(|A-2~!t-jOV6{}q-Z!-7) zt1GciD(OI$W8#TPUu>Q`-sNgreau2|o5~Nii}&X=m7F$Sn0>I?y*Xz?RM3r-m-**f zc8TrjeAS<@BWnudYEzKcYR@%Cu^tXRJclD%wC3>(es#sQHr!0_1!XrJ%nD7MywrXU zC+oT9U%C?OtP&1nMS?79|Gc2-;VNOj7F&*e3!j*%oImiU>3dV(jfAfYHk_Pf{P0ba z`PG@MheOkOBKB(VL|!^GhyA%IPq=K6(i`6oy=KPhizf%EaRL>r%EU-IRaMe=%&^*@r4aP-Uv-;QnjA^?5jqygp*EJhX z&YEcaFs8};=1i8uR~2|7_G*4aNmlQuEh;ywP<1RpZTs z-W3~8&T2G%c%#Yu?nKtZS0C_1EY{+Q3_3rD{kSMkxNw1zOzekV8zc24g+FigX;%2o zYvH~2f@}7giI&2BniZdA0}Wz)k2IJzADW>0^+;ub&A|dwN%ccBS?)hjF7lGH0m+n+a!^Y&a=3(fDCRlljAmEQhZy;fdI+$rBlLdJg+>L7s5oVx>8uAA0SD)Rz|i zi0V_U=$$)<_u3keMHa$+iWSCkjs`I&8%(zznxMM%Nacq5g9WMwIs+cCCW`oZ|NU(G zCi+9vs{hH&sX%O?0n|WFtDBNbwVgD`46aK4Pc;P;-IE|`jN3Q6{ z@3v!IKl9f#-f8=^ayC^x^SQD7!P%Ye2Md<&=85DREK5d?b<=4a4SMeXrUJ#emy!5$9u9$nKilTOxawWeS@`{PIbhe07sz+M)RJf3G4wJiEIn zVaKI3o`_#Di6<`k$+52NbDs7&p}Ogz*X$ytD`idME5u4|UH_I;zWO5l`j@F>z=vB) z&)!VPv~Kkc>u#ID$u6{~bGwSfx-Hzy)3$|5Y+B+zhyAu7Px!4~;f3D>_Y`bha@#ZO zK<9?r*OLqmW=|CH<&iH#JVdc%+qd#NNl=d{`}xykSWhyR%~O{Us7Fk=vM#vw{}g}SxOJGdFN{9 zZ2I=ZXGi~ov-SK33zp_dY`C)T(1fM?Eco;ECDvULRd@QTT+w*9Ir!SQ8o%wLHSbqj zn?<~GPn^7!J^fHFtMh?rO%J_djS^Psw<>z)7R%l7Gl*Fk?bq@u_`{*ys_JXs{)ov_ z{vj8BJ!iv}<%=5CUSFTP-|C6aj@}D}5*aUS*bh(Lm3|;-f0wZHwZ+o@%N4!nzb=!@ z0ZX(!a9Q!MRaozY{oY)wI~{Yj*kCEL*H2rAGB_I=yljAA=Bn4qvGp}{$K81lc);+{`mptb4!VJCMN1mz1kIw_3qb$ zuY1;C+v%#eOklJg}b1mmN+gj6E4o_W{eBhD|m-Do3Pi=l|PS|m2 z${Y^U`43qCOZvszf3~dB`4M+{OU?$9`G?eAOP*`#XLUZTe6V2YO34i-%MVRhdftNn zo;XkVta-uZuG?_3>d4Fw)dxR(n47R;k{(Y)P~wS8 z*>l+ci}8eC5>wW7>ywWHH#HFo= zCM-QZhy6cCoA%4TdXD`y$sXoS=6%_IN%cQs{)pA|dwkdVp#T5$d+s*-jo$SlW|7zD zaMp9TaT>&U-jCF)kNtP@Tm4V@y8kBM!?~QN?JJTqiSfKHwy#C&LHV+%cYmW> z9)53C`BTUIm;JuStnd$QOn%7^iUn%)Jx)LU_=|nr)A#Y;{@Oo@OW3R$D`FP;z(?X4 zpXkAYrIosOa#y{J6|eudorC-Ev=E6+Y3848BzVGSoj-JX;j3G}|1Z4wpl8L;mYw+~ z#{Mar>)t26GhV+_XZmsZXZzFl{J(!tD`(r4j`;F_w;T=2C!4XZzD-t|#0LzLB%C{%DNvH67!`8OjFjJL?=SNQlkK zSoO}*J|R|{C%Wq5;`s&q|6XpNp`CIzp{>$jj>I~ts{gC_xqaJLWk2_CInQyf76WnU zH}PY;KK7cd?ESR2W#hRSw>HJdsn7jC&oCe2(7&R|rjd)!v?TTz2=Rp9y4U0j>IC$Q zwCTQGE}@;$o6u5eAhB-CTvq3+v*&Q!7n~!wb*{lN-olp5wcp<>_7qMlS@-nQi$C85 zrPq{;m_^_6GjyAL^|z12FFw_S1xvr{-U!J()9`iWp$$vVizc_MnfKKOK z`?8sJ_9|hC4SfL;+rI2s^nSwC#d6ONChWLW%iXqWvZdfWO$+5$`z}1^-Ew^8+U@Ht zzf_uSSr2mFbr$J0#-e7?yVk$heDYPU8c%KOl!P6Z)}+p-pH6tDD}Yocb+uhyS@m8!;5+cGs_ z$E=G@zM;o?B5XBzqK&nGaYfp`NR;DgTRl@pVins%7mKC`Jr%a2bxz4-I|eTmIW?YU;JohO=W7PrS&+X@)Ve@{j zk+bbwz?|DDb4`WYiVyi3#KGu!DZlv1%GQ| zHviEd#SbTf49iVC7_ju6rQoXkgOY{Z4{szCJV`0P@|>$}wLjP}-a~BOwc0t`wgt%C zPLVYgZc9GoXArYD`QS2e4KLH0_*(dAMe##HkYRh14hAgMv=GdyIVky2^x=#H1xHG@ ze}B%=wmKbbnC}rb@5kCX+u{OcE~mV;6>h6__BV*J-INf#6jT9EKeXX%&!Yc33(kWw z{l3i!D<I9O1cyVJ(%zi0f71kZ%crT!c9CvUy(Bk_&X z{$K&CS?DEUo`_3p4{a!2`yyZOPO=4!Gta&Q&5u4bLBmC4Me^HTQcoW#``^?G-TUlECKpoYcXNbro-dX}-RD|hyqwP}Yo_)2gkw}A|M zslcX_seklF;_8fiy*o*AJjtyf!%9Fd%Sc=!X_zDIv2DgTyT1~NJy63g-$?Lu*FKiD ztt)rd8vpb|A0jolYTH4EtyE;wdFgXhB5}1vz22V`IiA`!kYQIe)SXtkE<7)3SR)o< zH}l86zk3(1hZ?r*W`d`#)~}pxUFT=5DNjH2AKUYarKRQy_!@xo?LL4nOLYhWu`3bl{DNVmJ>Jg&%D1|*VpkzN9*;UtG^_Y zvth|Z(Oi@0*VjM3d0tzl#&f=PX@TF4s0}M8sihv6lomKgdfT=0`=36qPLty~4)&^w zx>IJ=!yA%@HsTfYX8x=DWqQ7Doj*7?d5W7wTzb=$JbUfe&wsyste?es`0)jiZ@l5$ zW}%bb86|lBT5O?~vv&UT$^E}Gqm&^{O8z=p+Q>Zm(z4tHwd)<3~aQU{R_hy3UEw_)6o45Y^cRRk`TDWb! zqShXKjD{NjP7)I=c#p1zIy#O zO2|~UmsQq}s#2(t-*)J|!q>T`F}lcjW{ zmmDhp_N#e?Dk%GSK9BzKZ+~zof8F`|8~@I`OH{INHY zvirSRQ1vCVU(2L#TR+^A4;J3Xw)}&s#M*kZ#E(DvuSWjgXS`^Mu*3$H-28`o?SJe4 zx$70XJ$8H7{Qqwby^c@6F{wmA-O2NIgkJyqf8tjUf1iB+t4+oG`rY5F=l`5@u47VJ zLbK}2TJHCzq1z9AXVk2buedg|Ak^l1%H62?`Ddps>6P4|vNtVpcEDDy@3)t`e}1s` z(cTHAzkl;aPcnPpqVY2Q^wYxE_5qeQ^S-v-RIwt}ok_ z{_J3Q{oB>?hp#mmFESC7*2y&Cer^`J{ZRHnHUEFRuKF84TxGHCvhC&14*J*UXB6x0QMXX`lHG7{Qq;x^ z;lZWaHDV#3p1qIWYbCs{YuoHK(XD5vU14ONRJT%GtJLvgC#(dv$swSA`|+-uC=V<%cjsw-ZsKZMrX6{8}zen|AuK#^?LC ziMKU#yDJM`_lq8z!Tp}|T*sxpoDEC-b$jlH+~vB>)}QmGFl_$0meomX)Lw@rZdQGJ zqCs_Ua^kvxtz5UaTj`!{-rlv*`PwRj98c+Dr782a#>lzP|NoBjw@+I1x#sHHGX~#c zD*OxFrrb+uR<+$^kRDvB{YKbe)5qh{xu(MFx-4gbgW!uA^R$xeg8`+wZ?50lV#9w= z>lqI?1oj^23}6C9)xOI&oxD+GC6MCNG_jVK8v(4MNoUfI09iCS5&}GF(P^Rma)!WRo;@!60x=>=nm3CI=t8#}vu08GX`N7&l6SlS<+5m3!#Ddy}`SK6vc)mVS`C-j@ z$vNEL1?C7|<(1aintE{AD~^YA7$!8^-+#4YW+^HX zYioEH_FhjaJ17~rd-K6dW@0(3qC{@(Sor+O`TbVeYB8c_k-8c=+qPIUPrJ80VMSJC zhH}ioJ75#9PCB#!)S!K33N|r!;oJh&=l;dlqkcv?MX#T@kLz5=uMXa6b=wkxuTH*j zt=D?X$I> zm>m|i;NQ2%Am!^CgPfP#>W3mhjm7;NTgncLZZSU^oBcJLJ9q!GD&GRPIa7GAoe;}e ztd7d)PEeccO#tT`F3uGwqbBsTPINLX>{v(x;CTyxm_LnJnp#3$acnkoD+4&>$eae}{i!!O*w zQnvQ`dfP9xX(ekO^i&8)uhG@L5%RKj;d|-S7oT6peKiwa$2D8WcKwE%RvnD5gF*c? zy)Uxs4pe^dX;t)Iugw!}U8Gb4j`Pc6PX8Zr{hE7Y-PeD%Er#bNofDlSXr9pgbq(um ztz7+{LT8@Z`oF8=(m{E9>3LDJXla84+f4~8F4Y~9068)`NMh5Lxra7n;8;+XoGRmeco$LzEf|B9@{su)o}m%s~O;E39{}=oW1rR)3v6B zUT?XRK?(6qWa5dS>aK-{!sLY?g0f98|DhibxsJ`fu&(!?ZJXt}Rlme`%@MqvyFn~x z)t4pl<^QZ4XFP5bJ@)Tk*y3|7s~0t@tzP(j{jHFan>kxWH;D0sR$W}o{qdmqO9S^E zOwSKa6j5(m({^wFE9Z;8H>~O*Zmv4*fBgG`TJk|IFd~-|ZezwI!9`jHCLjOAz z8$YrHJN}s9Gp_K&zW2qZzkGIRNzLG1YA$-#H2OH}8dm42$Aq7Oa=pc-Llc(%6ZLIb zTdRHuRMIWKJIBJX<>w*MGsZJxXTPoHW1pL=?j)-rW2KyTKSB3KNM=pqxdPE=zv{v_ zpJ@TjEkD-e%iXq(GlIKKYwnYa{yVJyevy906aK))V)CPg38jaAhc`JNy7n6qIG246 z?Rm)cZ1$;jXMgQ&-+6w|Ga<9tg7Mj)z%f~G@V!^<%+K2OX|p-QTZRpbu)!CcYx4Gq*Z6zhNXSe(D1A`*;Pa<~>4)Bnnnen+>73P) zSXcMRW<|MZn~v}K&VbLHZL8BQ8vmYo{$k^UYTwJ74ql3B691FVGJk%$g|J=Njg-tN zHl4G|66@wYwOO%Nq)o^7WM@DzN89Rfi(1?B&tF*{{JvmWQuES}tom=(bJ+Q>FHo!T zOPsuPrNjo4Z3#Q7rhZ=VEl6UM2`^|!Ut-<8hfls*&EI^T<^F7`dA!q(iSX@c_`mCO z`0*z5J>@)x!g3Y!xM%C|o^M$Cv8DOYRqOioh3A?lTRpT9Z`0vD3!Yu@)!RR#pRDG`OdXUP2!z)OmI&?z0!|8wMiW_Kd`j=PHRg!a7m)+;j7?t%~sxtCoUDt z;kdfLz-fn6fzq3*M_Df0&nGHBxBSsOsV%X2={{Ed6VV)Y_0a`te|!=rFHMx#aAkc# z(vGSx!nN(9ZJ!@Jk+M49s_5-ppcFE{>Fm{MyXJ0_dQ!Zz_d#_`?B;_(^-bdUbXn&g z*R>SRTfE_9&~=`OSKbCOxo0Z_)@t!YzM3Yy@RuM@cy+<0Tl3Dp+}8BIw)8lgcP&R; z!gqlhyYCNtcC0<5=6%;NVP);Xg014u9ltIzNLi`v*OC=&5cBq=X12ZE_TL{S4*S*BhbAn2W+}MJ_FzFNi~5?sKV{x) zSF8=#oU`G|G|&{*!ROyO&b9p3%Gq>9hk4p9L7s5;Lb)p%T+Y*GJ#krK#&Y=T#5wEw z9v9d4JTP_f-FWcQ&nEF>%B=IBD_aW7fjkxrno=`}kv&@(0Gee6O{tv|<_S+P*km>D z{LhU|*Tv?ZWAlE_5yx;|pl09s2R;>R4yk!BH%@q2aj>9N?78FFMFuG^LqM~B1~GF_ zu6$)<_x(9XTyY7Pw2rKL#X{@g50&yyJ146{lS8(U3t$Bx;w7A zJYi|EXqygrj*_Eo^|TUe-@hf5uRhFv^=+$!&j+ccu{RSks}FLAdpE6j_MXFeJK#o2 zW;mNpuC~OwsLO9{G~R+L4s*YjTYd&HTUWdW&5#OM)%&uE>?zAEHjB9B_JQf@q6e=p zDy1LVCSn$OYYwCLeD1c@VWsx`cB?AaG;CRTXu?uoOTkyh2MewmEniXg^VSy43g63W zIUBz0d(gTf_2BiTspnd9wQ@FX;bfk6Pnais?dv+ZDSkl`n?Mu8d-WvNRXt$2Y8StF z8|(Vgs@c5L;)M4+_@eOR*Ovn`H{^oWlB6BD^ttKbD)Dp8m&~}Fr`>zxvf??*;ZXlM z^L{xk10xcUoP_flK$B9g=e_o(NxVgnC4Rr4h48nv8%|#OZv#(>3Wre*9%q7wIplgY*I@E;*89UPYenfbk)Rb0T>IuJ7pcj3Cr&n1WWL7J z^e`*rTyu~-m-DrhIUMfdJmJd4UQ*N7zn#%^{fXy|gkGH=ZgPWI24*XHMU&KUfU|C zAKEEm7RhXo@Kr-%UD{I{jk604QcBNtZZJPsU~0S^d2Ne-Q~s8jtnuGL>swZCIQeP{ z<7)AP1*X=|9W(t}6<0fhR?xI*TMC{uHrV}O?*e7Bh_&4N7Cy0Aaeofy^ROE!rAHdB zZc5m3DgRvaqyrPK3aTFpV?8|eUxC!6Q=1h&$X#TVUL(eO-{O~Y1>cu;b@emDPQIunsC)X{m?X)!&Cn~Q&|!{k29A0p0!j;^VO~g(k}Jf^Vt8Mof&YQ zYxWv8$qi8gJmH{)uuIZK+SVMi5S*tgv94r(@Pv0Cb6!{FyzM)}3Q2Rkp+ zo@@E#mpJ(<2lKVariWhrmi%5-?ujR|8iXH8Ha+yRFJ`*rZ=+nLQnB80BJZ_}P3&>@ z-1GSVo|zfYFJcy{Zj>OaDY5R0%yUQ2Xbql7^+F{ZFN2tum45bB)6!kfbKGm@OKUD| zd2sOB=ceZ_=Zn>@7<0{D(=55+n;1`cRqy8oOKe5j)-YQNz5^L!r7pksl=0$lmiNBw z8xG#`{=o3M^x)@3*DZx#iMIM)W8{gb=4jL2d%QB>k|3A!wR3Ygwu6kBAKZWM>CKDQ zP2bndy^)ZsSrPDc--DeOf6w9k+IL7TTb*sqT9(68?H=1`yyR(B%x3p%iRNh2u07Z3 zKK~QXOW}jnH`{VH*ooRq_!aZv&x_)7Ex%k6CvR0`zNX&v(Cc=A+>|R#hbC+lR6kVC zdU)!#$6FS!t(dl@^?~g>XS0a+9C9|f>J@!kWYe8;7j8KDYXalz(1Qg_b1nJ3vH}xN z{Av(>2%3byU3}@{HJjjDK_BjYXOmu&&dNVyo4Aett$D@^w}sqD*?X|zYfr+COLlYE zRlhDUNZEU$^Mm@qf~9{go@VIJ(|xO0;a@X}_nPv-<|Thw&QJaJ*k^^Uh*_k+QNmqe zp72}KKQCA!C)&0~-9oTVU1Hr9dv%$&XN{NHvc8|neOey&C`s@ilaI7^ot zQtOUn4l{^(DRZuQQd)qI{HABKIhr4OJuh5!G18{m%6Z1OdDh|0qRVO*UTt`=^K#`J z&eFD|TWZtt;aKOtmWhf!Bhr zoU!Vplyw5@;i#!FnFqXn59ZxA8?L`+~gm&En(=(|Mj-Rd_1j%Pl|1<-E_~Rm=yQRp6Db zhAERx-41ZIX>UDQ88E3Xj7NOaulXQfy)EiOtg0<<7Hz9kG+FRqXUOh3oL3hm%}`r? zALOg7*`F7v>|H0Jl=9V5knQl)ThCb*U#oPxy6M8#z5DjFX_x$M$rd{JdF3}t;Z>=w z*L}m{8MP(WU15Lj==m$=V(y7o=}J6p+FuX9blv-5%_{bVyLm3SH;eA7PBPv2z%tZ+ z4(HY8MZ48j{{`9gs{8W-mE83&v{JU(g6#VB_{pMs6=_!|UvM?c*nW^J)~4~2_`%Ps z{#gjGQg;>i4Vw+NOZ~Z{=dJjQH7Bz2!FHWqiC7jL)+{=!cF_`f*7IwBJ@r{3CwkT_ z@-54ngdIWm=di23tZ<#IxVpE~Kw{k$dv&p|=Zx3PYhAYK$WPv|j8~i!?+MxLe>LBD zVO5yP)s(r?8=4+^B^Ss|S@K!*Y|EO@;7GQZ6K2A7ev_Mk-+77WCJ_(6godyiHIOu7|3M`}~wTu{(IE)2SuVRKo^(?Ydc<~k@!j|tnHm+CiO z=oU2RQi`lF*s3DADNDYIwzseO3rZW8cFYMf(K^4)O@!~X%5SrXg9S?qSdxDpsDXk^u!C z({o49OWumF|G7x;gkL(9>GJFB_ogo)Zol>&ta@bbb(v!y|B|W33%`U+{#p+5&dXV! z7pS}p`)H6-3yz^(PgRs^pH@5lQm&aj_ut=_;vT`=`{b8IpKG}!e{{R=wf7*0T`Hf$ zuIg#8`Hw5|zd)Vjx+T_goR+-*d2hl$v486~{A!Q?V-(|AzQ(@B<5$+s$|+x>8~z{q a&#s{4VEgvRGHnJ11_n=8KbLh*2~7Yt$u_$H literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_015.png b/example/output_data/primary/primary_015.png new file mode 100644 index 0000000000000000000000000000000000000000..e3bf7266f4b39101cc6659f8aa5b7cc21555cb39 GIT binary patch literal 4778 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

      HOG`l9q` zMWCZa%WBX{Q%|ddiXj^X&Zveew$*=|n`d)sS9E9S`c+fI^c(Y-uO(c`xuMAC`<2VV zFD&Tq78dVheVO;38})ZQB_D+g(dpf^LN!>UxcU@Un);^v}k!9 zyo~vSr`AEm5KYAy{;Qm1Drdp61R=udYqdzIJ}S>DAR6_AkB9 z(R4J~hEwdIe^G4Lc9ZLg@xJ?(R#o2JBF8?*{q&83J*W1cx^>Vh`b4tvvDw^*?s8r) zVc51rP{wJhaFeM=XoqU&;)w~ZcH16g-<0sO(Ak)7GihJc9jUu(%67{^FyYx4LX`E z?EzC;5@dr!A895T3azISQtY=O) z;-&Ieo-2_1e1Dc@$fb0_b8p+%^Igwx+ZDY!%CpCP7E5CJAydr^mi7S8)&$=m(In%? zS~?RJo?k0b9lmePKj9ZArj{+B* z&sQ}toy+m|$wKd~Ctli5*!)ZVrNyNFT#5T%Ij=8RAOQA5sb^@%dEVQPqn-9g8-7y@ zep>*x_DpclTiP}8|Qv%b+(7hS4&%1@#2z@&gnZ3c5F}TGdyyn z_x|Qv9}k_ZlKb#$*Yi*fzI~hjO)@>=T1Rd$ z$G_Np+;(G>_$Pjww)3h#mi*niZ$UtP=4XC$wv~2g(}FH#sz$7xEqU;J)K#x*3YP?5 zO??t%?S7;F?F^~587YcegxjaYO)S~>Jk%@d@7Ip&f|Y9ySDaUm@$(auaY_|z`sx|l zv6=nYh582ZEivIAou{+UbCMT%)gwR4cfypvfgQcI9)dbOIbP=MyqcZ44k_!+?5?(J zRZf0($~)YP{dnx6=-IyudQ{?rYFGYT@^SGLXTz|Aw(H#lbhAUVS&k{&C(9kHwRvdN zq-N1_N{gj>!YYAm{yB*}|MuqZDKK4mn%Q4bEokq~_7okb{oS{2-WOR{AUq-ILXz&$ zLbZcjr5PN_n*VoNHa2}+(vv+Sy7Qk{?VQhImkwBURSK`;ma8zC!GH0Vw}6|lo}xyR z^NOgJ1oR?@)m8!%RX}6X8 zrzRY|v9`ETXua*1*7unmW|Ds%MQnN0Z@9eZ*!-{jn!<8gda}!!ZEi_6LFZj( z^p_oCZ4apAI#{&RW^Vu}8&|Bl~}UV8ChU&e-JgSHsOA29;5uP45`dgFd$LZCo> z$py(*-Ot@#ZJs2@9r>v6g~;qn9}mp;uJz({D&djf3|o`0a5XkcyP;tJYMn(a$$sp|K4xwdKF7V%_pDmi0`-ReGczg*r|W&2RkxRO z+Hp3~=c`iXHauAsF(-dz-P=DL$0PS^WRxoYn9y2ZCa3>l&&n4XLdhG=r5+2$+8zFL zh4VVof^w0jTF=mq{p{Zi^weZElU(!Xe({QHf7;8vu=j*ujeO1j{d?D+?Nf1^`gBh( z@8(TuVQKfLUj6;>nC|kgj2tRcroI$Depio^wJ~Us$Idky4?fO1cB${6RYmA}h9{!) zL^;KLkF0$j>>}FzHtAz**6B$pg+8`l9#&p?d?t6cKi;{^-hOQF3z`@qDITV~KGNQ+HaujJiOtN(>0h~~ z*3FxeP%HAd;>O$1jVnI>(wL@d^7+`L1y?P4p6N6h2Ck@mCi*Xy``t>*Bp zdJF43V{0MZ%+PH1lHh$9?ErFTx8So!%L*;Z(!2e z`=uAJ-MFqcX^sE+`!iWiA6j|s|F5G`l{fM-4;6b_iAUKijp3-7B)U>|Uie`Z$Aa_j zD$+@H=PvZ@?taY7y-oN8W7BVy(53c*`=(g6-VRlZ5X5lqqEZvV&=W6f$_w@YI;taEcTFDlVg+EU}=baZVJ2_5a@AJJo zwwv6Xnz5H9`Te6G4$W^_zBN9G^9+3%++x2pOmNR??xjixH+`7>_2sI~VdX8R?Y9=M z3ZHhg*0srW_sc8$)~%1u{r+qEE{{o~{Vc1moVm4qPWB}g?u8Q-E^u!N%|5$B%EVHy zq2$e68TpM1pX9RIk3~d0Tobus zYbRU3xm2>*L8YaBy7!|vudVqT_W#p!l`Gr7r9M6O*;VTQG~Tm&o_({okhcG$Ge#!Q}?<42+a~Z7@bpHaO3Kse7E&dR znDnu{xF#UUx=}*lj`>Qhzuh0!UeWE^UB&pOR&UxPW$6n>Wv$k6Id0*LW^8ZM{+#o5 z?cW&VzEsBNc8gW=%nojP5$gQ*wN&})+@@bLJ8tD}eSP!k@9VoxZmOGA7;R(nc>0}m z`;aR}`@-hm?F?JLYU}LB&EhHw57?Wk)kBx|3;vsW%e8R+*8jQ9aSLJ_(vRn7?%O1! z`Zl;IOLxQ8`PpL0-bEjUzRmUBu;$OYZ`GV(`F-GNxjM9rZz>za$?fuZ$Nd-+qKE&fxP#-V6z8>pxpR zIz*JO`1|Xt;G{{kcT)_pSY>@BYk5<=rgh z@iyIKOH}Au9+~_6w>e)pevtDFeVN@de`(vqKk4Gz;%(eHuerxM=l9+)U#Z)&(`$-b z{=fR{JvU!XO`Z76PUFH^<%6^CdMx1-(@ZXD-O}YcciW_&#=*UhHmgRn1+izwbo4zgG z&q9JN&Vzp|HWbb^H?I5VmB(b?w6y&N z3$u97!iRyYvr->cP zY~R$sWWRgU(b-*Fvx;S3FWzu_mT=hbwfjtWv;1=T8@h4j#*3GnxSutB_*JF6q~cEh zgV_QbY*+KmGBi>#)YY45agYBt=O31Xzg0t*-WRl+Ugh@NV0S|24la9fZr;a>6aHMC zs=>K#PSw=yQsQSHWkq(JF7#Y*Kc^}5_oZ{K**x(__h$(po6j8FWGj^u z^ET2v<(kk-R^#WIYwygine*oAfvR+mq#38TuA18UxOT(b1HaWmm%bOQn?B3!w?N$1 zU5h5i)ZSL8=euR0xW@KM-0%Na&HReCsAxakA;h~`Eh6N`_e*Yr_gm$~tMo^IYwW}0Z=9YS{eGKo?}1Nw5klN7^UwM$TDirx*y-VnwXH#qr>Aao z{jt5md$pG!=d{$kt2uoolg})_C$aZu;nvrN>8IvLSAKT8lXH2MMX>tGpdU}>as)W5 z=erbqe>P>}V@nRXh6kRjykwP3G`@nYikMe(Q|u7;mgklMCzu`g-^iM*-Llj9t+Mpm z>sua235h<7{GHV+J24^i>)M+tKg6$py1(^jlH}sl&FR~(FE@2N%Xgl&ckSxC&(!W% z8++QFW>zRvT)%RR< z?{I1rM}D~7bhVC6;fFe7&Sk0dcmM3I3=HbCe3;Vlz;jhrl}kq8t39Wt-()>D*?8Lz z4q=^d?4pHNiZ1_nJn_KQID7Eza~@{=8O< zJ-6wSbo=wkX7^Ih?9b)4?`zz;wI}lN`@L>epC)I`(Cti&yZ&2C_;}2W7d{_ULUnzW zzG!TXdwTj!#l1PZzqNGln8JNfvi(+~L0&fF6}_HmEsXj#;i?g{Hk#a;F7dJ`cX{K| zE>|}D>d*X%@9sTiVSK=P>G=0I%vMLZ71cZ=XZ~>c`QYSR&n;B}WeOFOR?X8BoHeCt z{U_Dvq|jSO!e*ai>XWy!potrkzwYwh_t9!@49(c#PQQJju>nYTl7`= zVx2XIl%S30Rgc*mv0i7xe;MyCaQPti`nILZ@7LRTq|F2#X$NwAZoj2k7R9}(tmgHh zI^UcXpEh5sh|9IPzV`al>eJ_g(zA=MzrMbC_191#;jd~de_FKhsh4y}z80OhpyKnL zr|stZ#sB#1I<@|;%=JYdnGQ}4`RY)x|AdA6<43@BHbH7ci%H_pkj}t`Z>=+<$a#?W)X6o8<$KKDwT5D7QC^`L)R`?z`1R1?w}l z6J^YM<&_KG?3paQ&HB;>;lOWRNo;qSE!{Q%wmAUc$qnOQmwKtxM+Nxz*{#eyx zgFuqmVr}#FEO{nn`GS{!WmaDA6pjCxzFJskPtEmTMZJol|8y^|x^~a`|Ge0sUp)%` ze04{IW+WKu`wA_}UH{Qs%kbvJ4=%rw9oJS(?M>F%CVYakNqu9~S=oax_gwwD_28oO z`xAexj%SaW_h$C7`PZ0CHeIcbJ$?Al?yLRv+pG>U{n)-EdeYHp@uu>ew>~rVKK`EL z^``IF^;_PRLL#3-CMHb%<+;;Pe@;*0`E73MoLlUw`e$2qYFe(lmM*(Z_ylXyZ`ClH zZ*N@sp4eyamexPGQ()Cr=?u-MZ4YK2=oLGA@AWO#>$@DT|0?V$Q;WD;sdQxZ$M^Tn zuai2{lesZ_>G@v0X@?58qMl~wlf9?a{rlGVr_D3VQJ=uf^4)ih zQTSS~-x)8ugYtS==fAl6U-{zHk2+H|ddsdzF8+S2V}9%It&f6VAMbwN$I^X#TgHXY zy;>XB{>=%yJkfVsxA6MtV<{Wf&8mKBHLavrwOK!E?c!^@V^8ws$^7oKd3wVyL7!vZ zku3H9l6SBES$9(O&)uBX_qzmZv;%eLS8*Q5s5$>ily67I@3%f1R&+F*X0Ca8oTsCUvW>`esufwf78!i)bBfR$M)RpRa2z>juf-B-0-bSXA*oH&EoHMz`gG+%e96F zo@BAme`z{|K4K*L!BDuwI>^& zC7({0I#Tjw*Vg_ey-THj-;MjRjD`1c%<(B_qMJ;oD##sw<^+y9^w?D7OZt_4 zCcm~F(<(hbAtCg6BU5;6lvVGS?iERev#-@$*s}6iz{iNW$q8#ECQVqr<*trElJLaP zx;LNR|J{+NF2LOMTRm)f$XbDK^S1B0_48|#`p&9@*}v}_%INN}*r0gz9rH8cHP<4Z zo-bF8P;H->rW{kMxZ?QUuf;E4U$eVpHtk1Qeej0Dc!3-56Z@uKkv}aF^&#Tcjm(mJ zGc7he+c|l<@Qyt72i#5S8&5qs{w5->&_y6e?fU%=rh{ok4_DpXGE=zhmWSE2i-(l% zy4VV>3H!~%d9740a+SO8*^P(OP0mfd-g7Q$_m#^Re=S=a_|SDmG`GrBgQikXvEw#b z$?3nt_WFJJ_%CL=@CU|&dxf>18CD-&`=#}`lXHB@lat#_Z1$DP?G66_!@O;ql2H_g zikW-vmOW`gYwkrXovXun?dyN3E5EjFk?L*sn!EJQ(z4mxqSA$4u8(ysDxIrrysQ76 zbW^EknB}~y>MQ?-{`>N1ns%jRac@_r%x%syjd~xp%~joKwK6O8m@0Gl+g`VToHI=< z+=)t!(pw~N%51%;*I|5h^|c5Nd*QjUoY$rv|N37lK(%h`{HeRL-g+jbKD>G9rMvY( z{kod%>U--ZWrdtye(|qb=3~y5A1o@)O`8w-`>(U%|Mt;Wp@o&jKWXYk@fMlqYrU$a z^v?YMo!-Qft<^X?<8$}wPhX|%4(u~b_20lyr>=TSWz+Ip|NN$pGMy`uHpY6|)Nc_! zQ~mOX?Z0c)bGN?h_2;_3_dxQw7e=qYa~bpt3$5K-BW$sr@!(%!?Po^S%4@%+m)X3Z zv8nCSH;$>Sl^ZVB9QXJ!!{wCcCc}#G^#X6Y1-?%`VjA33`gED2uHq|I&zq|wLT(A$ zNzIR4Eb#1FPoQc~?IF%SvH6S4Kg-s={q!|wALpED4G(ICR$pEf_H;(Zi*Cl6o6DB@ z7jJ$s$MxrnJ@+1&T=LkIsn{dT)BRuUu3OEz?wjXWUY~MZwAd~F)sc1IXD#bpx_4P@ zxnKMxz*Q@xf*4{q-#=3>u55~oxo|bU6PHnFF z);e2VmE_Ey9=HEznOA-B?Y%B*@!cZoI!nvHTDJ}AC$)}$yO3dWjPHNcMhnf0Nq=iB z)eF|K#6HNij!r5qx|)@Cr{hP|8>Jh3O~QMQ%+K&WWVqz*qE+G7c6>Rudha&lgR4Gn zJkvNYOqo~p>bwpuvF*+kozLEtM^|;$1z#{Kk19?}%Y7MoXvLKTLxF25vNMHdhuS@V zI_H35gZf6Rlj?HPytRfC%o`6c{KiP3{BSVDCk-nshf(bpBM>bZhjo~!;2tq)P`e#wG2b$|A3cC4*`Wx8jdnaMF0@snrQU1Zd^t5lEJ`g4-u!Brop zELi$ggKd&Trlo0a-5(am=O5>9{B_FVgKu2bRgKO%UA?{6!x$2M4{f}CKDO@p!#$lQ z2Y;)EsfVu>D4MrDDKB`cM(h9manf^=C;pK=yewCfJ$3eKzNLA$R7y?abf4`OUL&Qx zHcxpk$FI-XU#yBR9a)^UdGZhM^ZZ^r;wmGwnry4DZEb!W_4vGvZkcUu^u}fB-dPrU zGc7VLPCwo{L*?M)h`GK zKAbr*cF{z`g^@4+OWkv17P9HQx^kc56WjdIqMo=nH~Dp!=kI5izQbN7cRA#dp;Y{0 zcU`+%GkPnw#@(Nr@O8_jb1UbuP1+%N;#tbpSna|`+YWK9O8GO%{mX1AUjFXbzSCFp zxgKSG%|B{);Zl9LGkq$VcvaL(9m z7WeediqOK%Dv=zoC-wN$y}zW;v^~4Q%Z26s?L4u($Un()885oIYa`-1XFa^KGLF}t zQ|?LUtty@D_s*|_Hou81fb%*EIX|LSYRxZr>y!!5okMi3^RX$w$xc*n>uZUw4 z8Xl)^^_{xYVS@I}1UtcBS0BwXocYiq{mHd<=MUZ$laxnoYJH{AZT@VM*c z<;#ESWL?$ZUB6m?>-@JYhjy_vAMfhAs%iD(z>SFyY=yO-nOie%{?Rdc-v+TA0p-2< zc~dpi{SM4|!MfO2$osbZ`e*G^t3uY-^{8GcyRvVpNs9l5s`Zh#yeBPR*Q@mI{#zE# zX~+22p1*T^Qcu?Liyt|f*?*G5a%%m``i$^WlcJoVqgvuJt;$BONDef}8z zv^cGr#J8nEVE+tZ9lr-`v!8r_WLR-T`6{dRzszLIs2f$usU91u{#31x+%h@qw|3v! zW|HOHt*s&#&^QC=Q9p`+gfL^ZmI#-v+S>hsYMelCq}Mql{?hN;-6%CSbui^ z8Ft>KwKb`ep_1Dxbh2JYuJvO-6We80U_j*N5#IGBdT{au^<`nWo{hBi& z;p>m=T+g`wSMvnE=ZT)S*mm@NP`a=EYl|qqTjsv1`-^;c{Ilm4xTYo+S$bpXaS2&P zZx@!6xAV;UZvJtxc)lmpa#@@H?-i2DR*k}6H7703mw&-}SWCR@R!q&CqrRIty`LRe z5v3-nyvw(LahY827v%|OH@+`hY#g>e>5N~}TFKpCQbpqX>!RYsE-0L{{UEd8P}sF6 zO*>s*pFA=3$d=^o^OIErRQ=|$?6yezQammANX>+vnQMiXK0R{b!>^4RUsi=%{8-WM zB;M~H5n9(~7Ad47b>yD$%QabdI&NkQe1ETXtzrLF@!q@H_Gc~D%udze6?k@S-zK4B zcHffra&u%)=91I5s#DMWB>f@((UcD|Eei36E{a#;Ieyi{cUatnEFYvw2=WcFa?k zh&Ogu`R10pNhLyg-mDv*CV%pjYyX>edg;OK-9{=GiZ`|)lWL#B21@73>CAG_3a;CYOg<2#k^ z+Sr};Q-8hr7JJCJuHV{X#^#uGb*HfU^va8F^S2}`Ke4%z_fmcD&Hc4)1Rv*=kB>WMygL;HA1E1 zGXGw6;i%qwS0ns?E!w(r>8L*`BjFZ6u7yk@9sy(N6)*=g!V6~-{!GO zb!zeIiA$zg?Cm;Qc;U-@+4D>-JGXw>qQaecUU`pf^1I6(7djNmCkY<>&N6@IV$}~b zj@SnkIh?3oaraXAw zJHprgiS=!Ma3kWls)hDREz9*+s=}UMP1yI#MSJFl%?j-Y<~}g@{c!q`{Bf^aa*F$e zmOd?MZJobm@2;w&1s)sr9iJAK&bCcuPuSLpD*pHS|8EgpVjZ&agu%0QzB9}(OWON; zZ4y|+c|;~+_3u|#3TFvfEaAPv^IZ7PGlpnOp(h&Wm5%6dd$W4lMr-@7j6dzpW`^VWl1X7k!FFP)Wj z+h~htq>E_x?*$9*_waVd&3nKb^7`>gPO$^~vcz&^u7|H@S+Yc-V*Qb>=G3QN6SA9( zjvKA8=hV_y%x9e>N)0y>d=iI3!aPa zmRA&f@owv_>09#E3f6>W_iwO&X1r&+@I{u2u#BeSNvk8*O*!M=^5f`~gujeYr{`Qz zbDlSQ*R=LyW>cd|Ce7?m$yJdGuQfS#`qs5u$7gRow(iKWSJh==XB=NuuWd42eOqsT zdFWJ*Z^!Spy=6%`bSX{Ry2i~p-sgpO@ueS&V_O8S$z^TtTlrQwGykjerj=Pa;kWDd z)csYvt6y)n{o)VJ&UUp(#g6rI3mYc4wjarBv43Lnj;BH{!!&u$tdyz0-apu{eQj|&cXK$5=d7*S{A>0`p{E-UMCO&`&JU~($y)k$`OOnc_IVzQy~%dqd%-TXW7mG% zUDKOIRUplEVA^tGuIloN;-|Tjs{(Gaqy79a38n1g9FS`XBaX-Yl@?<}p5nJD>N6 zDkrO+dVROowY+cpbBoO%<#Rov&Pmxt3hSKjiaqk!dVSquJMEock```!YPpS_<4v~f zI+la){-4`xc|Q3tbL)NCJ#+sB7wzBrN8p^r6}x2h=&xRv;!pqN;}mPW|FGo!jOfaU z-)BOunABC@x^zrmieuZ>dC#5H;@A9p?^9CrVn=~NQNfG{f1Ysh)_!EzZ@DjOzDd;^ zuXP6`tWA34WA{!f=&CtVI-OYFVG2eckpw=ej2mzbZ3#3P)sY&^D_+#&6>HK_!giyIuZKJGbyf z5$?SD`ge7bqks4Qs`&9FR`K$$nWhJsKCHgudSo9v)9uA8=Is}oEwuaMzKNfI%&Uud z7yoYi?ETZ(tiKnxT=mReFyZ|liwn*6vX82dc};olo8p_L^S7!tVCC$o)2EqhZrvB$ zboKMyO()N*u$8Y(DwHw(w&(bFrlwqfg&qErS~u*U<+@?jB}tb#X18zj&SZGx_;2zg z^+T5Jx6*SW|Hyp(7&T#!ykk~ns^12i)#ZYm{x0`Bw8U;-&3Kuc-&U<6kdx2A`N{t5 zgIe<)B+sQpRHBygY*micuwc}ReYyL{Gd|#JT z7-MRtY*EpayzXhmc9rhrt=0Zpjy*Q#IcML`T>mTS>th$$E&r6}l&+|~7WeGcRnQ=O zncWAAnYUsRJvT&IMQE#U7M|9iWcw<>;I>Dp_msW>A( zTla7E-!zM}zb<+F?`9+j{*d*H|GT2{Ncy$^Gqt9LUY~gOZnhiCjOA|nYsHo` zD7u?=S7szBam_gQAYZ!NXPr*tG3Tub_oU`;{mhp5eqot*`^|lO>$LxF{r%#`k$9KV_&MXe*D1J^w(EQ?SZ`DbDrPopC@F>Jn;}S+|#=CSMeq} zN$o(vrT=EOp1igFD*sd|ug8}zo%y_R#*ybfxqJSs`uaN4PFP>_-ombYvp{@t7F*040@`5thXYuupVKCjW> z)_y(4If`?RzVvBa()?B7M0n?=qDe_IZ-EGVOQIHvW7q+b&|V&6_WC zJ!PuP(iis1vKDnRrL~n+{rAQ`|;o|&AYY-cYT|?(R6X~6#KZkv)|;8#wJ@&@)qGJdCj{0{#om&$vTxM z#oL=@Pl(CvYSfF87dU5g56c+c!VhyDB23<6&q2rGS&O6}&$Qa`*keS0U$YVkQuF|J@>9r$0$9 z6P`1?dgElZ+2Lx5+fuW*nzf!RzAwJ>ab63R@Av9IZu8;G$?oXW>)1Iyt+BlLU{!C( z^x(f&7`S7<{m|lIQWek&s##sX#k63bl}q@dh-}{V8o9bLdwy;I<#t~A{gS-4_nMs7 zdiuk2H>)Tbmu+}>Txa{VSpAHjfd=zE1Wr8HeXW;SZDp}+R^@}{kd$+RbMlt>AM*-H zSy^W`bEdD}y4t{%%f)nm->b{`m6mmxsqy~9FE=fpTe{y{+jaC;_8a%loh(f?`OeK| z%bRLrqeXW9X%IPRDf(uyYs#LPc1ymnKD^`nR&JZ_zy4ot_df_eK9{rN{iKAcf75f% zX1#kE4q64cXmY>YH`|(9tSonT{nqmoJ6?KMZeQw!y^o@5_sn*KG+m<3=sj8hBWK zgAr@oza$-=m1*gkX|uaw!KL}ySyk(21mEktyM}MMO2pb3k-yGoJxgtNeDMEv{bsYh zIX!REqb7$n)K2@c;Og@d0hZ_X?kpcbZ)6NS)Q?BozQ;Hd)g{>KYf<>C4meG*VQcrZ+xyE` z7hdhz*c5CM@X-9=-g!4XlHcsVuU?=NWUxBIFzJ1Jm~hKx{;kzF?YCBm8h*1@jbN#3 zziex^=H`v9J1W0@Uv=ed)>GTI<1r@~)?M@XWBd2x3bBY6j~|yaEnnoKlw4mVYVrO4 z+l34aQi+}}jv@Rv^n3e2ZF+U?G;z*3Pj+ms3Vm#6{p}6guRKn%SOe+c^T$Is&&m30 zYx?=qX4AH?(=WV!YYCjV#@O=RdsBq`d?s(EbR$k@y+zNMo&F>_O?c0+@_5sWxf2!y zEtd>9TK_(4j_Y}!+(my=rME^@94%qn%o*M5zwP+Ky@s3CMy@`vugAn~hkw$_tLgh@ zO+6r}FK|QM{*bLa=d^v9B^U1naO~vU8f{s5d&SrINZGx8q7VC9gO`~pSJ-{}^x$!7 zyQ9JX+grnX({i`HadS95RqSIFBg@aI|9zfelKHdWbIN=WIw0vTD}Rv#%ze zICJZRUqM;FKVM<>ahC4V&$njmHUCk*E{So^^M&76|G)J6rC*(QW2@VWSF;=Tv_HPK zV6x|yVh69>2!Bwyea9yzJtty|#MgM+>+5FEDL<64b>hmiT=OgSDpcKA_DRoe-wSHW z%)M%#B=cV44O?T*y5ik;Ysxd1XdhEi*n95g{l9B#{TaZ`n8~7Y-Jf1wU45%!v-BTp zwFs8F&Zh9D*zUFL_W5)DRwYere1BKVier=Q)CaYbby$2&wHXt+Io{0HIJ8%ubDCY& zuauf88I8vmwR_#q`mj#!>@R_blTGbr-s*99P;POz`0mF#pBE3GUu|1n7PqVS*vTEs z*0MC^@TRVP_hdI4%cS3yjDg+BiyxftEP^aO`N_96y3(~^@23xsmNLdBy?T4OXWPtM zYd%RIEPuQ6*mdU3p3-4C6)H`py8|!0^5WjPmL)t>WnVJWKI;a9RcWdUD@)sY{;t$M zQafRz(AHH`-c`mOn|!>l^7+|=&f)^MPE1K){E@rh&x{L)r-j>i3D|_{G(5jh{qlOo zU5ASID&3{4_E&m2)4B{`%@wJ3D*OvAxH&gQYobgx7r1 z=GM=jEf}h^t(noTy2rKPye(Vep6^O`-rLM_U4H-S8kQq&3LEZ6aD1;yG)`#3 z+<#PD_D9-^xQ%iX>(1Udc_nS?`>pFE<5>P>&u%}vnpc0G;Jm71+dyAV~AAB}syS_fM z?z%;_qSDXLtCA{@I2ngsGtFn;;bfe(S<5c6@xGO+!e!+QUXg>ZcP0X#+NimpQ%Y^oe8VxUwv_vGeoS zdgaZ$lO3%rLi2U$XBSCukKlzqyE8IVsAq4 zuYJiyQ^8@(z25bk-__OH;{5kH{=8dT?!RGAlF-q!xAhL%u8K%`uy50({oL{w_MeY1 z_c>5%yG^*_Ty&&q_r9Bv;kwI13qM5d33!>#ooZ8d-u>C5r?Z#aFIS70CnfMBZ_mAN zd)`hfv)SqP^RBf1=UF?r*La^kUw-kSxe!a*vQI9;wf?M5HL6^Spa$Q5k9(@}{&|r* zY&gT-9XX(V&a@(A&WEJqtGi0K?q<4m<04z1^?{8Unav;MMEB0WVPSEw_};0eo~bLY zn)h9A>-Wl4sVNIz?=^qVjtYCZ(^uTMnC@G?+xyZj_fcHk^fH^RU;4UPrkPfl9+!1! zG%$*Eud=JK&pLf2Z8@KWNO^vRYCb5% zK3$o5WX8mgC)+OWT=U&?lNf);PoFTZKPobJNBXL`sWN;1 zeBKoN>GTyh=JQJ$9?Uu35*OobJ?~$2wx(>bwfsHxjS}y#{`r+RZ)1eckK%i$*jj$f zo~iJk(eFI#sox(ZwZ3*=;W&8SzUa!FpQ%~Nom<)Wlzx3Cp1S*s_3n9-3^%WzX?^hD zwnvMuzPHhl>Udz8pUV1s{YAgo9pE9OrxLlVw@hAG#rh%t@~20S-(Ek-Ic>YxJx)Q# zJ611KrMdUp{+w18?(~{D_t8#nj=z696wcpz+0WV>;2z_7zua#fLs8hGvMIZ4^PS#5 zVV*k6y|J?5Q>Dys1>}3-6r26%;pmET^M|n?B14SKU(I5iZL8!1Bww-r(2s9$hah z-g4M;!Sg*+`L{$V-1!_(ePl=Z`Z&Y+>IW}vz1XBsuXLdJ;O*~1^FpVC>ZQX8vU`s8 z&0t^7uyC%kz>}!-(itWWALeZT#0064)NRDwOTH*)f9-nSoW4g%F4l(gn$+CI^468F z9K=(eWJpF!H&@$;ZDzFoC;TKjKXt|nA6~;Hwez36k{5WC@77ezmr$i|GS6H+d(zuj z(c{;9BwSC0_f<&q=E^6~ZRbfM!ldxZ~+T75ZYmwNVW(={nK_pIa>Eg&bbIMt|j zB`Zafts5V-s3>UF1@002xA*0@D@||RUOiYTnEPxt zBgd!_01O;FE%3IczAMGYDxmv$8Pf)a#W8TbL5d}_7q6dwuc&X$(%b*BzSY{a(QHtN7k2@g-MS9`0+urF?AL3)4+gH&(GesQ;&R>b$i| zgy1a~6=#-@+3UVbfHLuG+07?Dh9A+h7P$5Mx}@i|rUYS|lcCEyBNze?PM1pBY;T=VA_kJN)D!Yq~dKfY&i z`g8W!t!&G;T~oiGZSwl>{($SEUTxTMy;mPEO-@+5SyJ-2$2%6o{8NifuJzPknl*=W z&D~J$wac;%3tm{}KjjAxK3KNjT3ZwT>#*VJD&@(>+dC?z6rQ}I)@{dP_&RmUU2Pj- z%RkxYtu2o*%)a<>0n41t4UfyO_A9);Wy7Im)%D>4x1@I9Ztu1CPReSTPX2KEhu^1P zQ$zQ!o;LH=nT-0TvnL{^DO9YA2#WaDaCgpT2I*gdDK&>4$oMp=@05DE_#)fGd+oOt zAFH4KD)jAXZ8ec2KRq}6s`)6ePWu>Wjn7?< zDiQLT)h$1~rc4WF*^|#v@=Y`QYnOuF!LB|1?%kKl9de!?Rlvjs@qA^&gCy z@?o7tV8dCDwOeKUqBn1DG+lW5e38oH4|BFhnKGLE%2H=P6xn`j?VRx2TaM(ZE)rUE z!rjZiX{-D1(0ydVUF}9Z zqb1`K9=$_<`M0_kZpbj-G<|2)(GT}3_LS~+>U`fZ&AsJV zIm5yCcUtPV&FjC|sJ`KogZFLaBjJm-%vmI`aYd!-AHn`Riy9a|s&wq#Kc6Lg{y**K z#UY}nfA8zLa{JNzW&UmIf|89NtQFO7Z2ay!sqVscugmI>7a!qp(cxNgWl`(3>wbH~ ze$@8*KatrP+$6d*^vWFNi0yUN{i2oe>#n38d3?mwR#~9#z3H0wR(nMn>nCYfCM?zt z)9F*iNGuv^{k!E>9$ zy#{q}{L9YQs4w=c<<-&%d__5Kf~ z_O%DD-&wxj{_%hI_~>x)-n3R|sbn)xvP+Ky(OSC)uXh?~9(%CEW4(R-?Ru?WE-^p8TeIH$Te9UR z`=9e2b4&iRe>*?@@;d(x%hQ6TeB23tXU^^TxTxkw%lcA$W%tJ^*Fp58BEwSDKh z=bI|xc`v+8-zGER=v~kt*G#XYf$xtfze%f8+0m4pa&?J}a`5a(fjQrIaEWIIE3N7( zo%KyD;@b?LKbx5zK9^DYuuosB*=9oXlwAuI8`S6T?s}AT@uKxKYr%*12WGK+_S{f( zB>C&?PL8>YwjMt!Rr#s&$}>NQA3Ki=S?s&0QZY$e+d^QL!@kQ4%M5<3zIgQZJI|}y zO?%|8X?4afGn-l3y+%W5P5gJ|cN;bA%U&2i`Ycn`?_8SvDR|PgN~= zVUn`OB~_c%T~%krm7?iqJzPG&-pZ^=*^R0Er=B^dJ#bC_ z{cqNRnUfv77Fq_(GW4@A7d`oWWt=VNv~p>Ffg`yI6AKTvN=>y`*>$vLangpa;3anD zu9bSHr=_SCJQ5Ljvf3rna;?Laq!z|~ZZ~?|uC(obWq4?E!qbg=joxY3R4vyMll*h` z+mgpD0)L{5f8PJ}k5k5ik>mWrZyfWtZrfXHyS7U7sAS^X$6I`IH@$Wj*sbYyJOAMp zt!sL7-RAh+H}+$AeXQ7FT_w|}n+G2)T6BK5Y}WQ)8!nfr+`nuRxALg0uuj7buYe_Q zr*71DEC>_jZhpMM%iZghdzr$Y+t)dl{LW{3baUcHp{X0MNYDIWdv$evv1*dBN`(3R zc`T=wNy?q7{kntYedtl93ckJTug&@@_x?5~M>^ZV;uW>#>fOtP=KRpp%UT>eGv}V^ z!LBP49?a|KTzssS^=9hrz{0qb+2Lp2GcW~C`ue-y*8ckb?gy{??@!ubd+54+_mw{z zAMjuJYv})M$*If6dhYcCBw;eyS}|ydkgZWw~}& z#Oe<2|8@UMwn?9~{N(gw7W4V3pMSO7aCg7huV9~eKG~^Z{qKo$a)TzsHt4Tilyg3g zWtV$BOJ%L)(_i|3qG$hSwwJs5?)*Qa#sptgFJm^zV-ZWQX1>3n`|(uM3NE&Tw@w|6 z)sA4;IJH5v@K)qWi;o}6pB>LWzwrCl1N(RFZ@4~>Wyz)ng?~T4#!k{U__2>yQOEy!ZusL+aIZFy$vh+M(Gjh%k~8T$@1~x&8lsy5$MK=btP4e_&?%`bGLJHN|gszPjF395L~md-#>e z1t*N%<_mld6qXZj%$xs<TR}vo?zX$SD}J$YxdW!CutYMrI>vd#GCyKtm>~hdF7b& z#pg>Fy?sAJSe4_Pb@$Q2gT1>dKX+eyZM$La0Xt|Obo-(tG}YtHpSLR_6^@+cZ2H>$ zVsgUS*X`}UH)Q`2-}Ah&{MmPzs`#$&w#}^{-uF!Y@{9T7{QjfKDSPZ3p6~y5X#f4a zZ-t*+E&2XczT#YbW&HetZ_g7M-~5kRa$<8tpm^-Q^xYg^p0ECK{$K*beDj^#(ko9l z3dDCh?KrN!_56>;M}zl9+3S~`*||G>1IM}lhtKTr+$|LNJ$Ff+#EI(Z|4SPDD>u$P zP-WA8D|c4rpNmXWrQUC=7Jpl=GsnNF)a_1L{;EK$pbh!jkLy5%$mv-FZDR7L5HavOdnM-W=ne3*&vtMO7N`oqttkvFUEbd#`!K8sFuc zDBk#=wxERP*%C|cZNGjoZ%h~e@c#RG=Qr#22%LNNzwf&Gk@=C4g?z7tzx~a1+PCOj zlHifLvaA0U{_j+MTdBiz_utPLh6xI%qnTQM++U!unciqhOED}z~QfQZvUf6 zD}7lO$**7Ab@$!zmWeWpOk+eBNA{K9-dvPu-B_Vu(|&91F4z2kz~nU#_A!-PKREX| zEvtCdHtk9BO@BR|RN6gw3j=$?UVFFyn96*c^9U$?{9ai0Y{f^-%Mv#yhifW{Z&E+l z#e8t*)cZm^0uKxMi)xFVU-(@kM_qus>3P8J(Cy2swu)b@ds8L;OC{oY595TzQGzeC zx707U399DXyZiCI_B)*OoZnu1&3~lcBK?Yl_Kx{=iZ<=fmDl^B$^M1$PM-A++^gn6`&(>Hoqh0&h zfwNXd97(Gq0=F&RS^as><9XXSzpqJ9tVw+|OY0*03#~woUtU+{?|*AAS{oJ*s^|MZ zvnQ?c5lQ);Cw}O9P5rvf>-{4>7xG?A_Rwp(p%wPzE9XXe?uVs%kLSk&Ybg{ z-|Ov&XYEe#Rn_{`Z})!Ji}&BpKPZf_f6uL0Uix9@z1LA66Bn#r=YOJbS&zatA(714 z59Zj<`4fMkaOvsq&wuUPmR^|$nU1>EDSG~rVL<=x8k56Z@nvDZ?k#O{Em(j5)9E1D zzAL6yX&1lk-RU+zd7u3@;SY?5idWRKttubhvHqUUO z!|&Z+tCq85PrbHUNWRHNI$dSDXx+ST8osB?TibqaoZBD^na9|@@s(Qrs_@@iqf+CI z>Xw;JRIvD+^H_9-!(}0V(QMfh3r>3a7bR_&+rYa+;Refhy9e8|J}nM%U(3Jzg|6$D zL;HRko}ZjB*P8FZzn_~=y%(Leu4lIRee3s~|8Dp>@Oxj_a+0O#ZQ!D|%Xz%vxpotG zr9{2)?>K#G$M%goe|Pj=jpw>Zvn8q3AdH6HPXGwR!ZTyC_pdU)o((jVrH@?Sa= z{x3csY|yyM7ztInNhA-fDX~*m1V4vQ7J~@=vv^!YjW#x)IDIZ@jhh*s981o0{gmz1RK3 z`GZWw_Xm5Nj;C0xZgO34dXC_msTwaO&Uk+Q8L@l4eL>wsKp(lKtxW{O%Hm zj`cfIF1)>~6~Xe|`bD4T7Tv-s(d^VeHkS8m&(Aqr#$@PN$+z|Qj~Rt)rq+Y+ubl7&g3e<~rA3yM*aL@YxO?~FE`|kg^HSejZBY0us6jtr|)%I7l zt9z8*3O}j1{v%Ixjp)X^qK|v}tLAB4lbhi9TX;Up%MEiKWOpb;u)HsH$bYKhwscu! z&ii9r_cy65e?KGP?pI|Ij!(H0F3t&iF*`6^^L_b^;MNmAI|LrSzHV>Y|I;qv?BXN; z4@LGb|M0#%%H*DW$8U}fkK4QTTh{;l9rJxpnEkG3%WL&wy{daTlH{MR{n63oAMyR* z#(Cn6dGh~2b+AlX?)gu3ipi?4t^_@MwaPW+sKVpN9g`nTaou0OCPDDdcmJCyGsCq_ pD|9bZl*-tCl&Pv`Jn;HI^S&1Kc4-0DR0akH22WQ%mvv4FO#q-t(Rcs= literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_017.png b/example/output_data/primary/primary_017.png new file mode 100644 index 0000000000000000000000000000000000000000..3c2618f8ca5cab8d91025611379d795fd42e5c4c GIT binary patch literal 6351 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 KKbLh*2~7YFam`); literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_018.png b/example/output_data/primary/primary_018.png new file mode 100644 index 0000000000000000000000000000000000000000..bfdbf2c79e69801fe47e87121d69f5be7914f189 GIT binary patch literal 8900 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_019.png b/example/output_data/primary/primary_019.png new file mode 100644 index 0000000000000000000000000000000000000000..0a51631c692bf8c7c5cffef1a5a622ad490b9dfb GIT binary patch literal 9141 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_020.png b/example/output_data/primary/primary_020.png new file mode 100644 index 0000000000000000000000000000000000000000..26c82e8c6c371bf1698f57ad2daa490866ceffa6 GIT binary patch literal 5768 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_022.png b/example/output_data/primary/primary_022.png new file mode 100644 index 0000000000000000000000000000000000000000..6408bf13294109d0ac9a7113cb4c3901d7b6a7a9 GIT binary patch literal 7705 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_024.png b/example/output_data/primary/primary_024.png new file mode 100644 index 0000000000000000000000000000000000000000..d1643de03e34bceac34057cf7f3760dfa881e480 GIT binary patch literal 5344 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_025.png b/example/output_data/primary/primary_025.png new file mode 100644 index 0000000000000000000000000000000000000000..c45581a59328775ab45f0e041b5c48c0796e384d GIT binary patch literal 6234 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_026.png b/example/output_data/primary/primary_026.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb9c19e9634704909e724a556b8d7ff46111100 GIT binary patch literal 12161 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_027.png b/example/output_data/primary/primary_027.png new file mode 100644 index 0000000000000000000000000000000000000000..e113fd53965fc15e6cd8faad57a646be49aae794 GIT binary patch literal 15319 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 A<^TWy literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_028.png b/example/output_data/primary/primary_028.png new file mode 100644 index 0000000000000000000000000000000000000000..ecc88a28d9692c9e85c09acca604607be1e60010 GIT binary patch literal 8837 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_029.png b/example/output_data/primary/primary_029.png new file mode 100644 index 0000000000000000000000000000000000000000..46c9235a1385407c6df33c32f2e716e2df10cad4 GIT binary patch literal 14114 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⁢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 My85}Sb4q9e0DQ8#V*mgE literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_031.png b/example/output_data/primary/primary_031.png new file mode 100644 index 0000000000000000000000000000000000000000..180e785b7995e112887f260a65954f21516da64e GIT binary patch literal 26276 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 OVDNPHb6Mw<&;$VOf?iJm literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_032.png b/example/output_data/primary/primary_032.png new file mode 100644 index 0000000000000000000000000000000000000000..47077c194cfe203086b30a892eecad8a8c21fae7 GIT binary patch literal 7399 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_033.png b/example/output_data/primary/primary_033.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe9c2d19914214d0a557eebd1e45b35af8b7e0a GIT binary patch literal 5549 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 E0NgKk00000 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_034.png b/example/output_data/primary/primary_034.png new file mode 100644 index 0000000000000000000000000000000000000000..88c20830fab0fdd2133e15f440643d09853b19a3 GIT binary patch literal 10666 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+eO>w3V!PUfx5n`b=}MU)YLh+Ra-}L6YEQPDm{B(&>*l6+Oq>&9 zR?FLHl-?An(flpCfwRWth$6!|S*1sdzbY_Xd$~V~pMfDEn?>irCVRn&YuOn$_%Vqw zIHWR(72FgM{J%wx<$zUfi&FUmsn&N4`i9M{G3G8VnKo<M&E9MEVKPSihL7$Pk!msn=f#*3^Tn+0u zBMubT9nbuBs%@)$u@ z?s$Le(}Rlw(>NLT32bP%ed-Fo`8_vTu>K{0`Gx=rvMz61QzI2zx3 z^)SA^y40>Tf+1}~gYo-walDDU*%H39=q%9toyf=$aX>uvRlE5*Lzg4=@A+5~?p{e? zRA2w5wzShqC*k>-1jfZiU!7aC|8m|oW!SBjz{n7i)+r!yHA>EAlMlz68In2)^P1fcr&emwK{xJ-HxseE*x)WHLzBjKR7&awymI3hNf zr@m@$onOweIpRPbi0iG-FBhrCQs#1?$yPJi-lXE4qRc;@H*F29I>{Wy5Jl>1r?K~g zL|YnIs{@zSWmvQ+>IgIKPEaqu(XCpZxBuw6cL(@5A~uNcWtnaBn$gVTK$ES8;kEd` zSvGx(;||Fk@VSz3P;QG}p1t`NIfes!SafdeGWzO#*l^Bo>1iB|zMEY*qOW@w{fcgo9ygYAZivyxm;DkjTcpZK2QK3k5t|HOkn{ zKpr?4mIl_Z4RTnH?gWs2BPOvmv7H_F1wXF-Xpwb0DuboWl~-)d-S-mH*|)ptifu?@ z5?cdF_|HJz`(VY$eJyA8=5Y7_M>JiS)^s$metDhG5ph6Ev#5Qm*2c4sz7==fZ4@AY~|G!FNca4PG#U;eKyB1vFFX4-}Y;?vk)Z+59@Rdt#%TdDko zBRE{PdHC%(q|WwCEy0mL=d8i}e*L%p5psLHe>6$4=p@*GT62GEf5(rnPe0BVShqlq zkvj@psvMq|a%cTVwu;FOtZO6XV&*M%N=Rc8+XC^s?WxUj3yc`KZ!G8WZat90qLXp* zQ$qAKuEv=h5f{9`wtmw)U)A6xGnIMmjJ>a%kL}p_Q{a$ZK(C}u#?qGf7khsQzuMTa zibW@5VN1c)$)LDeDX`+0km8nv$_@6C)3_S5&LkYX1P-7BsnfU`y;yW2X5Cy}ml~nP zvTB11hqv~}zdf99%Khj0z+@b;VTsT*w(AeVBeYoVDJ2}7q{F}Nus~TQJBSkm zG3c?8(mzf`?uyO^R&T@Vt#_cL#1?7c>57M&U0PY>pv z?)V`+jjOSnMQ6n;gKeKA1&{JvyO!GHxND0n+XZ<>?o~6Iu3mg^FIZn!|Gz$G@=~V< zOpM%FRy93qc?9Ple^sWKec4Dyl*yhW;={J{8?9?%erRtOc;|G?qI+s?JL4DU15K_| zt}!R%?LQQx2�&K3ZAfTh`nkUA<4%O5*U@ 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 C2b0GD literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_035.png b/example/output_data/primary/primary_035.png new file mode 100644 index 0000000000000000000000000000000000000000..d747470a5fc3387e0378c13b8b12c2d64e5db84b GIT binary patch literal 31164 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

      ewqO1Jl~Gi?=coFD66GJQ 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 l8Ig?l3Sga29w(7BevL9RXp+soH$f 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_038.png b/example/output_data/primary/primary_038.png new file mode 100644 index 0000000000000000000000000000000000000000..22b2ada0862715b78d538e7e407264698df3f47d GIT binary patch literal 7359 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 Q7#J8lUHx3vIVCg!0C1DyBme*a literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_039.png b/example/output_data/primary/primary_039.png new file mode 100644 index 0000000000000000000000000000000000000000..c772118149371c7f00acdde20e1ef4655e28c826 GIT binary patch literal 7862 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_040.png b/example/output_data/primary/primary_040.png new file mode 100644 index 0000000000000000000000000000000000000000..6c22caa9fbf0f73e843b6eab3eb3628a19067f46 GIT binary patch literal 8257 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_044.png b/example/output_data/primary/primary_044.png new file mode 100644 index 0000000000000000000000000000000000000000..daec4264124af8c1f819d3830e06e0bfaaaee5a6 GIT binary patch literal 9482 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_045.png b/example/output_data/primary/primary_045.png new file mode 100644 index 0000000000000000000000000000000000000000..fccf0b706086a8c3bdbd9049f7a61193d76eded0 GIT binary patch literal 12269 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5MHeOr3_%q-ShdZqgt-^g}8^mupjNWZe>cI80J$?rT$>L%P;lHvJ> zDd5M9VxB&woS9mux9r#wptDD%lAA&2ZuX@4d(|1Y|6G4hn4w{{*2($zCO6#P>(b16 z;L_fwAG%nz7an9vxT$sW{k_QzzyDmWW@7lTRPkhgMD@{E85Tjz7GnF+zqLh;x;DTbLBWt6thpM^0|Wc(t}J1l6Jof<5>@QaYisOC<||3U~p4Q zV7w6iv_R{_X4bdY5;g`gi80iM_+_t&E4tCQ@TtI-I`KJL_tf>Z56#5ezoVi|RL2E#I58m_>&{F1XSrV(#<4L`+krm zHjLa2=R=Qihn-ycw@J33OQ4}&>+xK!n(vW2gm&C8;1y$FFD<+O(z>FnfptT9=~Iav zx4oxqVfY;q-gmt0XVzlXy^Pqo|8pJ|JGo2gH0)iWeLT48 ztYXYonYhv|;W=~IxD)tab^k7w=u4jc^RtutwoHZ_n@+v7ab0?z>Dy^;tL<}~#B-)J zux@aj`tkdwsv`w5(aX>C&*g|`=GiWT0# zaBa<|JqcgmZT_ZZ$+AxVvmfg-wFJgBfvGzWYFVCn?!P7c&9vGL4A+(vWwot(?X#~u zcfEFX;>JQLod(ktI=eSoh5!6>Md3|H1M7yAsb5)Em+vpCou_-x^TaaF2nO$v$oLIj zeAAB<&UF;nz#z7C)47DHced*`@7-|2f{{CcQ|mQv*!z9ArZJXz9AJ8}a?`(rsdx6T z%;?^`;f4t#_k#9QW=&VE--^~KBru*?xoK^}RGTu-Ibzvh*#y3+Z&_ED-_rik-N0(F z^i)}M=%+iZbECIJdX1V zO`H)7$t$#vM=#miq|X__a2~`ql{x$FP=*=W{VC}2!-_^!x8bTXxXxuhohzYj*s}Xgxe8;Mu>Z}b%<05h< znMN?gubgvDDl?L=?&x)m7hJQ?2%Mod zC^3mSxNg{$wklULYLdLLjb4db0^{#c!8Lh?5Cuj|VjJv555AHM&eOV;#49#iC4upG zpx~N!rVx22Cb12*q6c3E7RLxJckMpTryB z$u@B@X_W-V+kt{>jzR5DViMa>Cwed|r+904=iUvV92K#?E5Wq&p~beo;)bc!Ctuzc zK42B%$Ln1>_oUh0)PLMo-+#<8P~;WcASc>;^@`T#xl%2>!W$Z%uI30U{yEhy{=V3I zm6Tu>orIlQO;_h=-O`pgX}?#U;lp&R-TATSY}#b*o&3J}^7H!p+^b7}{V_0NXXu>TP>`!|L2aZQW}L8zq^<3g&kuY)xDLvfMHK zh9D#N4qw*|QM*rl^5@-_vGE3r^-kvdtLI#Mv**iPF8^Pm|Jw|NdBr~L>^hd^t#vwo zy-;-`$cztxt{ZO6Qfz9QE;d^s;o!Ycmesn_AeXV< zP-Nu(wn{1D?ZH{MRv+2Tag&FU``a?5h_^?<9y{R28L>fJ^k7#0wQF&Evo9uXtYQ+& ziFMs@YcV8tWj9~c$O)Z$cl*vK|JH2X>*ZISxOLynAxI{JB~!^g)J^``Ws7GMn`e7v{)5XLzEz{OS4wv#v}{{`S(e{oAV2dB->3 zOM0uYdfCAy(^dNKHs?dssciIRUgQ1rie-3xB6pXfj=K<8;^i z&}(})$eOtwXi{Cx5q9TU__nWqD(-W0hj|@nQeDLnc4yt9y-lrx8xlOVnnb@#PWp4= z+dOUE_Wk0Zgzg<6xTfOFEpyS>&XWvpl1pCI$=HsnlwXLw3jX3+jLZT zLxPX!!LCeRP!>BJ6ZNL`XclLLL0ebCQJXE{8@QOnY!)j;7|sWW@{Hha(}*?G8d&>R zaD<)luV!7Xm~hZmt4Xvrgzx>T?AqmqyTx?HR)6t-&v`&A#P97v@B1q^1n+;elU-XW z;b8fzH~YlRt5&}Ge&xaMxQMmyO&-KCiPbDyCv$ktmhcT$Ok#6ZYach*eyZ;F>L(Xs z{=Ty1+%dm_wKL(U5wB&=mY$%S_-s<{I++-!C z^KJFM9sJ$~;OunZ@SEnN|3dus=DO}knwg_j1&$f_14;H;W}K!rBAYoBh2WnI(JaI`FhMf+MVI4~Om zIU?4?yKYF5-V#1Pdm~%-RlyCQ66a_cq`)$eV(k99k|Qjq|J$o--6)+f*8@qQ(7GLB znd5rlmmjl4f5XvFp)A_l-iF((U%ydYOj|i&V~ps*uD7c#OgW@g5;oe19_;#iA@1(7 zqj3>yx*Coag|KLUTe@g(Q?Jm57weTGHrhM$_4<6Bdn{{9MDx*A91&lF1=rlrzio72 z8E3>9kOD|*-QWhY-}yk2OMd*FKCLEEm0Q|38tbe48`f6*{>DgfAEx>{REfluWP0`JG6=lY>+s= z{2RZt_UAa;fK2N_K zJ9z5j+@|=Cs}7xmB)_mNH@Le)1vc#Pe>!{bnz(a$&lh@aK6);5eL^{lPG0cN;>j0I z^Y8e@o-kXh{qO9k`^>jrwqwoNr}9-V9253x z`SJFxRsDIfTBu-d!%_FC6W5EcIGS{POZbLpCNcJ@oq9)Ne(v~@vW2}Zb#=!2Wfzio z#a1gMyp2s=lu-Ka{LNZjF>8Y-1yZYj`7yt6KX7aHDV~F`{!IS6&!UZYv+m(7QClK( z<~3|JpDNjWHGE4%&JA#Z#c-E1qB`)U%o?pIoifL2Q`_pqjZ93}u7!$Sh^TezKFS96 zG4lovrfXrLViF)_X1>*?{bJRL8!MQuT?-MDShH`@(IjVZFfvB)FlK9OX>*2&>Wa-? zvUiq$w<*}xvZ+&9R6hL=>1H3!?s+;vp#AYjZ?g~6lluSNm$|k2|67~>y+6w* z)gRr?EB0D-xm}CuD(&N|%m00;erd*C;St+&X1ShQgaq%kpisMY`YUq2sGI7FX@8sL zyx2$n|9+MKm#c+7Sn^)GbY<#e-%Cjwok|Uj)+@F@oz0}jt(u_g8f$rP%c;zTzu&)k zqkleX@6q$jdw-fI9AsIexf1*#J_W-x{EPvw1=`gM)f?*H2RG<2r;$2)qAj)zL!`53AQN zI+(PPWsPMB%j(%zKyk{wWG_>mN`mi7rHH#{SBrB)+8{MoiX!;gxm6N;7b->At~vKE zdt-#aThRh`#%v$agIOYRM;n!Zusghkg!Iw1O&4*VhsA zI=~}r~Q)v0~^?Cbuoo$j`C39=ywQ{MLi;EtlO=MYf zK7?iU(G}Xq4FtXaH>h(&JlATvs+75LM&!|z2e)QyWb1Yn+8}f=>*K3ahCM#jtTvhV z8CNSstZftPo*A+wJp1yZqe+F|BsXX^U43``1?(CgVyr=IZao& zGB?hckt=!aWL$*K1v{p&r^z!``P+9LU9ElmLkl=G7|b54E}xuwJ2<>Aa^b1t-(D@f zY;$AIb(veMuT{$3$v^S%_M!9VJ~tTu|1$4@%Bxd`+F?H>Hfa58th@!uEVDPQWm~;Y zX0xEEuGr#Bacl2K*JvjMZrjYZTJPQUu1rndaTuz0^S_2r%hCeT^;>s8lx^)f zV$HsN;ZbYO$SGgh)^zP%Q?_=U%wb+gwz;w7E9;uBgrgJ1y45q+Z#x_pp>w8+Da>`l zBd1u)wtPr2y&>{6e}w44uKbLR6%)Q?MMv>Xw`^*S$U6Y4qZfSI*t9}#b3&?Cd$8Bq z_a+T*qwd*7Oug(s?P{so8n>hSBJLcW=Xv|d{i&>xe$Am5BR(!Tb-dX2YP!@K=c6kf z6N>&ahq-P@O1YNwu{Zu>ZQAOnJ(DLKeIdR(Qn&U}eIqGdBL1lq=aF=_?P?HaBCVg%r5awCsA4zK&S(E|A_A3l<%H zq<>30A?-0c$jeO`8_OVd{tS0eVR5Vi6zv-YM0LgfFWk#yRbiJ9%Azgi*S$3wV&fiA zL3ZddSXF|kuGlT@1=D}8ca4a@)9z|jU$xug<~klr79HvCciyo*7f!zA4RhU*)Vd{N z_tL#gR=e&cT%DR6VWWHP9nZzMw^s%Jf73Z+AOFuU*0SyDkGYqfzIUmA=F3>$aPD8; zhF6c2_4*U1o}2${|KrZRiKT{{?DGS|F5f-Q2CBhVm)}d;n7RMaQPCIgHk{a7^ow!7 zQp`rj(z5^IHYd$jJ-VXs?NE~7zmw5?_b2>0a{O85Ml=6vR-Ge%eyfW&Jh4^#Z;-hg9C5j0LL+e3> zt=jUvOlA%TnpSJc$A4UX-sBsk-*aP{ST@+8-I*KJ9?xn%;P$8dj|HE3hG$&SufQLw zS<@zl@}(z7-_P9O=sfAa_ow}}%Mb3$*ziCxYR$#JUGm=>&R$43cs6QFgz(CY^)t@x zpZrIAUi=xaW>)^oNxexY9_D_zS}w(qEVSW)p6GiGnVGqgGorfpZkRE*fz|(FlI@eX zZ_JLYlujsS(b*C0+Woa%#uuMJSV8)h+`&GUAg0)*SHqPj6U|qa&^Y5rN{B4hK=+*5#dMG(zGK-GH)UId2 z_bg8cMSMQq!=fV*I`{7NB-Nk0_E!Dh`fzeQdxRw;x7+enKNC(Yv~0K+HD^+q8IxGg zI#A@StK*E?5^>-eM}z^VZrCK}4ZFTA-JsXDb4$fKLup2CwZQc6<#&?)p2++E>cBqE z2!olQU!}Ek+qc~lZt&kyk!Qrs$gLKf{=NOpx>Gw#v)iV{KJ!nw&7w2oO68#+S98TS zL;7exdQ9ujxEyHmygK!9uT;_RYdpGf9~#aIZb&Gy&e>S!Qhn5DtA*-W9TuG#F|n5S zK-IDJKc8+f?i*94tK{!hXS^N$^G4j>l3B-j;wJyu^ZERhqa49ir?{5xQH_j2bvthppPFDl#=Gz(FUthd*oDtm}df@<}RRRx~8M$}e4CppJvYS0}x|pumWT6cU zX74K6BjkLHGaT#y#RSK2>5PqYNZ2TLFDcY+AEVH< zW3%klR1yv@3JJTM^!J1b?=^!@$xI~*2?rPH?m60InqBBM>m*0S28*dzw?qVktX{32 zaPX1tmZMTeXRSHbb|>oT9)BM7bq=evYQjOKP_g?-Tki=sr0aUc@3=H zq3PenuO;#BRcAPF!5x(A(e~}<`-8$PIuTo1w?#NFyS->3C@p^l30Upkzd?*!EdRvA z{}+D0HLW)dsc%c!uu%H(@8#cF8nWx2i>%Y?&f2u>LQ#cm%j&iooA|%V=i)bu=ocQ6 z414fr|I7C!{E_RAXKv|~`>)&n-tWzw2`8DaT$mKUfAak2EALJ2f1bG^LG)bo8rh6O z#h0-XM!pSMKX-U+i0!FjUAFvS)76N8Zqw4{P;q5#(^Kc_Q;0b~$$kU+VEY&=eXO z(QP_)TI?Uw-_o198CYdGA~tA=>WXcbR&u!e;P0>LYu}sP5M$&HOJ~;&>)yK|&&Z{r zDfN?{Q^eA9?=|N9if!rKyI~SXfU#uJkC{)?pI2_sl+uYSE^&9>+jsWY6o0@|!o$)--6l$Hnu`c!L^UHQwGZl~U3NC2SjA&+EeLYk6+LG+B zdy^Kb?ypm~KmR>@$9G{q!38@!V|zZRFmi{j|FrSd%*>_lQld?3N(JvddB6X*0Ap9+ zm7^T~LK_l?`R+?X>ndX1*P@U~A)>}w`9u+9z+ z?`!nmx+BkOvEYV;$!R$ovmW_hTy&Hv%>6)e_~Yp{F|$n%F0YpTc=?a@$^C9sIzP_+SNr+@dGbqc{tF2Q_0E>`I#nk# zS}#4=bT?z>-lJ9jOU~ELdicgLG0S<<|I-W4HnC@JNZ6jXV*0D3nvm|+;|Er8L~PKW z8hJnP$3M-wGoM!`h6_Wde5KRJo94GM-fKuvbE>lmES1)o6fiVUtICuqiaB= zgz1|ne7nsbzk4@7)AG%%+PAk_|DQ^n_22mLoC9C=D<`pWm#shd&iw5ib-rjfA&VJOv{!vDwU@-efG}1TU02&?9!ttCjOP3`JoPz`tNhqEr0#0QE_{& z*DvdK@q?fHv(4@PJw5*4a(Dgd()ByyK|A7HZE*dUhu!nQI0N@2~;9jeQZez*Tzc_YadG)Q=u zMdyKVY1#hb?yV-JhIPxIzTfb5+WEuRqW|3s5slDgiHj`xYDt%atqbbWo|@SbjgA8yCXMf7s{7wwWbZuI1_wd#4@m+$w7dsoYCl9JMS zApKnQ(t3UStP9=q1+_`gSZPDuOpcdlA=PUc_kI#DenZNS%?LwK)hVlLVw?Dt$ ze)aZkre_bf?V8QTy(2KzQto7brrftxU?=Q+_DWlKIqOIJMHib`1vWHT=X{ZEEj9E@ zJYn+iRZMqqdvM0b(kFRLVg>EHifoz^|Fr)Ji|q-PFsj{QbzLdLF`Y@QU^(yB2(Xqt z4`0Qc*38)Z?6vo&54P2b9~l_AcLc{;#&v@1S`xp*>Uz-)_t*Y>r}I}oj!95w(Rsiq zye%U4PW$f=kfED;3QE@{DgIFgMetpaZ0XaAgRhe29GdX7b#=L}yuWnV`I86AI3o@; zt7UC$`zZHHA8c{a;j25RT~@8!5_v!S|LmL zOp_dJZ3bEdIzR~+)X7Z?Ew*EPm5s>?68b(+1_*4?Lf$Mpcy zynvrG)K;C=v0HVXU%#$0#QB=^x^tm^)#;(vXC8RP8F66pzd3j17aq;(|99}acf((+ zyXzn4Ulp%U;c?z3xbEK8jLmk*`a18v-2Yh2^%RPJ^FZ@4yE!5baA?Vk@45b%|LUhZ+&9|`OeZSd<_~{f_iPLIp9|$$ z8^pF{GPni(yb)*nao)Gx_k`-d>ApE#VEX9y>-IO=F>|Fiy?-l{bM=6%NyGsUt;O3S z4)2{GS8Td-T0i%LMt#nR11|G8tjhN$zkb?QVCp0#vFUw5>AFqlgWGg}|N8xDi@CYE z`Sy=_U#IPn&Hwu2@t(Us3QPC=eO_EwT3uVCcev2b`ThF0hw|RXPmekf^K8f7W5oyF zKAX+PJ>$aq~{P9IqpT}C#wDzJbYDcrq;TjBjUgjxtxu!lJ0;90i|8JijusKb?zc4Ry_ScoC?&n7Bw)m$R z)BDu)_8tA#y59~xQezS`Sa?eFip_+ceZSs)`M`bWXN{fVmM34A7nn}_ZoJWc|KAm* zf*W>BG>tgW^6Je$;rALczE9tqM!Ns!3}1ifYQ#PLjh_$9HWy!=x;y)f#MA~>pPaUG zk$X%3{aecaFzduNA;18IP&Vvzx8)SH`!T>8h?AaZ2uwA#j9oh-QD(q z&$&9WP??c?#zFDrPxA_QmcN+sbW(xo{As}_R;@E`yjgPJ@7~$7x%}HdpT2hGaeuJn z!%I5(`I2${)Av{IopJj%)4nk2eY}=2MbBQ=A3pc_y)FOtqxVfB4*1N=*m&;h(H|WT zU5l@JpI&(Km!PlM?6lcz32x8t=gHl>@ajuI|DM>o6F2R`=hy!JEcfT;p0v5uskXoF zB!`ThYWRnJutq@;8b(v-JFlp5BhcgWtF zzDn=d((1DhSKhWd-|Tuhfzeoc|Bwg}7LkL}ON z1?`AhernU~HHz)sLOP{&I!$ccFP`i<`s?FU_q%Vde>8I`-dZN=E4F(1K_)Ay%J?0SWt97=Y+$1g*p0S~!?_Bhn_`7KbokID1r%5%43T*XW94L%Wwx(<~*-^;cIjUvN+Lb!WDO-Cs?dG@*Qfqk8 znk(9GId}G+_N9wY899m79JY%%(A2YM_wS|GW#VSI*F{*Z>@LjvcIc6`lum-9+CA~t zwTHcy^K4(J=N2Kr$Q?0ZSCP%7p8SP7=LaB$^s6j72?y2kHfk+T_-b9BFZHwT;*0wq`wnl-v~1OR z;c$RSY)w(cQX6}@mxC%ox}P)67uwL!`n$O7|4Fgc zpGr6Ea_wHQ)lBrd?vn2Redb%3x~~-J@|ET%D?v=KKHbTj1kEpn3d) z{qa9~^ zm&IFMocVmOo$vXa|7qI(?LQK}v*;wK+Wia*Jzl%1?&_wdt4kG|u3h4>Y*}O2G_m2R zx=s=MwdHm4dHY`#{P{HPO4I%J`$>j>E^X=A?jF`%@BdFJf$_EB7XPNJUF(8xC}rq+ zrru$FU*L9t>Dt0N_4UWMXVprr3HxHUPRub|^HoyKk@-KqKh|dw+mJK$@~72XO~bBl z;fV4M@T_y0d~}6Q5&N{2pHA*(+W)I;>qOCG&N^-HU+VVn-CWSIcf*fvHtvXNry`T5 zc85KD+I`z?OU9O}Uy|2#QcR?D5+t=w-#)%-yQ0+EouPcox!>n5&bfMkl~?RS_|w_P zvYtnoL=~^DNLO4eu%W?DtLf_6D3-OBSC3Y7i~Uyvt#tXkiX*H)OK{7xAj_KG)$dIr z^clHlxVvtU^6p+>+CJa1rnX($?pj<#40!DV%j%U|IHH2HENgQg`Z0+a^mZkfP8V~` z)|z@-Z0~lNd$kx)QE}w72e(c*yqcAk(qHjr~_I@oenBHsju>zn^c%Ma;RF zz<7S;oH`%jb<>u*E;e0OEw*=awUo{S!>Pf^U+d0n;=Pz*yZX~tzxV4umOiyNi8xTJ zRc{`4HB;}-a@WOQ*L2Ojx3iNCw7MaAtEsa|RDadk`;M#i+{%0pFzpK$T(d2&W5L&s z?J`ma%WT$lPmC4b&~X0h)Z}gH9SchP72DNbKYjBf+%A6p(RUmX2i!|#a(8ZscV<}| zef6e=%YjGspcM~&ixZCSR&2Va`zmLPxR^VW*qc~c_k&&Qc?7qttBmh2tvfX#R(M0g z`d1cQVRy1R7JQwm*j`ZTcj1;PBlowo6E9nXHarq^W?AbUzjqQ>h}_-ZwYzP`R`{esYq za@p-`4mO#th)6zK#(VR)ldEH`x-G@J;Bjm^dMKBX^ORD z_KAfvi}xNnE3{!jdshN$ztpDQ1)-jGPYSH2fW`>@L=SQuGfMdjibgZ%15K78EZQ?p zO(+8|{o$TgsWfap*b?Hh{}PxC}wOI~}c{_8vjow%o8l23To zY;IngX*s9w_gv=-Rc94TzJ4=a{^0m4j))IayAoKdFKt@0;A&rSiO@;_l2UH*tqY7uGz@+&uqzmP^gEwH?xZNihkHS?H?%oRx2lLj2At~wIkMh z|AMPYw%1N^M7;5L-M}Pw{gQe{=$hkEg4r8x^mmzt9r)39X1Ckvsx_e(5;oR~_KF(J zomMHW`+8%T`?8&{hDijo^B*JoOhi>L0E-m}ITB+%)X{afZFT zGxI^vEyt5Wn8aR(3a)ARDruB=VU>z~k%jKbB#wwR zAQxTBKT!b+tX;wzBKo@$SaZ%#C(M*9YeD zRN8=j!NJ)5bme1>2*zr&CmR=piYv!*MCiDKqV7S;iNB7gtJb_@(fPF+q@pJG#9PPg zj;|4OIU~LpKl#Gzyn$)Q*$KCs!j4w0>0{CPwSpsz;k-nVZN}B3CvsSHo`njoVK`>; zOe#k-*U$K=K@>eiaBE6*F6(CFr&BO=oYOe(E~D3 zcKlIqe`K$p`)q44lh|dDskU4G$Zm<6WN%p$Z@1rYCTI;t@5(vXA}Xs59PHm#NEiLs zXY*zDDY?uI67H_atQ%Z(96#fZu5@TvyQ+KQMUIG?bxIM8ZycW% z1ipA>-MdzB!;ck3Tw#9fOm7aK=ZI9^%+}p}Dzo?MZ$pOPj}Bc}d@tDx{ijerKK{tLR<&-YPFY(-+KEukLg<2)k2Xq3>9v!C#o76wwjj8 zuxc|L3ldij=ZuIBJRZ1#DS@lh@RKfM_S?3{z8jblvetY4JCc2tH|O$(w5f+D+ZOJ1 zU|9Bil9jpehHEPxIh|qnqL^~mo{FrgOW*FV$58gJcKi2NHvN1oYYapG z@qy|lh7By%ypj5ru1s>Fmbn7I>UbDrcr0`7e=u&pd%xVF`D;(tF)oI6nK$pMmYPKL zugF-#@E~sL;n&ak^j0b-++Dm*hMD31YMFbnKQ@21QBzB}yQuGRb#`ccoeD#NZ|Y}7 z?*qU5K$(K!Sg82pV;m9l!FlFD$*ZJ00*tR?z*5gX&hm{@xMjwB@}chHsm>d`Vy>|< zJlk~9`xQsTROc!`7Hx(XiOq`H`x#e*!hM6t{>>}BU%k->%_%cP%z_5C#yUxhrc zta+@uTw*g1xaGjZP>^>b@ps#N%Qye_8Jy1C0Btrf9N4r~=hq~wztUhQR`@)fpe(k{ zZ+AS{9S1&xlJ>thHvPt*+1G$lf5G}wi=3|2Fs_Ejz=6N7lHO$eY6t}-Z-!-I;>qfl zS=U(gHHk79EWci|-{H#-#?^g`6IdC(T(V5*-Ohh)!ewh_;p^Ni48LC1+&xsd&NTv* z>=PpInJf9G@kgCEjhK3w)2&yOVS|e9^4DT~pX**72L}biwDnH~Hl^)ba;_E}h77MS w8T~Hh&W~;m-FS?PA!5B%-};%Vr~lNS)6&r4+93Otfq{X+)78&qol`;+0I+R%>i_@% literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_046.png b/example/output_data/primary/primary_046.png new file mode 100644 index 0000000000000000000000000000000000000000..69ec8dcefd17e5d6cd0ed3742d1e41806ea058cf GIT binary patch literal 8573 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_047.png b/example/output_data/primary/primary_047.png new file mode 100644 index 0000000000000000000000000000000000000000..d1aca8b4f0325c919ef7267ab045c94f41a39d16 GIT binary patch literal 7449 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=A@-JzX3_D(1Ysn_Hx0xrp_`Yw^A7gVvr|HPv#j(SCVO=3@<>0d@0*11FbAC5Ik2 zDShqbk?*;WiNV46zxj6t28L~J2bdT#e5gV!Rr@Klfq~)HiuTvD8(0}W%$oJ&^_#*; z|DQ>6G8|yLa`@}p-?_YE3vZM@hK9eZe%^~J&5a9dW@UI2Y#Sqg zrz(+ySBznUzG->?&P+#;u)A%Hd&b&xAmwjYOYVg@YuoB43lGnXzMR0wa69Dlhlgj@ zg5+~oO4e8uXG`fYBv@z7vzoKhl#!buV*jk^eCc^-6VEdo*mZReOu^i&S+eKu%yNCl zaNyS!6WcjEO+og`nJ$(&cV`wGH$y~w)sAypz8(?)nRYWv&Gy+cR*;IAuLZG=*`>v}vv*67ghi66$Z(wM6c~$3C z!Lw^J-*^~&R;Lw06)X$feB&K zGUsdrdBqrVVtWtIR9|+GsX=#jp~Yt&79EBgi=^6(&!0#<&#=MNlrMeWOg3(YZHtaQ zJj0zh(V8L0vG?#yahGORhU~D%1qh6LYN z4_9rCGT{|tSmW4xEz1?;rW94a^f*OcF$SH`-orD)y_#7Wyn`PXJeztsf$_kkD;9Gq znOSrgBATSyjq^JW&tpu;Gv!OaC&4SmaAxVThi9ZyCt5R{SqNf*T&#K3VooKyNd$wz z)T$k~suDkgnA@a|-+9x+#?5dngg<=k)pa1>@|Z@gmc5+7=-{o&m+scg%5e6I#hjTc zQaTJ3An*SK39VmIXkl#65y9}GN2=YpcrwWL6(H7hHf{#F(8mR7a!C`d8EilSVFL>3 z?;tY{nnW-Zc-zM0?mgfjrNgiz#VnG))=WX_#gVG_ac#=H0MOv$+otOx8srk=ETBiZnFb)kjvWRT8SQ@->x zF|nP@8+<`5GbtU0ZJ^*d%|1d4S68jH!4W!FkD;d zmVGoSa|1)fbfI?R%@rV_#m63=S<}SE-S8A-#p*=|nG$Y-T=I$|fhG!s8n7KEz9;kWsFzYp|nOigKfiGDy z#fO(=ZeW-ZW*f6LEN2EAcSGitjI}p-dBqqWYZY1;?_PY6DFJNobdv~%E#Z#~(#m`f zFg-ApPw(&Fy?(#?Pw};)yHyhyKkPYuIcNVRcI~yI*3UPjGtB!uv5xV#>O(G*2!`3g za(l|Zq#t;#vV3vQyS-{}=CE-mc%?r0`=p9t*Y`i~PVGJ4cz%ERe~)HXbIynj)!Xke zmHk?tQu*QD#m#TeFI~v^;@WGUh0nHh{QdhV+xqW*-WZ_`3D@g>pRZ4>kDAu_ee%<7 z_SvDA|6Bi^{`Q~TLdNV34P~dAzxOT6sQ(wc^ZWO6pLec%b|vcPclQ045)Q^q$u_s2 zRHQ!l&&yBBS7U1DHorS%`}X{=s~Kw(6d1XuEwZV2zryo(@TBwB_Dj6$-iTCwExoZs zO1kaPWEPzY7s(3y$dk9`PhER3$;vcJyQ0xFBFDM%!@Y@H?F(W(_y29$8umemSM0Gi z^Luse%=&GI%y?z4%n)jEGl|HkFMBVsq|b46cl}N4FBAXm_uMHpOJKvabv%3K_uT&% z!)@PbKRK~CYfG2`6XWa9rw6OuZ^^29Q^`*fXqO`SQN^|6}oQ5?r=3he=l0Z~VrdaPrl|SGK}#-|wI0JoN5Z?OXl> zziN(7QSf^XJWwy-V+3UM2T$=d$<<|H{5`N7(R+6bJ}FtJ zutAGS?0`ttuMHtZSxf3Z*H!3kuv*5!cr561E!PK$HLsfQ|CT&{|A1HK28O6r?XN3; zo0QxQ>0Id;Vadq7pmo-Dr>i^rIl?y-F^L`6oaHy4eaH5Q+K&D&ifgk!L>c!1EhVZM0zupKd%@l9T^5H$?ma&0BF7R?5*N0g}6}3CX%p4Ce?N}AqrrjPxY?@2YUbiAR$E4D%3^s+y5TyRpBfSJz$ zrfuux)_HS;xtC?P`wDMpc)Mz5dF@r*vh4P=o7uQ;%$xP|didQS{dEV_GB-55T@iWB zYQyUD?alv&**DlUE_XsSJTyrcW)(@>lCq1TR+b>?l#j$so>@f&QdxFH?w}R zz4%e#>*d3H$d5DPz|41VKF;6Cc5!v&^O6TUAGa+!@Qx$mz@{r}>?2gmvfJkhZ)kYB z!cv!G{pP+Wre7a%z3FRUJ+nSddTnUYt+jXC7H!D3bLBX*T5etT?~(_)heQQ<#SEs; z3eFCFF6|aFO@iBj!u$!0Pe)WX!EIJ8MUkmO=32cnE zE;uHlXfSuJFQ?qq8B#3!E+#NOUTvxS?_HX#XSM1wwnljtorD|lpLj(8x^#0SI^@H`-MF;DzV@UTAWO{qG`}MUcU$ReavwF)3 zs`0mk>aUAV*AV-eYv4tzg8Z!dT-G1)xecwPa6Mi z(Hm=JB|Ms0ZPus#&Ytw<8lR10GpkMh>$jnMcQDy_9AKIkyy34;OrI!12OMXr?(z|b1XJQloecukguaCG4CTKc6D7^m9>f2Q3 zzFl9Bri41KK9cwLz-b>rCgF&{zl6iGA3$UPZos@};l)udO$?6P;T>;0w| zGKcr-N;X{Nh;UGTpWeUwoBsW$Uk`jO-0`owH2lB{7M%xO=jTYRob<3U^Tp@+7g8f0 z{MuEacc6nsCt=1UY2${c1#i`)PPFQMXBI!uA~Thl=d*gaQHW*rorJ%k+_Aqj59}}8 zreI*n$eoe!4T4GuF(mX6WDeUDQB{ky~QflXD^u`}K94J?*z_-yF}N zEVQ9Pd)MaUPp3bhS6{36dcEG><5oHeK}=#Fc1+S%z3O!>zSOvn@rLYe69(SWV*Urq zzt0e2QCohHDK3QXdfqX^J0AphZ)M&ru%Y4j)EJ%3TIv1b+y1SRS$DT5nW4=408`wC z2VcYAUyNhi42ptXn~&G;vwu@`_^iIq`ZKl+3Ga1^*yW0Cbatv#{@(TZ2kh zu@AdX+k7p3n_S7w8T+*0ZJG@8hH56U3m2H2rhVgzU|{5~ICuR1l9IpcRW(6ISD#k; zcZyTz{KvHmz4xuFk$L~#{Zn0_=wIualJ(N%Ddtmud{NlI!6a62*xiqN*1diEgJblH z?6*a{|NluhR`zrF^voKWx@RHw{14a|xpzENN>Kf~v+nD?=wlBnkLOqK|M6)?<7$^` zR-Lv6);k5N395gsk6q1`dMERvyk@2$^Ym|A5dt86ZU=sO)NA>jeOUkM!*siSIj0YN z6>Ya-?p91-G{3_U;rZL3_>bXw7Cm-rW^N^r7-xj(-;I{Ztg{~X|J5zvowJf!;@dCb0vNEeDEUJ+wOd=+nDLQJ;)+7I=>|LHWSb3`1--u2~j%lntj*FtnM*u{JfFvVS8%5O9OWq9ed&boJnd#~<4 zocwxyL#x1shO(?*6N+;-pE_Z`ehGhh>67`)1``@sZ5HrU|GNKW?WG%zuWgsFm1Yog zIlz?nBJTgUl}*>)?9;1btX5B8eEiBN?t<3LpTe!%nWj!)txlKMNszkxFx*pq%e~9` zUH13nSK0imom^<4^kya-_l&UV`z~7LZT^t6+VuCY)tcXzFkEvx!1OHmbM3DW+S2i> zS>Lp3IwjP_*2y&&+i*SqBr)&vQ(rS_RVWX5FGn1k~;BMy85rPXQ49lLTiwP@e4X5^08?z$zM zN%X^9e?g|#g)@_%NF^*Zi8!!p&(VkH4m`@-&|tmm@YXXHZQ8q3>YvH69LQx7V{k}j z65C)GD;B8W3hF0Oq$eT{ard`83*b( zBM$7UbvwW$=6-||$nGq-{D&m!xX(>=)y5#o&8H>On;vd(A(yF6E_A-?8`iS3R>wgNdf z8P0e#v*t|Jm2QyyYyO>q!7Z@()$`XihZ(+kHnaYD^!ZKU%xr=4Kc^p+U&xU&xq&q& z+;=|z>ph1VzPTS@+O}4$a(=bIfqNVg2fjsq;PU~uDcrhQeY_4ZeRJ$)_3=2s#HLZq z|DY07Q7AET|8O<`&Twm`VJL@>(*dS$M?(}17#X>5Os^_rm1t~WedFJ|(kUT?No<4v zGOk8J&WHncSG%#kM}3T?+OiDg*PyqyQ(tZ z(3fM6%K@exA^PhWm^mXDu3!1`d)2kdcE&Z6{RNrsd@{F-|I2(G9pirH z2vJ7viUZGYJ~q0p@a*DJ{z&n60<`t@Noi%8X%$q;wkGuN?lWT)X({ zSu>#oRu-KG_p67$D*s*gp23_Wg2DO9;jcGR7-JH7#SR3R{@qpY{t6_1fO*&Eh&;g0Bz9nRmY?G4Ggd;NcyAEPYSDR6&!W>1mL;>A zSw(O|LwiYj|Nk?l9i=anQW%-U9ExN86jz_K5=u~G5<4KV>x<%R{}!Daij3R|IsnZ!OUcvqln+?V(?>&;YFYmm%JwV&ei4O)7I zH!v)_cJxvC4GTu@1in~5#nZcVZpbilC-~JT$BN}lXkaziE~UtA=5~Nd?n~vj9cN5C z-mZFid(HQV>8#QU35+_f;;%O)D6{A^EVW#B`d8N`fiSNFOc9G_*=5|+=MM8cz!b4c z?_{)(x-iHMl)`)2fDQz zc|J5ezU?~w^89ByexCQ!YTXvI8edFc%<&b^6+7c|fa%7nSx@5EoNbcih+v4m<~p0z zSYQLgw*_vqS%rl*Fnn9oZN{zkD7fVS!}EHr{bw!s;=(R%kL=`cImBTS!BBnW>2JLc zrRNSF_{I^zP#t!eeXYG=E(b4X1Vi=prTmd%2c3@)f;>MdCpq~8Y_2+;2?5_`-TWnxp%gEjE@yeIpYx8fc zm=Y_vfk7gCx?Rf66;os@z5kbUHL%OxH`?{3KIxEyYV8HDU#=hT<|sE_%m9rWh|jl3 z`OKoj@a&@Ng`~|O#?`0KukocG`{=;TB*t($p!n7;#|ueMS#%htEp@w)^p!;?0g~n# zV^;`niO^-_Zb)7IQ*O(vIn9m7IU*R=IQz&1vW6;n5Nexwpn-s!;NJihTsN<8{71n z#3qA8+CdDE$aFpX=CHYiHaU|TSobVAW6MwxH$C`*m*4DZ(<<8zZv&Zo_YQNzwp}&% zw_N$6$omIWW+oWEy7{>OOXBPJKYN?N<4C=%ANM#MU}}ioRl^^}H~pC-lNiIFW!~~z zWc1E9v*<8LEIRh^(w|qlwS4Rn4}NUBxb%Ov?VAWs`7J{KEkD?UMzdU}U$$D?Kf_L? zla0Hgi;er8mgUx{ZIw4vdBqsETsvyUZ>^rdcpzfepF7VSZ`@)HZaET$SQRI#K!FwxajIF z(9p1s>-6_)r@4Myz4Rc{yaflFPELss+3zH!!w|7aZ(CJ_A|rRjq37U2FCl){7su0% zmscw!Fdn#7axqKyPJJ;y14Bj7^vko>OtQ<_yIgNi(bF9QuyuF|`{T;TuH>K$IcN@L1mGmnWVerS33rf_B^&jE#4 zzu=DP54)a$w6ml>_-oHR|Guq7oBO=u>sfRde)vjO*k_72*yZ2(U;g-?a`wtR-8%dE zPJ2w{ld>^A!F@80eCwlDeidu@qg-upD&ljB3f<7jvB`d7Uxc=pWik#ESe z{eP`?+tMZc(W-~8$ufz3Xvxl(w!Z7IoM(@{>+j;%)p>W@)2Dt()E3;L2TC>H?-_}S zZ8~+}cjq_ud4Y?r?ovo#WVZQKW~h)dwekB_`wca!%fqsdxBGEN94LKy>ump$JD%$G zyJBk9_x_5yK7W?WZ|3L#zWsgmhPNVDt0o+bn%ek%_7;29pL@RYdhW8{x$D8-SJ{la z12^r~bYbK^7QlATKWx*t~{#;z3tzgpXn0Y$$UDrh%4&k zvnXB0?x&i}kRhofX1os0sKT@d`6+-LbAAlzMB72L4Jp5ef(DLT(8=G|soz5Ao=_IJz-I<6Yo|4^G8C+QvUGzgcpAm1 zf-CR?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+%`Us;CB}B){N8tag5+kNRxVCWc_;7TIPKsw#S7W*mo@5|T!S!j)VR3=H2_-+lY}gEu2L!-Fu>|4yNko;>|3xyF$PlyWS<3cTBCex zuC;Py=VrJu|JGH`U7^cC`hN!+S3*=K+|CM@zXDaUY}WFU)qWQbGBIphT=uo|?yBID z4GaxmSI=AuTe2h>B}V(*mIip019KO@JD=GfV6~#I%TMx2{fw8aHiW z+El3GpI6qc+W|4|LyhU|mk_7hxW9dM4C=W4(9JKQuK$u1UVZ^$+zh|7@1P34uZ+E$ z39;{indz?3bdZ;(ua3RC_SZx{F@_JjrS7iM28k`dy6#n2tS>t^!;e*N+h6%vMKCnv zT|H8=fg$01R>^8P2X=0TZ_CO;x4%jRiRovRte)q>&dsoG4M=PyNUS@nWOdq?c)MNI z^^>=}tF!(Y!;o+?E4*}d+V@G9p5C7H#Q%H7NyC)AoUdzd$PiRCxo82n=CnpKVtb5$E$Cd8lJDdxHhWsHPbcArK@+vG8pW= z6?%8o)fs9DbA#AIw{tVB3tt?)HK?CE;`x+yugVw?ly6o0G&Dg7NnG(7|t};u%$@qGT(TZKM3~K^=^R6CStDi78c-N}itOtZZf${cG z8Phe*)PU063^Sa2^RDvcTEpa(udI6&_V$_`GgN+uYj2*YC(D}qQ$f}jc)eYfC(5k< z^ThN03obmfopDv8dDU&!4gRLPLg##)H0iv)qoU=X?Ehhj||zb!&H<_Ff9TtJjdaD)#EyM{Lvei}Yh<%eKeK z7r0c1fr24H&U9DkowwgMb9na%&0ks)x}E!hA;_mQPMF*_nIg0Q=l32V`PE>PbF)fT zS9HAmeo!k`wtV}oCGQVGf)<<%K05T@&)9NAqc9KT`-Z)%F0Or)IdAvm>dwGNlfWSy z9lCo}^wG&@%U9016uS6GswT*TYeIYTL^nsB+X}LO`Wle^5vy*6-qjLIuw=|$aYUn# z_tb({WsJouFRo20oF=)U%`3cD==x%i!ip(ig;_rtv)3HaDC`9*+`j7K+9c6y;v3q$ zdW5d81F5rEUKYB&OEj|lfRt9OsaMQ?Q2cF(H{BJw=2{ukwTRBZN7q0uJXi*b!i`0@ zc_W-vN~fXp@*-0{%_Xf zU2EgI^QYVag>3hHP?|oN!m`Hl>*7P#h4+VlDxFyK|Lg^GuXmwrq1&_XXO*me;K;JZ zRKs%bUuVfb`|_vUSzQv^aeo^q_$o9Qvva-b?)_U>@ApVr^}BYn){*tmy?LTG6C1Xs zsovMWIeE^%v~aeoAmesv9np^lC3%~<4O>N3x5rM{RRWe^3+wCn)b=Zf2bm%lSY%N{7IygqT@JH0&^}nxw?46W7#c{65k@>$YZvWuhXSyqNg9FpG zdsBR>9bbVG$DP$BUzZ8|zwCbVm=nZ^X$@P`RWG-#{g|!3EB4NMo>w;o;wPKMwODLx zoDjM=npImdp)lan?{ECUd)(tockc*)`6~K*_oYeKY=3N5S^L}ln*FwG4WJCbx>_mW zW9-SNx9xqt)^+BIm;X4if5KFir}>|j@4vrm!qsb{kFrZvCmdzbsS7K*4Kgo3zI6AG zQ1K1tG<8qD{^VQ(^3s}l4M(4Ph3DV>_fYV7z@{_#Q_eg%<@zo);5pw%kZ%l`#I|e3 z)?QKi8Qr%u@1Fa1E;IK7Nm8n(Iij7HuHF@EZ6qVQ zFKyHQJ4P#}xBa+p7g@SG;WCTPvhYoNHeA(iUUhq`w} zrz|>htDk(lZSS+NBy@ZB(_j6Yr#Z7{v#B1h|NNXIVnZd9*!kd3cizfF(gUj(pX{0^ zFBw-q`SE_qlMnfim)H8U>fEql?5>=0X7k^}BA{F&w(N<-hIt#Z_SFB}F7t2Q|Gs;l z?x?RWVBP)U{vGxMep_qeSAUw8oDo@cBWv-jnzvNgOTMMSW`xo8En0hjC^>w$c;k&A|N?w-vzB&Ki|EI6))rIF}tV8Wf z7kcs4pFbq}=HBwzx0CW!=l?vBZnry1tiUJukNMP^Wo7?;5C7lSfAIbJ+BvIt*Vd@b zzx%drz5UnyRx76eyBqhp#@u}S*?VgaCfRyT+YR=|eYX91cWdviW3~WX8n`wa-wQWP3-os)7B>+NxA!Qac@>q?)9Um{^aY&Ffv<3tcgFlYg_#c zr#ddGE{?cox;mo#79zqNpsha)1#`()Mj`W@ktSL~aAuid@>M0YP({^bqdzo|JenKoJ(6jsvZ*kpv>4^t0lP2Pct?)bo=Tj_kXSK zKUlGW-@Ek7myhcwzup!8_cmwv0e%)84Z&@7L2RWH@2;ElWby6Nv?sL%`~Q7-I=yWD zuI)nW8t!vM7=(PX%~55#uDNve=JMUU`Zp9auKxE4q{6F3`#}+j;f8h7UxhWr23pZ`4n>EjPuf7<-7n}7HB*}wPSJ$tt8+U+;&51ws18{N6#>xAgP zXACs%3T?1E^)UOtt=X??;dOWJ+h-tGNUYxtv68INzhbz8$=E>FZypHttT z*S(DEWeV#oc>3&_*~zm~Iu+Z5Zrk6<{j#w%OZM9ScDtgO8&mV%UcFt&8~*=^Q1-fp zlYh*=Gah)iMdonGNyD74SCxKp_tcryNZ$EhVOgJ+klFrAHO6&EQ@R#^)w}uZd(w74 z+F8HRx@l*QC?yp6)cZ zirB!W`t8=PE9rjei~CjHn`YiE-~OqpX3f62Kbq!LD!vPn`*O#$b((kl_gUZ53t4m` zW(y_0R$tB(c2d!&ckY{*-n9xTQ`v39Ga6@eMr=q^y?;1t)BAj-(85Y+Ld4bzJmG#e%n~>(_ql?@hP%S+72ir@&rT z=f>nqS9SF#*?;f6X1*xP?@jsF+v1Ed?gyG|wQu^}*!4Tb;dcV#WpLN)%!;Q5s?{eI zWA;9sV5}E8Ym3U{KQk=u1YTU%d7zd>=fQ%f&o_joS*_E|aAWjOn`r$Z_ViEgp!cP} z*&DPuA`YC7I@i87W#{W{C2JcbBcJfySyocIXJ_W@hZe`GWA2KqYt#QSPk6Z$Q;ZKg z_YPm_E0^xppH^JF#YR16s*Jf!l@2iX^ZnY`< z-9GF6^dpQB0*u@hYo=vxuV3N$??{9|go(1#gUYCNxBn$paGmqs*QVXTD!iega?77R zf1M?5{~NapsKqd9D16`r#e?D;LRjI%J-RU(ck94INmL)F^OkjI%S9UJvUF7ax(+-D)*6+UMx93Xi?`FQ> z*}ZO!w=KH`A|{;w!)>;;`h{-$-gT2M&wQ?WJVr&Bkvq|a!{+A9ccGb{wf=UezH48* z^2f%r=Ip}Rq3>+B?LW-C>-*6L*~hL=~@ z@tyxweLivRmG#%RRqlOj8|{~G!)3tC$UVdD?W_Fszkh%C1}mPACYfgxh~!x zeSbmx+<)n(#Mx%_Hn7%&7Cl?D-+f=E^d7?lzapDiWz>u3TbfP2SA4W;RW)yU!2ZW) zqf8Dqxc-Q@D~?!l>%P|?16~82s8DB7LX+v~W}!1Al2m^HsL~EfnwdWPBJ7`e@E=wS6XiM z*CqNm^RK+C=WM99Etg+ow#qp*pmgtp-M6lW_WxTKSR5?A`l##t#+$n7i!Yk3+H168 zc~khOuR&>#*SBxgx_JU*_T;y({!Qd9`O>g8%I|>H^4_fVJnwEtHLYC{d-u+Z_fop$ zxyP=*e;vB(_iVl;2ZD6%6Xsq%cgMd+I&%80t9N_;)m@&?HY3JX?T^jp8|(htG+M4P zPx!k8WXdYnZ)cXKv@hPDy`{!>_6J?@zYnLl%km%i8dvlyecxZr=3nUr`%AyG>c0!z zZ6)(}>yPavm;B{D7cU6iee3_uX{YzS+4MdC=FJ?j85hi~BerKOzNOu~>h)36tnl7{ z>k1B@uQq+YyZ-OjkmEWP?DKrsU(12Ku3>5WYxQQCvtDz5SZL{L)=%DE_2X-G-MfEt zf4Nkj{m8!L-|KqYHnEjFJEk^#T&%5*DedQ@NZ#DL+XUeztUG1;) z*nHT3v$s?J{&}CgB`zOidZ(VC8!LIme(~|B@YeM&udb8&>$|$F^vCn4ul|N8e|E}t|GB?+z8@C9Tk`f`-QMu> z-xdCGfA?_uIJ0MWpIY#$YHoPam+u^^>TdOwZ}x94zHR*F{ZG4JUsv|;J@431ZMoe` z?tu}gBjR}Xan$--p^NutUS0Rk;#c*C;@ie5$2Wvu`Wrj_$=>P>Q`bLS^*!mc&Vw>0 zG4|Ae?c27xynR*hCEVX`a`qLS^}owcDt(`%B7ZWv{KC??b@#fvC78AgZ}<@@d8c05 z_TH}F-mj~sO8m8TI{DeX{`!i=zZM@n9#?Chmt>`qz*sJ@VMnawm7T|Xx2|@pzq~4T zZt<7$m8(Bpc#-`6Nk_l|ro87mPI;iFG~3sEug&`&|Nrni_U)?8|CWUoKaH&C4)|Q! z@^|&c^V9U_tBdVqzT?N<{ama0SM>GQcUFGab*m57iv0HCz0iEiHSYP_YZ8}lIlODl z_3bkM7wXwYGI=j;K3cpr@aAJ%V7VZakSfzU{eKq2*70&s=%m>H5t6-Tl`ON4Dsm zeEs22o0E8fG$Xg4WWV_HcSTp%txG(7-d*eGz5{=kdq0}e;}q`sZ`zVl{&{=(68~?k zxO|VFfk`Z8$+PO|uP=5VZGWG6etq-qZ7Ci>c9TAt|Gd2SK>u|`9~PYlVN7B%t4m7v z#9p$!|Ks;{-J9=Uyf^=AwYutjcaPn>x;=b}N(qeHg*H5hTe|u$+k>^gzZw+G-TlO0 zwkG#iOYsjyy_{bKu{3+z7F zHpE^&*t9h3W_<*t7bw*S%`K$E@(}U{k4i^oJyU9gJN51?!MUaB>O>BRr%_^S5ww!tDJ}esm;;b@@I2X?du+n#MfT? z;*O-k0>KMO5vJuA2&;k?(gw|RFrt@wMTb#u0w1nW7O4X2Kr_ihoJF|mPF zW{S=B-B$vmRB#lstnV8&B;FR*BoS8 zmOPv7LAmbp?{{|{vDh6Wye@0syX4X=Ua+G$rN?3g_J-mK> z^ZK{qo4$X)|GA;pxxUI!lW#{~1FMZ&{lr(nulW1<_oqp$Idz(EKpSINGf4joH@81;(frO_lIuADL&D?O+U7qDY zF=xbq$C0O4-t;uE+MHiG;p@LIiy0~`7`ZFfedMgFPjcbN>1$v;^V-x&Y=b3}n1Q__ z_YDa~?g%zT?i&Kvl~|@dwmtq@`kG`v^8-I7u?;f1?S9iHu&$ZYz^dcjJ%M%2Jky8+ zpSH+2U5lP%^m-!09hU=4(^fvcaZ+ou94DxonXogekNf`VHSSCWqS+f7Qdh_RJ+W}{ z)ii6NhHlP?1D~$0dLx(t_PUJ&P(Ye*k(=IZ<+UyVM73u*akh2(<+$6 zHrRm}8BAgu{6LHdCb121rtK3#pWE^@7&3B4Y`0p)z^#zL_&VHOG$D;iYy+?9$@v_S z2b4G>4wUV2JHaI8cz|h}>j@??hXYL8+)ps2sUpJB_sH=H#BI^D>vr+$5sn_dQ_dn~GYW-1p&KzL< z`3Hag#P7oWy!=1!^iTi$xJj%)SypF8@XQ~Tdy5}Fy>~r#vHpwZD?6Y6eLFwi-{$$9 z>X=fO@4w#)2b^HaQ%KmToBHVaS2?i=y_$Rev9qeDbPihWi#p*Wyu4n%q&9F~!!@RXVfA-8f za42}L<>U{gdwiWYbv1+*|LQsPap82wzs5W6@A};&ej&2{fR?cRdi4zl^xJgjUw^V# zb^YP~$)YT)pGd50+r8_0%=VWVl2?Kcu8z;S|6l6Hp7-g3)42D4y7c_(HL(c4xwR#y zW=>v_@cZAh-~SWu7w51})v*h_B4aoESmcJdpH{gc)k|0Zl|SiTvO7Wj-|uVtv&8F` z9$?~`x|9Eb_~DnS`(OUKZ}ZJ~d2iOIt+!Px4yOIxK26VVLyBs*AM;~*75m~J3)kEI z52$-vHuaCpo@4RsI+J?c8l|_+iIdzXG+i&cVj8$1n{Qe6=-2be`>fq635>VHp4l~6 zgX-*cQpSgrI3o_2U6ncHZvFXpcKrLBZl)Xeaf`VeU{bqc^g6P|wEbfI$;6Ut>kV~( zmPsD<%>p$ntF$U4jSoFx(Mhq&D1chrIRD#fJu~`z37_Qx6N1cZ=abWBk2bkt9FDpIu?o#%?^#`+r_u1XP0(QM8 zXT*WxD>lzInVKFCOx~~BY|ORO6&f4`ij3S9dnW0{T=m)Y;?@1ve%~j3@P#^Eog?Bv za_y53y)Tx|f4rBs?(@0Uh;^nX=78P*M>&D9|Krb3f3NG?=SGw+owfe{ngmWzOMSsD zwGKqqa)n=0MoqZUzIDX?MpWOn(%er>+<^j-?9^OZ>>Nb+R*UQHc7nvAlEd|XmIWIj)r$r@6BXj;GO8{ z;uykeb9{R29sN6+Tke16ir5D>*!q^6(*dS;9}cG$9`mwpS@V7SX?qXvl647h!G@aO zdMmV{p>xWgAD%bL*WbH0xxcI~`6B0fc3zzb>8mNh$!?6?Ga`QP>;7HvH+28OjF)w` z_aaK(9DD7^tPKvcQq|iYpossnaMc#)8&!XQR84$twn}w>yw0yRb_c#Lm*(@go^meX zD>$n4a-=yy<4R$C4_`h0`XMp=ysf@D+nW1nT~P@eBEjKn+$YJZlVGL0cxi<0$=3__ zJP}xD$In0aPeS$Cso5L!YBx<_-F?Z;wDQ+4Jx1<|d9#w2ulk=Ltyd)fTy-YL3@=bv zU*X(7QD8&E^Q@oy-o4UYUS55nf=O;|Z`S&fugCJHH?Z0`oW7nd@bAMG?)h9FLUKbU zuRhkpBxbPR>^mbv%mPryI7@sFi%!DMI$8dGPd2r_d)9M+d268Wr~Q(A%r}-4-Jia{ zWV_jquSer6&cA2&@n`4W;e1+lck{fmuVK6=uM2!FdSuw}95fPDe01x4#%(?anB*S3 ze^9sc-|74H^;`!gaYh_4y1J8}0n{5V7I8$%8_TmF&}RWfN&kI`Eowid7ds_fWYI~e zeYJu~r>B8+O>nR4`vXZkL-;-@=(blTR^Ex;^Q=O1uKnHU$oZ@~4GpY5OU``Ww*IHo zsx&K}21RA32Y$Ktwr|g6-r&F_w!wG4WgkD|Jf8zh*WQ-CV`li_cYtZx)lF+k1H|?+ z8w+e`VE_4h&-SX9dCOlEFoO8%8lU%;&V9eO@vqQ^hPM@#h2A}!jmw2MG~}+f^wGB8 zv}SAKfn}T#2fkh9h&&L?8F9ewicER!`pt5j8eOS&6$_-&rJ2+@BN)DCY_#M4 z;dX#&hSO=qjJ<9bm_AK9%*E6oJ@*I4&zhIlG&iJT+3?X{adwl+kI}%FI=&hb@!rX);llS3rxRUvd>SKU9)l4W41L`QJ@*Rg2ma) z*Rq#%$?S^Azgz3bZT5QqPJV{6)iy77UXNM!Y}WPM$Lw+Ie^z?OST83);3 zCTx^_>Uh33D&gnB`|Nw)nV$da#-42?A1k^g!I(wooHl>ex&xa8)9tL<6kjiWX2CDK zp)Mq;ghM*X<%iEx$Mdn#36=XF?OYbXUH0tx=CDcM)f8e@AAKQUmU5R7WHA$W%!>D6 zrN-+n{bkNBmO1UVMdtsXUvFjax%V@7fB))!q3CFM+~+%6S*K;keV_IG(6p&ChYn2l zO!%Kr^6+(`u}IX;Ew3~J0ER~+SkY5c(h1Nv0(S4$5IQe{+%tB*R}q;a$U@ii1&9c zbQed;Ksv#0IEl@Z6%hcfgKPOI+zjSi`wEX*D{rCATpIhweCvI{4b4Qz%xq!ibUk$4%ettLk!sMsq;|OpM$X zYoG1t_?!EsT6}Hb|CftX6T9zxU-9I}_h05^UG1Hm5eLdm+gl$U?sY!?HGErUMC+xy zb+YW{5nPvwh)o=)dCp>f<&VF=XJDnrE`f5>x)b;*W`{ElO+s>4GYzVW8 z*ideI|9ImC?Tc5Nq+cW)jJqmRzo)9V;Ap1q{oPTfyP`gDGje}hcFbbJ>#Z_PVfB57 zqI>usvb(ixP&Yl+=(GID4}o(R4mR1YFyu?A(iJ;;SdvLBC$hItq5pc3jQqDm?+Z!K zdpHtTXZ0}8^zVEvzbV@)VuPvavBop&UBkOU0|9GSY~;2+9rox~`uB$(hB`J7l(p3reLjj#16<054X7vt9mf={wB|_x9 z7DvPe71Lvl1)XBnM>l7BIjmY_9IzJ=^7WWRtd@KTw8tYW+TJ(jKaT%)de?1%$IuX&`=F>aI>V~ zCOweK{(z(!3q@I-YoK6!FfmG}YyO0Wqnkhuu?g;;`$#>(ljds=UOy+*>v3Xr?1uWwrYT3$-< zQv`@NCv4Nrj|=(4`U8_?I1ZeTGTW^YcOWSWBo(tfwb=Tow4l*ksmBfs%K|sOdM*Dd zp>RK#cXiXNb<_C7wy)mEZOw2#c+;%c@>~&jmL0PYXsDc`^Y2$Xli2l@7q>DcSbB-= zyxMFU5wi>wU^@P%m9|%1IQXa>WWyTwlW$^mWp&Q2E-X`EczxOE_g8*aoqZr5B>as^ z+x>5$pkh2Ih&IHk`b&Z=2c?Ar-?rMM2JUIt3O3`7|7qv)E_01FhP=?Ct6%w9*Q{NAaVt}U=F~sC zK#q(Kef-9Op`vA4Jjju^7J-bcST;#NR+ll`JFAD8F~Lvuxi0Nr(?3LCS^06?OrS5~ud7kHo z$St!ihd4CnUNO`$c{XMcn|FWS0d?l3SguoOFahH!9jaMW<5bTBY5 za29w(7BevL9RXp+soH$f3=9eko-U3d6?5L+&8}K~V$<4(53R21w^tWcJt_z;^PaL< zeQWfhzsxh7G6g)mPTc;!u6=6SH2sL{4^JrkoKPa#@NLGDe9!oq{mkc$3-2>d{jL6; zk-?(F^Vj6x3Lk`ozsm+#GKpPS?~kqkQCg|AT~2&(z=dtk0c#2WF6PMge=n8;~tROhy-2n8Yqf3Flv6m>|i>ozV%hg;gPe zQP=RILaep0qGSdGBXBefhRO%1GDn%K%2G}suq8N3`l*k*yWBtAMT$-o6-C4jUzazr?A`?DJyl+!M&nt@4Ocnvgj-bGugrHu#qEz zVS;p`WCkB2_ll{V=BW%CB8=QCz%j$BoWN*mbW!B4kZ_}91`i|m3PD?Ih5!>LF@`58 zN;=HEN+9`<%Xk<-Dz_R6u47nGz@oFjOik)ebkd`LEK)89n6jLktr z32tb(HKW3rt>KX1hK5-)K>lZB5(^L(=DoPqP;gcw8%X%VdS-@Dg#<_Bln8dPV;1j6)cS0 zD;hxwKvXe-(bV7~&s`0vj48fn!FINi4ufxc9%jLKd9`DQfpR7#BFP=qw0PJ0!{w($&B^<&;Zv z^=h9x+Z`TrL^!MjrRFTb4Ga%*TGAI(f)(CtVO$WzqO-sStfi-cb;=1B;gZunEE!-k zUB0|vaJb45!BC(k{7~`*10%P_#7^@>h7}Tw+#0>00GO(rz_`@#;)8oe!r%2TfPzv= z>JHj77ffJ<<_QcdWEi|NcK zu6#>m|EZ#Q=Cg~NSf8XV+H`T#Qv1Z8o5eEZ7`acJb!oO{FllRGec}dUfFjC0>eco| z?A#gm_V46pcrnlO*Qr_oi=LPJoKBV)Twpz?#8PDBd0#1E>l>w)?%O9Em0au~J_95e zcrjyUfAWmKx6i-1&uG%kB{m^A=B|Ua&*8tnm)`%bAF8vUGGqh81CIMq{O3b9HarvD z&@jg*WPMc1;}??sj1FNwf=oMSWEA9IowqW68E50Nz=KRhpwL&6Kfd8(rH?R^FUSK< z&DGUDuY2EmuSjA%tCYZ)-aWr?&%tev7cJC!X>EUhv7m!7$Tg4s=a}8Fs5+L+5Wu4q zabTw2uDyci1COq{zdCpy$f!k4tPJlz74qoU=$?J&FnL7+WBP}i$M19hpUdU8*XO+H zHvNTNtS0RZtTHDT*B%P3o|l^w|L7vef~x<|>=+h!?%T9qWJ7?ywEOuA9)>O#R&I}z z@^3CbxHoS~_Dn-x4wF_cu?bE2Zx-9y^(kKbK6}>PzaN(~u3#3`c_6!QqkMGLw!p0` z`d|J%_DwZpV?&z2hKBGT$NnjY^X8w5e|){Ri`(wHnrrfJp?)`pt4Un~6>a%%-V2)e zu=~cp-xcZ{UVe@bEH=6K1Su`oMd$IndvnGn5)b^nx|Bd}=6P>FYM3%&~ zthuzaZ-2jy6k|wd1FO!*-oN29uQ6ZyQp^#VY9xF4#=aIUF;G2Y@Lc-$%6#(K8P*^J&wDNl>ipgv!4Qa1NKfx87HvJp z4SrsHTgM*2s}-^0M05Kp|MyOp{~c`q)HP))hxpVri)VZ?1IKqrdqZoNj!j7IzO3cb zCD$zZE_LVn4vt9o6L)XyJF-~N;o}S?m$~nnrmFl8D}QgNw~RY@bK#es;|vQpLpB6V zeC@SimWWMzl2`n}SvyvwEDiF428h6h0QUdC>mUF7en?&P&%5F;(%ZWyeANrTxqYF# za>F7+*N#n*r!jue`D`2_+ZTGTluRxre%%p zx?OpTmxjM)lK;fO5pm+E`M3E&6{6bdtw%z`8!RTT+#`B>yUyMy_QL;6tc%#WpBLqR ziP+l|wk#m~)Mc^RZ+N*9!t$mYur3z0D?fW*>WoNN~%I|F*cE-=^6TRHdGH&xAPjE07_94c-H4kho~7_SrlElwwRA>-*S7OWNGo1|VH z%v!mzw$uHwwa=Vd4wXY9iqm##&ETpzV*brPLF(R(?xd)<>$3`XT>xceXWyn7b}T{* zn_8>)ZHyNUzor#dm@Y7@%yj*4cWLfIFV=hP?3SOh7(qT34>)+}KxpOBtj_#5-;ZpO zS+}g{Xio9g!naQH$0vN0I9HT1J5eBAo=JZ}(^c#HH`dS7juu@#C0oFbCp_`*>6ou! zn|yN3w;i{UI{%|mCyvX;<-n_{`ESfs4@{)N(oz!nSa~;%xZ1d)Th1YN-}oL+Hr~}($);*JMYJj-Z+;uH(ceqf8+Rz7OiQT zheLW_PAM=goGQA>C)KzAY0|34Wd?6&*!A3><)wX=v0rdQ)^q9K9Xt5eC(ZP$n`}H+ zYMt7;BBwBY?QQP^ADKLqx_s)(!&|q5boWafh-~>cp7C;Ly1=YWE!r#R zZ04>7CnZnc^Z+*9Ikg#+TBqtSkZY(4IJl}e|4lOc^@X8pF0ayDmh&*{+|>1xQWtHs zeReTIdbh{@WUoIzr!~3GcM#<+UCSd7WV*Ie)aXx+jPi^x zrILrPe(x{&JK@iB$53t!VbL|0ejc-ndt$YwtF(f@XXT6n)8|&(C#9}hyzqCYesNlO=)F~2zHKx47o;Yp@A~n@L9Nzqxz(3{9;@^832o7S`D30=@c!%4 zZ<<_xC*HAp_rEh+ei75n(;2b(ddrwL=ha=kYjR}v{r3}Aa(DM_+>m*2>)FyXAy-{( z!oS^d3p-G_XG`q5s;7o|NxvqnUD3-Grl+SB=K7)c?;W43A?uRXeVM8=yEfnCM9J>S z&GV{y*m?cC<#|Qdu5LTtxwekAK%;8Ixo6V9PaK%KM*Q`!d(-b5hf1$|7W4AgQoW?e zHd`C1)rA*z1yy%UncAH#uO!WMEwUzAe&*TvZ25aOsB=dwQ#*9^$k)0PULS3%9$t*- z{rTA-ar(Z@<6HR~x6Dwonbp1WfYur7W&6YJUn>SL63+_`e&|(Izw3faa`oq$Z-pMe z*EY|vJMxkv!o5&%&8kPzztas(#n-8=yY75VWS!HY$C;5Aa*`dGux)j&a7Ay zYieVs`#twi*zaQ^4|m7-u$rkl>R-F;bJmZ0UE$l=dS428*yXs5jQ8#_arScbkyp|@ zr&KdF|IOm0&&!Vpr;EgWJ=E#H?A@WObF%-QakyM?xuhsq<@=?_hV7MIo*PV@z0}Ux z9XZVrasE?pt;vC}Uv@<-6JO_;@yaU3H|DhB>qQGsJyn&+=Q@cGZn`}yW^#mk0o1de=Boae@x-JSntap1b; zt0Lrj`Db#3b5D!wb>5@am}57U0R1$z5Eu#vFcl&nPF{*tB>HZ7$4T8DZhH0gdcLX-?lQ|Eb;ky$WiYv z>>%lo4Ql%~_WQkElaxDeW2#b2?utdPf*QA)e_xd69V~oxwW-=Nen-~sE>XGLfk%yU z_cYAn2)7myWzc&3xa?}dA%~C8&M(#C`(f!A^IJfcT}S*Nm-UZh|HOnJW~pB;m|Szl z%;wpzy{8)clO_J^t~hY}Qks1AvSbTKfy?c4Pw$)aXXWf}?^_#ecm53RUl;fys!}KN zOKETXzh`%Qy&t`~U2|ud_pUXy^HyGXE%+;R=Q`_%LuPmNZSKv!|7&H!&J__4UH?`5 z59U6qAv|@p`VCN%EWqmehfTIKSA|~vIj1(Ju=w}trWtl`Tz)g2cHQ8_bbd}?hEj~} z%jnpB*Yk?*vajZUThD7OdgES-)}vj`svJqbHWa>P19^h;=dXR4-|P~VVr)+yGfc5* zyR<`UW!TYY^>Zey_+NB4d@Dzk?+^3uj4IEie;+u#EZn|#vGBT}1y!aW3g_hYKa#q9 zKXp;nR>hv#FU7V*?Aa3aHe^Fg$eIF!`VIL?F?$byjl2`n8@4*>^Q+Lp;_0cJNxwEQ zehuGHlPvF{wJK@m5_`v%)#9e%duQ46$?42{`S?c8)~wF6cHexC2Pn$BU;a=rQ_fiN z{KJI(Rm{`!-!Qiq-2JQiPjboprOV0>T~(6?)ti%c+WpubSygnm{ghtQ)RO;9vPQDb zPn%}gt?{X4JZ=81(YZH&*7cj#i&G{ldUVT+tzJ6u?^tzg`n_p~>2eV8|vxpJ6+|H`Cz3J(qq*kLDY20>oJi$%g zf834E_1#K&EMX+)oV9;dX!yzPVoTmOcD}mW*<|s1gTm8LP}o?^>b<=@?{$pt&X>sx z*|Xo>e%XHGlGoQ$$3OnoUKRGRZK>p@kA)@|mrp&}KFz=0a(@0BX7`VUJD_jh>2mvf(q3hK&p4wL_kjE6jJD%zJ6|52 z{A7K?&trBIX7xX|Vex&u&ivoU_mkG|*jZV_%=zmszo5&FNw3z%{j^v&k8{Vj?ODD1 zbF}P!TclXA{SiHKvt9jkI4CF-STC>rufP}b@16Plc~*|IPo8lJ^_Du6=6hB9y3^LI zekLt*x!&co&HryG@to+hM^E;}A1+XgzBjOaG5=Jd!(xS1QPX}ilzl3!$-cYlXV?FA z|KeWwm~0PM=-AB9UlPX(iplUF7VqB8_j=jMbxkNZzTS4$sdxK}_C~CYn!K~?>BS1I zRpD2Q?p|ws`>^z-!*O<<`#0F<8TbqCh%C&1!yN7N`fsrA+zBEj z+Lvdy-4VNTuY1uqO! z^5_3$As4hZYI5PM3yVLRu$ugMETOlIfBuAZO;4qNJDfRg$QQDEx_3rIK(y~i%jxL_ zscXW%UVHOybHDSlX_qq?kWbyWKI_@5T@ zqSi)DUb$%U(&xR;zO9=PvFA(U_4TeV9z``qq|b`o@BjV1;pLU@FW2*{%Y~n9YWu!s zrAE=kg5Qzbly4nBW;o}==9vATd***AmY+5Koy~Q}IR}nh;+f0&=vF(wjlJs&>EACV zzuc#2yQ1go@+gs#`y%(NSKd4Rac$}95Bn;MtIuoSC_i=l;*so28UH~6wpib;@2bfX z`G-$554rn1^^=z~4SnjhC-3S+BOl>;R<0RInQV6qOYLiS*t)(*(h}JI`|qNsFZbzx zym3PFMcuCttBSn7E-TSrv+j51fuAA87o+B@rDU?XH0_#i7XuFDTd7g;^;#=-?{~T; z8geiy=~VpHS$z-h&ORO*xHaqS$_755qkZKWZl%W(j@!lcgMad_ z&`UEtPcDiqd~PWqbKq!Qt=Cu{sMdhY{7F`p({Own8uyd8g=K}##78uQX z6wA6Ux^&64S$896F?O>2t@AAky)ROqy1K$R_UYrYtD)0x*1b#4uG`&rduclVc+b^$o zCk~hFk2&=H&HjxsO!ow*EL&x|ch8Kx&F(?%S67*?4cYii-%jUj1M`l$_`QdW3s_MsbI zt`xpfbIbIu+~j`02@zGMoLT>#RmR1fvOe&~SHtr9TSmbnvOSk~=BaNGyCrg7B++l# z*S0VGg^npxlwX9cn!ZZs`t+sWG7p`&ZR`f*Pk+$;lFn!kTtvW z<@e01-s{zTxYt?i=qin1J$>X7k4E3h9oh0h2dyS$?^K-o`ujpw$NjS(eQb$Z9r5{D z*{X02mw>|Sc1up$s>&Z<>14Y1+l2{z(^%JrufHI1`K_$BMs+7c#G}U08>K&&^LKv-=6l8M#{MbDHdZVi%Qk%Bc2)$igqxl^ax-{cihG@mEvo zlJ%x<3NQcUi#A>1&YG>Z<>v8uFC`k(SyN})EooBKz0Y*{wH)uu9h<+FaK5Uto1t}$ zn{QQ;>iUG85wjT28pzhYb!NI2*2SANG3iXjqVt(ozMtAJyg{zu?*2>Fv+}D$AKk9~ zm-JKB>uW~S%MC9N*Ui3DE0gq};MY(rvR!r%9R%W94;#)zPYHrv2 zLUQ)kz3nwFY_Y9?)4$VX2vIf30wlukZ<&rg2ooSb2o-p&B_}7|}w)h(E z4`~hUa<-`zA3oGnwQBz~N!-+snv@t=a`MZyFNxNSr?>3!suHNrdB~u1d4pypf52;@ z@Qsu1{?j?ju&3zl;VR~7FY9DiDKLo!2r*ro9OJn<;$+@`VLcz-D~GmJ|JpE5t^9J) zf=LzUm{qxUg-#CCoL?(rB+DEyVZrU}+gs*cJM|^;rl^kmaf^VThn_QObh|5;c|_=X z1sz%$yPDsl9u4#4N@e2TSW8{{HxW(jJiRA5nGx zUK=xBIks5PT6I;@-q?eSs#y0NQK_9Dd+<}??ib&)PyC6hV|XQAqCNXDr)tPXpOEzp z;;f$W?&dpxTO7*{{M)fKq~RK?uKuHLt~1l0Jda8|pnb_taMm~dcbp4qb*_F`#B#YM z|L!-CuV3%wnwD8v=&u#Rpz?1+)y*rq+H>z)8~%@ccw|2JmZv+prga{*Wqk8|(fUuR z`C${|)+JoL!?$F^-6!vM>CQEnKW)DLT!A2Yv4*sYcg!n7`_jsV&%Sk#+P|E`_jGND z&tYbV$It3r|F5YNYsft;var9}=QpFr$;E>HRmrnHywr5M{C3NE1*y!&?|(M$N~$_h zXu;4h+ju!=Inbv4G|#mHQ9np3`+W88xI-VC;zLR z|I3L%ngHtMHCIbF=hZZ*8SN?7sr#69O03+h)H z`2JW8%AOX&qB;xImi;x#yR$SsqFozKb?_@`wuc%{5j zjyb!L;pOZ_s?sr&Hk&X{;1<55QDjl1-;-78qe=L2G^+C*+1V&W@!F6hKy*DyzH21sp=Ez_6w&Be? zFq0#~Ay4g4=$l1}VW*Ad-9y*yKYaB`voS}*X7GeZ%WBnS56cvVZ5kU`r?fP%K1ouF zv3+#0d)?Lsou`Shc zxX%%BAkwF0b@*0;(2QTQ%bL=HYrMYfD7bqnh*K_SS@erdH@7R7F!F;;oWT+P-r%Zf zXoi)hk8YtVZ-n9O-oh7)=5zmeeg6(SgUNZ99aZ5M-bS^~`|Kb#L(Y8u|BM~)qXicQ z{`&hn-sOeUcaDey6Mb4%hs12J+MRC0mbv%mo@rdsS&CAsPU5@V4>0v5Da9=Pw)i3M zZT^3j%Z{IYzBY7epTMF(rILl(EIJQ3)DB%0tTFrbD&6+@mmTq422=ey+%j!THpZ}M zxlgv9Fsrkmbjy#>?DtpZXeNLD85z@VwsZc$FBLmER-TIIu3gx~x+Fy@=IMr#mA1lD zS4Oe^t^0Rl$J)?ckIu6jDJL-M?>=MqPbp^Z(@me=hu<|$^-W@65IY1~3sAL1{hFq)6>9eld2ihY8Vr{ z#9`)>g7~QSGGB%JnV)iA)F^zWv`I06@%;|&@MX7U6#2d`y&v4Fc(`yu4LA_|91k$X zebtV6XmbCTt?X;1`$_W!dW9BppA_8C5H7Ip)5b!ci~DzTL{`LhxOJND`XI(6_Ce=R zXx#l>p(06oPGXlhFKXoKiwoA4Po4N5jwmG^zv$HGC&WKZ5HoY^ScWLkG z9W(P5@|<13&V3{4)<&n@{g1!Dx&JJ_WBW~uHuZhST>ZsP2`mbHbmk~u%*`7&!pts* zUN5}!)wFKvx{GBe|5tC>5Ib+D{GzkR*Ps7uJ!jL;(0cjmumc}A*lxYKBlg%^tKSvB z@^|)6%)Rc$${mqh_3&1cUEh7}`yBck3wiYG_I7)Ty%Jayxad--CX?8PBVUfS&aRc= zj67MBU7OjqH>O4Bil)orBT})V4|JRq(yEkW&hC8YJnhKMR{dRCcU|Yi_Rf!e@kr;8 z-^_Q@yAAHPuPgW^SlY`aW{~bBvQ9-SvUA3zeTF+$q%8Dx+&^D?+3iCsKCg6jy8duQ z0;6#7p#szAiza<->u!5_aKew@yQJ2p>|BwMIQ8r?|BY_f8&@PSUTS>kwP?~;HtFL9 z2fmjDo^+~rGV%JpP68n{MN?@IuU0=(Z_I+Rf-3mWn zAh@X^y%i*#edOr8i}Jz83QP+N8(*;J$Q(XtfBh)yqQ-L8yH@hg#CK0?yYO{w;;;XU z9$KcW%ir(ZWZtxK%fcg1|xa@a<^ zXkK}s!1QC`pLu_0ue_b6a9JR)sQBV!);XFki$h9`w z9FALeYFa_TMjz%`X^(%{-sXRNoV8U?DvKrX7$D3gHE%3L_^ml+4bGu zTyJa|@3gUyN3#E+p!igs1!{^?OD|u4acaKN%^N{^%e=J1KRyfp8gf!=XO-#wnAY%3 zf3&nBa&mr~Uw&I@yS`-Sy(-^DCuMUDLt}PEJ$kk5-+;G()^Y}(=8F}{A{v)bZUUyDB+dZFau zt<#md#p@lO=E&@i%n;dXTq?9qZQV1cYp%{OZBy*}%6H`Lm709n`0O=rOGR!AVMgw+ zMx|ow)YdI?x)z$d=ez#iN%MYHgO+n_;1he5^2#K}(|7IUr@!tVzCUTT-=Dux`xG00 z1srs$^^t8~Z5jS`>Kd_S?CRd@mpH25lMUI>FlmDi^Q$DKn7>a~RdGVbvHIKsIbVn| za(^`tTvt~ZD!pmn)i8!mZkPC7YbP=vG2AM`Vohj#CcHBA|>gyloy*Io%#$?T(cQgB$4`gygXw2>`_$m@EsY&rsuW{;HuO))!jsy7`dMs3a-2NOv?!3hzYY_U;A?|vdv*LM}$UqXTj8-)jK9!E&iINmr>F4 z|6)OT#kpq20+v~K0{Mg=z7klMBz3-~boF7(O=q#o&Hb!*ySlNR+?{7$pC%t4wy#f^yWz6nh5|d`hpRZ& z1v^c1SH862<`2og(K<5K8Vq&H2@hk`4uuBBw70KWy<)+f)VEjX+?KbHO&5G*qjo5? zFs6N8Y{sK~c9(-DD8(>F3T!Cg6MncVV%=egvGqhf>4|A zPZLrfOT_&btGKwOKocxJt+ODMH~i8B*RNa-$2lS_`Z^0jWy3d3NPSetenFQ>tS?b1 zCiL{zvJ*yy`Zb|))9anTFoCmF*5j7TEx9jm^iCBeSM!PLa9=tmDQ-@XS z9lruQlUQ7`QcUUT9lw6(hi?lu zXHZ?()cSk|NBG{&g~_^X3=yse4%Mk03ibEdo+@rvx}W9nI%8JnTaOR2ovvj7&2ry3 z?y@6m;>&-vmAW2(Gj_axU*rAnZ}qGX$+On|`pRk{a=FF9lOy6rno`Wwb6aGVG`(9L z*zK5gcKVXjIsu-a<`;ez=NDQ3`$E-;MF(XqZZA$(aoDk{H}n3MxPYeLpBEindV78R zp84sel5GE#e=c94!c-}+VZ%9>9a>W}tvy&}EB4QP7hX7DRjc3a$-_r>3`R*^0;hdi zRtwG8)_f)Sa@EQ+;!?fm)V^deH}C}>Je03?=;}?Mnc6|;4c3OOe-?4uNMD>${6q(r z*t?k=;qHce3y;Nl%7v^K`KvCT|A}Fj%Yj3^odr{yUN#ti^Ge+H|7p$N;MncIel+_t zH;4&tFfb5YH!t;8`LVdEj#+2Vy}J4**skA7j6p-(HbNmL*D&;oe5uOib@x`!a92L} z@R1q2(W0iS*1`|7lC-|`>zD*I*+z#d|622Y@soP<6Q9e{8 zc+#t@cS2L`*`gmRonQjl)%x;BfvEde_xDHD&fQq;wCL54@YgWPcG7shlPF!`3@#^Z%?yVacOnSM(PWv2h z)s{bA8Jfkp*KDehY}npe6(&l$;@fp6T(sZG&%kcDlskOgZ7a9%yY8RldEf8Ne!u^I z)OM z@XnbWQLYB5E8~1^q&~`tZ&#flXd7YrsrP@}?GSGP+bCCyjo-68FHCs<=Z`!u!^(|5 z&b%?-PpfRv%9!!!kKk$RIp<31lYjqg7btnPMukD9Q}d9}PYb`l!TrmA&)fMgKG(-b zcAi@B`>T_(|2bzgb>9{M+07(>+_rI*yIRw=g+7th>yy?!+<72%>b=KG35=408;U*@ zssz{`ce!BY;&^p+r@QjJ=a0TI8!08sJ$QVg!_>CU1yg%gu6T7-COdiWan}P(MoI~? zAemAfVaM0GtYPcbhQ_kZLCGMp9`;?IQo_? z<%kjQ`T|}3*&h}^w9WeU{^6CyufhdRTklc%yequ=&&9uqOb)6m65c+1?9sZ4PfaUo zw$IUUkl{CuAI)V;aXAq6=&{FwRkJ%6Y+d!>-fGow-S{IiuVaqhU+Zw1BSNTgRjFFj zHQ8WOuphSV+_ATz=NC_eT_4M;eKRRK{eKrJV57LTJSYu3&Y?(;=l_vko0y z@V&55no;tq|x{6sCN2wWZWO`C`*TbLOpD5UT=|f}c8`z7p~^>(RxIYP~#Z zg~c|Er;kr`Xq`1fi#LiF?6@6;g}WIf=L&hO;x6by!+#l_lF7TF^NsM zXb90YZKf7S6fZbDC3fuaZRoiKaavW1mPy9US?l7?78<^|4-SO-_+MI}vBbX_6%(1O zgpQpxVOg6mDzs%^y8Qn&bz#DFCVzG*elBDh+KEXT$$W#c643&NKh zMRkL>gUXa{NAHjg4QKwHtYvU0Z{k~%Q5v&%){b3S*31EFS`iL;%UnctgTG&0z4M;* zz1S8X1!a(+W2aVB$oh8yN0}xFGIDFUUXXS?y~zJth*dxhVXuX%|aQI`aEHFesp5w%_0`&20aR17m^iRUa_H1+oauA{di82p@A zxmR3jUcR3A~uQ^8L!gVb_lp3Ce+L62`sUuXZnTJ#5{;{Kx*|B_@YS|0aL2 zpY$)>`NFUNkB|RPwO&-r!n^R3b8hH+pWMH84yh{=7VA!L+V(kLaBO!_n+b=%hQ_u~TKKo&7JkKpx z53u(X)-Ev9idxgl`hXWSy2`Q2I%DS&`$b$V4^({wnJn5@o?Cf13gkaNu>UOF1LlhA zO5J1J)6l^BAjYwjRd@OqO((I2W{<6_KtpyR|)`qTgCc`F_%rhDzDvJTBRo?4yb zz`i1ZaYb;zy{>EhZLA)Q35<-~4tJYAvFM76H?wW%QY&Z3HJp2!CqC=&?(PrlDK4zs z4$)2L)@EG%zz0@4yXhQfl%5_N?*nlrv4(A|vhrJ&z2{|6W)f?#W04i#0!}LJYUK>I zMoaVC_GfVvYVNzfJBGy$l!X|6iA>qI=x3H}g7N{&%*Pf#Jdu zgS=&m8IfP^dq=#LJ&?E}f$_k^rnatYLiXW2Q)E2#D%1oOtSf z`no<#fUQ;p!-VeF+g9xcl?yKe4>C2(S?2wUA%lyNo1v)a;s-vH4v>Ycfk&C7K-);} zG_6Qt>;=sQaK?meY-khMz_36h1iVz6VS$L=st5;V@Yb1C5e~u;86pf`kCHwHE?^AV zz_7r?ev)0WJWE44NRNr$%l;J!jH1d3j1DU^D%e-Kg7&EF%&1`3ay!7(5VUhe65~|R zCX|yak{CgI9vn`B?Bf#Lz_6esWMjjt4Hq;Rrkp$aXfZhFI`GyN$ul&hgN$aA>t*Ny z88Yj_2fmQT23Cfx1s6Z?g)}v=GME+y9%a&UIKb3!E8r+omph2DV?`2UE65$aE0P#p zlNSauteDt+)V;9@6dF+*e`tUf0yA7WrCQs?B^IE-B*t*%O@BrOJD1A=riNJ{CxcnH zKu&H2g$y^y954gqDZQ1$2{ z#{&Tt9R`MmBcN#`>3%nclL*zIHS#L1aI^P*%3ztm!w7T9motk69fS~?t^3^=@)2GM zILd_NF&-N!#yudvK`btKe39dUDqL?vwOlX5JVXHeIJ;QzKrlxH)RPRSZKN3AAfzLn zU*t#-hkNosvRp5N8Qj?n+bT_%DnJPsV%LU#cjbmqgk67aq!@LS;6ZM4yjY$gVBde{ Z#?l3SguoOFahH!9jaMW<5bTBY5 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_051.png b/example/output_data/primary/primary_051.png new file mode 100644 index 0000000000000000000000000000000000000000..123bb0c35841a50e0aef16a499ebba447dd8ba42 GIT binary patch literal 12672 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 Z%;6f3I~Qvl7#J8BJYD@<);T3K0RRxH3r_$5 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_052.png b/example/output_data/primary/primary_052.png new file mode 100644 index 0000000000000000000000000000000000000000..64a24930b67263515dfb0946e3d87017a10fd290 GIT binary patch literal 7824 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_053.png b/example/output_data/primary/primary_053.png new file mode 100644 index 0000000000000000000000000000000000000000..1041998001db8bb14f8a9ab7506f22d173622f23 GIT binary patch literal 6396 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3SguoOFahH!9jaMW<5bTBY5 za29w(7BevL9RXp+soH$f3=9(UJY5_^D(1Ysn>|U`Qmo-(wCo%1jYdaK1+4A)`S8p} z?bA;`Jxx>zhQuIB6V=@v^?TbH_!53upN*cb$sm@<&OPJ)*8RtRu9n@9Y+uFC zp!0I|s+on>E6;pi|1YjRUf+R3$6`WswA=qj4_|0ZF8xyc>G9i*^||w&#Oohmo^!D2 z@Q-))UllF9YGT~uTQC29@_g&bs@LAaBmx8k3E;oXp2wjts5sTA4TTZK|_d;IH?r0bHZm(7{?!F*o#miC(mnSKdI zYzRx;)Hkm#Wc#EC5pRB6_Nv=^K#@}?B5LNE#o^~H?xw09RNT z5RHl6@Iv}W*oW7we4Ysh%TJ}quGN|&XZkPwe$qnbK>7V!_A!?EB^1V_Zt63W_51!y z`g#0=Lt8iBP%Lk#i@AK@-;|S9yUgdr?d)S~VJi<@hNF z7VS5RbU&1-s47-_?xxbC??v%^3)mZv)|^U_{D#xFM4;{hKIAutj)HaPMWku(#H14%>2B!e*{fe#qkKRZ=}ISDgFC z!hPu*PNm3NK4#(8DEt?2U}KS0p&0j#nU!TA;hTj_>o#_?zB!ZJ7^?Q#!{Q*@*6!=} z`+s>d*gX8wv4Q8l_T>6kfwFI6p7)>L`NU9hgL3{y{ePV57OT!}-xPk!+}^d>{^QRTOb6IFbrJ%q_#YT5Zjff;j+icG$0BvZ zrjeD$>pkN+tNYblAG8`-+pkse7sP^m@zR>@z-AV)4Ssxkn5ES=Jh*V{=pT((b zA87mXcSCvtYgozb-==vL>}DtU#AM>6uU#r^la{GqH}gnfd>y8)eSq!H3tNT@x2xBb zea{Mc{6}T;H)-Yvab+7CxR-usi2p6RE|0;?If3!^g-0cFr*+>SVB^qv;Ple=K(48u zze)CeLxz3I8yFl}4gc7iF)J%O=MYYOjb z#Z3*Nf)NK?UfLcg&g#%fFl7X=nec$`JWy4{Chyx3FvtL>q z_KBKf_Oz~@znx7?aYI9LMq%BjmoZ`n#*M5zW_7cF@6DRSzkm9=$qd$N8yd8|-ZMT6 zeO#lrx@<1X4b4VYnc(irzgN_^onX4esq>)gQgy>qi|MRq91<9tuT?kHWzCV3{MYTg zRn~`o-EW!uT7_1#MGJ4;%(|<_7hkxo=STwTwY)RCW zO~0{0Z21K#`>f^PWY}J~CNQ2^*j6rmsF71A;ZW|o%&3YS4tCWI4book8NV%T&6a(T zz#?`aC~C(wMn0zmM)N86nBN5Ves+IXk;AcDWkW;fwd#iCjE6O1Z)O}|da<%KTQ;Gc zMaIHZ)nJ$a*tWyVU1W$&jF?zlf>kmU&mW4X4O`K$Q1Z?2WQ02ySQmJ z>uSXf4cbxf87o|RgEJ~?I94leVEDGEwK!^nP=4X92(}p#_1PJPzk+9<)hy&%+Ywx{ zHE;5Phc^x~-B>MFwq=2^b;JR2z5gb4yFY%u(Id3{f>z~c?HTMqE%6+iD1x>w0@e?v3tf#j$f zyXC3j+;$t9S?@eBD}NXAXwT}ea(SK4KfFm`{IE;xdF)z_^sN>)jjVS*+^c5Tw(RK3 zfIaRVGII_vy$h-0KX7e}Mf}%-pL{MGk1~Ra0tWUAZTYD`{=I)VyIgToaM^|i>#6sc zH?ZsO;hyL$5OIKa?RSPZk=*?PH+B0t7+hp zS1{s$Ig6Nfz@wUpnJqVxzOsmY;N8A+vr=kAt(cPb^9j}rw=W*rEpU^ik+tSCvC3+CT1U@A%9fxP2-6qYf6a z4-G>9N|KDD=KOyj^++a)@5E+?evZccE%%rYypEb9r`Xs2c<#-lw6YBh7Sqfkz2}_I z*}7r#(c)9bui8c&kc}}rO?6Gn1FKC&k?!{D_V?OKD;{q>!1PXGgT(?N`TYL= z4ZF9hr*7)o$GQA}_T*Bh1jh1$+1BjgZC8(fT@ycZ&Eh2myQYKHKlp!Y!!LzbsZ&o{ zMOn;wr@EoR`ijN>tFZ|O*;VJkQEcN`rFVWS%=ki=zbmaN*4#DGp z{FnJ$yLjyI%eZx!3=KNE-|BZ}&Rny&`fz5?xw-q}-4Yo2wKo2>S4?2kwL2DeWY_!K zT9Zpv=FC&t&|tmg$Dg{=2YI=hrv0$nrpNzbPtli+pvrdE)B{WnOSkTjjjmU>{~uq| zw+39Li^>$Szk9MNa7JwBXKSJLnHzr}epsEz&dqRb5%2wVxwTs?-dg?qeO8S_=YgND zUwx@w?DB@#)#m?ZZn!n&e-%Fi!;#}VX3g7PwEz7xkdn*Iat>Wm&)u6$&n^5~_ObV@ zV8j7oulI}zzq95Xex;jdFPBoxBF3PzvTcJELnEur!Y^_R+m^R&uo8H$#PaUSq1<;L zTB<(Ys$6w=Lo+Kw@yhr;Y2R7I3YM3B{PjHCp0ne}uepsfZ3mbdbWG=LR#IXS`!E4q z0BmqFZ4s5{&|#pkOxI#Z=O_apNK!p`_5FmA{Knz2GfV_vU6+ zn-yQ>81{uf{$laL_D#ga)&ool_E{A&C$uVDIBZsc-J%`T{x$qY#!_qR2!@>K-u~&W z+v1uJ%sjv}??T(wk~xisS3fLNSgpE&;l@0v_ z;k&Ya=9?PU5e#eGdpq`vuTNaeBKD!B?BlK6cPc9$7Aow1B&f(xdo}T^p!u5)S)B)- zxe?ySC2wqzvU}8aS15u(XLZ~0#y9g0FwJ{nRz5G_u=||?4km7ofGYk2x2}E=G?(de ze#dZT^|8$BrxeThj_`?1Snx%z!Bneo-(|0uLIWo5ilEoF4B26iMZ)duCp3TR5NL=g zji^1t%bv#0T@kdq;;mWvqtAQ83KGgTFjU0$2B+WN+SIY3nRU++a6H9c{Za9kNk9-J z8`j%#|DkMCL949J1J=A^`!yebwQd&(FK9i$G-=8`<_#@U%iWvS#W&2hQDS*uR~jLk z(w=|wAXv^|y41S(26j%J2drzqGn`p_>}N4c_I1yMU=}fk`BOhwHho}fWZeT!G{5t% zfcQ%7cNi^JAAY4^z2^v@*oQ^n1iNQVTl1RIs1dpv7aT;tZYMr%hK-*cY+Rm<=!CB$hv36 zSGk7jD+1vg6#6+BzpXp=b5H1ND^5^8iMyf~xBF~uY1WP=Myn4U0txG1ZP?YsD5k!l zfdw2tKN9{dcy_Cp!$Pl-b%VO9-}H8?Gkmd}Itq=q?}RTrmiheD(}fr29$=a@^&YcK zaPQ~DZ`VqN6j;O#e7l-hIzu+hIf3z{*L%jkqlsk^s*S8F8GG3+<_Ym_KHSBr)3A1B z;jNv&gdcH*o$`I>&;(8^n^zV7nt$W?y#uR23RWC`WnjH#o_mYKByg};KQpk-={mp^ zu^D6r8>fy!=j}U}uNKUZHSG)PV< zXg@Id)rP9&3OTbt#$Bs!c)Pmr*3MP6#~I?(H!xgVaO@{jV8Uk>u?b5+x#+iZR)_Wt z$wt--!Mug6)+!qsT)+Whwxn%G)7(#bP7QKibKdPN5@mifNmfT;;_W-{gC3PQ@1CoD zL${Ij%#ts133I*XJYH2gmu1Gp156QKoQ16HiW?ecf|^?1Adb?82A8$p8D6Wddl0}P zcHquGwUVzUnf$@xM%)vxX9fe46dt6i?ydZ;#TVeK& zro+M!4x5_qKZ|pYVPxW-5&Y8jz@}FztbE=Hj43N7i&~g8vYuJ-MJ_>7)o**ym3_$! zuN5~mq^$kUa9XQypNB|-!Ul%8kJfiC@zp48Xh?bc=h-45vz9VS0Ce==?9q7Haxz4$9u;l z#vjuTFr|f6@lVLExvp@4mx=p9+~anO?dOUaR;zDlm^t+x^AnB3QP$@ea@r0srCq4v zpRl^+_N~Tt4xNVgJJ!lpOaO`M#pVAo`)(D<`0jyPdBgfC1<}?YM64qY_}tnstWGoPIz{%@9qn-BQTUO^7-b^~cly;?xzhL%V?F2O@Zi{6`Yt}yIIgrPx zli>FD(brRX#oMb{&v+y-9uGP6PSilUk@d_PP~mjgg|m?Lj8_8V@y8z(K>ds}IjP%s zPEX90O=l?cPhjNM+RMJ7npMXsf$?|{NT+optImoq|39sL&vC$zLnk3^?RN%-ZsCXn zg%Nt>`*ZTl9%<~{ z5eK$p9eaO%$J~%-zr*X_ukPAh%jOQsG$mY|Uh)UzY!VeE9ot z_xwXI&u{ow^(Z_3xAu~KjA9Aw+!cN^*DUt8_B-7D{iJ`+VgH=-Q!Wd?`jA^zwt>Mq z;y?(fZ6$xT_EzDq*+yaqrg7+4bQwju`?m`-#0y4jC{5ke7bfht-B0Pw$HJQz>-HWn zW#YcJ%IDg}tV1sa-MPCL|E+4&Y-IJ;o?N=+WC7CysYcdF(8!2-!(qXQ4|757EY1df z4xPT$poSRJ16QW*znY*18$(3Lfh23NQid?Mgp2Xup@#!*oI1~fL8A$b8;W6rDhvXG zOx@m~u^C|o8oh8VPK^W;Y``R5TkCeG=hgp4skM+xhAA)fUSBkf#sSm zM1R3yLuQCm7=+$vgN89U)fo~TZ*zc~gq#c!3->`rGZ-19&HNL literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_054.png b/example/output_data/primary/primary_054.png new file mode 100644 index 0000000000000000000000000000000000000000..2001237628ff6a826384f24960d506459700bd1a GIT binary patch literal 11227 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 UnsM|f0|Nttr>mdKI;Vst0QMjP4*&oF literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_055.png b/example/output_data/primary/primary_055.png new file mode 100644 index 0000000000000000000000000000000000000000..eb26248d5ed337d9f75a1e363250398f95be2745 GIT binary patch literal 12364 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_057.png b/example/output_data/primary/primary_057.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbadc81521e91b4ef736cbd622bb9b6409be944 GIT binary patch literal 7456 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3SguoOFahH!9jaMW<5bTBY5 za29w(7BevL9RXp+soH$f3=A@dJY5_^D(1Ys8{K#B*rXK~0~SBOy3zgGP37B#Zp%Ig ze3|AFD*B)MV6}E(f;w{aAtBrpp8*Jlws(8nUiaNrz^*n@@E2hQ0PvD;O= z;M*WAt@FUSwLF5sS}@`OJO5qAGUW{n3}tE?8u&%!b}_#>qFnw!93-6B%=#zjp{&>e zJ{GYL-RFjxym9MA_VJfK|uz+Y|`^PaP8+&_XrCgux89GGuY!d@}^029NF znFpBug*;qnePFgt5&OSq3#|`C=WJ-$A6n7Q`hl&H_0L)7@`mjkIt&eSIdvZ7gN)pB zP`Ug;G04a>Y}`L$Kt}2dMI3kzGIA!=NV{;5k=-^$?E64Qdgp9tSPwRmsgbn?WaM<1 zk=bA)L9VQp+r?}Ha%CLINPnS-1K&YL&Vm}b4{YRQnw^V zzsopJ2^v7TAQNpsjx+?Bc!rI;!Uv>~Unt^0GRVXkP!r{XL5^&;DPos!BbIyi_ z<6uWJG_u;9b1rXahdHtkY$V8$g|FjvZ7SG*OyL##Fyp+P=;xP`2bM!45FCqO;=_#f za$BCyoX#+#`2dsLcV(r2`7`a69>oiOd@m5mpv}Zx5!-r#=|{@}rhCDPn;61a#6Ilf zn#lS=x{>wGVy6^F9Tu?-^SLIn3NUfsh;BW>l;@wo_R0uCk#aIkZFPK^co!!5*%OtarK&Fr5oj+|+PeAmTu!mWx;cHxsu-c5Dqdnn2GxV$lpJ@4=`1Lg6N;Z28M3|iklk#3q&wf zuM~)MaN*Ets15DVaY$f%v(72y;8{+c2IY_rogIdatOZlJCbF8VZeZvOQQY*PjYaIh zMJ*SxJ3R-OESy_UG)W6aFr=>(h%69h;(p*Gs>Ge=kia-+ty9XuqntVoa#}88F*6P@ zy;$m$a?q7ir(qsQV8Q{W7hn~CIy&a>)o1ic`n&pQzuxv8>w5Z6{0gse5jW74)_Gt! zzgFwn<;}IBH&PC|a_BTn1i6Tzk=0-p*F@II!VwJ0s{|qq3>#T(o^57-E4NdAwNuK$ zB`jheX7u#m|4^?Z|6g2i?fufc#ZD;)TR_79d;3>Bsu5M4kh}BDuea;BUVRb) z5>VREkh?8Bd4)iv0cRs?jsEn=`8AQzzJ1|}n-Z9qxPQ!hd$mH#MU2NUfieDc>NWHD z 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 JtaD0e0sza-(P{ty literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_062.png b/example/output_data/primary/primary_062.png new file mode 100644 index 0000000000000000000000000000000000000000..96f5cfb6442c254459e54c9c36ade1aac07f1623 GIT binary patch literal 6202 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

      B4>vNm#~z9L_gw2PtJsoO8%MAIS=}?1 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 LS3j3^P6?l3SguoOFahH!9jaMW<5bTBY5 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 U-dn#gFfcH9y85}Sb4q9e0K(3}y8r+H literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_069.png b/example/output_data/primary/primary_069.png new file mode 100644 index 0000000000000000000000000000000000000000..b7b327def0cba095ed39b1f2288b19a0aab24a5a GIT binary patch literal 36872 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_070.png b/example/output_data/primary/primary_070.png new file mode 100644 index 0000000000000000000000000000000000000000..ecc868708665e13cee436d0ede941a2ac765fc80 GIT binary patch literal 5049 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

      64=N%gSC-$gNXji^B4V0j;xIR!d1vR zzsptgjvR{^gH54R%t0HqHqPJ~E5v`WHnKAKNAdD2t+V5A|jjS7F)|YATlGKo)*>^jKo3Xvf&d%CKtx zH_=C2@Aw{l{-&^jVS!%9>fZ@UL6Z+((SQD^uavouxsjFOYa6>@`1fWH-+A>;33nw} z#12FjWc{v~wX!I5Va^fJ1KMIs3$z6y7_vY7nxlPL>Z10MtF?xPJ{GN=zjkVJ=rs5r zTq$muz3;jCl1hKf%4Y)sq_)>$a7TOb$rcbESJcEKu;#pS7IL3)cS zYTZJ%tEw%EFlTCHEpWdx;TP+D$C!gME*Z}j_T@2ylDK1xBWE0s@VUf5E_qO-_D$jA zxANpyT(^Knzm3!TgHy*n29VWz)>Su@IKSfF_WH;KHl5~wM*ZUAy5@31c4@}tNp#hQc~DU5Eooz)D-eEx z4djQ78m;{xhlH_LVMBniLT`kicw8Mr&r@>l) zkKamhU4r}`3ALD}&QxhT4i>Qk%OAI0;VxwT{it-V#{0+z+kYA=Y+$gPYgqNPWk=KB zh5L06yNJAYc1U2XF)~}?w|B=cF?H)3;`(iz)0;H@a{RNt#n^EAlmE}HOZ(K~>~5?S z53eitfAFs2>m#{ShF|w5T3_S6!6vBFu=_!O8ABeo;LN81>C@R8SqsG9WUxQjR$=I~ zL!>)shYW{K!|nukYliJdyLWRwEK}IPaPE-2VGsL!Zs)ku8#P+J8xJr=bYHJ*w>`%B zHolQjrt^Aby?*+!Bb#`|SsPhDbS{y5!&9IV$0NM1^~HTv#{|Y2F2D1N$3EmYY;FjM zXz$dx#tIUY^6SvHPzNbvEv&K>h+vq{cDT793=|~Yof_AUI)DSOMxEPy$v+2qhGhyu zo8?};3j&1+=c4d}GO)sx>#fVzNC$w@sIbI*+ZQfhxX$&8GbM6AHV%0BMPUQOI=?>& z&wtc6Y(5xpy-LUH;TDAr3=9eJK0Y_@HHjZyBhJvsx`9>y&{u}+50AEQ7F%Dp;zD03 z^D@T-Mur3b45nvDt1W6!2Zd7Uqvt%I?l|sXQe!z3Hsf?zmOunU`0ITj}F1ns!n z{v3XvA9X%-+`+8I;+Q+*LmdZ)PJ{LXh_B-+1dp!jnk@S{}iTlADfxS)EhYS*HeJ;rd zuD5PHz+_?V=d%7m-3*CKS&WBD%>^PD(vNW#vVK3xZ5SZk9h3n|OlJ&iILg~Hyrq3y z*vmmVI}GAq3n5{r1)@F``Fvp4|2-1Ou%cf)aE;guf%UzP35;_@+t?W;)N(ij*DM3& zoDN9nrXO%wvQ$*<)iy;Aod#p4FI*2g#RJ!b2^`HjHhszQi+&6-^V)yKUyhnn75Ft) z)4sv~&?1pnhdwUjblJdgt|8d|ddi>M@=rMqa2gs;xhk|M!q*{zaSm@AJL5e^mMw=D ziL7ckz+@qu=kd4Ej^V)H4@o;`o&u%w2Y+TrsO5Bq+xs5uD}6jUVUo22?>0Z7t%`pa z*J&Kd|HA%2c%w$^FN24BrCc^JWIfpW*X)y_&3p4_%nTdEp6v>4<`8q>wOZS6b9BGM zIyuHq0*RUYr7^5Z5e)8=cI|mMiCuwTaN4(kxSj;{R|8Y N44$rjF6*2UngCM*>yH2c literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_001.png b/example/output_data/random/random_001.png new file mode 100644 index 0000000000000000000000000000000000000000..70bfd60cc73becae11aea9432fd217b3067ee7ad GIT binary patch literal 8550 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 YUN!FtyOEs8z`(%Z>FVdQ&MBb@0Ar?LLjV8( literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_002.png b/example/output_data/random/random_002.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c39abfbb83e02ef3d28b58341664e5b9267e39 GIT binary patch literal 7787 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_003.png b/example/output_data/random/random_003.png new file mode 100644 index 0000000000000000000000000000000000000000..180d6023dea178885892717d499526c7489f4701 GIT binary patch literal 7724 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 qFGs}tbzkQ(7?l3Sga29w(7BevL9RXp+soH$f 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 qFGs}tbzkQ(7?l3Sga29w(7BevL9RXp+soH$f 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_007.png b/example/output_data/random/random_007.png new file mode 100644 index 0000000000000000000000000000000000000000..f87c630555c7054ed4a205313040a7a97931aaa2 GIT binary patch literal 10159 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%0A>p9rC#!cim(B`U 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 Y?f$cr{`)YCfq{X+)78&qol`;+0BX~NBLDyZ literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_008.png b/example/output_data/random/random_008.png new file mode 100644 index 0000000000000000000000000000000000000000..e03a4ea61a72348cb102e8e090dedfef11eecb41 GIT binary patch literal 11149 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 E04x~X^8f$< literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_010.png b/example/output_data/random/random_010.png new file mode 100644 index 0000000000000000000000000000000000000000..f1fbd7b5f347464a596c8b50a23e56e4e0b99fa5 GIT binary patch literal 9809 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_012.png b/example/output_data/random/random_012.png new file mode 100644 index 0000000000000000000000000000000000000000..ae4e39f268b382c65fee5a89b3c061cf2ed1add3 GIT binary patch literal 7909 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_013.png b/example/output_data/random/random_013.png new file mode 100644 index 0000000000000000000000000000000000000000..681af5e16d9d4022c414a75066e5d3967c886558 GIT binary patch literal 12090 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+eOvna#72z^R_BFJ-0|R3o0RRo$Zp~fKb4%+BAL#6{1enTCJJdb zzF5C^?}k~kF3!*uQ0WToJ=EV(!Ts&Cn4rCvKhuv%C3hI?KK}RePq5g3h}~q%tMr$g z3~PS~8b$n`e6-1|@;y`eq=Qi z82r+cL02GQ>LjH{OTVZvG^7h8OjYS-Wr!6@m^vj)Ibgd?lqo~GU;^VE?RL|M1Faj4FnW4m~Ayhb5nqdKV-qc{} z?H3w%`5LCr{;y@jzaWcg&8;O@Ij$TRS9~DMv_|UZhqhgn{Y>*Wu&s8xmgIQ1XvZXh z9}{@O*48+;RV}^Bu|cUhR6A0KA!8a(*x8hg3;cqi3eKi%WLV&76tQ*k(I%_Pd?xt` z2UpG25o0iMZwTGJMXJ&2$%R#nJ3Jd$KZveZJiwGEl(1D{tsBFFEGC_X^(O>BZvLXu z5XHG6YGRl&Lx66sRMg{31uNRWD;G5Lgk^8ZWoUSHGGXh9?P)6xD?Zb=-TA?$;nj(R ztsY|BuNH(d7c?`hcGY|)eU^zKR48Gqml*e{(+fkH3#OVz=x!F{KK0p-W!;2>Su=IS z7(zVRR+sLxb&g!80u}?gF~ps1HT$NB0KceS2F2#9?2$SQE4mm~vuBzz{XV%cl=(v+ z1NQ^#q8HEj_9!2Cw?;9$t4)A0V3VmE7yK*CoQkViOjrK*y}Vq6k&U5 z8zV#4q=T=f>WIBb@9LP|@niJ|n}#fo4OLUalt0AmyTZWDv}WGV1MPn+_A_!{OZa*w zO6P_@-&(1L|C0{Bnwx)hL;n`3#)T&nzWRxAGnAkAF4@~5_rjfD{tR!&BRgN6}_Ap)t7mf`K+dfM%=_n|%L?nBz z7G$X4ViaRIaEv8lvFB>R8-5@=J1#6sjL}nXfBxYflM`EZ%q=s91D8)E^qw)#y>U z67iy!HTv^X);9G6NzYmsZhx$6dKlS!6y#4ozHp&K4^lQ*d|oTPZDN?RfsCZiIgrbR znRL!w%3|54);`S~_mUawJD3>k zR1Z9=+Z6F(hK!)Sw?C7{K`9-%WL+_vW7TYJD$PfeQ#LX@2xiien;fS6VWW)LuEPyr zw+knH+_6Qf@%EOi21U*d3=C#!2Oec#%3@h}dSNItkH>7beaBT_e6V~kEYZg!c7Jg$ zGs7O`=A++#mhs6KUrq-Lf}AOyvf)OXj@X@PVagY5C3UtbcC#}4S8YC8ma_4|E={F4 zrAO-zeP$?AK9FRcY08woui-!dOGM6TPnLC`?=>upXg<1a&C#aUMLX0Ld0g1K-~L?2 z_kQVBjuKzC?zbnC7!52K#cq4A7Gz*kKEQOtxvyjXQgy~RN2PS;sjqdDnESQUfJah? zp`n*^L&dx;QjHzXFF6^i1C*ZpoZ|Z6m-^c8tR>!T-On#?YrObViu>@ygGut6B6{9j zTfXKy3rME+L=vNcfTYeh=uFcT@|Ew*+!62DZP z(PlP}*zZY4nGzU`BHs9mbx#Dj)wAK~ze`yyfe|nG4htj%w&{o|Upgz>mdGoX8qs|; z<4&_co6>hzm7#mnr7V^PzKqKbvRiT!R5DGO?oK?oi0_se!v#S`u~HAgk3m&J3>$bE#lB8B znj~VWR5xuN%LgAOomUf`#JC&uBA)ogUdn2T+qr>xm)e0vc78TJ2MYOOgO!%pT}v`- zk`WAkXvyHOd|;8C=9;5S3o@B>Ua54uzK?TetF4L6B;pr5P%=RL#y_QF6w&v*B z@Fx@-MQm}t&Bh?5*z6jevhjsyRIh`1%7%9E}JYxNDE7qf*FYcFnN{BdDZ<-PSun-|m@MSO8LYq%zp zWOx1fq0cYwi9CN3+QQE@&y%hD--#r~aNW(}JFlonwD5@4PCB|sHPiHy%IV8& z+bPNil6W#rndZ)R%4YKtN?^R8cvJh7P=aCK7O915mL}47uWYH9!+o}K;@`k3rVXn_ ziuW%JDUzI@tT&#t-@96AMR2a<9$kMM;5waDB5=&#emEx&Uf6ra{xE4DrO zp8cWas*8UMe%>`brcA2z)bY1lCO@+H$6@`(^PjoWKRw&dYd(c`Q=bYX1TtrDP&gE| zX1C64bGI9b{*NO5F!j2w>=#mWiRdn!UK;kG;Oq8;_~0Gy6-dr|(TQ1y z_!isrx~`nez+K_cb$ap*?~FTJHp-N}bcRIThj|R#ewVVIv~BqnxpG1fD4jCtWGNkB z+UM}PZTZEse;H3TU-52W_0BXca_;)R^iW8OT2EG2vC1sxZ(X-CE;C%;5%SOPbw9uL z+uN72p0KTzTrrzREM{@;;ki?|%%?xzq-h!MlUQiIRXE|GspcK0=X#n`xNhG6batk< zFO%I87mn>quAX4O7JF}M&OX=9U&5y^PfPB#;@t2+*{`I0)}u|a&V4_R9G`CS&d%WI z&xq3xEf$C6edCcYRDNOox9_yH(|^f4j=#LYE`QXY-92?`f3n>^C8d9&WkOpwv2oi? z0)^Mo4RYPjXE|lFMJXO=I{&9@XG-y{9}ZD}b*%mhopsB<5HY2UW5WaE*Ak8szH+XW zu4vQTlD0sVN#{q$?KicKTuYs{EjMM(EfiI(Nx575;D~5k`Gu!{PcNJCm{a_OZpK-M z=oFA+3+`{YSGn?t%8Nr=D&{yBxN@^Ze3)7K=;*Cm)=vYp{w$Ia+Zn%M$J}okf`^os z%{bk*DwhAk)4$#((zdglk^`eu4m7zhy?R1+n!K^)9F_M92dtvlUNjZoTIj;j@3nC6 z<-^lb=W4nvFF&!+XN4&l9_ak zXNxx*_r6yp+_G{DPFsJUCDvceu`c7R{ULRk8s9!kM&s7=|8_sMc)!J>&;AhKo+PWj zoeyNXewDlYsjT_4zT-!1j@k!Nua*z7`3tK)ZYX`tw)9Z>GKn3te~UyJU$9bj`mrwF za6b1vG3ogMT2GXvx-Z#D>ik$2{a(RyrvH+PdL>`iw4k+#`b#4At!%r)SmMCOt)X)C z_ch+&i8BKxgL5?FKK};R^GfD5?OT5REO5V zy{#Zy_Fcb4eB!^NJNF*lS(;Gw?MT$bF#Fv%A6G1!uy>KVQN)I+rE1xdB}=cq_bcpE zh^#IjXRU;nrDhE9TazS->D#cu`j4Qn6npZ!Sp(#QSvzmNU* z{~TS_T@jtLvdL2P&a%fF1FGb9=bXO2_e)I9w)gp7EgQD}Ir?AiXpG+^ zW4lhv{s>BwdZVK&_uQ$tAve>6E4r%t?QbQ&!rHg__kL8aGCZ0ZGBf!_^irG0Ggh5b zJokG2o$@X_jtvRk=j|l@KHA+lNR_9cWzhh_0x0a zt-oy={Ze<$@mcZrFBMn3DvQ{2ESUB4#+%!2rff*i4nE^KT`2y5|9RPqkzv_?KVB)- zdcMoKZ2u#~CU|e@iGF7*m(>RAP}~YWMMLzQGx14{)SxNJ!Cq_Tx#q$&|BEX*SC;G>lY~^uSf* zgO@B3Hjc$xmv4MJqj}Bsj3-%#MGmh$e(GYNX-Sk#nB0?eL^E;!;KT}g}Ws7Nm`zJzUS5MgZx*X?wy^sSZup7AEVfZ zxUQc|;z}n>P1+HZczM}{S&b7x0kHE6i`lfKb7``R9_>&C<%TPs-?}z(Y-qS$bjEvj zo!e2zYYa;d$@H2_&plMjF4@b#{o~Hcsm@w9{i};KM6dZ}vmJY^)!9zj^BCs zD&JJm-TCgF{`guecQ2f0+W@lsNAAUI_J)< z(wVyK#iG;IQ-7D`a;=qgVCz=0(iPn|ZJvYbsvPU7VfN-RT5IOL5p{9-qpbBuV@bK? zv-J-ze|-M(N3ovK?6W?{4aMg;^A^onf8jjq^N;5~&9MGEr~Ay4)5|)3_`Cekv+nKx zd;ihL{a(IIt3IS{o_donUogKrcU6Ml{Ts_Fx}8}+uSkvlzy3>&(mkb1(J?Z`E1N8B zH^?U0o%1^Xc-`OX6$y4`(L2vd>2O8M)mhGpUtieq?0<`I%Tu765groWirN^%;Zb@tSUQ)E&X#e9)kH5{o z7<2sXo&JS(txr~bIohhk5)q=|etG+)nSIH67VS}? z(lyUAp3V3@f5!guCz~$M_-p;_q|2G@M}NlVs0B!?I%!=CxS5vO)up#||JQGNJM>p; z7wVc8oLPD`;*7}jr+>J87t5D7-CtejdQ|_Zm6o5X+Qp9P zN0XO2Mg%J@NwS=!d3#N0AeZ<2Kfj&SkIEE3T6}8yr}B{cGrr(dVA6Zx42@aq8!QmjlUw`y8 zcE6JT=J3k%>TS5shi|O(fsnuKd6zMHGVHj?5VAi7;xif)RL#GBPsyaz6eOwkE z6mmW9)!r_zR@aC-eEn6MZ{E6dDf-CmByZ6(FOPi-J1FySx9<1ImpgT~mE7?<|M;-( z+Hdi<>iJ&(fBR|AqcEvn%_x_JXCaH?ErXtjI|8?Rt^Vxe2S{?*$+1 z{<-b?Wxs`{%r@uF&U<;_)3ZIx=NC_$d8g!U_8Aeu`u8^d|D)b*?)nzq*YUrTD{so* znOuE4@8)Uzd*AWn^A8L6gUw>Ik|tWqdMteWt^ALUZR7ViFaHO|n#U}j1;wyU65D=w z?-Y)g9;~Uequ1>{T_mE{D*LGB)0!2j&MwNi(n?)&#ldF^?*{iRj9%W_buT!;Qc}n2 z(v8$FN3Tonoi^`4uBOz9Bv%pJXGJzE*S5aDvw>Ao$7=GTuD;vb=Un6R5A-xzaOvnf zLEhAjK_b@AE@l1MmKyeX+NnO_6;l|x`PTXiiQc=Uy!Kd9P{_@je^a(=Ki!vId*-dl z%Pms-eH&P#1rsi=e403SaZ}Zu>Z>gLnlke(n{_nF?S6b=WN|{BwGWUMB?vgDI&beXvaDHLl$%1Ze&WCbLI#yF3e`+yz zElqzZQ~V*|PmSr(O8dQTp}#dA%`rHss$SSHAy9n&N^~@R>p0C zz$Y_q|M}G-A8z(Q&?tgO!S(7|=}TEUZerQinq~ISR_)AS>JUgU>^T)}zT|3zOV_Gs zGZzyvmp3t5KC1;aygDa1t~qTcdTsWqSwXGe)q7T$z1y94cbTH?_m@E-WjqIO#JHYN zsB^!%R=OzU!Zt;D^$+PG+w1*`LW-U~wXHk;E?iX1zO7-Y`Rv>|x_e#s=xz%+I7jSu z^h-;f@BXR3pKV$CIIK#pJiq;@U2S#ujCsFnj`l0gJ}V}ee=Wgq!B@rji;L!Mk?M|k zH^1xK*-OzTVR|v|F3b48{WLF3IiN*IkvVEwuAlvLCF4qUcUIL6UDmtjn_RB>l5+f0 zNnfSzwf{EnH5-15_%FVh^E>~gZkDd-vK0$hw%svb`n)LF`pSm+ayKt!?O*oX_PU5y zt6B8VwLe&LwmIFd%Jq5qQ)k0Nuc>&Dj8)m=ZYP4chddXRi{vCZtYcc$H2bS)_Hqfo@s zn|q&{xi&|x*>Y?9%bn-L|5$9gdF+l(QF?)8+56Cv_5V97Hx_No31jZQTkqbycYe{F z-@QjaeiV*>vOn4HT-Yxmr}bMh8#*ffo2^)4>loF$JNn&puWu(!^8>$rxi|aKCY8TW zqMpBeIZJz`)9#cF3QDVT?@m};aJ!9dQ-mOI+Qz!$>t3H<%|9LJ_@i@Dmbe5Y=m5~<-A)@|2`2|XV9WP`Ct?Gdclw9kDlKYQM@bJ%C1h=wDbJaj1t50 z#@Q48%YJ4R`QOv=|H$P@X$HF-#4+N^{TbtvfR3!HK2wYNBlPj5^OhwNSrPbh6V%>-bamk0QHu zG)^1J-_lQv70dBaFW;fHw$5(Kj3Y}$1nn1J2w(Jc^1dlE4kSy>cvNj&RvCY)Fz#Dv z$LVaT2K~tgn`Ud}+zr_BGs8J@&9hr(E+YFUnI7LG_geMY*2t-G23%_kL=|f^j;2~I zXuQVYvR`b@vADZlNL%ixIE}YlJ5KnvDZI?LQ2mpow0m!fAGnt%bXmyFKW$x zzj4d2pCUTGtLx{9_fKcM^lN|q1P1PRlNPNKj%(4mW_u|s$E)jf^1JmKayNYnCF7qb z87Jlk-zi_~Z`b!aCn&C$Ss>xy-D}y&T=PGGy(WD+$<*NNYb_mr_c_dKHB+`$8LU0l z@m+Gc%=YWrp+ynbp7mc6ZYcXBI$eEF@Yy93L_U`koy@!wWf?Vb**pIo-?a5MM`*6< z5GkJ1zf<#>rkvA;(Ak-$ZZY~-pFZAk#%k_8^V3i3FB$SrJlNE}WW}nG8DWp}rrq4b zcF8%@)J)Yi^!Oe3WjoH~?7aW*=E^vG|5$?3Ky{bo*-d0g@2>FluNBYz{8?~&5Ty70lmg-72BZi-myd;DYS$6`CXca|@9mA2XbJzJeJSHr1+H69#vQN6ouGo2&X zbhOoeNqFq;w#U~#-_Pf2w$K5o0gm-_tkw(rHuj^3ZA zRbl(?#-&1S+kW3~mCnEKrb*{aKG>A+9q7BV;BVf&r?WqO@|6CW^-ruf{CZGG@fpVO zzxyub$cJ2Q;)7Sf--f#Q%W6S;T+IjkRc}`J({}jEQ-q4h?A;H-7 zl6!jl4mpz(NwMF>de!TKP9!<*{U>;D;)aRxg^~~dbi`%{{O{?oU;pQGY@X=mKex;O z?cV>&{me(t&D$@XEZlj2c}Cj(!we}K5`s0m(nQzoon7v!vDD)KUCUWJH|efDrY3rB z4pTVihJ@nRQFqU&?HWJNJF~i+{vO_Da`Y+F9=C6{C4QX(X5Z(}cwMR< z?DA*t{majHtdV=VcixZsM=}X}-~Bui|J|DF&GNN>`Ib7Z=;sl$aqZF)Q`mp>+|8M6 z;=A2NZupdmbF6Bl=_IrI)9S2E#f*Nn|eGCzKvzcKrn$PR^OR{zk0 zOev9TewR!<>J{kvOk~2rrsrCBb}c*+d@5<`sMT)<7+^@DxT%3AH z=JS^28EL1kKLx2t*^pqaX{UGH#_;mwu*Z5*=aSyuTk}Bc}08TzwDdx zXr=kF-}i6)T=lnYb4098MSsQpFWVMgXOvQJX5Ibk&D(EBcn-gNy&=e?vi{Iyy<283 z5&f*GClU^>yQKcVu50g z9xi!kl<1P4E3I^II@i{`23^h#4Re(z#sec{hBM<1M%3H9VhikcsPOWEE5Vs?^OQODfV8Xwo!xwWAFByjv4=3+@?>wyDhJ7wwDjn zE`ZVyrf&8IB(T&iAh$x%#u(aj$pwuwyVz7xM_Gi&+= zZbq@5CA%kuC2Cs5w2OY+7jh$3gwsELqIJ&`0oQkiwbAU|ca@*nFMjwke)=P$4X=zQ zwJg8L&h7T;e8-R7UsR?^y?;|z^vk#iY?a>o52Z#C29vambvH$nUf#vH?~s(vf(?FR zyUU{;qwiN3PMyJG^1T0&FhiMTc}qD?aa*4mpwlH>Wq7T)e6*_Sw*Hj zlKJU-@k?j*+&3@Xy1uWKZs_OOkRTEqQX_pJOa0r7EmFG|g>du>BplSJb33YfXiLQ% z$Fe2O_7C^U?Amkq@0QGlz(2;%TrR%fba}_x$lSiAr3yn`TWHXEAK2_Y?K()d-vi~*}Ood7QsKpQc>M^ z0%sZ=m$_s1Fa6H8nzi7jX5+0B36AfVSaw&!s1C`_T~TC4_hMUTKJC#%Unf=OUxmEJs zANQU99g?K9!CF%1#l@FiTVpEZX1_A%o*I@sec6sTZ{{std`0VyN;B(TP#&^qU;e_N zTh#EtulF+3*WVS1-CI|1SbnKGLrzY|(YJH2T)ULyV_v_S`K84^onue4H5R+pPvKZ- zo`2Do_3d8gIl(2ex-;JWGL8QAqQv+JUxI>H%Z16BRyw?TrDgSpCif*BUH>_D{=O3l zj{du1?(DnvFzI`Tby8wB2#?O^39^lN8fFVxF8A=5xBW}a^L2N zSoSERh#qG)?kWS><1qz%yI)y!o0=RH{VR~*$iM7G+28L0m$KgYx!-jA(ITYyC82}$ zQuf?woWW;u7g_z9d~bKzt(U*}(;SQXyIIc)B{;55S>I>%&VOQ3-Q4AyE;GobPqg0hO5m5# zzwqPTcQ0qL%=*y(VO#6BIqPKp#8${%{UP|=-Jjz-n^jPDB{8_&1ah? zzPal4JaWyu+5JxODH|4;{^z^7dbQR0q`Ck0#1ttV*!xezmhl1O<-#+p&mAN!p9MW! zDc#DW7UJ6}5M@+y{abZOj9STWyNoU~-V0qK#qLd@xxLprHvcwlza-3%H}PPTm`~xp zNj?50vySfi<~i4SrGS=dGpp`}kS~nQsT&)#I5#XPyIknQ`uxJ0zIXl=x{~VEtXG8+ z9N(s_mz%Qa_HW^T5jhT5St0^9zqEMPRGblX{JXkMp>hUjT06ivS90IN%SYdN=U;p~ zpKa~sld@S;l^&fBko&W#&wBU#7w`D4PCD2m<-1V#uv*H-2BVY>3*7$qb?kRedvqJb z*C}eh<#XInbPn@d55xFOt`OHwfvn`j-^bWAgqL0A5K(VtHT8U0*F0N#!RFtm3#+-~ zXD$>niU{b|d^UN>yF30D3dLRvJm2&wD7{{7iyIqv*23i9!n_lXGObcN&?L146u*fQ zvUleTte7UGIK`}WUij{aYnO`7bl(kHxHIR?t>rr&b9PNS*mP;l?pr56{c8y>*{b#D z$|G(4IyR8-q@XjR+Kkuu?0&6yt)X=BrtB((15H88W~>gYZ`~U1Uw;00jCvqwDS)6? zOTej@s}9Cg$bC_5FZ~n1$S5{tLYQ)ns{HYl4`dh^#opv`*{-ixcU>UCG4Wc$!FzYI zH%xF8+c`ht4WH}DgoE=gfg;#oP4q>#<$)*G2Q;-cfg)bwm`HKvhRdHTrQg&f$a}SH z5MS!}ZJ7_pQ4PUEazSUf`-^X88c3u%X}Ga*&&%c7et4lwq>hFY8~41oAyO?uMHx34 zSUEO4n7L;6A`{z<3piArDyE6#J@Jv9!kJjkq*KwR`RvWq$x@&-Z539kP8Dq3w;0>h znpva0R|{q>@Zs1klyGobP(-=w+)G(3^Sl~Zqh}_?m46N2ku|~UWYWRBH3ys4&bb!* z^w8&q=#sMbyBr%5xZ4Y~Wf=Z>cM9y&ZY>Sp;yhEJOz}X|`x%FJY2TU@ru;#~tL1}i zlQzS;2?v|jTdm#g)%u*VKS-@*`Q(F5>pfNrMm@@Ms<4vOsR-ffzLhy&N6cm_1Gk)E zYialw#kFn;!CoyNIL^8-?r7!_yK{O`S=C}64u9ol*6$vx1*;M^THEw8aN8NTy1xCQ zdAufvdA4xELHA`dyqouPooAk>2#$^g!Av?oI$Ym=d1uNJ@qtBb=V4v3t;Ss4cN2@5 zbatq%b$byR)q7w&XazvPToJLY%pY`(A~u*Djgbn`OEfvvvO%-^&cl?h&$$H&CRIrX zm!)iYaAZ-Ln|e3v?1=}PI1Y-soO$c9>`-xoAIAoT)(2clUyd~KY6=={6ImzGqMGV- zqlHK8v6teGCe!Y_iNe1U43}x1+kTL-p;uGTXrAV|w-QAcXFANC!ujwvOGM9c(dG{u zw@5X%b8e96e!%rkxtsOA(t#wIOjD-qORsX+90_gdQC#cBP@x1`_uypB_Jb?c>4%Y| z&aY`s1+4K))x~ON+C_ZH?%H{MYW@R;H$I&c?0gqq7tL{;DX`C_!FB#Urvlb!kJW-Z zx*59vy(ne9J?Usud*lfD+hro6#6 z)v2PxE@Dgi+~TtfCu-P4_w8ISQy?y>bE{~_r}NA9sxva5I$o${!Jg5g`{C(4WMJ{+5}A>;J=OTrBYBj50qZ#*%#%%^bQ{s$$0(pO%HVR*po z)v_g#%RIj=N<;Y2a+ZiKj?>FlxJUIKux8SErM{!-*NLQq?K(xv^P03*1oP=iKVW9k zd8N9esp@4Xt9+2s62DASrmul&EwfWLtniQOb(s6*NYiYVh%2gV-54?^2q}K`5d3KT zEH2zZdJ5-5ElHhM6PyZIb%WGeR;O&x&~JUf6{XhA`krHhMt0Xu*=GLqjPR)51|daO z-@<+S6&Olf*t(6D6?{&6(P^X@GvQ!TeK5zm1?FPA53@3g{jTo(dDudH9y^0gr;y_B zqI$;{(~T7WOy?2%Eg0i?e+uWr{V5x6v_IfFrqInQsCXcWKhu=yuh(ipwxup7ia{$+ znI{~4RCy_j<=6rr4kn#>Dy_e{53RVA)xxMLxM{CQleR=;-%n!(Hnjsu(V8sb2D@rx zmNykQ9Ab&cN$=X}z54-I1uvtR^Jcd0T%U*knhvOT-<6!fBX-}s^#NCfe|kBa+JQ&a z%LHN=4|EAB-hV7+alm~Fr{okKv3T_zOm>TXPAo{-@I&gLXn}sD4x38z(Z?*|2b7C4 zZXPILiLg-v8PYQ^g2$tC!tbS5ISTYso!FF{kJetwVyS33`i=)Qa^G>_~gWLj_ z6UT!%)-~j62pb8gI^}sQ?qJ%s*yn^p%7z_zpn%PvePCM3Mu`?4vG?GRh42`P7E(+P=2+M8JXkG-fl24w9VYf0&QZM=6jhzlnzR{i^zeu^X(!a5YANw!%Pwis zUceGAe92OB4QO%O2K7iCE460RRa>MOzo~V*9%qSA_F65-aAS(l!;GLE`xOHCQ=P0- zn@uN)G-)r;JJnL+)nM8MV%u3hJFoVlhasCK*kw=41FjYRc74GIEe{BDY^X9n`tx5C zgJ~5nquAYzC-$a;+#@urp8>+qveP$2Sv*Blum>`tceh?;ijFKgq!C099kgOqYYxekglgm|&7cGYAFcep==Gjk5ZYSZ8| zZzXCzFxYyp7L-yxkabezojym8vsiaqWb@T7O_uNj5hZ2I6PebC`6%vSYG~6C+;%{> zpdnCG_>zX?np>Rf8YY66jA3V4!Wk~8s2+;qT*r`hs>Q^kA$0K;DMq(xVag^B4WYBQ zNHI=0y2$cc!c~>EZVYK+yD!hM_wsL846=`5Zh+DnN3MgS2hyi-W_AcAW@@s8GkgzF zTcXIcX40~b3eJO~2W*SZ#Ct4cWLgun%;J8$K*RZ`k1a&!FyHZP2t6c{caI0WqInUg z*v|L4Ad|`?-uN-IL{t}Z%QU?ATrH@z#AS#2K~V-CN49MJChdl|8p1)Al51=^)-h~b zsxCHl^1-TYTcj943p_<9AFNsiV*BywO0Ss4@H+BR7E3~ORZ^g#>Y;RxhyR)wssq%P z1Q|s{gVN`X?xXKQyc)JH6=~9DaOf;B1_kMoRgB-3`gpXaY}jT1P62PcXHMYyTc7<; W?av!_)7uOT3=E#GelF{r5}E*lw1B|? literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_014.png b/example/output_data/random/random_014.png new file mode 100644 index 0000000000000000000000000000000000000000..fa460579e7ea63ecc8c0031537b80e4444fbbfac GIT binary patch literal 11311 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ν^I*%#c1L#>$W_xZ%Z%+dmh_{<+ydCrDyGK5g4DDU`(+{*c_&agq3vAcK68zzaFY~>Fg zu;`dAx+vRF${F!yL5lc+46hqcSonMoBq{6eW^fBVbeh@12Bf?@yIhEAgBWAC?36c5 z5}uvcb*mWIRT4HXoEFQV{7Y`V`%*@k2@OZv?s#$>n8l(~7PN^wK}2;oL&ICnh@2Iv z;tUL$EIMXa^w!<=^pLp7pyPZXNnLd}1H+BphNH)#${2f=vw;d_JR0PlM~ENwEwJ zIc^7%+;u_zZf!W)ckAd@YtHE(UeC4vy|G%9VfSw_E2SG(pPu&J{(0fljvun?|If;v zvuW!DR+%}nI%U^3aVPMr`aOJQ<#E;G?(2Z>y6g%0Ok&o>>JNqLj=ikdu=n%+s}^sQ zuKqp6cw=^h>!L}q4ADPi=f4m7+ZD{gY@xx}J$LIHrW-+fqw+HgxgzKPEoPW3wBbhN z?j2?74;NmkSkt&SZY=}*BRwaf9g{y4c>T%F%IE*LyMF$k?+k2d?AgvuJtkYXtN;Hi&x6z|CD7!nc5egoU5X*zgukHY@>xj=gqg)FNs?Va)!qvze6kU8vA^S{F=o&V?u-L zr28M&|MxmD%WH4c_Jk5<154Wom7RMgZ%7k8xH#+0<(_}aev&c?K}=!=^M(FDi_Klz z>i&`;Sa^fSrA^!q0;^kBi-Qd6kkb*`Ik`aUYu4S%_b)7C_c_id)(MX54=aUsIy=<2 z*6AczF^P5B7^PRJ`aOIWp2TZvbIR~h4;=jn3}g?g`B+y*jTa6`lQtE)|K zum7MSn;P`LQf`leOg#7kKxjzZC zI`H62!o)LkTbwlw-HmtF=_C{|i7{*5Wc^Td{lSYYiMtFuz6X>dPwO>^oBAzW`gB_1 zcB$ew+ZeqsH6LZT<2hs9ks0N@b<2*d?DhXGXCT4Y&A4N-!QC^yk3lvyC_AxT*u)(X z-CO8xbZ2qg+BYxWUuFN`bRdc0or+KJBZ*ocQ$P1Ps@r=??{I}UiR}^CAmMXTFF|+n z9n%W_#nNnwDUK}-M+KtF7_(OyUXN{_zcR7pupW!Xj&`+jwugR)Vy9ZXyIa2B`NFL$ zw)v9oHHin4S#-b>y?@pml>65<{bCx6&W?6vC$@{5xFg(c*XwRG6hTi!7B zt)Fv!R>a|Zbw@NqHcia`XtnYB5~~CoCb8xW@$2_DcUf#xKD%dEIQQR(+1WQ)4@_Xu zVFMXA58Psie09|;{q3V$`tBbN&0u5uWc^Q-aj#75**^x)<9hOLOn4u=BaOYgG3K6U z#O5xGc~Z+0t_H0>@m>2%a_+J3dNINq9=r&XI9<>$rM4%3S*ke0VZjX&9;fvlRD?-^ zM3rI_f%imt&h>zLOe6#?Z+GJW5 zAN;=6U{_+X>23xO^#ntS{xdHZff{UwPrSP7#jd-XL87bS=mD=X#?MiOD_$(ls+i&z z{`S$Y=WFXZrYR;Iya;Z`&N#Y$0_(0xuO7BG98Gw2bnEVk^OC;5sx$r9n^*C3!Q@%7 z3`;=O>5jE2;s*1<;jnq-$6s-;=08;1v3%yPx^ z1C!^3Ha8qy5LL$b`9k&8c;4W9yI0<1b>L#`cHBAnL!RoBi@GyD{bPlOQsbo913SDp z!lPF{T(N;$bE+w41kb8eaRc__&9_%6%G|tHFdxtT{{k`aI7c3#Y{%IQW-q zcSL;HChms2oDn_?Qp63GO~1&KvpR0=ot0_g3@gtZOiGyNSrOcM`Qp?_-`_u_tM^{L@Zq1T>TZS`QyY#R zh$>@D)&eydH)!pS;9qr<)j`TOg6Etu=lu_N4#w<1T(hSA#o;91vJEp_PU(6VQxE+koe(k>E>1~%RE%#u> z{I53-HeKBNU3)@&_b1&s-{r5L%l2Hu_)RszaL2S*hCS=sHu9EVZa-SZqQiDwZ(XUF zvBd6(@+|S|sw>%UOqbJ9+wddz-uv2iy&tI()8f`xzdW3zTee}wfk(%=ujk*pcjkDK z_-ntnd!`+cO0Z`Vo2+@0^+`tIuch%jr2KjJMwIXTWQtstq%a9QrG*>SwLe{Wsm;UH_V_*gv~8OD3_&J8EX?ebak(v$=Rhxc2*qKW(DZ z9(7Fc-13I$)0Bu`_Vbl5wjZ@((NWv@Vs49S%j(E07QI>8J5zhsriwG{7Tho+;G|xH zz5U}7n-ensjs)qSKfbj)ySdrYjIkSJ#<#EE{{%j|vh9#emc-2uE2rO=@JbWhUQ2{edU7fp&gwCkDJK{%oD|D&C+x7^wf3ko#tqzz-JM(BFg>s<+h}(| zZ=GsjpZ9?zrS3bPKkij17)x4;l;;)HFo{jpy2+Ze`sn_2{#nN@=1ZBSzYE*U-Qdd+ z;j<)Fd_zAtch$^IKEw|Sjbgc}hf~BVrp z7w~r{3vZZlqPp?b`(FF`A>d5*tI(%n`K(xm67>YbPUhAX{S_wXHg2)_6LaVJ)i+ED z!Jsfs*S{=w`FqM#3)VF!{~Pc4WWGh>?h^j)$D5j27jLL8_37iZf53XakTb%dOQ>pn zM8sJ=hFwK2CsgdJXZqFc2{`oe!9+{7KL<{K-?rAS&-Fl(()PGj>=n;{$sW2o@#^ZS z+`l$hsJXZJJlQM1kNrnu%qH#zpXs#`s;fC(_#H?xy1&kj&!PDD$EyYP%o7v5zqxw`sA;zEjG*G1lkY_5dH-mfzJ0OSJBGxv zvJDCPUqOBQ6W0&1o%IE$?FIad+}{EYDHmG&6#jJB_typsK1S|uAB5IL70DWGDJzVf zl+|GOCE?(;tT|G%w@&%+sJz1V&JzCaWPuF{*=ccwzKegepE>+ULPqe=v}yaYKfFK6 ze&_Wj{?%!sjPYs-2g9=F+|$m=ll)z+AHo^6e#?cVlHk*N47&t2Byg+x)rOmH@A=3P zDfrOu5dYTh?BK|m(;Ha#PW@4CvSZHuo2+LRrimNuDvR?@;{9OCB=+T-vB}oM(_b7; zs$&xS67u-Vy$eOB6PWz=+g;ei-JmbLVZrpOtxWz|;@2l>6dSQ~SFK2#@nZE)*X=X1 zzu2cG)-F2sa*ypH@h-`m2bE!xzvsKQoy2*OrFpJKQE}?GwBRh}$ zF6aB#5xij6p9fRL@+SQbIIYL9&*eZ<`c#Y5?);4}svSFTKV0=Tiqrjy-n#mGzuFTb zn8a)rA9=+8MprRrvwZj8RG{5MsB&SB|BDq zG>h39@ng;u->q+$9%M3!-C2F?W!lcAhp(3E`*gRS_q-Xid&jl*qcJQxJKTHg7fVEC zsd{E{gwMVDhAC|!f43!P#D|$uho%;6<#j$KAF`RdVK-;Qhly2j)6WW-wrCe!eZ%xX zlSypP@+14>-pvYkTPJl$H2GrtQ5zPW9bu0}*8OWK_z%w!d!m ztSHY#Qt#VW@2Xb)5O!9N;hj>#!S3nG2UBO?RBq8e2C}7{Ga}%z$^ERC$_F_fc3HkS zoW#c@_FC&>{`FVUI`fpXIKq40ZsK2^BFb1Uydff(xA)EeVCNl4prrj{O2g5ptT}zm z%5S1vk7%ZHg`ZiFCeFYwxFN#5H+b3v`Ezy0Z_j0jmvOsxZnd4xG4+JP8q+sXdlh4r zYTsl%^8%7#-YF#%#+b6KF6RuF0i|?1m4reYQiG5zJ7*V_8$V={!b^mH!K4&!4t&KS2cp%Bolx6kqDL>48zh1g@ zp81i1R~ci$vY1`q{gC&xvZ=mnvr5 zEp+JWgMG(eu5VV~VzKv_cb4dfiT{7!&;Ih1*)8Dl*SxFV8&+99J+ri>;ONGehm&gl z@7*c*_}BBI-M{{v@3r6mPev~Aocwg_P{Fd*a$%3(-VN2wnOdNu`)}_#?+WH5m-~-O z-A_k9J@)*%`~B;cX@W}UeIf&0kxJ$p*GevnFc zna{o^eX8_)?zGpdo_|$k{@xBFZ1*VdWueGd8bjV zr+V+-UCVE`J$N5>ef`r}Z=aI&!?*WhPq}#F?t!d4C*ORlS;p>`jC!cShB0WD}^vpW`lynOknUk z`v1SQA;)o*RQ}?W_T9pyu+&D{l}{3v(&d_PFwk`7CTJC{-}NbH}Jx>i<6Tnn20p|5L>oYL5nmH?$;ZJ`9 ztMhN!L!vcHQpFkG7rAg8-nEDIZ)<_+-m0ya4o+NVUMy0!A;II&)x=u<*?M<(s!smM z5n&+nkZWG}X6}X#fei@;hps-Hx}o`M>}frQdl#Bn4-2g0TYu!`Jl4;rMKF-~dRro7+ z_uClm-C8$U*DOmDKk$e}=Z0_Z_Vc1S59j@L{lg=zGkf(-)&u`JA~tkO9TI)>^4D+P zZ>k9gpJj1`&v>wJ`sv(5lR{ZIA~vj*IwX21blRj?25#XE3C5-^+DeBSF2-Jc!=#{e z=3rCrl?v%~HsJ-4`<>U_yZW@)_UvJ$c3GVl>)HyAYOC&UxEhluK5dOs#GD3JP_n34 z+VXF8i0Wdj|it9M9@8d`WPWH*L|5+xhS0D$$JeUmH%OvUBfS12X0P z-&?Q3Z_a&rSZR6#Yy2nc7Hx^xlX?xTmP#$lW91z82(0V4Z67)}D;>bSo*oe7``)g5~pu6N&8Hb|FqX z9wn;ov1u#3*&e#NE5VUT><&mwvyYwq(kAYNKqj$0t6K_K-7n~^`o{{^WhGNXe zE#QVzOy={gD%TEVvFKDRJ$Ad`>Z2<%x69VCzHpWo`z^fTL4DSq+I0!s%{>(z|5h_@ zeZv$n!H`!#@Q~D~VDRX9hu4P=;HK12Na_4~gs%x^f_l(k2G-K%#~ z8LErwPS>&Mh=EFS;a}_3f;V%62FS#MoOdJ{tIF{6txpv{;B@9-lAvjewps9_FP|j{CNx^;W>W}ohYB?fg?z|UR*YN%78zu__#%|`{viZx+xWh}p zW512;ASbpo9ChRjKahUraFR8X7`sZ$M&-ZZ!k@&CePhw#bK8-Wt}4Utw>C}ufFoyw zOh>`db6ysxqhw)V9pSU4rNDKT(6a6RZ?8qqzpL|WL-WxkUL4^EitTQNZ+Pw?&m<^^u^V4Z{)xM{oZ#bP<_zu{j##+NY`fQq3T$Gj(0?Nq*b zUi8D|7N_Jgct9;Xv%k`xO_J_`kZcFfCZvOEm^~J)oJclaS9`KcIkZ344ssb8z zf0xAGo$`IppB!<6j{AkDe(Ub!OQnP> z>={Mr0`K?ov}&^@*)V@#n0!aFrCg6K%;~-82LbmMhWVhW9ghQ$`I{deV3&i&gCO%Z z?qA{={SB5eK2Sbp%;3MFnYF;1b8q;8U>2Q*Xc>Mcf9UK5!#&9G`;2K22e5vS`x|~h zT;ejr2f4?R4f-IBYg_JVKk)u{T8|+?;@js&zc&etca#bkK}IMk)uoFw$aI1=@8)2P z+w=YMg}E&Ugx@4E?%BZ?d`R?z3M2Oe*UrloZTX5ZjPXhdjC&0B%D!+pz_jDaCT@m4 zhso9lxciSYT5W7*6?pj3!XcbV%%SCiEY>>^lN>?I~JXUTveriDdLPWy$!5u-d5i@$h7NnGwT}P z|Dxboq+3yCj0XfcLDNZPj0XZi3?2zqGw`_ivXinA)7i=sl*=|Wlx}^))Ua4+Lxbtm zH%tx6!W$Y)GYiD}WGD0Mix2p6 z&hSCz(KgJR7Ryjj!X&l> zs)6SB4p@1){5h$|6w%ngy5@1Ug%V2{cupkEhj{~^vQ)#|8wVkY;97vwf6)!n&_VqO zXHI3Q2Jm!MPXZ}bl z$->Urtr0ZQ2yzVr!(2%dE}8j?iw~TGX+9q2)NH-M8mgRO0b&YFNNzIo8@~fgee2W2 z8P>QRVCs8YUB-Bz3mixY!lqlm!tA^vixA8!;7Q3oP^WqgEQy1Kz(n8bHg;QPO@wx2 z)`K1U+8q}=a4~XQY?~I#ut5pKRSXL@=L>!`-_6nB`=|G^zh%SRo6rCRn@%jzw>njv zVT~6w0}`tXkGeO}E`QGIF(nAsKmHQTmyixCBftd(A;S2iti`?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+O)R@@wN34UerUPES2v+5l~`j=qe*f3DsFC;uRm&<{HZrFQp{eqq1}Gc9+n4zag+XJ*m5@f{^kCflfgQ8vQO`GhJth^u@4dT zN(qd!)e{&Q*7zJ?l3T6z^JbM0!*^AXz#I1%R}Pz5+MJEO!3UY-)*o{#Pq@sY!_Y95 zGvdJG%&QDJa~fC~HW)E-SL~5mE7jmzEUI{+O`EfkH~1hEL&VGm)-8d_i>)_AGKoQi zg*PxTgsCMk=3dz`N#KSKBR4}r>Maw7w;5L%a;9*JUGVGeeRn{OGlGFZTX;i5*_JE@ zGp_?o3=uc&Ki#R~I*@l2r0|mcC-sxXQ(iV6U;XhGbIzqZ%Mwq?Y?^1Z{{f>-R~YXB zwzJh6vYr(zoy2Mr)q7nwq1bQso$O~5zG{1B8cQa$$9Qt&TzI{j10-bZB*t*SJT~vL zLJDJl&|@#BgyMVeo4=MwY%OG9_%Z2x{;__pOyab@np@!;PNXOkqV_;Zl>B zwy)TDQT9g9ZRW5=z03vH;X+K(oBR%VwdgQ3G=F6ZTNEz#q1JSr3X56t-G-?zrm`}; zxtE(OWoM-NQ#4nm;Wa3Vj{Fi`vv}6dNlO(q3)V{A=5Fxa5r4qyk~TNPjhVmM*SM_L zd0-V~${_u5M#I!Sd5;+wHYE0QN1W75*?VMn$b+@uc-?V7v_*cVQ8*}+7cj}}oFs6g z;dt1FzN{~&m>A4f`yTMxQpljUdSfetMBMI%sT`39qCt*YkbA&NXcI#N?@Q$b)#YtV zZdn}IcXh`k0f{(!M(v9r7qpn=O4$V)?Qi}on=6yhza@)-?fdyJJ3g;e`|1D8>)L#k z`t5UgJ`@B$yWX(>wjc9@-M^xgY{H9QO*J*0%gJzH`WNX9lY&qDnkx4?=fK{Ks|-Br z-b2EHXZinzQk9g0b)XRE$(;ihtqx4?6p*+T0kQnWy$VL{O4&`zmKig?TYBuhxxpGk z<}js{gV%OW5|FsDgHd~?^R&1~28Z-xd=V#Kw=G%v(x<@`?EY&%7`11{chtK`vokE< zuD$o>r`Yk|;?s_OX2^TK?EHZR+X4?-mA{!98s*0n;oAFm>VXN{#5YU|-T?~rjD*>Y z+82*8ZgW`8mJo28H==U_D}%|#w_q14ufDj7QR33KbxJkor&y-^?c@DmAQUdd#C)rc z_4SIhbtx~WvNGJcS;qu&XGfOKd*;J8!@;q6?4g%ag2Qi~h|ai3h68usm?x;Nziq)# zyQ)xC(O^z3`ro8pornHVCD*4;9xNjnvDvg*{IKFJrL6q^vTp)bpi*VFs*Oa^aL ztuqG#Sk@Gq-m+j|Fc;o1EvrT6MQ<4IfdrN{-#H=~4w!RB$XlAJTs_8kYZb`3U8_0P z2O90)VPE^H^1xqE{C03%GxhT0^<2Kpn2~|)!}%MjC39yzv7hM-jnOw3ru;1b@P6B6 zh8=BO*TS#NsY>mlv{gjYRdrwmNn5J z2e2|-Tl?iy)A1D>*|{a!8n(7g3YKPnP?y!Blfc1rEy@d&DkpJ7yw(!j^k5z+O(`a< zUF))5hv9}L<7>GrKgHE1b2)RoL4Fdr^XBKhzU|jEd!I8#KU{YH07J-zcfKH{vW%|< z`}S_~I_-JD?aGb&93}n-s-_f4d_C248|1}?hOZu~w=5VA@Nq=+gJMHBE5;L~C~G0u zCWBn5s98qsYwmAkl-uXDnr%U`R)p@=jK>W30~i0|F7Z8(wbtzfQ$w%dhN^|(Vln<8 z6-;6NrxLGdb2GH5C461>%CUC>D+9CO1~;XY zgPy(GoQ-*$5sM+Q$gu0F)}g?uXWrkNZ}-#YhEcc>)7+qgQlTeTD!#l@qISWr_qqKA zRmSWT)syczA{j17GG>>UE{}^0zC06L3zT>rxYabvGUacVHV@+hW~OUlS27+S_y@{) zB_~5$qQA_ke7VGA9=lDGHfJN>%7omBaghucrZj8~Rb6hzw;|QkY!~xg!42C$Wzn|t zQ(GL`S=Ox87Tm<};2_HyTaAm_-ETpu_<}5BwmvlS7;@&B@m4SCWsY7P%6vgmbdBw$ z2~*at-1vvL#Pz_f)yeDETq+V`*x<`_ZQj(wE5gMVUtY!dqNibNIXKErvFNnu9190& z6%7|GGD_u(^q=V;0nTZ%fd?Ngaa*s$5YgChG~4u+g~2i@?>i3WEIRjA32u_;*XC^O zs^WJLw8576HI!-8-B!`T-nRa@IjNY`}LGF zimz3_?YyvjmbH!fY0>${cOP>zHw$mr5qENB@8K&YY6X$L&Cj2Gepq4oyCTa_aDlQ^ z@2Aq>XT>Mp-(c{M?>m2b*E9R7)7~kzJ@tI@*T35d-jHDIem`^4pHnsWG`Uv+!V_c%5E+KDd< z{+#)Gy2W%=%m!U1vF*Z}eq3?aH`Z2NX#ITq``LVpwZz|aHXOC`dS?E{e}0Xe^_QF8 zXSg(1Jed+7_HX(7f*6J?H4a8eQ`VRsBYPdsYeeouTzSt+j%y0!#dNW zY*iWl2Oj;~Qutv1x%j+yGaCA?1}{3rn#&Pk(>B3%(slDqdy)@mbx&;7ToqFg&m`6# zT=es6&313g>X4#UOYRgl-z)iHv??Ne7RbkITn{|jXjZOi8z1~>Lc`QIHS*V_mSqSt z-v1u{n)5*2x*v}g)*UZ?t!BEO`BI65{i-70?vFq2M@Oa9his_O5nVG^+j8!Le$E$t zAsgT2SoKU3OY}VOXrrF(?JuWpP1IbTw}77`BGvHQv!8DspM4`fJBisgLg~rHx+h;f zpMHOMp5NlSQ~0!eGqd2_)j#iDdQ|ew^7#L_sojMu6E5Bp;q@#}KIN<(;kp0d)4k#M zex19Yzv_Uo>(uVG!W&++$3*m*XWD_09SBwJ-alI(;gu=dItV=X3Y=lCf5 zb@L1QoDm?k`KgAR7(r^Q<3HW`Id4V(x#P<7^7~KEnH^`g=U9ov{-CE)AKCr#|6QzN z`mnG_V!r(^l^u?jGX6KOReseh-uiZL!A@z@nB-Ze|NN-&(aNka0*ml^t> zwb!qgxU+iJ&%z%oL|Hd*F?JhHJ$l07Rr3BjSDu}|cb)h36V+nX)oYA}9~d!q7fwCO zF?~hc-t}ANG2~2dIC|q$QcLmW#5KInKd1(;TkW^@!ulmCd9^`#|CcvxXVEzp{>bHE zs&nXiFS&ipe>J})ADqh(k#jh>WliFh&HeTF-k1y8Yz3GZ~ zrZ*fd-=brJ1eI;MD`re`j=(P7;!b&FSp6-aOH(-B@)?(Eo(AP z&0$!6^uD>4`qVS~&3X5kv=++-Vkr+RI5`M#U?i=V9ty8eH8et1!(<%W+@v5`Fo ze02mj*_v8~m9M||e*V07|5f*;pL)7C?D*3IpC0_wnG%uIF3K5^6WrT(wfgGQd#fjX z{~k4!{rpqr`bXt#VM+-bV^#C`_L@UHern3P)nVSMcT?>orrJj2#7Fj&EO;Vf6?RAG z`qg`@C+U5UihZp5u9n9<=wQX&75@rfieR)*y=Glx- zlcpcOQKh%rZrSuFPYb5p{=fJ6H2cd%-}cUt*RF|Q+drM}*@FU}suc+v^-XV?=bSB( z$nMtvGsib{?X-}M4{o#Qd|RH9cR%2kU-Q&IUd?;MRcGJG{yI}A-|fL{7M*V^b=;1b z$R7K3LVw4{RaY+^Gg7wcvWs|g+k1|~EX#dguAB*1s5x9LcjNo2lpFiPwpVrTi}>KG z74hcw$5V$^ezf_q>!rap_nL)sL)T6#o1mDO%Ov(YEcx>96>^)tuSyZGUfXarQmN(0 zyftd);;Z)U_-B&J7jZu(a?d|*pYHwl3pZ@?;fP<<#MpSlBALpD6P^Zv~9+Fzy9UxjwA zx+-cTQ((%-eQs)o(=UVib9VFA{r2yhA9j7#;VF0H6*=y-Hn4iDeoOwEbrq~!eCm!z zV(U~A4ys0(e@VCMDebNIxcch$6aO7u4Xo3zSWL9J^5y69H9>o|0=Mo8>@=4zU}faK z7c8c%z506nt1n;wKY44vAZzQaTUAUK>>0W3f*#$i;?G+Ja{k>qLDB8M*Bq+uXTU zBJsNXpL6Ky-5MW{G21C7985oz^kn0{P_Vh1rOZ9s`8gsAdWGKK2oFDR_pkD2@G|cC zzZPn)3giEz&LmcIU~SQZs8qvEO^;9epFLWA-zNQ>+t*q3tDh8cg>Bs>z5QHc`O1WY zTTdlD*|+R)#QL8up{v!hUUNF^583cw^`7kbi$71Ff8@A#RaNMstg8W$JqPMnCL9d6 zEMLE3-`~~G=j83EefWQ#Z{XHf4rh1YexC3?WWxjNd5gs_Xq{XC<@d*LS6?J8-QaR{ zm9o~Zf{9#WHSN`+>)v0A-aGwC$hldIvaTxb6w?#h@W482PDI$p=UwM#8ma5nu5Boc zP-=;eklPt}vR*q#|Gmuwd%e9boMEvas~PfFBplS8^Zfef9Y9QV;*;&3etbp-t+oRD$Dyrs$~=N|BdCqR%(1 zUsV|I6d|x7f!B0Z#Ofat|LA%C{CniWYURaZRQFS=?{rGJ0Z)d-va5BG;`Nbp@1@mgbM^#r^6Pn8UFgAO)r ztrY+7Dy|jbu3D`6x;&=9qG^*v;_;9T3Aw8x?wjoWyL!^kk2U9BAOB*xD%#4slCm2#ZE4_Wig{C zi_Q*t^;z0~Eq_=1`VoA8b<*7RMoc9R2b!ui1CLg<$Xnj!54w=G{zxsSB9qvi=~~x* z)#>y-+2Zbf;nm?QRZJJ=HL!jUS=9Aa^>Xh2%H9Q6o2B}#cdI8H+`BTVcG11(^F_AY z`YGIRzFR$k@phGrQ zTl{90s#8VF)BKrF54L`0U(w8--nI0w>5UiX`c@_!RQ_|KX41Nu{x@{4TobNX>*kuR zyYwr|0$x#_3X}J*^ey}iWbG`1L$>Vmx;kxc@WCec%QtInOtqroKh`{azh`QCI*ZN% zW>A)n@_kfn+9XyW%E&FZ_6Y9+_i*J5MtPwP3s_IL+zwFAh%H(fzQ#7?vxct zd$Y4_8`rNE+%j!ig$xta%&$a7sc4ww5@;H{QqBSp~G?(os5%45ACkx zm}g8qT*za+-}wFhU0YWE{qx?-FY)z{pZh=mGK^}|`@2=5!|&aNS?AudAD_Nx*6HaB zb5BgMbn%fiPMLoAhj#zW|5GkMF73Q8Z?&X}b!~4&(^E6k<)?g&(obK?GKvrQ^ljgr zr;PF2)9UuTvi|?Sa%y(fftm+gS`inbB71gkUCeb&RkeRLN3E-6&;Cp9OJ7`)d|l&z zedpuetFP~-F~1kuuz-CU=jUxEn}StqS=N58l=*+B`}{nu%ZYzVzdfJzv(LwrNt{2i zQ=sa?uasM@x2l+GH8OXXL=R*N#shTyf zS@`TqW8KZle>ZC59z1%m{+ckuxhpG@R4ezsp20tL&a}1nc27O?@tf)K^Y(T3_-^;E zU8Q&IrGZ?1`~1bWNBV9);oDnzuEuFi@AHoZ!G7s=OZVhgu7BH*&30=h-|_P=j&C*A zinuV_KJY-}+7*?5ciTKI$v^r$gMVY9R>XzHvEPo&TGX_)$$R~a-PL-$DONpspEp~A zWRmx3$Me=j^x%^sU|p{ zFAG0vRd0Fgs(GEXce9RfrSy(BkE=8oxvRp&9zWap@bh#~W6r0tUOrr@6Qqo6cf|;`r3Il^3%D*WPiNS-0^eL+3Pv`x=dYJU(24KIX%kj zapi$o%MR~2c>B+ago``Rs&}mqJbG*SOM_``#SPUfx(zF9XU}i^UdS0?^6k&hwM<^}X`1#!3_kjniQa`)yee5078zSi4yun2FSbX>X_c{eD z6AotR2){dCBH?}5(jos<(j30z^wV8h5hV{cFMqJ?wCVlLFSV}y{G7P?{*%(UM}3YT zWP@kjf98H*5%YXo*13uIG`b6e?|iWAT{tl9XmGI8_i7OjYBY!44EJG|q~@zTSa9@*#35xV1f z^7eM=r3Y=Sw%xRw11Sy{$$pn=IlkI*Z-4!%Klk26oc%TRr| zcL>eCcYou~v+sh-$`3!E^z&1pf94II*>@yeI(^^2zv0PtbB*Tb>h}BdYvc?>7`q#F z?%(_0l`_$?e3$;G9eod1nayM0pvBmIkRvkx%3%xBIn4Ki#gsQlGKn>>tlT}VXwQ_q z<9)O5nlGGJyXWDhJ0jlA8xqZS8m|zVeNWtM>&?GEHic}yIe&FE@1bQY6AV{Ox}N`c z`I~<}shfXWoJwLbb3c%jpt^qg_y=;zddw`hohDfc59G8=~t>yFAd@5Y)8?wIRs8Mal`Nsxzowpz6X4vVny^t(HE+4|^i!a26NAl___gW`ud7bI z4t@W4Q)1mKYwg;fBKY%Quf1J-m3OifQ{s6OP>~2^$?v zr?1z!GjYCR_4Jr8v@{%boBF2i^6zD73!M0Go$Lo*YpZZk&($tk-Ss3=cc`NjAi$wjrzdPsE-kZ-6&-3b!+o6+sUN+8p z!h9u%pL=_^%=MStv3~vAgR{is|Hu5Pwe2}1emC0gt-0K$Q%N$192m7L_dd#bFZ$-* zuGx2%Z~i#z!&Ht0lb}tzecvAr-N?ojp?~wwW%eJlj>o!M%xKfmwt>EdVC*IlZRa|r)ebt8OL_s2V1B>LB{JiqaMx3yOLN1GJe zI!etxU{xN!NNy7`4QN>h*fKfTv?bK{n|$FBRnd?#LR)wA`XOhevR`3-i# z;*WQ}%!ygYBx`?vpZ=sXim(3|ZRl-VGpq5Pf5hdlDR<9E{y6Z1@wIZP;k?;mi)-Vp z!;PnxpYwmQpRYb%-hOWN%9;DuYR>+(O)f9XmT^J(ZN3Qkl^~z|_%Ungaqs_p&6@2W zgHGIL$?e9Lb6;Db}+liS>8Ct1_8? zuwKu6?U>o#>m_^Z_e6vH#0)%+tgFQ@KYIN1(&Hds^ZXavSEpRwepxbU=7!B&(_V=d zs4`}=%>Ubxm9u02>`7qOJdkOh!vU$I;rCDYw|~5TbAGnp)OEW~ttm@cJp111 zq&I%M)2^+YwEgYw`T8~Y63jN;^7M}@`nh-a_s?(I8;*LOy}h9{#&6E7v#X3%XLCoY zRwaFOa1#5ikWd(TR%YA0Pun(atyax9-#(S?bHqh~&^0U1PPhHG?~zxWih|&V9d2h| zpSo5Yr?33(Qjzny^*j>-*g~TH53rR#h-T5*x9r(lqepqo*V>%II#UmMFXIRg*RFTP+zZHcRVfJ2epNb@+&p%akuk?&N z*LUgQoP9rwU%yK)tMQpH|9@+IRQ-EfnWrCa?B7#tvwzS3n)tfB*YA%$thlqV>1geg zIrmoVOJNsXJL&rD(z;ak`(L*C-u(D)^`zHYq4q}8*PXWhf3E*1WEL-WaqG{W#e3oL1f4e#NeYFX* zXS?_1-r4hu=h)U=e!TD91nE1cyL(^pxy!e6iPdUYhHf_dy6l(c`uw`zuMMUh_kX&& zZ|+_1+nFC`3Qg5|(Qg;=W%08uK0p2(e9pTx?S|ib)x$oe^IrF@@ z{>>AAKb}go@z*{tnRGeQH=Wmfd5OtPQQ7-}HDBgv1g>lgX#m_rBQK)~JQAo;f`$GH~ak;;a@eiRqwmOf#WP zUiaG8^qnsLYT&n4eS(e2OH=--PNF?N2a6<9Syhx5E0yqUyqZ=5+f>G}4{n%y7Q*;QBWI?VrL zFSmMIjUMCL2&I(URxzo+?>K~uF@c6rZWq3s8Dsq7+4o7?U(fZ=EHb@&$yvLVS1aOu zZKSBq18x?bZOO&zM<-oZT)nJ&%Z~Pjt$!{#+xIt!=?HF;Juc?-^^L~aw9QSEu7`{H zN&bPGnzx?n#KE0mbVSUJk8{5v7 zRq69SyXf@z_Q@+}eu_Qleght`lnL?-pM9@CJl*f+zke#ScN_BsHr#06B+(vnDOUaJ zCW-AYEQJ0oxQCkEf)BX9C2W-Uzj>f;&7|u~r)Zu% z|L1UfSi{$q2^;lQKQDXAcgyqcvdy<&<}9-M(WhB#Apg&j*=AD1(SK8pS}d8g&TQ}W zGna3^3VL{Lx?|&2&WJaciznINOgND>gXvV#9Uv*lg!!f74>uM?WW@e;o&w*u~HNpgUy4jqRHx+OJ+*_I;DY_Jpq9cL%0(L~Q8% z8xeeO+GDA{b)ch;Og^zxyxr;+`#!}|O6u9#F? zG=AiWn2_^i*#*_<&SA`^(l;NMJ@aSLd64!0%!Bv0UtTPpRImQ?{;|(Lnr2o0Oh5JD zbd>4xd=<}sr9X;uji>%U$tHKX`K7_Nwql01M1C>ts`o2RE*zV>NuvGhoa;}gwf){` zw(+>G*)HaIrG$->&d+mWZe8Ph=Ub{*`0RVzg*N4su&+zu7t_gowCsZE-Q24GGe0ti z_0~ol2xZZUSatIR+uKRo6<0qr-`YAMb+L7UDkHa^=FMZ1!ul1pZytEe^}!G{YH3t= zRMoS5`(?|zmrw2f2wpjJp0mOK#*=eiW?N4Fy)&ivj)>LES7lZwU)o(=Y-S5oe-$ zw%hjgikHhS{|-E>`Mp;tDYt}u-Ga&1UAn=N~>k7W+MW(tnko^_kZy{$)Yh7A5|y-PW(yBo%f0-Vw2?tWJG6MQ`8AS(Y(> zeeO#?$Obv_)1!hr-!=44p1v7qHRG~*|D@@AN(}l#`=%egc=3GdDermw$FCf$nRYyF z9y4G2)G=2@6YuAF8+0QF{?nh;HQB4=U;;!?!R<)(v|W*o}cPJ zo6YB0{_O44*17*;{++wM^l<(1vqg9Rdw%ZLZ>)<{TGBY_`spBM^O;&R*K0(JJ#X8h z!_E7lcqZTDpPv#x&B*yNX<_)z#@|94GE$m*C$w(#(^PtT1UPFQV^xx452`A3$u zZ`hf4UHuc}c3iIi)1?5OZBdIk2s5-vvgPXB)NcbB(g){kqv zCvR{0pndpn&c0PC|F+FH`X5uDqHOQ|;9|&z7cM8&z9q}1XrL>krRg&hvNk&gru(V{Fs&et#%GeUf4Ajb_*7 zW?ST6t4iMzw>!G*ySDF4?a2F?8C*Q)<#epJ#)NC@s%`9R-25=wbo%#XU;g=?-?RK~ zb4}Mh+HiKWi^uXTv#lW(smb20&+TWc{46)ybTg;cbh+x`#`%X1T#ry%QY^h=>bZ+) zRmrkbbAFXseJ{8(JyhyE^A2n8mXbW@w~S`nLsvd2y)k#w#{7cXX*`MMAsZwdPNwbJ zlfSNO>YiFo$sf-@YXtl0+IU@_$xxoeFUGv$=9#)RzFTuGqTU^!waEUU`oD8B>*`YP z?fbT0SDpDzGnW|iO^?@YzF`}^?&;mndpCPe|D-4B&klsnKF1Oh=armoQ9os&!-oPT~X>)C3adexuvbKX=k{!X22&AhU5@5|b*@9egk8(;pNo%M|O zgT3(=U5iFx#_oet_V7hA-;3S8W!?c>-Pq*-8#gn$%&u^T4WLuDtzVxg6T!%NhoLJyx zx6kx6!+UA7*ejYhLnhw{^U{$#v>;@I#Eo?SyR+Wi|CPV1YiiCa&m8Yy9mzupAsZGf zoz)wz<`t*Uee26VUDLeH%*}!u7A&>DdGO??OF@a52K~GmGv)mhxp$>^PH4s}hb5mBuu@Oh7|1-erEH_m435b1 zfTAcP9p7{&od~5AXRkKf({GYye#nR{DolN-H4mhGQPa`3Dc6L5?3*<=WTVjb%R7a= z+b&G4Kc+3c<-5J-zp1isfBu{Ni~V)E{P z*ktiz6R7Cy(apOs!8YPTckJ84R$7w(=1sEIp4oiu{fe}M%_|ce^|Q)$ls|i}{(t}X zdUMU0ho|P|eJEfO`;uh-R;psftV-rTKPNr>e3S9cQP60H%$1rwQEb~QPQ@IJ5@Rjj zX~O$GonP!rO1b*(>?*D|uNZgk_g??Q^zfY@3~rz?=Ag}+QxBa#_v(Mf)XSpt!nc=;>Ft#{?@}XXonvWJOK{9Dt5j9IYgu+- z$Ffk#4{Z&sdo|apGq9@`KM>#a;53WQi;3EtFI_upBR}vmi808p-l)&L&*MOoobOt7 z2Jt!XPczx6Brq2275cmB0T+|lmlfOQG1M$LvQOtnO9ShH>sN0~XO$P&u)w`O%Aa9f z$)5hiOdI|eJq@gTwbrULgm3yOdrx2k!;aX_WlIX&4lpIisyd0ua70{KEOqyeWN@c8 zk0O&8L-y*zR>j@w36A|)uQ?BJ#U!5Sg_ zDy0~zFmgBSo5~T%;|>kOxtfBTB)S?{4@h{m=(H&&FdFm;DRwJ@!a(!0Cria@mlKPs znZy_#YYJ|9ajRcNf2}&Bj?MEcXQe9QPu671?$w z&)T!xMYVg~iUdZ3eL_=pb}1z|zV~{~c|gIdMQ0Z%oh5Y&x>#aWThyzc`>DoxJAC=REKP~qRi9o4bYOLt6) ze#&qle8*D0@PLC&aW5Y6J+`WUuk5W zduO5et{sPGc$HK?=M~jq*x}ll_kNFJf+PR38;2Q{wJ*M%8_uG`5aArz^JZ29D?_%X zrKwVFU+Q7m%gY$63|z&_Z*+ZjTVnb9hO5r*MNO;>*+E;Cn8dy~ikCO|3T|LX@cor2 z$jHs`ZvD1-4E@U{TYqs7FTb&Elf+FMkZs!`j2DeuVs8!?m(<+n6xGSd?fNUZLEPWc zR4Mhci4<#tyOo*J+Kg^T7*X<%j0oqF_y8b<`fg{aPNywZy=YHV3{Qlnsr;L9|Q zhzqkCSm#uq-1Bm;**tdhjV>Izz8{si_AGP12G%iI%65~PgS-yI3t!8gsuW&tR_>@- zi@L1~B0G8CGYfBESP-6SXvD+F9d+rb><^z#xkzTA4Gas){RKC%B~P|y=y{-7+`mR@ z>U+iv6E59MBd(gGQ!Y?)G@dg9eAE-{9l zWiI_|Ky#c1i#AET>}p_L>vQp_><-_~Z@hDbHZUZlRHc-99%u?HDP+I)Y08uEXQwP; z1vW4waL+S}kF+qI$L`6Z!*HWb%6600qRG}9PsS? z#;Yx`fuZ60mlL~Y`n~&*v14@_4XvGwkr`Uz0Dq;ladZ73v&4i{1Ly zXvW~hh<#c6FPml(r`jY77YK(&ZFD0U5&ZIbv23Wb>EF2CEf|JHlj_J8D(4Lr-h Pz`)??>gTe~DWM4fjgHX5 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_017.png b/example/output_data/random/random_017.png new file mode 100644 index 0000000000000000000000000000000000000000..5434bdd85d5db81662b7374ee1bee388e63a2704 GIT binary patch literal 8311 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_020.png b/example/output_data/random/random_020.png new file mode 100644 index 0000000000000000000000000000000000000000..e17f4fb6d2fbf397ba6d334f83074ab96976e522 GIT binary patch literal 12134 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 bpV9u=-+e5rXU8!xFfe$!`njxgN@xNA;GB7c literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_021.png b/example/output_data/random/random_021.png new file mode 100644 index 0000000000000000000000000000000000000000..82262699a0e52c0e29b9e7310ecc91d6cbb784de GIT binary patch literal 9570 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+%?^9)b(!tPiuLFB1oZZ#q;$+I>2LX`_+nQgh7$J!i*(YH z7%wR5I-R<#)=~p;&?)0Ld=BYQ2L-X`I-P)8z;~;Kp~Qu?yJ|(!!G92gUKzG4OEbJ^ zYH+ok)5+?fzJ+6Dx0&J_Z-|TZ+U_#GXy6hnjl3@%x;Y_QD+1)6uRBD(9<67PQb}NB z$bq=G!PQppZ1l{7ObZ30z`tgO4`-UI|VuTl_`28%}XV zY{~EI*nVj?LxV75_qVfxA4OM1FoZaRBUiEfSKCU* z!S@jRel6-^bzlwI@S0)g3=>hrDdCLGbHdZi9PDBXjvcgv`wYFJvw=M6O6M6mvIYn9#^2 z_BilpQVJwU9|s;~N=Vm==uqt-GMs5`$a=x!{pN;)CCDd1pJG|wL94+^3>JKD9x_69(7%dLuF zuyJ7Jez&yCl^i%X-E%s@^gvD5sbWf)qV8pIYJCtG)yi;ZK@;ow zfTN2-Ax^b%7Ugb;{}W!td|`>m@>}^@+j$vYEoovs|EuHaDkp{r!3_^0HI?>(N~(H^ zqV{mfish4A1 zzrS)0oQGJWjXv->a71iayCsTIVv?BR8^_fXqA~@Y#Izzdu&;G$SjZW%p&caG)xcUk zQ~A-}FKP@L2R+|ym~J^O>|xcZi#cKr-$OPe_-jQlI16o1*na+!G($o@G_`0XYVBoY z_@)$_b8onssrZ z7RO(zdWURg*rk-<=r=viNxgNOBB=u23f%k3fu4V$Cx^lY6%|qKfd>T|9w^xXH@*c(i6#ck3$4m%N94WF1=&?rtU1rHc{aX3#M4UlP>%3 z%a!Zgz{MF6aH=L^Iq$x{)x3ZfJhoH& z|EyK6H-4O-wQyy^L5*h_J92;A{(NB0dBNspl7Ud9IbEgTEQGPgc6aAnRtEb^OoWo~Z2wwT#9pY9LWoG;7t{^>W+&~;kj z+V#gWsjuyJ8^hP2gH5xRT#b74d%tVz)iu%kmlcH?+2#NF&epbm_sRs*51Z36n8dE6 z^*6iA8@jgU9*&aB$-a4h@(}AX2ORh$p67jz9tLsyBXGfLZ&Go7B{ucMEm~ZF) zN&=teWw(hCzQ~vGzWcJEVZp%3>Uz@FV|8nfl*2#Uat zbVIvjQTwc^`xbpL4-To=s<=NZ@5J9bg`bN}rtnD4;1avC=9t#Ci!!&`bTf-i$lhAo z#JY9$&aP5D*QM=KgaoJ8U*2A@|JVG_^GbrH(*v|30(Q?@9q~M9$1Q;e4hNcUEnV@t z>(Ko(g*$V9?5$E>A5z5}{ljXv?bKT=cYF^tiERlwYBlSzNxM$K)X9&&&;LIqUHbNH zuY86)p$!XIHE*puYJFvSF$`JZQCk69!u`-vK0xA+4~lqZTz17EJE(e|6`y2m)f{z z+e$xC`BcB2>yPkl*0&<3YgfPWnzmRf<2Wek*=WpN`|?%#)|Y##jE-vNoDH|ze{|*+ z_oauc)`Y$N`G0m;{(;L|I2MK~w{#b8uM0k#zJ0%5&6_`EZ!aaozd!cJjhb&8*H`GZto^>p^@8ulH|1SM z3$t|BUeod^e3i%*amDvQ)3mQqv9ZZY5yHDhh(mM8y*~VV|Z&YQkl`fdIc%4`D z)bIN4rWe>4xueXEep0XqT5T{rv-J1dL&wjbEw5So`1zde2KB#-O;_lpa7Ju#JkWG) z>D5#F^0sPKhlHLe3SrJI@L}GfcQh#0Gj+RRk9Ysez4qt+^L{t1n9#s#`{HfRnp=N6 zQ}eRkCktnN5|M;G-(;d7+HY^a&+Dz@T~ik|inq5FvFN-A?Bdc}t^e!nNk!L% z6HMi=X?{0v+ijU4QuR&tbik)MpQYoBPDQdcd#x@l=aXJqrxkHw^P2FQzu#ice%`Te z>D67<>4|~%jNDab$6q#h+z5_Zd(&sptK7U6S}+ynWuIFFg;F&*!uF3vWnJ$=sTk)g7-|Jjdz! zo`csH&$#P+?c+bQ<3>3grGgt0T;^{)oP23*ylQ>&N}D}L|K=Y0xq&Oz_m*kO-23-q zJUwbzbR+`1RG+7CM^2YxSibq|%nM&PR?UCqQ^@tXSm*ohEmy_MLzqj2Hzb5;mT^U{ zpTYO~_p86r&kk#qgr;|$7LV97r!#2IJM~EZ>gL^`O4UK}<%em14KCe3v)c60z6++Y zKk|>SS1b`VoqmsDiekdS6G1xs4f6vFr>DlP6?6)B-Xz0s)Vkk0Yq2YbPQU;Ai$A(u z{M*0I{I=+^Qd#NCz-Lb#>{}O0t(e)sI%mm>0=?Iw!E@SP^uNEK%onbgmodGe^k3`q z7ccz0)md~NEZ3|%$5)=tb=*~CTG;E$EIO}L6Bws2jc5upW&Th-^IX_**ObjCkBatX zEr??h`>^}7;q;vk>^9BfTm4w6%=jpqcsNJI74HK~d9#yFN(Jl8OqAVrZNKZTnl-ce zR$tgUb4%3xUrgr?E%IX$`!GYZu5InhQ_o8!H(gtHSgXYLt##ZE4uhjF)8BhJy?P|0 zQ#K(?J9g&dDeTL3%+u_XpTGXkcRf&$Y&G7+W~28=*-yOE$vtGljSI@_o!!mX{oQ)L zy)$k4|{6O^M`@2coub;nt zxFkZFKQ?pgy}#{qT3u^dbj&`T;kj1w^zZg~yY%eOH{W_+-RS-P@|Kr5vG=b&JN$ON zg>BmW)n*B?MzYt^ox&H+%Z^%G{$DXYF;JedoA+(4&*74%W$PTw*5A9n?#;Q9i2IK} z#lEy~woSirT5s8j;+P|o-GBQRR{cG_+xOuLwk(x|iyL1adi%ArE%;4(++O_&rcW>B zAN%>H%zXV>i=*3)yZ-q$p~(G0RRv!*7h|^+XM}*@_pRFcwfCky+kE@k@vh&wY}sAG zQ&;ak{^ey(tx3tq4oXq}mLtXpvpWSEN4fz7Vx7Q!h`wb!WQy=k#-vXZbq+Ul%{D zO$m1nPU&K-{}8gGt)AE6>N4%^)$`Nffb58G&6_WSy?iojO~7V+uq6-|N1L z4VQQsxnJC#JDsrYIC z%&ng;N9TOmJagL*r4K@)It{yXuH5$CD01pqKuRR2J+N(Y6YGb=^AF#y`L^xjgDdVa z_RXas!Fwbu;(s09U>PpRG-X2A>lgFv<~^LVSZYN(mzV>mX2{0AWtXHI-f~7TEVZa9 z`6ze#{G-&*iF3F8Ncte8>(nr5&y;iA?cM7vbEZ_SNMM}uMKpOkS8z_q-mV{&9oM#8 z6>nW`v5axSl9Fx9R?ok>{`-xUH%wZ!xivjmxfg5^c^tOUY;~L~N5~bI157IpW-z}G z*4Z4s@{L)7e%l?!tc^D}lr!5Ub58wyE&fJi#1%(Y?ge6tLpCluZ1wzyT0k3@n1ip| zilo}(K{2zw|9I4wwSZ46g2D9V-mb0D*&j{>@?LQ~z_j9|j9~s!^No{VZdle--QdHb z(=hAI#pfsA1*{VAFpo>j zp|?u1%zw2g+rlQ+fYsMlM`%uK{QJgL1uDBXYF(1=#xt?0vRUm_91#pT*Um7KmZzq0je zF=v;WGpti$SrNw_E}Uln`juFEV&F6`F^9LSR&cGYnZGwweBA;YQJn^{D?_P^mwLfmcutnv2A+M(2!&R2g`SZPUpMdP0G$;3v2ygr9j|B_0Qu9>l-g zU?#mzN#?49CzF_icaY1T^dEB1wLcgzaxX9~eiJ^ybM;nfP&i0{1ghu0`d1lonJ<2K z$IdTo5;GcDFU+#sW?%Whc-n($X8(4%o=x8_d(|P1Nz5Vp*^O;YS5tR1ZDP@B5X&u$ zIV^HIFfg`#_0J7{tltlGu;?@h`fdza=e6$-Uy08Fri{R@=f}I2S?pbxa4XIFYmt~( zDn|sv+FA2{7;E}H%(_>g?>oaQzo8K%ShZ#E^d!qAB_|44D>)+=lsz_X5&3^4;bE5E zUPd-h7-seTezqaVt~$Lv*zxuVbN&_J6l-2M&sy#hg_!wH!wt*9sfFED&Ol5 z53}sn1Ru0DkYeOska|6Cy208o1#L#|1?G46W_(^fr`5HNNzCDNkdC{4jr_guyPC{> zmYN?>_@}*>kzwAK+NXaXrmws9EFwtb$>Ju^;1VNu!@0BR+vm2r%GE!*uVl=iyW`vK z-~QKPO&LzK%PttD0?L>b9m+xbAQVK$3S!?Zo^9~UmSgoMbg+WC8H z@BWB+XEOC3!(8DF3|ZUuo%_A_gkA$XX9UCApE`RR!_F=>Kj1Lu317hMl8F0Wd5hdX z-^{g-`L?u)HQ6N43w;w$%-vhLQl=q%O?~sc_9ZVrlxg~${aE8L%jrbbt@JsE zriPzNvu6@JuzB6zZ*v}}FPN45TfyY$BvHFZWlwvIHT|Y1d98Tk-Yp<;{pZz+Xt{eo zH-5anJH@W1|GUN6f{zO{S#-WBB`_vOh0ovjxafFBSN-#4N_Fxk^XK2c=KSpN?R1XF z^4W(Ilb$FfFv={oh}~;1d(Cp1S^Ta~Klh(acv>V=!@f!}f${IGN6(KYz5Y;ga`D=| zQO}n2E544Bc#>eZ`>l@7x8xJD8Rxe|DeJW_x2)S&cE4s@+^@6Y-Vs%;6H41Z@BbtB z@6yVNTw(#!Gq<|Me+R?x2>_ZuyZ)ypQKYdo4E{dsm zwY9+T`1zS@LUPnae|OCrUJNsd}8Xup0}cR=N-)V|;ovz+T1m{@cklwZ#3 z-C_4$garXrseeF z>Xs-ha_?z5|>EP^;9?KvXe zcpqq*^Ukt5v+Mb@xz7aV{D_TO>-@Xtvc1;d;BD%l0T{jh+B1d!AI|u&YD-kRYQjc+ zM(%AUYp<2wekT-OF>&_gdyk(R%l+rLId3(`!^q%2(o3El{(W6;kDl$^nff(6-@cen z`~67fUA^GL6>K1<+g?hvUGH(WFze~v>U)=WrL8e`)I2`@N}+s9EJwr!v!j|Wveq2Y z^L{^J?3G$_xXPxZ#G=@OyW4i=!KRXk^S5i_SN~_*>$SR6qc1DLo=NQSOuqc%4y9}S z&L;9S8}eFzsr&cAynVvaX`sPLzSq@rv_gtGLIgJ2T$IR@dwt9Ket&7vG&k;;wzlAqs_*<e-EdqTl@5YP|cm{30c-h$&MK#fVhneV!WyQ5re>Kl4{aIG+ADXYbzD`tt?qjNQ3Qer)HR!S$B)#_{lyIy12x_XCei zHP3_})Ck()!TRormQ!Bzedj*MQ=*Lq%ibG=bDFP6__*8qWAst3W6wH8@2DhvwAde$ zn3K7c>A%1RhKf5fZ1*0Dr)}7wbM$Ncyfpm=j;T67TDipRm;SI!{;EDLebsUEhg=q3 z8*KzNbS9x!yR~>t!&?h! z?z(`3QodZG+6mS3)*R#q1^vt=7NKiwPP1&A_UOwK-Kn?Pt~jx-F4qiM(_mw#^l0rD zwFP`kVe5l9!W`l>mG&KaFU{fn?yqNJg{;Qu1J)}NN|jr?L<89UKOC4){W(Y?j{Vi7 zLkFx62OrD|Hc67l~@+IXj_R8>H}7@`JgKD-*8jwRVYK z(DUb#oYD}wTBJ$z!akAH4;Qa|W2RuvxY|sUMSFpMeBy(-4>=;XdMHLP)_N@rJyF23 zbNaMHAFK@6nBVibu&$mWq7`-^!e(NM0#jI?CX050Pv%yq<1A}pf;hq$iX|%2Ihd~9 z1F_wUGenJ87_;>?S+pCxgLFdIfLd$*OxLb~WVhF}G`L=8S+jPDz#4{kQ^T}Nj#);m z_j)L!-H>i6-R-wB!B)GqOZ32M8_T7^|EJz_C=QyV6*jMwagW;3mnXBdw)5VY#dU3O z(25AgHxHGS?s?@iZBtFSJIQGS6W1@B>enG%9qT{*p1Mw=Xun$P!_oyCviHxkp6hS$ z!OuNp!!?jL(I0Pj<}W|rZM$%(a@(DLP&jE_EVTY$uF13KGOy?w5v?$Wtv@*Q*?h&1 z@kW3GM@iFf|BPjmq&2l$!xUpB@=w@;Ocv6d_L*~;`oEm#n|avoW!|v>YjsEro>M1T zd;C*Q{;m&|^5*-_F`PU+IYH`rJuApx0RdKP_VbFJ-6+EX8VuF@TP3FuBU{_{d1FS{ z{&2x%1)&N79#(6?P)33Fs$tP;<;jeJ2hZxWJa>GBdRefvse>wg9gLBl{ z3mtV#VO$5fPGnf^xhoYUzA7&5!Cbbj_mzAWigKhF$==J8z4Ary|GD6gTOJEP4=I!W z&{3ux0ZMy3mlA7B=XFhAa+Pap_WGu&PDi@uJW~t=+sk!mYuU9_S02 zv3ylb)Y^cJzaV;LeG32EgtoYUZqeMr)F|%z z@WT0n7Si3PrgDP<{sC*S#h2m)O~1d>L-M2xeE&5}b=tr*ZwlY)O0A?ynM&=woI7;x z^Mr93haC{UlxXUIlr?j!lj=8qux3ZiGr@)C%rYr>y)n!sgN)D@C#zP{-s3ICFjmv%4%(z z2Qj@#Q|6baA=|x`M;_}Q5{YU&a7u*l?-DMMz+Xt9%`AyH8yqjxd8QAY;XO_5@#8={mznTVPk|%7EH`{I;@T z?RA#~ncs_iQ4gwF9pQMsZg=0)3aiJa#WTc~WoB-5QuAi@KFVcP`daCs_d~DO{e5RP z#)Qr|mDl`nPu(QzfQ{AvE4f2Ubk>HQa5&Jk?(XOF(VVjxYuu0AH?Z?C`yXD#%&=j1 z|Bt^*1aHh}V2#}!IyY!QPen;s zREOc%C)p;k-N6T$5_IG@?%AXE#)Fl+;p394T++fD7$hb)mX|GY1P*jJZqvJoMYRf*uue>pdG9eE}A9E=MNHGdiB%h~TAAWup$!ZP*_m67WOSVvZgg+n*tWEZm7%)O?AnHq4GanX_Z2gEJy^LJzI_n{ z^@Sbtv?3TbY~K>~a$W-~gQY};e3zIa!;=KQYz?glh6&w`-xF6PFgoZ#Jo;oo6Dxz| z(yLz6S#%gqoIOzeeG3Ppf_ZVo-Qa^v4MKLxkF;6V`mIc0bl{9ne6TlJD}o`wD{5_t z^8u!YNj!VXJ-Y=Myo^5FQ)T34@bX$cRWC!3$srTswK9+*sU=svF0<$`tT+nuTE$FB z5Z7Jjtx-sz zkm%Y=SxY6E#2BueIZ!=$3kTzZv}YS;fg*jY@rQddqB;yK?z+3|nSPI@9~2Q{ORjod zWzk{CXl?wS26CMCnM6}(R&IuwU)$X~E)$wIA%$HZUwG zmEX99du3Y#E5lmv)l(mV94UV8*s3-zF@`UPZbn=MIc#1{`+`tLQ5}XCC*584OufgV z6~S;}_LiuVeg~Kud3 z;mf%L)n!pF3>U16BW{AyJO?D&d_c*AB|h`<#;^{QUCNT3 z(!k1)bNaw;F-3+AhQ$#eU+{sVt&KMd#QwG~=|y9?s18GdeCAd@kXODLzksNo@5p|S zRfi$LK65J{C?0QI7dai;%Dj~eBv_xhwao7T6T_z;Ft4$tZD44yu}jJn=L410pFCD? zO^#||aEN1`(+l$16Vn4XLDoCe-M?6RA?P3z!>8XJpd}?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+%`UofLWu3c6Sm(@ags+*X@nj7tN3+`&aEbzRq#p>`lWW$PnEis1P;Dd|&Rz)zF_^@_ctxRIPU?8gVYH1g%!{U$)E2e`K z2yIvqerpZG1rA1ThJGHl4ldFKnd-pWy$xh7gQ(6ekhM=kHe`UTof>>_k?*Pqh7cdtZnKq1i~)wCI=4X9 zE)Cg`0kU>#(7{EyAO#+*-P=G46h(DzE$?D=NDbMLF<(oJVQS#PMf@NIF09>lE0P!k z1R1;SmUR3O6b!zZ%iz$`;OhUcrGeE!ltt&)L^Ev$5hbXL^+7IXWD;XIaE?Xi*JLwo zhB;>z1pZ3>p~29)BH^O`VRuFi7uN25AWIv##A<_&GA&>b)%mr&i}k?CkPR2XF+m;b&STTe zv>DzUn8DUzu#K@Hc4dNN%SK*?H(spVdLbJbZgg^q#jHqT+#oEf6A^rrDS=%pV#Bg7 z)&qPY8xp)lxf{e+CLElmCB~p1bg(HpWFtdGBbV5nMO~~1xI;EPP+k?mVB^WkZ3hyV z9J1koF-X9XmD>*FVBwGr541r79<1E^Kq{J9bbfesb;t`EPQA;<@K#{M1G##q156L{ zn8fZV=Y}!-XlY<&*kH`a{cft6HbafW0VakUGaFd@J!XqCC!7xAIU{kt; z9oGT%kPQzaS4A+?IIwchTiV5XfIVcx1JP9x40jeZv91p|%JhIuRHtI9mKcMyR>TLb zP#p%dkPQi-h+nfJ;hCxy3E~UwrGRll8ztJANPK-V_=vyJ#2k_WtTu7$o;jRr+*pW zvwfnHaPVSJF2jr9uKK2{t#UdRvo`WF)Or@``qy^Pp8q&>!vj!yc*=WIo^Bt$I^p0=kkG_OFYQ*JUjgBr^8WZ?a$|qM!6u=QjSQze z3O&H4dj%Y2vIy^T)((rl-~ac+0bk8$^)KwF$?ugn%`aBs6rIw&=|3Aq{ zGQCkhT6*Wu)8pzw8y2+m|GUZ=$*|t@bd}TmtLZX=OboRifln+xi21%_aJU^b=hlHb zenxJu9be~8eeBq9e8~#Eh**w@fK%JAM!SU0mta^mZPBfSQpE&E-nyyx7#x^`Lgd%z zvFNOD?AmE)JoPS{!_=Ud=Bs?-hVu^ww*+v9>NI@6^r|%3Jb@!3pj*VZ_7j7JPt>(T zo7coW>=4MB?3K^(K;>og|8K>Wv6b_$ru!7N-}=L=EZwm0u9w{YMK8OqPU8~0vh3me z8w~TlDewCAM?Jx@x32E59>W#y15Hw;K}zgD+_m;L7QZ;y6!r2bQ`O|K*JiaP-+uZX zXo^~Tmg~ZzFGu^WRTCV~hHPw@wv<1P-{C;htfgnU0(Ng%BikEO(bmAaHTWn~)WoD8 z38fD;omR~C4{>-K6m!~C_Uxvr)&^Dv8}-(NuZ-?37nqK>IQRxxaQ$iG65Db>-EaY$ zX2_a%OPW~M1{`Jb@?4noRY6oIqt!p>z|Ei)5w@NOn!=vU$e+z_5yf@zl`E6j7A5`H zAqD&n_k%dXtOYkLPz7bFZ_}MN+?uIYp3$3Do}jO3vR>YWl{@OOaH3@|) zW;C#_J-P7a-j4H4Qzp172XTa{3vO6oYWXFRvENfMVy@4DCNWDjmVJ|)HfVWFw%+2k z`S;0vzd~N}H+wD7uREj3qLUGNYmJQ0fkj1{&;FgUUo9WpqwK_x5!sdfZ~qqlB~H~3 z?X@B<7#(j>|NY|fQhOFIkHognqahm>r0)01PcW(c`b+m&f@)0RCK0LY(h3QVuY+Fl z_M}8zlX-twOh%_Q;p&X{OU)VfC>;I6X+HJtF^OfDq!U~+KPR(ZPFs=S`1(uyoF~s; zZQUHnH|3FXH=cE@mv3}SPQ^ov6>*&_P*sZHF=P9+wRm}R35bW|NF7EjZ={t$) znUS`FH$>fAE-=rZ;{T*#!rUbl@sBR-xF^cUUG-6UovT>cws-qaEj4r05Bl@lBtdJ7 zINxG+?x^jyPs(E|8Zsk`587VXvSrP$)olx#SZyyw?p&Pt_1Ag#_bl6&7VubTi0U-> zTgp9gy!>fdl&J|L_k+BhU)WYecI^~5O42Li3Ue-Y;aI!-tLGi{Z*zSX{_pbl{rFGf zL-?6so1mF*1NcRCUK~^nSUPF;i@6_p)-2f(wwgsNFW?~4j|u;@!-DRt3p>cGw$nMk zC-cU|rOEEpvVMrHTVv)>tmNd}_&$azD`! zuLDhSPYYarY*_h)?S@xj^^fOk|2bXN)>2AvJl~UDabZi<+W)I&h{*eg_|N`d_Hyed z2llBKn^`~1|2i{EZ)@jApVPO0o!sB?+bP&8$@zm-vebg|W2QC-D%vjl6z*N5cKlC( z8{f`pc`Fhe-xpQP`k)66Mdu}{rLMfp0vkYz@0_e?0}0GDY8KqEpxiR0eYel)Sc6W@0ROmD)($D9u+wzz)FCcwm#X(o^=^^9}*GM>9UOIWFJ6JoV}lzV?8FOl)RT z?;Y5AX_M41&UWDq2`ba=)`XNve~pmmFS}Jgbz10(reMwp2EmJ0Z$@xUzOvB3Ho`!v zHlkZ|mh|}ze{*Vo7SDNP^~E@eFVu3^sh$f`qB;`2$%mw+EadilUHf5|{rwC6E4mt3 zc~&)l=?Z{K`t{eN3FC#V#Dmvy#q991e4+J8qgN z=BJezS?~67EyM4?gH3`@C3ZBK9{pNxCw}|r*(}iuyo}s#rIObTwlE!U)?9ZmtCoeM z#Pt9Z+va!sPd)#;N%J3Xn8S7!9f_;wpT5oKxz=f^n{D@ey0>D)!3Gu`iHqsM2X~vT zjr(u;ZMv6Y#K8kBItdEuvi!@QPQUb=?Xb{>2FIs=?NhiywH1`^xN;;*6*1itY5x|# zG}SbZkwa8R;(Dr9#Sxo=k`)OX9#^!9T;DM3+wTnyx7+^MiA8wM-WtvBlkZcwXJtI*0YetOnMSd+nx2 z_0kt)Zf2@EB%_nS7qNeT)p9wTO0ii|2!BbqxO4r#s^71E`jyv4Ot=3p!ym3&e>~>P zsp@y^60LGNZ01K67dOv}`@iz%*I0&Rp$!eIWn^P#8?TMCzfu47^T+v28`KgQ=SKPa zo$dd7ly)f3>b$d{M)B&Iq12y8mpse@Py0U-Qg&sky+hdIl!3W^cumT%V=pA69++_@Mc3 z`1FU181#iUJUBdIDc8k)F;&b57O?1ablg_V=2Bd38hpjDt+s37>IDrAtl^sf_O8$4 z@|W25>g48qHRrAGeok4XrP1SapsBowM}AY$OWr+?T0ipeN89&SRqp;;{yd-Ob2r|NpM1`djuDjSZ~kPd~J7G7Wyot5bC6 z-)`d{msc7{Fml_ahJ{(jNt`d}=>PZb#pxzNj))ISMV!L2KNZ`*J-=>t$NBkwbHDvN z+R()jQ7~O(m7wYDr0pMhUT&RV_nVpT-vbsNj{{A+ml|lVX4RMBe`fJw(`%V``&%}0 zM0}V4Qhh7a#<{Qgzr@!s2Q~J!WrHZ6Z*puJk`a-DqE@3+qq@7FCem?H8^E#cthq8U>|o97-g zo^#J@`r-TXFQzxJ>c3vIUTyll1KLF|d2KY>7cRM=&d6Oh@ln}{U)7I$|N3maUD3Aa zt$*7jr+gNj8@^q?`&P89Nq%FnxAyjxx~$FhT+W^g<(b6ZXt~N>-(r)gwYSlI?eF!U z?BqX1i_~-(wHhj1U}xkmoBpn1zE^+UGK&YhW+?lfp7s6zh5d^Hq(k_eJr~w8i4}ZR zmU<;TKWzPMuh#NcZys_=^fa)VylQxSaI45}-j4cQ;aT?=x~lCwthn!2dg#j)UzRP~ zvHtfYzFS}3&-mU6P$7guiJ z!KTA&wfRNwo0=c3`4#d}Z2htw|Mtnn99_9?Rr%}ALrJnf53sZ7B!rzUykYBSA-89R zUV`fm9jRB(I|MQ=Y+3X3NBpW&j{-nG&eMuGu;!H4S>50{Wi}N*pRTgCn(Or0`idtj z_l*61&kt4axP5Z7a8XE%$f-mP%`2VavDsx|cUS%g_)FQ#!i8{z5QEWPyx(i@~O}zCFu!$nihZ zn8h{wr|s{K(~BPRXhj&T(v;F-@m+nr)%sJhN!%C1DI(_-5)Q7IRaN!j_^VRAt(`aL zXV@gTN_cS{7v7NIa(UCUrs|3lTh{D+ASY&d@A=-er919U|7vdKF(F`11FLe@sw&g9 zap4P zMW0_E=XJZRy6e+f&kJlwFgYv7AEx5IHM-iD%h@wgo=FVUo{cHs=a2NyU#}xtR$T@1 zamCyQR^`l9Ra>We=O-vwK2zJf=jZ!b_aDYFiS;B!T?46~x#*Se@)eJ&jwDNZah?Ap zqS&)&r8>Lvz4-p%lb4&LGdGuMAKjm6O6)FBO*X;k^+kN#Fv$({*tUGz^+sZF&@1`$a z`F5Y$@wbnoY9lwOCODp7mg>v;{lk>5zNk(GrMB=FskeJ+4sKxmNtWi7S>+^2lOeC(Ejuts>d5b*Kjy{K1^m3`;yVMb3;I3 z{*PKMd$~OlpJseeYG1hIgFYj7)s>PRSp_!EeSG@$bywVLBkS|`IR5{V;Fy0YE!R)^ zvE;V4w})?e6~=pfo9%i(WWxgW;4@RFgp^62pY4_Zpwi7zH|UOdPi?;ceHNV;o|BE& zUz3tLe?Yy+@@EmnEje93Gd^7VT5vWqr|P%6jqi?6H>Zp5 z_x$2}plMp{uXRBWYu_xo_>m_%bFDsvenp-*fltT>V zM0GL(Z>>2SEze(8aPQ>|fwt$GP8q&k$J#sVRHxrN@Vdyv)>ssjFmyc)+gGpii&>UY zXLI=4h3WRpf_)qdWrNSCXWo^y^)1Y8diS8>!y!XO9$!}OC_OZfNc zgAce^LQR;idyobpyNgQwd;>d<~UqRV{LoTA&@m;TIq}e(Ti^@*ct*3 zHhsF3CVNQ4S%yE(LapWDiUdc^;22{!t?j)=R&wVHx|ee%S}=)CnUKU6UY~S9f6wJj z&tB}SV&yq0s5nRWXv_i02Ptp1X|7wkTjsFIJWI8fg)0&c&b+j#uG=3 z8wfCRpEJtYfA!k0rhPG4!q1C;8uJ_#RFu&@TBEY!VrAjaDU*|DJU+;Myv3jg)U%BB zKK-iuRZ`Smxfc}z5`D@}7KcQxJNasD@BPJNHZRdzRJcts;o!ZX82xNN*Yco+nUTdj zSL;hBKCb1Kx}fXcvSIm_HGM4kpr-yFnd|Mc4eK(C+HIH2@ZZm}+JB9Hxm+2?jRoP# z2P+tjS;Z@Rx8&8@toY9*(cHiqt+`G;YSxYNY2Nt@IVD*?g(9q>C(+TKqU8dQ@8zN@uP7!glLHgw!sT1j9Cw zrmHV|(sy|C9dEgy$k@Gaslb|56TI^m#94~`Uf|3mR_mo0A!-V01Qqyj+!fsL!kg>h zDyu&B#*aJR%>3qidiLoV+Mle~iRze3-9P&D`~}fwx6JUUYx0KtIbV*hR00?18E2l( zZVoAvK42#!cxj%<``7E(TEfzz_Wldb5@v9$Ty6#gmRnp8v2x zZh$~R^W*HMS^BbfeOD(AE~i_x zl|?_C>n29#U$Aj+d82(aX631e90eM|88WwS_Rr{U%3o^EWaE6`QK{xLeYRkU^$sug z-#WO9{dA$Ci6_6GnU0qwudR054ui@xd zMuUZ2%R${-<$Hd5japOhuzcXMjj;XwX7__FYhF*}vaG3n;uw4;{eer{|@*i>@n!F;((Kuv-m)Gg4%+#GNTJs$;z4Z1r z7J`IX)@)vy8XLZnMQfJP(ciBN8Eyz|=rcR|maTMQm!8D=f>k2dr6n6yy*y~;6czUU z&qdY0;jT;1a)o#vxOG_Mn1+GCW67?|Z}_ejyZl(QWz8`SgDES&uytH`!^bPI;hkw~ zoK}VT-q`=52i#=@>(q2t$7w~Z`MtiTJa9^~(~4PK*KUcd3i+^5vnPE;2Us91DlAm% z$03pT`TXaPmK|~u&o)knK zn{Xb#9!p9s=wc1kl-`i{_tf-neYyIfyFTuF z?KN$&qeaK#gKA68a*2e-A2{`JrNoM^k344sjy7e@`7iQNWWN1J-55vLWmjL@FEu;3 zH)cNbRg2|KQ>T^Qbuaz-ajh)l)ChV0SNpS?w8TOl&S;oAt+YC`XxGPm@uoYOSzqqY z^1HRhLGU-rn#{`EY^!AUJ#0<$Ev%iS(*AFC+lnN|!t?BFwyb%bykCY%v?Lki%Bg1B z1-pJThechhKBmqfTVQj;BveP^)#K$H%Xieic`mQR18JezoE2^jxUv;A81Z>!vc1F| zkv?|o1zoI1Yx+h0_xXR|7h)^VZsR%|c(f_$)O}ZukQbNgryjoC+#7tfN$FpB6|+O` zvLAnTvCb-5nZ&p}=pd8XvJ3TBB|~*A<~FeANSwbgcS~gBVM`?zvt_AgS-&4xcPWjP zPd$NA`|_)=>-+C@hE-aK_$enaYVTtz*KTbqx0ooWlkoJ@ONI82JaaF7;9DMWkV!1~ zC2s*+sE$P|m)Hi6LR%%1c?+{wMHELh$j{%SS-7E5}-(Wb+-`g<7{h=Gf*2O^s5 z(#2QaFH~hYVT~2fXz5GJ0M3z_(j?LqbNd#QBD{@*DHj$|Y`z z2=1SLec5(?|HIaA+*rBW(rlQurS2t~Yeg8CJeIuiL$;4QkzFgoV9m-eY%4C#54h1H zyCUJ>hPvaXDKGaYspf_~NMsV@$(G$vVz&9C`IEegMr9|7OCraNKdg*@xI!RKA>rT$ zpZw=-BD3y3WbNZf^!T-Y$K;z4A4C|r+frURtlVwWyz?8vcDS+2DJ2{XSY|M?m&IWh6Ijd#sv$uL^3jRA1nBoKJV~Hh4vq^RhtrA4>Y~=O{}tBZtzt0-(q&| zUC$${{2n=FfJPP$pIBIRbm676*2bAn_+n>2`pZ&o5y2IFPcdXeg2FN5f=SyAb~QfC zENWjTdEP-WbMv7D7M&ND*4AHR5>xk{Ey|{p;80Mi2tO`nQ%4<<2&<6g5x*%J7~7>;`<+KD+|e8PA4;uF86K`wtdzV{ll zFmmro@nN3oHCxn5HG#2U-ImCO&P-wq&yD4~&sBB_G<@E5HGcj384$Sl`c}4Bz)9F09-QR!h!u@dh7c zTELgN+39e|28I=<@6YJx34T}$nz3Y9aXQ-NPtVSuvQnxEi~-YSX5Gu2r|iV=YKob* z30V8mvs}D^2bmV+sqMY2z{uV3>o4!*dzoDzHQ&W%-OKE1V0HLgRIzEoG7BY^1+tl& zotB1dV90R4wI)DQREOc#IsY&)cnPQ4BcB8ww#>Y8sc++X@Re$O{B+G89}BC z+qOh5WYUUY*rJ;owxWScjG^{JilQjUQvQ6wkIF1Ms}?k|I>h(nF950f^3-TwqShY% zwq;GM4)sB2j<@Ewem}S&WCOzs|E`@6@Al|$fwabFZa(C>|5R5E0|Uz{&{_bHg78~w z3WP*;7=ER@iK&AEr9LgCa1*HU%dotn`}Is;tsVSr3z}FDSlm;3ls;qP(T6NL496xO zRtWN2cv80E;}V08Db6bs7!Br$uuUw|VB~HvTq>~10yNJ9npS?}z{=gQap_quYk>_6 z3b|nw6P2A9b`&h-vkpAS)W9A7YJ)H%H^a3Sow5fV0u0-h&FJU8pEU0uAAit6riQgL z>#jUhWfEh!Gs*eHqs%@I#s|j1XB1yYKdikVBC5mi!>6w!{-KwwoKgbgf$*Rm+b6Vh zL@*Tei#Umu3vXa}5U2TU!q@W8Y|>0(3^tFB_x@K)*{BGas0U3OTShQ^SP>m>dG=(I zD=RmH+*jRaKO-tD|7yqZowe4AVA#-p-_SmB2G{#$trZE32juQ0)g3Yry~iFZuz?{# z-${&{k(=S0N{S$p7{eR?6H@aUSQ*>}Hnn}*`-P2RL3Dm$ZJ5329rooQmw4nG_7`*r zY+?hsbYc-lB(qV52*WvpqcWTBCGo|U_)fNFn4@@n>m*aryPWC*8yFtwShlQj1o>u} z%;%>UoWib~>|{Q0^U|hQCtpo#U}aEUk}A4smr4SogJx!A{qa9B_IC}IF*1008^*8x z99AL!#%;1S!<1=CkNjiWCtk8)yF>~GmqimN4=#2B`?oXBcwU}abYL_aBE0`{2h=(SKoV7wbV~*2me3C z1V)F|MI4b+g*GrONVRNP!zF3L#b7%li7ztWuwAd~lZYb27X@f&fE3$<6bo!%SfFmH zRM$EobcR|v!wcW2Fx$wZAO|eovc@S)aGnxN!@Q+4)?cmE-qU~Z#X+Wqd7#SZx@F`X zkZOQ3gmf(HZU~YF5-yv z2PK6ccSMR$RCQaHd{p&)$8g|zQH*wE@Wr{HNMP7E&G|%CLjxjgHw1I5{n zc#!w!gA6$iN(*)>35*Q=-lu@j9rFBv`BNz@?vT;Q+i7^z+ zb9A}}4h6Q)V%Oc@1RboE@i@T5aPGUFVdQ&MBb@00G?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+%`Up_vrYBFS}p!1?>y$r@;ra!<;0RZ6FKBO>rI8e@;9ile)Qe5 zF^uJLz$TsLs*`S<@sZi1`jdx&q50?aJIo9WH>4Q384?nh#25}7V9{Y{XylAwU|<&B zz`($!mcYos<8y$CL1IP&D}#Z-uv6$Ee=>T~`JKlZ88&ck)lJ*Lz|a=ZA9{d^p(6Be z6srzHL->_A-%rVHi3|)m&c2_FPyW8{Kl>mPLxtPfn*~!jA{ZF@SMQWqC&b9j@W9YC z{BWpJ0wcqn_0Q6Fc;ytaGwks9{G@GuI5dfko8iH>Nl%n>cVy+&?`&XYDDXY${7_49 z0|SGecBMs(Dk$_TRsCC6t5kY_viwrPz!3Ic`Q-eXoh;|}o=IS2__9|3V#{iAh$S+- z5P=1z0T8<^+E!IP&6Z1G<7T+A{nlz`fej1|e^>3b5@6(JxUu}!YUW>tf3~wQMC_RL zB>k4&TV;c0R)#m;XIFq-(O|n$(iZHB4dSMgTUNUqU}E^TAZ=5@)EiIu7;<7gKWR^H zU44W{jA28n>RZ)n1(XJ^9?`zX`(u z4!cQzPHId)uyeYk4nu;q7{uK-x>}+75*#5;*cu%H@yWF{-(ES*ILO3sZRNLDO&k#n z2Yy|Ni6bmT#93QZtH3M+G8Fl)=md)dIfR+q$z9c zAYmb*I-4Wh^V75^#qS&$7@jDfoUijs$l|+EGb_WHd`SE??99~xD>hip+XfD|XPYiU zg6+)0Z?BGl{IM*wy0jVOCabOC=3WPw7?uTAmmaP=W6Qvhz@9Z}e&+5i?;AjY6JxrY zE4;ITm7!;4S~uwvw8yTu6*S|4~QBB*x(4aVV%k%@4{+G^JO^W1< zU^rml)v~&;ft6v;I+q<*iV2Ji>oo<}Ro$CZbIz87A>k+}F7)&oi}j5o7!G`HS-qJ> zhv9+cp{uS;VhkTF9=_6ImgT(UqaBhVJ#sgs>Mk2r1pR4(t-_1^IFw6^5j?wLCVD&ur{kCn5-vuVIbzrYJ z>IgPjOUd%=o%jXC6OLV&t9_Qzy0O=?<44#?z;B&0hDf zZv$(O*N!MwM(%&Rmh*?be6>F2{`9LZH<;MeW7f7cuw9k=!$86)cBTAH!n=SZK z+uFl_i)V2}A2{5y`l{fD1QFHmt!s}2DHVji4GnWV&~$O?x?9^>ZB~5KTCJFH@QK%( z+e~?@_MTeB5n-@eD3SZevTs_el@ksoO}Vk1b;+{a-QVp#TU2y5uy%*+%DON1#;dnr zt00ru8mG<;tkU7iF}WQLtgC~Q?u+I4^cHM2WD;8w)ma<8p~&>mRW{Cu4U$V&Ur*aU zYaLhg1`gHS>EFIrc;)ppu+9b>rW4j#ur-lM?2Qvhi-PK*tH(GaHdw2Ee|!7a<*R8= zJ{~wXg(KWrA>rVS6(jeK1xNPj zN=zu&s?8);&_3z+w_MKXf@uX?t(n9=ED$>D`;hU_RXxs#1KeKWZ*MnkZdrX-XhQ?z z)EnDb=iXZVrmKOqXNk*=r0rSjH(4`@88iz0-gcw+*6KHt8d!bSlw94XYqsK>)^61V zMq_QkZ8utGeOtuw-nhTnRbWE{tLDc1?$A|&>wY*LU=mw(WS?%>Lbn}{q#3y*8ZTYV z-W=^4-m0q>q8w8=t$}ro56Iq{PS_u~X>xwiz*=x0n94l?$4qn!qR>RCIse zTKm{sH#z>EcrizHp4Odep*`?q6%VvSs?3n)#J7Ib98`2CHG-UwiN>M|h9Z z0j7waOQFBFsRb&>7)mj6Cv5b3b6d)@x8Uds7M+Grjh*@Tugza)Ccf|4<0t?8F1z*? z9DTu}({NSu?%VWt_qUh6UHUI~Lf~2_&)J6elMnR=az-$$4%=0gt@&}*T$VLL54%q8 zdHPr-A@Ue|#Lh|24_!Ov9M)NIbjdBrHJ56?tp2{7N&G<9)I0Lq%w#rrwP>rA*L7|v z`C4M1D%{AOF!kL{&P^8^LX~0+yMKRAm|DXhv)wO@F@dp6W`o@&xz(VsET4D(N!+Ke zD$~@M#1ACB{h;IYuuGD+TrBbA_XATi%y>3PJdb?03n(cQ8my zE;!2MbDe#4$<>)%3_Y$pk`$k1n?&u>Dqu8dxwYD0@zatb{n)EgObzZ=<639xswd11 zUS!I`aQ$jrD{DmAfmhlWrI;EP-&(yv;5Ao7t!k7r!<$gw-@pFbeYSYeQ_8+(-=)yC ziVWMqD>*jEnjRAE-u|}XYBJy>Da`S}uB9&791WIJIl|ZUHGEwmv{sQ}S&&l9MlYso ztG&XvwlPS6LN$vs!dW}EbeYnD&t5IsVZH~XqF=5$z*?}sf6MRK*JmC#sB=aHYlD3C zz~*5WufT?B3qZ!Y>_{?ZS);0TQHtq?{KGC@!420y;t97~w9VWOL@fsSq(OJZUM^{c zgj~m$tBge(x31jFC9Rl{8wfIAC-QCR4FSe%evnHd)>Re#e=ZyU|M{W&ty@8wloQ^D zc3u-mUKMLQXGXz=Id|-NJzv)P7C$^c>9HsO@?Q(z+}U6Gp6$^;?L)U^>)GW3FWaTv zPnTow@i?$3bdl+iyIdv)&4(z zZjH(39bd98l$3h!&tDd*9J5iIN$k94Z0zTmU0YXAbKP(Cy{o`NA^{-PoLR_Y%_MeNbLaa9zq4jH-1=+X{ytv*&u^aPM|7^oP2~uG zGppffjn}#DZ7=kV=M_us$_lSPs&n!%?BTzdQcOF3jo%S-1AGyUtl>7M*D??zt~{HvMfQi zOm8@9B&&C`=*8^fcY#_7Z=*YTzj!Of9292~dtKXuX5XDU$B^FCjW$W*~bLD!nbzrczfsKqR!_^ za}*Oc`pIYVH=I55IH4Nkpj!2WgLgrVt%_6gYivIp444(?yRUs+{|yKJm{hjzubXbp zwVe7UpLuVYW`Q|l_t#Z>xr()7?`F;Jm}Ta(?|Jons|V5$VejBgy^-r?CGTK*r%`RN``Mqq>H?0D3#_rP9d%3cMcU7(SJtFgae%5-Xa^VdT_M0PeJYQzj zPg`B{|59MI%8Ltp`hpuG_TO5)!Bq8l@6%f6Jv(2-KM&r~H2q~W>xPoEt>^!rGpv|8 zd42VhGe`eLzd66-4=>LF9{k(^uMxG)|u^H|9kTL>ivB2+fN#^ znSM&LViLO@P%XOS{8Hru&x($3b-w%T-)5bLhNEROjy4^Ct5$x;>Pqe_`_oK+vfnWt zNSHOp{xa8&H&N?$Y}r^>YW7(^(UnDK+v5Vpj0c8l`3VKnIBtraZuv0B_x=BWC*GFF z&;EISlK_+0?VxJW9ryR9Yp$DQ8{uNB?-z23dd1D~7@ zl(6V*TmMb#!>p@&GBq#GYuw2Z@#b(AAIAo!t>NOUU8>ohDJ5*=-x}U{ea$1^?!Vz@ z+z%w#hZQl2yuIqW(dNV+ z6RFhru$vl!Vyiqq6~A-5vv_7T!Pea%^E(yYJL5;ppm zzGFP#wkN%j@%5C~sfPTF+zr?N%&KOn?Uoj>PMK`|JEU5)BJSXOJ9B2)56Jo@j_kC=iEe9 zzS@ni_8e~TT`}|L&X7g6hmV|U{eAL!!Il4;tLIvCmS~>tFrRUdX>)`@&&~PXs>gY4 zr?JlutNQxj`ONd?>fiZ|-M%)~XRlB_#A?*cnzk`P!uM8lzVUU2E$KU=ZFk=1_wx;( z&*`)NmItT@=a~Ji{N4t}t>Nm+Z4bw*9zRf`=P>u3e^%90#~BBkQrtI3NYCp}e}3u? z^9=Ws*A+^4+{8UmpjWgqQLL% z)vLRoXV%TqInDh)thng@o9pkUY*9?Q^kBnXJ|%AJpB>WjGe7j6?0GAhb?fPc!#9r? zI2~w;w!0*E`t_N|H|7)t9gnEXIaf2!(?@KBms-5sn%KXR>$zi86AtRCzRliodAWK> z)%UY?YftGgW`!y`}>Pr~Arnh?|q8WqB^@>h*o1G8_>fdTyZ30hSEp?F#$%ec zR-(0m_57;6T;Wsi{atB(-@bU|5_Mmx4RR53Z~k-eO}}pr$cA|t=L0_feRAIAK$6KVlLM>o zU2a<=rPwWKy0>c8mv{VI|NLmMx@sS?>{t5()wB%>8uK>>PHWxuJhe{OI6{9*`UaO1 zEoTxA2Ke1ycSZ6zYP<%vqGgwjJt>YY48JG1oT2VA=OA>{G2iTO?%k@2gyK_j>)EAG^9w{f$?P z*~q{o*7Np*+wYgm+&Ug-ulqjk|95w}^R>+B7r1|~_iE7=b3V|dc}0d_C-vII1D~^Q z&G|gq<;A7@zu?Zo8KI4(wr*epT2%`AIrP&%X+2!JLiA+VEg{o z$Ftw}m;89#e(35_=lSOr^Ee-9S~*oF-1^I-#FtsOj=z@Jx%k<+386(i5qm{S ze=K%9bhUB9(bqbHhpx=p!p`j7rW1MAu)SxhdDgoaJ)82W&)&ViU3}Cj(}b&drRBM_ zsS!pgF@HU07cX2{_BFgO_U7@h&!%T&_dGqLK6$_As%3NkR%P_4-n(cZ>fN$|#q{mL zN9B8j(<`Ry6~*lSZGZV$-{F&$Uw=>UfA>a0UuNE`+swbWXNBvZX_}kbIpO-ugH5U{ zVr_LKuX)FF*gidWe0t3?-p}<$|Kkosd$-Krd*JevCwq5(IJ$LpKZ};cyarb9B8$I& zjlWGj^RVPl$|}#EqKE$up4X0_UsK=nXXoepv8Pph?PF9uGyUvV#O_rOkX`noMgLfO zr@*uoPbzpepJK%i5JOH~s&H@BH|DJ5$jA*UQUpy-eu*rzbk?$@le7 zuD`#RbG38x@6GF2wPs9fILeW={?jHQ$83$QtJ{0;dj9^bbAP{y@4mRHOC?iXY63rf zWt{*1bW8o=(8*?3%|4z^%w*AFOF30rqS|zAaaMT!(+V5Azkd!&O}l8evSj<^Bh|+e zSAN**vLK0a)uE0kt$uDtxaVrBO14|5xi zI8?6EGP?I(B#dc!}jUL;T0#V`afwG=JAKU zd?!CmX!e@N*8`Fz3&OUpHb3{pdy%;478V`0l9vm=%sV~1dDfc89Q%W|OLp!7X76p8Q^)`6AxGH^Fq)q~q0r zrXT+_Kj)0laXI<)sk8eXSIt=2qO#S?=K4%r$sV+5r}`Q114)TqZ!Sm8oV5P=j z@|N#buQJRwopCF4t#AS-i;mbTmkUt~C#{dJo+VQs`aCX^WwkgcfHt@=iE)Q3Wvq=j z`StYo7YF_|+zM^vy5?{oN!5#Gt>|jY`P?jPw6ns$E^0Cr+7K~Q$T55AxxJS-BGj|O zS+#C3F?LVYy6Byq%Ccsj(B2gZyIFM17PwuAnt5yW?f|8LgLNDcIUb#HQQDs-nmJ#Y zdE9W8&{^BW{VY0WD~{N$6XY&p;HXLo6$`QpKUR_$4x7S9_ zYJ zmtPC(omxBnxSE{)0ZS$^>##-BuQ^TGqL^Li-MT$aPTV{pL6JqrW6|_$OjqJ!Ss1x1 z`Wjf{r@UBdy4Y1u^xo}dj1N2xG;Q{Jb9t8INvG*tlgkoLG6^eea9|RP302DQUGq)r z02gOO!E_v6nm8j2 zb_qFVD{KvC6!SXJbaDzu6f3>)NqZ_T~+{1@MpEhir;KWCPxmo?jc z-IATLV6LRj4Bt-4wc=OeSR(`&yTjgws)a0?er=F}HUzcvU>zse}~RChj;Sb2uuJNqKG>&H*lp0@DU*y#V- zPxWp8Dap12OfwGN+U=gc!K?iD&EGMX@7mkmoB#V>+Oc^dN*Q-o9-E|SV9nV5@LR%E zneF^jx#N`+_O5Wbu*=!gx;o2LbVg^x(Ta1noA{3ZPrEcRC!ljdY5QTJt@7*!hK$`G z=TxVd?(LWT5eG6VplD9yR(^pQ9Sui!=;_)|TPL^4adKI4(d4_&8=p^kv9#3L_xIzC zIUGI?2a+Vc`er}(?whG_vsSMnrguT9>siAL)0=<$nI+mAjv7s^InS}_V6)ekOS=|5 zt1w%0T+G0LvHPiZtZl5H$?mTWLch1H)39u-?AK0EU=n*B{AsJKi!l4K-BUQC%;%UL z+xu;XRqfR)RV)_H2a^7J>8RT+ak;Q-;gdhfT0f-@=?U&i_|BrUZE4BXqDQh`ENiW& zth<-B=(c*w!F8MwInkX@kIeRBS<8Osch}29mp5cHiTw^rvi!J6Xz!MH1@E=fgcr({ z`5Z{v?-j1AJ}*!?BlhC`Cv|TRJyU(29ymMDjZLSeft6h~ZTmjWi{7vOme0PwK6cXb zC)F$R-K2yKR{NWqZ@;&;WP5+jv(2mJ?>>JfcUx!srLw_r)E^xqS0{|;YXZOQiOJV)e)046b=gX?n)%CBtkTrgk9 z`_}(8B_AfuTJN~}jG52_9`6=|t^bVQ#T35m#zy~amv&+GKN5+8XA%xxxmUHl zS?z7g`NY)RVqqI!z4cS4McCC`e7JG*$(sQY^2QMxQcR`qU5H6?%T`f6e)GcB?M#iO zM$N3=Va0Qv-nz5KMc6n>IrGxLi2o_g#tS#_rEN&i^)kCxvgt_AH4ZPce>)meg*GJQ zX5C_bwsjl-YEWsz;dM*?rJDbOhNprX5_-MLiZ-kf+`<-iIWF};Kfjx5!ogWrx3Hf+ zo1db$b5G5Vlg13kLX(7Tdd{eoM{J%|CYJrV`rz!CdjkKp-~K*w_P;>e47Ag?SwEWVTXBeUkslSRfpr+LJ394DK_)TXGjpHz#o;aPIBaOQ=69=6Z# z-#mFLVfKFhmdyhH&EMWBF@Bz~?34eb|GvNF|NEC)|L~vmf3lh3pY6Y+^s+Afn^C9w zbN-trADJI-bUDGnC+@nrx=c*2~h<=_aby zw

    9. FWNo*+VPq8-ZpX8rnf8)aI@&J6}?V;vcPobq`B>DnrD4>d@a>~UB&FcVeXuw zbfwgHjBorWzZN##9e9~-*yU%hu%wkgxK$zEkOOsqC;2a*)F%ekFB z`Pb;s{`y~kSvPLBOVU3Z|BYwgkz~$1p$!rzjM>)|J$pRgd|w*J*^_@Y4@dk@H#zM1 zr+8j{StZMw=~pdI3#=2^AaP+vuGFcSzwPz^{0x{i`S*I3joJPiJNch%4KMeNo;dyL zjp?i#MC#r$FmS|y)&hugMCABbe*So8bJBLd{X&}}HVXaT^ni!4TUI;$UB9h%S>IBp zuyro`bzTT=c(APK*<;1@qiG&iTf-AM^fofrb4D1fxU{?8pZ(*^Ws|bj9}>vQscYwm zFlc0*zcFp)1j8#g{+xRUst#D^y50z{7Htc96gA_`tOnM}kq+`}iq9k&P7|7a|E4Y@ z_qTQ5w0L}%0|Vs4Gr(lBpGfMGLFpY zlGJ%%y*a|??R=T^P4^ycJpO9tL8f!Y-A7|eYSWp&9Ar9o`R?4EdzR-u3`mz_2Tg(` zRJQ1ZofA?ln3?MIEN$n6sYcDLF=;a=?3{TrX(@{i!!+L$Nv%49OxGjTQZ#kMHz}oU zXn3t7yh$W&Q-mNR_l|X*)d9__0-GW@y;~0CPUDP}I^C)>$NMS6_MIhs-k_3!hT}Kdk49aIYvr7IkV)?Gqw{NA z--gbZ(7<}2>}p(VCr8AADQW>hmA z;4&?|DRb?)?QzXktH%~MSiM^gJpOk?)iYxGca{B*KAwKTqVu58_s!v?xwCfUDNf$N z&Rx-08?h$R_qW=^+Gm9uBGWcBJU1!kXNU_}eA{}l(1wQR7Si2YSAVofGhq^A_#Ij; z%BGaScs?^}vGwhM#e$m6n@`GC%J z!zf+s(-P3sZNyHsw{G9lt_2>jxK})R9m_h6 zxhrQhuHTa&t*Mh3KSdDCvp zy|dXig5iTkx>!+j1M42Y)okCEb^5-KQB7bxV4QVpLg;f@w$myJjO()(g))PN@~oJ| zKI}?+$9SM8>z27h>Al1aI=4(14qsT+Xsez1J$dhOX}(D_4l*@dH{JMhu0D%Sf`soJ z&lCHuazy?CnHi8(QmNkAz{=yQuaj~0#+N?trwj)k@J+v*nRNNL-^_zdZGq3_7<796 zM(keZ%WN>`aONwA)!(#sC$e!f91E(Rde@+tmB)Q^pv8ORb5?9oyx{75hpzT zbfe~uDd&nd&Xw8~`#rve)~i&V&Y5hV17-R^6Z9pV)KY!awzs^@{|Re4ftV zGW)K#&3my!JYozvj&DQLo(5SmY!Ed)?)`EKN3^lf28M)ezO~YPzc+n3HEWKlQ$mIB zt?U{S0?)c3X zV}oYap2Iw1I>*y*r5;LqR`{j^wBEvM`lXq38d!T4d)|H_FeBdglln9+b(I9h19Dfk z{C)Xq&*2-~jNA<04h20-0jC1{$64nm+Gef)B*e%q(ci%O`jMrzgm(*r!|U=%{X5w=@}_NQ_*h}i^E$YC>heF< zbu9-Xye9ou`Nt-W!-rkB zR$G4uFRPLcyu2+hW7F@MIv^JmygBYQ=}-Od8|#vc*)RWMU|?YIboFyt=akR{06`-j Au>b%7 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_024.png b/example/output_data/random/random_024.png new file mode 100644 index 0000000000000000000000000000000000000000..0c973fca743b2575ab17acfd28f106543c3ab61c GIT binary patch literal 9721 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 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_025.png b/example/output_data/random/random_025.png new file mode 100644 index 0000000000000000000000000000000000000000..a70725817a264c1f2372a70df2406aba7d81b565 GIT binary patch literal 7163 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 KelF{r5}E*z8myoI literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_026.png b/example/output_data/random/random_026.png new file mode 100644 index 0000000000000000000000000000000000000000..3f109f2c244e274ca00f0adde4239a9bf9f23856 GIT binary patch literal 11099 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3Sga29w(7BevL9RXp+soH$f z3=9eko-U3d6?5L+%`SVqZ4=vtSG&*c*=1z3*gY*JWuLvuQIp&Hkt&Q#)#-_jFH2Nj zB>pyL5UX=N;(efeugej8!9eMLW(KQo^=sJ=ocz<-@%&mdL&LtmT*eW1R2HmU-+)QHq+NXOY+SqP6=Q-E zli2Oxr?L$vIU{oPou`&FEK^I^*bkCXGTXTs!bsb2W4hLR2A>l=V!wl)$~JIvM!W&J zaYloxQ{Tc<)(pai%|{JGD%lg1(l%K5MSf*4&|vINj?`jFV4B8Zd2RlVkV^K3#+e5n zRis{JK9InobE`nXgn?OjLx%F<#tRHQ-Uk-V1z9Ozw(~MrJBM+^mgf!`3~b44-QQ$5 zc)@x=zVSOJr1&@BsceJejDw5h`C8Z#1kyIV@Q(b-P~gNQ_BZgUY{O*X4KMuLwB9q! znbqJr|I{k>2H}k-=h}fnOg)LMd*8}Wdib>=_f)1jA*UUNJs!FxzPiVWe%4 zn634m!6bpLd*jMad=AV^V#y%C@FjFkuw3zp??B_31Vi@FdyEznBz2wzhS@T_aXFBr zH;s$YqCwT^*(Y_q(0hyt?r9rl_(y(a*kH)mZD}bW)ga3maYhpqEpOZoB*lRu%q^!V z9l|)1(8#=y@x}~E9Z&>H3vXDkri!6rf~wOFP{{YrIM^i3?!>%7&^Tg4NSH0dpN0n3 z>{WZ1KPWJAUo#4+WPhN@B(`Vynkt4J&A#tG%mev{FKxpEV~`qVID<*7X4#r5h97L+ zEgxh-vBYj1fndafoW#zev!i{f6T`lPLW*}DgCpgD`k91-dqKe}%E(=JsPO_rjnjdq z`6oawl^5FZU^z%id-k1&5QcHY2Mv&0li0ZBo;qYOgt6#UghYO2@HsD}nBzLNoMGLW zgo9zAv^P~!=SC1n#`8ea+LfR93~U*>w@q7k%KE?)7M&Z;Aep0Ts9?)T%Oae**Q&|fEwi1@{ijy3KL|OK;CMcylHEepIO2kF=siY|rg7s{Ud(7YpNJ_C9-j!JJ)!D;jZ9@2X9WTN*8)x z`+C}zh2qmV9)h?`@_*yrd{2GRDybvUs`Y;Ik8|5|j3Y110&$raGJ>?b1%=r%8#S}0 zDEdpmnp9q8N!*wdfxcQgiV^(dvMA%W`=u-{9-+4%;tL99Dn_0s<}i} z0vmVQ=Q~vlIq&ZueS0ZO;6PIY>*kXiLenj_er0G7W#mr#>>p#c-~RaRsj7Z!^z#1a znQ|l?l+%&8`$@ZIr>*+>zi+(`+b1eLx#G2F-^_1`j@fA&5=yogd1imT^{?}K^P>FC zQFCH4Z5d|FYhc~Owl?}kRp03|(^ZcMYp!Ky(1}oLiL^QX_jH5g^qFh-{HvcPX#M?S zl|g}tafCs4{o{W(S4d5dTzk7y$N!_%X4iI^+01)?#J^@_P!D`u`c3O`?ulQUe^{3& z9hPQ#3o!^ZSMYmU++k_Pw;T}$lc(P(&-RP^{r=7EO|cp3ePBuI;~O*;C~V5(TN1I{vP9-AAcy(?p-xE2r45*e1syFpVQoFZJs7 z4|CsJgl&^c`70V_+|2qVednAL{2JF8)^bK1*tpMlVbSf~PXk`@ro3i6Fhxi3kdM(f z&8r_)+}^jQ|Jc-z+eBKrKHXms!@NZ$;b6`;y{j9R@A=mE{wLd0sRgRuEe9&E{Mg0A z5`N0m!JA3!%(7z^j!W7$d|h~}iow9tyTxGkrdRG$KJH3?eZQi*?@`EC3Om_wp&i@vKh`^)XnM>MVX*in^EKaNERNng*)k3aDW1`Y=3gLe`Y+B-hxhpA?$n)a zIi?&l`WjdR9&f$leB{9IEt|eFBuGu;NOU`I_+iowH>0@e{Qmpryt*M{F-uaX;ro?} zSUa1)jhD9<@!l*FFc4+reqd~R@7?99e_!(FJAjfxQv<8rVfOBI2!qwPsu(6~UVJzyG1Hbo zVp;=h!4#?K6TVtYrOi&`=Lr_vz|dE=dgj$NQ=IpH>pR=Hmm`8fcS^7_eBp=$_s z`Q~5WU++J3&dY==vb4~;zph|LQv>UTpiVZ$)p~i>X6)Y-5*W9HEpj}uYijlhWqFZh ziU|kLc)e!)Fkfi;gwQBkiw&xb+zZ50ugZT)I3UNO(=cyJXg$YMsf27MF^7CFnUIgQ zl{tRz{w9DTWP$tkOr(R=z5NxU^?6W&AGD2+o)a(Xb&IpFRT7?Iu zwtl_!d>%j3Wx)*$RbffbmmW&>{J-fr^T7}norZgVJ7qWf-+kSen8hUK@cz`Q`ysJ+ z!qzcvQ%X3v#_Kg>!E_<(XY=jj|BF7*V-h9zC6VZS&KO zmN&BmK$XmaJUgyn>DDz;*69mk-^;YAB`}(7bUbmZR(@I$?}uO}u`{c-$sKsX7sYi) zmHBG+{OUWFK8^>NELLy2F00>v_U2nhPz`us=2N-ysP8+1XLK3y8Z6%Q>Sn~TrF_T2 z%`}=fc&}``Eqh<%I>UFPX4VZWdk!DEx^7B#gF7gx-%k|H5SMIkU%l&YY^_dzg@8m? z1M7y)p6`dR+81($oGxQq`jz3ql{W{QB;Rh!PY;unZ(qIZz4QC3Cl`zNoQwN;;DGI! z1V$T`#gRL1&4s#m#WuME8b-%>!v&LV*fX3DF#VX=qjxCuUFGxA!rL1y3-}qi(}Ewp zJ;iT7;iBsft0QY;oVUra%;{@j-5j{+p`+yImepG?RWTGuF^L`6o?0Th?o&s*ZnZrF zkLQ7=n<+i^7dLhHtUDAc?7xNlW^%_fQ%a=QDV42zw6E-UU|@eufQ7Dc1jGANFRWr*Wo%}K zMB8Z0nbyE+eDZ~w^cUU5uM55ktrzxcU+ZXL#{Nz*;h>Jut`ls3PrtB>S-aQ#&e^NV zax86N;gEv=L2lO{u3EWk$J!X?8rK6&kt-hjYvp=K?vM$H;G@@U0UTp*wzwu5Vlw_y4a!YT@ti6Zv_TD<>S}nfK`JE52~aYNuBr5y3TN4G2!5gPq(hOCBN`%EBG4hD=*{c ze1J)9a^bCltE~_hxg2P^c(Z=%gu-71SC9U_S;KI_mXX`-n~bcE=2xZ1Umj{LI{ba} z7CD9z&jU?@ch9XleRRLSuJevtL7BD;FXlC{^5`XZ6o_8DS?K=t*6nuI_ktT58dG_M z*C|<9zss2UWz$s!P!ng*>!;1fDpPnw*C|;=DaD+=#@z6ZBcecD@wJRm%j&&TkLDhK zc3@TmYrUj`%iW?Q>s@EN9V>XKwP^Aup6u<6siz$srnBhmxLs|(=cV(p2@hY1c)ezH z2xrle2%NrIw)(V$RZMEh50k9djG)fMj@$NY*+1;u^KI)x3BKuyF%FDr>Kx&f zZ?g{@%BUrG6->Rp&rIg<@>7qt74a4*CmdYvx9!ixuR)il87<=oUmm!=)=Y-^i|c`= zi77r4^g&|V4>Qku%(64JGRH5|l;cHL1MB^1AeZ$l{B-m;NWuG;yZ+_o+A@G#F@M!s z_7Am(_4(6$gxC3npWddIr+uA4kV&jZIeEvNk6OvI3QD7#msjtY-M|V~Yb&{2^3`9X zW!&Na>pna`UpPtEZ|PTt1(uB5`_?}8zR(^kcV>oG%+!jz*bm%v!}fmrme|<98ovrui6xpz2Dh%h z9sKv*<<-~s|MoB0ma`+~_L;Ee20f05g0jQ9U`HG2c{lw(cHa5Y`WG2DH|XW1FE(_L zXVLi)bbSBR=UdnF9^bICXXT-*#W9BpD?jX;cDk+q-gW0!kIIf$i#=pu5}R`~U~{8@@jU+tS&Sc_{Qq>eDyjZ+>6N+N1ljU`5dvW~b>aIu@%Hr?DF^;|y1g zo6g$*$v!aFYHrKUR6-Ky720wjr{zPr=Qf{Xm$!` z(b?gx9`2Sp$EG=jBb>c|VdU90Hoq7bax;m|xwvvV*i^~Cd%{iQzNb#zE1&a|VeX$G zCidT=>(%2K<)hZEU&G&-{Xlh>#Ie6d%eca~+lFs_>G7}ZMBIjR`_djH{J-x0HU7bE zqhG%p|LTGQq2v0@)we2S-dm>ZEQnlCex1EZ@9+KktM&1VCNCCS;4T|l{66*MOFdA$ zJg<23W47{}eK8T=cO_f&PX8Zu%-iO;_nw&FF@MZ`XYZOiy<>Xz>9WTscGTpW)!V+y z+*$E<+S-S&ccg2pSNF%QOTPE?-}Lw8?B_!-^X2^SURsq~`S<(s3f<&OuS3jb^bU(3 zE>HC_EdILb*LUMw%U!zS*KR!2-KjhAK+V1VT^o+Q7F9p(>@t7xN6GLDUb(gn-ODX5 zeo8nt<)PN2nEUG4d*s$`UcKo%vqSj5?_c9P_or{mi|?ox`)~W`&i~>k8M4g zhpuXzTBI-kZ>{{jjgmUgzC_Gyd;0x+&GY@&GooYo%}Rd<{S@}CldkWZtaCNpM|9o2 z-+WPz=iL8&YSsNC#TwTS^vG$O?22(}$^4UN+t8QlBf8G6=vaa1#>*|i?%@v(HEvt^ zB+mZFXP$Wf4Xxm!Vc!(P)E%on{_1`<-{QZ@*=NFAN(-&G?@4}f&uqHNzVH5RoA_@z zy#1*f6)xioc8(-m*)YZGD?~e!p1m z+GDr>M)@x+vQfXBq3`K-+)_39RDtNns*49#lFAE{`6(C7q-nkxGTK(wEnLBN^?3-?0mA3 zKeWGk$NQ5r%AT!S^K0T;qwcR;zREgHzs0s@snj8{xvP)cr);adaX!^YdY#d+d*xeK zKds8zCdDGNY<|PmkjL*ge3dyQ_PMg_+_#@8KGN%yo^gk(>ZRT}9G_`+v;se)j1{-`?xK6WFyacV^q-ls&P> z?2mp_?0NX@X;AX_l|4OuX+B2F_`)S+_looGIpTIzblPcwQ>F&n{-tlY7yS6Gq3yS9 z!$oERI+*Ukl=${n#>K@3)=r58rvWukKSh-$ccjqn_y} z=ZC*#oE_^Mv3-ZIMQgF1V4Ztgs!LhH1tE8F`zyxF_`_B8ZnyevH~DdK`&aq8w9~8V zPZZ@$xFS#`qp`inkAVk+~a=VDq=YQ{?AVr<8VRs zyI20*`+aS5&q}*spQnGSH@pix{H(%k%I`aGb^n-y+`UIt(k^)WuEm?K$~sZs&V#-^;)EOpNZ`Wm%h_DkPXQUE7;=L&kn@ z)!X9RyKPG<4V-sGNhrm*?wOmlzHr|6OKUtQ`K$jT;>-3-1ElnTTD;wC9b!= zao?41eSY+}=H9zH`(Npkf8SqlXwR~*w`cJu+?n=KYRfG7+C{n7PkHCa`tbd%d6IPJ zP^e2x)1i0ke+%aRy_ff6-aDxcr|goiZQ+}xddT+b2FtpNop)oe9Do1nGkay-^YiMl zVm%UTR1RN$RMuN;w=&0;;YQ5oDdw@KcbtjX(=u~y@V1)H|8=kR`tRR=H^1>|#n~9w zBi>UaGBOMP{>%Hb@10q7X|}aac2*SoS)MR%P_!yYrmYJzV%wEvko5iL>eANsv)Xo7 zvgb$NH#AXA07cl3%PVi+4b7{cp8q~($FI`?54DoEYqL+UTl>q`(yZN(Gh*+Gk7hZx zM{jR%U0!GZZNL3dKYL;0meu7`B$lWg_Km!=uJD|CSTsLF+2xwKLBE%z-dKM%^>)Vn z6VHA}J~}#YHGkAGhu`b+-X8c~KK=Zw>hp`gX0OVez4aOMg?+b;TGr;>+Vt!~^ZVz^ z9-lh8qh+;u?vC{{H&xV^-&2^kvDhNkZu*-CTd!_8K3nyW@yf*FKOXav9zQ+EbGk{s zqVM1|HsybIjddb7s~9%Se5UDNy&!dk%>5-(r&oM2f9E?rrpQpvI6Ob9lW{uR=|{G9 z3-&n5eU#F=zM%K&Kk+%yv0o(D@4sSq)WKDReagm%)sqvSy<(P}zP>efU0wFe%);Ld zH&^#;7ytcsQQPU|lAWrDCSD1!+}FA1fBjC@2flLAJAPdV<_VjmnAD@qet&TcbF$zD zx6sG$|3)3U*7oZB|LZk>^y1!o?D!SX$@o3i)#PUNS8Kis+46b@i!1AQ{JD`TCRtx! zzs}dKsOWv|&6cdhZ?1Ok{V``oxKpq4Kg}$xzA|&(r7DIEE1zllzuuC%Lgs(??}t2LN1BZz zejZFtWnb^9uDgDHW|_gXv$sF}%@0t2wLx-C#my&ESbSeEn0fF~vS~=){YzEn-);Z? zA#KLaUv0}JeyCPP-Lb3qruF#2^^(YSiv2YSH>NZk{eESGrJd3~KiBzxzE7{ zG4jLgdC3o!9_+AOC-cWE)0W|fAY=Dqo8vXnTJs*C`&Zji5)73*Xn+cn_Biby?c9S zT`SMFW5~U-jVJi^|7nJ0y=!-yvp)Cc2>-r!-_3&-W!bOKAMROS8fo+Y%>&zuTYk?{ zb^7-Crr1)c`s+8UIzLaZ(JdV@|yyHNA{-CZxT-iNxeuP@yu$8hIucubv) zgS^qbe>t5yikmB(RrP*{=49OWKbGxyF)?+|U!R)Y8Mo}>qWB(ud%W`4gM6#zEW6%i zneVst?4K@F9V4Z6{o~Z?|MzP+Pd9zvDtG_?*=Y6Z^?7SEJ4KH_%UGUwmVH6y{cOqi z?CXS%|G%KyT{va_9rt}L1*QM9|1G}$%SU(p{ANEVSGUJX>ry{PP5HLIec9cM|HKQ# zO0Pa&RNr+ybn5N;`$et`V}9SietfsA(AbF zhI0qybdF8F{_o{n`_=Y4=1Z-geeLz!?;qdITt!vu3iS&avR|T63e8)$%+3HmvVGzH#@{e3q?O74DsS@gSw`cIvSLy;CL!6hR6! z3>`h&I`(Hzj*zQ~2gS4*BX`+!#hAYi&`L6SP5Sz**@w%`&6pnEF zDTWs>CAeMR94{9~kQ(;rpKq@2dDr%3)fPF1 z8qWhwz9}5x{3m8S(U`L|=8jqQSMYd;I3u^*G{qR(j9HU-%u@?@x1B$^cS`nxdL}U& z73UpQ0iB&*Mt9~s2zcJZ*LN~9dSBShEP)TYOk#f`+6uld=mE)2Ir>)0PTPL!T6Tu{ zzeMxK{G`A-vw*O_CVm^fuc|)Xo4E9D20Awly8Xyt6nXlv08u4_)OuwQByPz2V2B_8kMc zU7WF-6J+d(9Vy+J-bOBa?pBKyo?0@q@R5FVjxEEF{)VF|MlGx7`pBaC3E!u*~Gm+hhtd zO*tx@439=h6>$8PDbd-zQ#sK@+3pGmCww7|Nu67KM=A1!7{r+m|Tq;mYpnyW|O zF7N**B;$1;DFLME)T;SmZ8ulTX>7Y|#md0I%?MfxaNQxEMTc#wV$55O!=cUpBhSsa z64v~nH^-JiV1q!fOwlW%~+M{e@xnU|^PGha__wA`YeP^ct% z=xXDXl#1gH?N z{fl`GM>#=b6Iz9lQeTWSQy=UNH+N>$IsWXzG*u_7>54J3pg?}F)qUHv=G(ag8!fk} zCS2Ue^YB%|p{wj_H>#%^-k2VmYs;Xfo^Wv`NLW>G|Cj6A4!`h^ytD2ht5x@|9e=-E zjBmQj5mBPyyu&J@Z4!_Ctb}h_5vNQq^fkDq8?~%vo09UwK`-yR#4qC+hBpi?vu{>0 z__!Tdq%3(Tl=*PT`+LndR~Ku8b5D~eXGDpT^Ny?qYpTSI;?ixic>Y`dk!`j+TJ?7G zLx~v^8(i5zCK|<<{?ObUo*b~Q(Tqh$>a@T*DM3&}?CP7V7qVV68fZ?vld0jnBWuZ; zs<3IH2h@Ms@P!_&&Hb62cSGGX{Y=6|kG6uV9&M9&=ASaCHkI<;BjbNyQ6ta8RSTDY z`1~yRTU_tjEpiN#1vXejv=x+Ym>wFu_OGxcsD$A87vlYz(Lj;0n>m#uT(%(Vg!-Ad z-qmr{@eDG~2OcSa{PceBlNyD`?@zt$Nse5n7|q+%$q^x=;Jjl|z3}F7{>4fzDEG0c7B&1} zXqmnJyIC|}lP5<+PDbs{Sp`?`yj6G}-+j!h?dEF9sn?hj3Yf&Cf1Yb(ICOR4DbTQ2 z0oUa7alT7ImKBEZN&kG6tP&%e_hPaCwn-n$mX%%-&slZ8E4kRBO;U$1D4IV(?|fqO z@9i`8&N~08_FPzV0uz&1&$5``w+eWcPe^=!_06WQ3=%UMSQi&wdtk1czCLTUkE(o$nIC2wor%*;@hS81YjHR$I3=?|FeQd* znl}6Xhn8{7VZATow`_W~d|?dpZ=+^bWrOOkzLII{!XlZ1(10ld<;ddHy%5zph)^cXH>? zSI6&_=yO;LYP`_!W{-iKT_W=rZ= ztkz7It2_1P>TV-7-S>%X-G65uY%+c!tv7?M1uQx*BHJD< z%E|v58{g1=Hd3i&o@M!jwR^v7Z?#&p!IF`?3OqK>%wVsS;JE%w93yD5#9;FGZ_zg& zv(FaZu)rPcHG_5W-S^naZ?rbB+HSJpD9Bob(Mdt;m)M*Qg=4Uvjmf)B#)5{E+ z0fR_+#(|O~gN@GtCWad`8dz-$Hy9rfV9|NuxlN9NAzEO=0&&T2ag01p2b$tm+~YIg zVdSm~0(nc9BjN(60%X{xlEBE2<8z=%?nXVUfe0ga71-NrIU+8AvL-{c@CF73GqnWA z?7riSprs%Ni$OEHw;^+UGj4gu>=SzEVOPFE+c@GvRIV+1NPCDS%Au&E?CYD*pxJzkx^f2vguD8QmlcKq1> zRbj@Z^*dzr{;B5_w9n;;xX{J>j^VHnRI9dR+J=nf$5O>aK>?x8yp7 zC2OUopH~FUyhjzVDjvANqLTs2{S4KD8y;kwPt0tyyYeBjW$vH#Ul|g#^xxkJ^OR1o zNZas01LVL1fh;-=k$|jY z8?k|zk-Kk7A{#fTkU4N>jyuP0fejBdB-7S2s3}6tTb!bCk->nIk-Kk^3$yL2hc-?( z8XH(aYpl2#5|Z~TJzDxzA%RQ3@Ml-^y&pM;o}EcJC}{L%Khum3sH%iA(~#o!Ue1Vu z79P_L3~EXV2L-PjV4Bg@z-nO4Zg=<@i;jg;o1{)dCr1PWgS7C5gnY0AloJ@wtZQSQ zpP0-f_D0valda(-N5lqmRVjvL5Gf(jM%W8M^%bJO(o&ryeSzEbYy<;%!bA&Bo*4GMkuk&n9#sleNteZ zMZXkZO&c#K#59J03=uQ6goANLAcs$BV66^h=1z!$#?KA!Hc6dxOF`i&$OsA)Cb2h) zhu?@ke{AD)qX!xa-zF?{VLot#MdwDd5HCZp@CJq*D?nk{(ZE`L!l0Sez!0i6M;D|u z#Cay$4Oj?nn+DPgTA?*dh<8pT@9CBej8N6!ym%w3P1Wh#>BjRLI2pOOO;LCe_2G-~xX6^<7P*VP`trQo<&(!u&X!?3B3*-686*DBEK{b`< z_j-m74o2>Vtx~IY9&TpQx#86&#LM8)(!hECn^ZwrOfDszZ4F8_lI8}5su=bw{VCHTxXVIycA{D`~2AXOf z1WKlDknrbyE_jF;8si^2cs7SK{Bb?N^dR4KN@fE)N5qE?P$B@Wi|P+p#0XlA%CKks pHaUhl(;Ha(PkeCZXxRV9J~(@G*VQofYz77f22WQ%mvv4FO#tCLc*p<% literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_027.png b/example/output_data/random/random_027.png new file mode 100644 index 0000000000000000000000000000000000000000..e4cd1001833906c6b899839abe670bbaa1e0d63c GIT binary patch literal 12574 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�U<@1 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 L`njxgN@xNAr5^u6 literal 0 HcmV?d00001 diff --git a/example/output_data/random/random_028.png b/example/output_data/random/random_028.png new file mode 100644 index 0000000000000000000000000000000000000000..4b4bb7213a104248dd39ed9ab41113747ca2ca8f GIT binary patch literal 12887 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 XGwsBWzdOLdz`)??>gTe~DWM4fPP(2F literal 0 HcmV?d00001 diff --git a/example/voronoi_advanced_tutorial.cpp b/example/voronoi_advanced_tutorial.cpp new file mode 100644 index 0000000..96ad969 --- /dev/null +++ b/example/voronoi_advanced_tutorial.cpp @@ -0,0 +1,145 @@ +// Boost.Polygon library voronoi_advanced_tutorial.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include +#include +#include + +// This will work properly only with GCC compiler. +#include +typedef long double fpt80; + +// Random generators and distributions. +#include +#include +#include + +#include +using namespace boost::polygon; + +struct my_ulp_comparison { + enum Result { + LESS = -1, + EQUAL = 0, + MORE = 1 + }; + + Result operator()(fpt80 a, fpt80 b, unsigned int maxUlps) const { + if (a == b) + return EQUAL; + if (a > b) { + Result res = operator()(b, a, maxUlps); + if (res == EQUAL) return res; + return (res == LESS) ? MORE : LESS; + } + ieee854_long_double lhs, rhs; + lhs.d = a; + rhs.d = b; + if (lhs.ieee.negative ^ rhs.ieee.negative) + return lhs.ieee.negative ? LESS : MORE; + boost::uint64_t le = lhs.ieee.exponent; le = + (le << 32) + lhs.ieee.mantissa0; + boost::uint64_t re = rhs.ieee.exponent; re = + (re << 32) + rhs.ieee.mantissa0; + if (lhs.ieee.negative) { + if (le - 1 > re) + return LESS; + le = (le == re) ? 0 : 1; + le = (le << 32) + lhs.ieee.mantissa1; + re = rhs.ieee.mantissa1; + return (re + maxUlps < le) ? LESS : EQUAL; + } else { + if (le + 1 < re) + return LESS; + le = lhs.ieee.mantissa0; + re = (le == re) ? 0 : 1; + re = (re << 32) + rhs.ieee.mantissa1; + return (le + maxUlps < re) ? LESS : EQUAL; + } + } +}; + +struct my_fpt_converter { + template + fpt80 operator()(const T& that) const { + return static_cast(that); + } + + template + fpt80 operator()(const typename detail::extended_int &that) const { + fpt80 result = 0.0; + for (std::size_t i = 1; i <= (std::min)((std::size_t)3, that.size()); ++i) { + if (i != 1) + result *= static_cast(0x100000000ULL); + result += that.chunks()[that.size() - i]; + } + return (that.count() < 0) ? -result : result; + } +}; + +// Voronoi diagram traits. +struct my_voronoi_diagram_traits { + typedef fpt80 coordinate_type; + typedef voronoi_cell cell_type; + typedef voronoi_vertex vertex_type; + typedef voronoi_edge edge_type; + typedef class { + public: + enum { ULPS = 128 }; + bool operator()(const vertex_type &v1, const vertex_type &v2) const { + return (ulp_cmp(v1.x(), v2.x(), ULPS) == my_ulp_comparison::EQUAL && + ulp_cmp(v1.y(), v2.y(), ULPS) == my_ulp_comparison::EQUAL); + } + private: + my_ulp_comparison ulp_cmp; + } vertex_equality_predicate_type; +}; + +// Voronoi ctype traits for 48-bit signed integer input coordinates. +struct my_voronoi_ctype_traits { + typedef boost::int64_t int_type; + typedef detail::extended_int<3> int_x2_type; + typedef detail::extended_int<3> uint_x2_type; + typedef detail::extended_int<128> big_int_type; + typedef fpt80 fpt_type; + typedef fpt80 efpt_type; + typedef my_ulp_comparison ulp_cmp_type; + typedef my_fpt_converter to_fpt_converter_type; + typedef my_fpt_converter to_efpt_converter_type; +}; + +const unsigned int GENERATED_POINTS = 100; +const boost::int64_t MAX = 0x1000000000000LL; + +int main() { + boost::mt19937_64 gen(std::time(0)); + boost::random::uniform_int_distribution distr(-MAX, MAX-1); + voronoi_builder vb; + for (size_t i = 0; i < GENERATED_POINTS; ++i) { + boost::int64_t x = distr(gen); + boost::int64_t y = distr(gen); + vb.insert_point(x, y); + } + + printf("Constructing Voronoi diagram of %d points...\n", GENERATED_POINTS); + boost::timer::cpu_timer t; + voronoi_diagram vd; + t.start(); + vb.construct(&vd); + boost::timer::cpu_times times = t.elapsed(); + std::string ftime = boost::timer::format(times, 5, "%w"); + + printf("Construction done in: %s seconds.\n", ftime.c_str()); + printf("Resulting Voronoi graph has the following stats:\n"); + printf("Number of Voronoi cells: %lu.\n", vd.num_cells()); + printf("Number of Voronoi vertices: %lu.\n", vd.num_vertices()); + printf("Number of Voronoi edges: %lu.\n", vd.num_edges()); + return 0; +} diff --git a/example/voronoi_basic_tutorial.cpp b/example/voronoi_basic_tutorial.cpp new file mode 100644 index 0000000..ea2b9e6 --- /dev/null +++ b/example/voronoi_basic_tutorial.cpp @@ -0,0 +1,193 @@ +// Boost.Polygon library voronoi_basic_tutorial.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#include +using boost::polygon::voronoi_builder; +using boost::polygon::voronoi_diagram; +using boost::polygon::x; +using boost::polygon::y; +using boost::polygon::low; +using boost::polygon::high; + +#include "voronoi_visual_utils.hpp" + +struct Point { + int a; + int b; + Point(int x, int y) : a(x), b(y) {} +}; + +struct Segment { + Point p0; + Point p1; + Segment(int x1, int y1, int x2, int y2) : p0(x1, y1), p1(x2, y2) {} +}; + +namespace boost { +namespace polygon { + +template <> +struct geometry_concept { + typedef point_concept type; +}; + +template <> +struct point_traits { + typedef int coordinate_type; + + static inline coordinate_type get( + const Point& point, orientation_2d orient) { + return (orient == HORIZONTAL) ? point.a : point.b; + } +}; + +template <> +struct geometry_concept { + typedef segment_concept type; +}; + +template <> +struct segment_traits { + typedef int coordinate_type; + typedef Point point_type; + + static inline point_type get(const Segment& segment, direction_1d dir) { + return dir.to_int() ? segment.p1 : segment.p0; + } +}; +} // polygon +} // boost + +// Traversing Voronoi edges using edge iterator. +int iterate_primary_edges1(const voronoi_diagram& vd) { + int result = 0; + for (voronoi_diagram::const_edge_iterator it = vd.edges().begin(); + it != vd.edges().end(); ++it) { + if (it->is_primary()) + ++result; + } + return result; +} + +// Traversing Voronoi edges using cell iterator. +int iterate_primary_edges2(const voronoi_diagram &vd) { + int result = 0; + for (voronoi_diagram::const_cell_iterator it = vd.cells().begin(); + it != vd.cells().end(); ++it) { + const voronoi_diagram::cell_type& cell = *it; + const voronoi_diagram::edge_type* edge = cell.incident_edge(); + // This is convenient way to iterate edges around Voronoi cell. + do { + if (edge->is_primary()) + ++result; + edge = edge->next(); + } while (edge != cell.incident_edge()); + } + return result; +} + +// Traversing Voronoi edges using vertex iterator. +// As opposite to the above two functions this one will not iterate through +// edges without finite endpoints and will iterate only once through edges +// with single finite endpoint. +int iterate_primary_edges3(const voronoi_diagram &vd) { + int result = 0; + for (voronoi_diagram::const_vertex_iterator it = + vd.vertices().begin(); it != vd.vertices().end(); ++it) { + const voronoi_diagram::vertex_type& vertex = *it; + const voronoi_diagram::edge_type* edge = vertex.incident_edge(); + // This is convenient way to iterate edges around Voronoi vertex. + do { + if (edge->is_primary()) + ++result; + edge = edge->rot_next(); + } while (edge != vertex.incident_edge()); + } + return result; +} + +int main() { + // Preparing Input Geometries. + std::vector points; + points.push_back(Point(0, 0)); + points.push_back(Point(1, 6)); + std::vector segments; + segments.push_back(Segment(-4, 5, 5, -1)); + segments.push_back(Segment(3, -11, 13, -1)); + + // Construction of the Voronoi Diagram. + voronoi_diagram vd; + construct_voronoi(points.begin(), points.end(), + segments.begin(), segments.end(), + &vd); + + // Traversing Voronoi Graph. + { + printf("Traversing Voronoi graph.\n"); + printf("Number of visited primary edges using edge iterator: %d\n", + iterate_primary_edges1(vd)); + printf("Number of visited primary edges using cell iterator: %d\n", + iterate_primary_edges2(vd)); + printf("Number of visited primary edges using vertex iterator: %d\n", + iterate_primary_edges3(vd)); + printf("\n"); + } + + // Using color member of the Voronoi primitives to store the average number + // of edges around each cell (including secondary edges). + { + printf("Number of edges (including secondary) around the Voronoi cells:\n"); + for (voronoi_diagram::const_edge_iterator it = vd.edges().begin(); + it != vd.edges().end(); ++it) { + std::size_t cnt = it->cell()->color(); + it->cell()->color(cnt + 1); + } + for (voronoi_diagram::const_cell_iterator it = vd.cells().begin(); + it != vd.cells().end(); ++it) { + printf("%lu ", it->color()); + } + printf("\n"); + printf("\n"); + } + + // Linking Voronoi cells with input geometries. + { + unsigned int cell_index = 0; + for (voronoi_diagram::const_cell_iterator it = vd.cells().begin(); + it != vd.cells().end(); ++it) { + if (it->contains_point()) { + std::size_t index = it->source_index(); + Point p = points[index]; + printf("Cell #%ud contains a point: (%d, %d).\n", + cell_index, x(p), y(p)); + } else { + std::size_t index = it->source_index() - points.size(); + Point p0 = low(segments[index]); + Point p1 = high(segments[index]); + if (it->source_category() == + boost::polygon::SOURCE_CATEGORY_SEGMENT_START_POINT) { + printf("Cell #%ud contains segment start point: (%d, %d).\n", + cell_index, x(p0), y(p0)); + } else if (it->source_category() == + boost::polygon::SOURCE_CATEGORY_SEGMENT_END_POINT) { + printf("Cell #%ud contains segment end point: (%d, %d).\n", + cell_index, x(p0), y(p0)); + } else { + printf("Cell #%ud contains a segment: ((%d, %d), (%d, %d)). \n", + cell_index, x(p0), y(p0), x(p1), y(p1)); + } + } + ++cell_index; + } + } + return 0; +} diff --git a/example/voronoi_visual_utils.hpp b/example/voronoi_visual_utils.hpp new file mode 100644 index 0000000..4ef2e9d --- /dev/null +++ b/example/voronoi_visual_utils.hpp @@ -0,0 +1,186 @@ +// Boost.Polygon library voronoi_graphic_utils.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_VORONOI_VISUAL_UTILS +#define BOOST_POLYGON_VORONOI_VISUAL_UTILS + +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace polygon { +// Utilities class, that contains set of routines handful for visualization. +template +class voronoi_visual_utils { + public: + // Discretize parabolic Voronoi edge. + // Parabolic Voronoi edges are always formed by one point and one segment + // from the initial input set. + // + // Args: + // point: input point. + // segment: input segment. + // max_dist: maximum discretization distance. + // discretization: point discretization of the given Voronoi edge. + // + // Template arguments: + // InCT: coordinate type of the input geometries (usually integer). + // Point: point type, should model point concept. + // Segment: segment type, should model segment concept. + // + // Important: + // discretization should contain both edge endpoints initially. + template class Point, + template class Segment> + static + typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_point_concept< + typename geometry_concept< Point >::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< Segment >::type + >::type + >::type + >::type, + void + >::type discretize( + const Point& point, + const Segment& segment, + const CT max_dist, + std::vector< Point >* discretization) { + // Apply the linear transformation to move start point of the segment to + // the point with coordinates (0, 0) and the direction of the segment to + // coincide the positive direction of the x-axis. + CT segm_vec_x = cast(x(high(segment))) - cast(x(low(segment))); + CT segm_vec_y = cast(y(high(segment))) - cast(y(low(segment))); + CT sqr_segment_length = segm_vec_x * segm_vec_x + segm_vec_y * segm_vec_y; + + // Compute x-coordinates of the endpoints of the edge + // in the transformed space. + CT projection_start = sqr_segment_length * + get_point_projection((*discretization)[0], segment); + CT projection_end = sqr_segment_length * + get_point_projection((*discretization)[1], segment); + + // Compute parabola parameters in the transformed space. + // Parabola has next representation: + // f(x) = ((x-rot_x)^2 + rot_y^2) / (2.0*rot_y). + CT point_vec_x = cast(x(point)) - cast(x(low(segment))); + CT point_vec_y = cast(y(point)) - cast(y(low(segment))); + CT rot_x = segm_vec_x * point_vec_x + segm_vec_y * point_vec_y; + CT rot_y = segm_vec_x * point_vec_y - segm_vec_y * point_vec_x; + + // Save the last point. + Point last_point = (*discretization)[1]; + discretization->pop_back(); + + // Use stack to avoid recursion. + std::stack point_stack; + point_stack.push(projection_end); + CT cur_x = projection_start; + CT cur_y = parabola_y(cur_x, rot_x, rot_y); + + // Adjust max_dist parameter in the transformed space. + const CT max_dist_transformed = max_dist * max_dist * sqr_segment_length; + while (!point_stack.empty()) { + CT new_x = point_stack.top(); + CT new_y = parabola_y(new_x, rot_x, rot_y); + + // Compute coordinates of the point of the parabola that is + // furthest from the current line segment. + CT mid_x = (new_y - cur_y) / (new_x - cur_x) * rot_y + rot_x; + CT mid_y = parabola_y(mid_x, rot_x, rot_y); + + // Compute maximum distance between the given parabolic arc + // and line segment that discretize it. + CT dist = (new_y - cur_y) * (mid_x - cur_x) - + (new_x - cur_x) * (mid_y - cur_y); + dist = dist * dist / ((new_y - cur_y) * (new_y - cur_y) + + (new_x - cur_x) * (new_x - cur_x)); + if (dist <= max_dist_transformed) { + // Distance between parabola and line segment is less than max_dist. + point_stack.pop(); + CT inter_x = (segm_vec_x * new_x - segm_vec_y * new_y) / + sqr_segment_length + cast(x(low(segment))); + CT inter_y = (segm_vec_x * new_y + segm_vec_y * new_x) / + sqr_segment_length + cast(y(low(segment))); + discretization->push_back(Point(inter_x, inter_y)); + cur_x = new_x; + cur_y = new_y; + } else { + point_stack.push(mid_x); + } + } + + // Update last point. + discretization->back() = last_point; + } + + private: + // Compute y(x) = ((x - a) * (x - a) + b * b) / (2 * b). + static CT parabola_y(CT x, CT a, CT b) { + return ((x - a) * (x - a) + b * b) / (b + b); + } + + // Get normalized length of the distance between: + // 1) point projection onto the segment + // 2) start point of the segment + // Return this length divided by the segment length. This is made to avoid + // sqrt computation during transformation from the initial space to the + // transformed one and vice versa. The assumption is made that projection of + // the point lies between the start-point and endpoint of the segment. + template class Point, + template class Segment> + static + typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_point_concept< + typename geometry_concept< Point >::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< Segment >::type + >::type + >::type + >::type, + CT + >::type get_point_projection( + const Point& point, const Segment& segment) { + CT segment_vec_x = cast(x(high(segment))) - cast(x(low(segment))); + CT segment_vec_y = cast(y(high(segment))) - cast(y(low(segment))); + CT point_vec_x = x(point) - cast(x(low(segment))); + CT point_vec_y = y(point) - cast(y(low(segment))); + CT sqr_segment_length = + segment_vec_x * segment_vec_x + segment_vec_y * segment_vec_y; + CT vec_dot = segment_vec_x * point_vec_x + segment_vec_y * point_vec_y; + return vec_dot / sqr_segment_length; + } + + template + static CT cast(const InCT& value) { + return static_cast(value); + } +}; +} +} + +#endif // BOOST_POLYGON_VORONOI_VISUAL_UTILS diff --git a/example/voronoi_visualizer.cpp b/example/voronoi_visualizer.cpp new file mode 100644 index 0000000..3049c38 --- /dev/null +++ b/example/voronoi_visualizer.cpp @@ -0,0 +1,509 @@ +// Boost.Polygon library voronoi_visualizer.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#include +#include + +#include +#include +using namespace boost::polygon; + +#include "voronoi_visual_utils.hpp" + +class GLWidget : public QGLWidget { + Q_OBJECT + + public: + explicit GLWidget(QMainWindow* parent = NULL) : + QGLWidget(QGLFormat(QGL::SampleBuffers), parent), + primary_edges_only_(false), + internal_edges_only_(false) { + startTimer(40); + } + + QSize sizeHint() const { + return QSize(600, 600); + } + + void build(const QString& file_path) { + // Clear all containers. + clear(); + + // Read data. + read_data(file_path); + + // No data, don't proceed. + if (!brect_initialized_) { + return; + } + + // Construct bounding rectangle. + construct_brect(); + + // Construct voronoi diagram. + construct_voronoi( + point_data_.begin(), point_data_.end(), + segment_data_.begin(), segment_data_.end(), + &vd_); + + // Color exterior edges. + for (const_edge_iterator it = vd_.edges().begin(); + it != vd_.edges().end(); ++it) { + if (!it->is_finite()) { + color_exterior(&(*it)); + } + } + + // Update view port. + update_view_port(); + } + + void show_primary_edges_only() { + primary_edges_only_ ^= true; + } + + void show_internal_edges_only() { + internal_edges_only_ ^= true; + } + + protected: + void initializeGL() { + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glEnable(GL_POINT_SMOOTH); + } + + void paintGL() { + qglClearColor(QColor::fromRgb(255, 255, 255)); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + draw_points(); + draw_segments(); + draw_vertices(); + draw_edges(); + } + + void resizeGL(int width, int height) { + int side = qMin(width, height); + glViewport((width - side) / 2, (height - side) / 2, side, side); + } + + void timerEvent(QTimerEvent* e) { + update(); + } + + private: + typedef double coordinate_type; + typedef point_data point_type; + typedef segment_data segment_type; + typedef rectangle_data rect_type; + typedef voronoi_builder VB; + typedef voronoi_diagram VD; + typedef VD::cell_type cell_type; + typedef VD::cell_type::source_index_type source_index_type; + typedef VD::cell_type::source_category_type source_category_type; + typedef VD::edge_type edge_type; + typedef VD::cell_container_type cell_container_type; + typedef VD::cell_container_type vertex_container_type; + typedef VD::edge_container_type edge_container_type; + typedef VD::const_cell_iterator const_cell_iterator; + typedef VD::const_vertex_iterator const_vertex_iterator; + typedef VD::const_edge_iterator const_edge_iterator; + + static const std::size_t EXTERNAL_COLOR = 1; + + void clear() { + brect_initialized_ = false; + point_data_.clear(); + segment_data_.clear(); + vd_.clear(); + } + + void read_data(const QString& file_path) { + QFile data(file_path); + if (!data.open(QFile::ReadOnly)) { + QMessageBox::warning( + this, tr("Voronoi Visualizer"), + tr("Disable to open file ") + file_path); + } + QTextStream in_stream(&data); + std::size_t num_points, num_segments; + int x1, y1, x2, y2; + in_stream >> num_points; + for (std::size_t i = 0; i < num_points; ++i) { + in_stream >> x1 >> y1; + point_type p(x1, y1); + update_brect(p); + point_data_.push_back(p); + } + in_stream >> num_segments; + for (std::size_t i = 0; i < num_segments; ++i) { + in_stream >> x1 >> y1 >> x2 >> y2; + point_type lp(x1, y1); + point_type hp(x2, y2); + update_brect(lp); + update_brect(hp); + segment_data_.push_back(segment_type(lp, hp)); + } + in_stream.flush(); + } + + void update_brect(const point_type& point) { + if (brect_initialized_) { + encompass(brect_, point); + } else { + set_points(brect_, point, point); + brect_initialized_ = true; + } + } + + void construct_brect() { + double side = (std::max)(xh(brect_) - xl(brect_), yh(brect_) - yl(brect_)); + center(shift_, brect_); + set_points(brect_, shift_, shift_); + bloat(brect_, side * 1.2); + } + + void color_exterior(const VD::edge_type* edge) { + if (edge->color() == EXTERNAL_COLOR) { + return; + } + edge->color(EXTERNAL_COLOR); + edge->twin()->color(EXTERNAL_COLOR); + const VD::vertex_type* v = edge->vertex1(); + if (v == NULL || !edge->is_primary()) { + return; + } + v->color(EXTERNAL_COLOR); + const VD::edge_type* e = v->incident_edge(); + do { + color_exterior(e); + e = e->rot_next(); + } while (e != v->incident_edge()); + } + + void update_view_port() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + rect_type view_rect = brect_; + deconvolve(view_rect, shift_); + glOrtho(xl(view_rect), xh(view_rect), + yl(view_rect), yh(view_rect), + -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + } + + void draw_points() { + // Draw input points and endpoints of the input segments. + glColor3f(0.0f, 0.5f, 1.0f); + glPointSize(9); + glBegin(GL_POINTS); + for (std::size_t i = 0; i < point_data_.size(); ++i) { + point_type point = point_data_[i]; + deconvolve(point, shift_); + glVertex2f(point.x(), point.y()); + } + for (std::size_t i = 0; i < segment_data_.size(); ++i) { + point_type lp = low(segment_data_[i]); + lp = deconvolve(lp, shift_); + glVertex2f(lp.x(), lp.y()); + point_type hp = high(segment_data_[i]); + hp = deconvolve(hp, shift_); + glVertex2f(hp.x(), hp.y()); + } + glEnd(); + } + + void draw_segments() { + // Draw input segments. + glColor3f(0.0f, 0.5f, 1.0f); + glLineWidth(2.7f); + glBegin(GL_LINES); + for (std::size_t i = 0; i < segment_data_.size(); ++i) { + point_type lp = low(segment_data_[i]); + lp = deconvolve(lp, shift_); + glVertex2f(lp.x(), lp.y()); + point_type hp = high(segment_data_[i]); + hp = deconvolve(hp, shift_); + glVertex2f(hp.x(), hp.y()); + } + glEnd(); + } + + void draw_vertices() { + // Draw voronoi vertices. + glColor3f(0.0f, 0.0f, 0.0f); + glPointSize(6); + glBegin(GL_POINTS); + for (const_vertex_iterator it = vd_.vertices().begin(); + it != vd_.vertices().end(); ++it) { + if (internal_edges_only_ && (it->color() == EXTERNAL_COLOR)) { + continue; + } + point_type vertex(it->x(), it->y()); + vertex = deconvolve(vertex, shift_); + glVertex2f(vertex.x(), vertex.y()); + } + glEnd(); + } + void draw_edges() { + // Draw voronoi edges. + glColor3f(0.0f, 0.0f, 0.0f); + glLineWidth(1.7f); + for (const_edge_iterator it = vd_.edges().begin(); + it != vd_.edges().end(); ++it) { + if (primary_edges_only_ && !it->is_primary()) { + continue; + } + if (internal_edges_only_ && (it->color() == EXTERNAL_COLOR)) { + continue; + } + std::vector samples; + if (!it->is_finite()) { + clip_infinite_edge(*it, &samples); + } else { + point_type vertex0(it->vertex0()->x(), it->vertex0()->y()); + samples.push_back(vertex0); + point_type vertex1(it->vertex1()->x(), it->vertex1()->y()); + samples.push_back(vertex1); + if (it->is_curved()) { + sample_curved_edge(*it, &samples); + } + } + glBegin(GL_LINE_STRIP); + for (std::size_t i = 0; i < samples.size(); ++i) { + point_type vertex = deconvolve(samples[i], shift_); + glVertex2f(vertex.x(), vertex.y()); + } + glEnd(); + } + } + + void clip_infinite_edge( + const edge_type& edge, std::vector* clipped_edge) { + const cell_type& cell1 = *edge.cell(); + const cell_type& cell2 = *edge.twin()->cell(); + point_type origin, direction; + // Infinite edges could not be created by two segment sites. + if (cell1.contains_point() && cell2.contains_point()) { + point_type p1 = retrieve_point(cell1); + point_type p2 = retrieve_point(cell2); + origin.x((p1.x() + p2.x()) * 0.5); + origin.y((p1.y() + p2.y()) * 0.5); + direction.x(p1.y() - p2.y()); + direction.y(p2.x() - p1.x()); + } else { + origin = cell1.contains_segment() ? + retrieve_point(cell2) : + retrieve_point(cell1); + segment_type segment = cell1.contains_segment() ? + retrieve_segment(cell1) : + retrieve_segment(cell2); + coordinate_type dx = high(segment).x() - low(segment).x(); + coordinate_type dy = high(segment).y() - low(segment).y(); + if ((low(segment) == origin) ^ cell1.contains_point()) { + direction.x(dy); + direction.y(-dx); + } else { + direction.x(-dy); + direction.y(dx); + } + } + coordinate_type side = xh(brect_) - xl(brect_); + coordinate_type koef = + side / (std::max)(fabs(direction.x()), fabs(direction.y())); + if (edge.vertex0() == NULL) { + clipped_edge->push_back(point_type( + origin.x() - direction.x() * koef, + origin.y() - direction.y() * koef)); + } else { + clipped_edge->push_back( + point_type(edge.vertex0()->x(), edge.vertex0()->y())); + } + if (edge.vertex1() == NULL) { + clipped_edge->push_back(point_type( + origin.x() + direction.x() * koef, + origin.y() + direction.y() * koef)); + } else { + clipped_edge->push_back( + point_type(edge.vertex1()->x(), edge.vertex1()->y())); + } + } + + void sample_curved_edge( + const edge_type& edge, + std::vector* sampled_edge) { + coordinate_type max_dist = 1E-3 * (xh(brect_) - xl(brect_)); + point_type point = edge.cell()->contains_point() ? + retrieve_point(*edge.cell()) : + retrieve_point(*edge.twin()->cell()); + segment_type segment = edge.cell()->contains_point() ? + retrieve_segment(*edge.twin()->cell()) : + retrieve_segment(*edge.cell()); + voronoi_visual_utils::discretize( + point, segment, max_dist, sampled_edge); + } + + point_type retrieve_point(const cell_type& cell) { + source_index_type index = cell.source_index(); + source_category_type category = cell.source_category(); + if (category == SOURCE_CATEGORY_SINGLE_POINT) { + return point_data_[index]; + } + index -= point_data_.size(); + if (category == SOURCE_CATEGORY_SEGMENT_START_POINT) { + return low(segment_data_[index]); + } else { + return high(segment_data_[index]); + } + } + + segment_type retrieve_segment(const cell_type& cell) { + source_index_type index = cell.source_index() - point_data_.size(); + return segment_data_[index]; + } + + point_type shift_; + std::vector point_data_; + std::vector segment_data_; + rect_type brect_; + VB vb_; + VD vd_; + bool brect_initialized_; + bool primary_edges_only_; + bool internal_edges_only_; +}; + +class MainWindow : public QWidget { + Q_OBJECT + + public: + MainWindow() { + glWidget_ = new GLWidget(); + file_dir_ = QDir(QDir::currentPath(), tr("*.txt")); + file_name_ = tr(""); + + QHBoxLayout* centralLayout = new QHBoxLayout; + centralLayout->addWidget(glWidget_); + centralLayout->addLayout(create_file_layout()); + setLayout(centralLayout); + + update_file_list(); + setWindowTitle(tr("Voronoi Visualizer")); + layout()->setSizeConstraint(QLayout::SetFixedSize); + } + + private slots: + void primary_edges_only() { + glWidget_->show_primary_edges_only(); + } + + void internal_edges_only() { + glWidget_->show_internal_edges_only(); + } + + void browse() { + QString new_path = QFileDialog::getExistingDirectory( + 0, tr("Choose Directory"), file_dir_.absolutePath()); + if (new_path.isEmpty()) { + return; + } + file_dir_.setPath(new_path); + update_file_list(); + } + + void build() { + file_name_ = file_list_->currentItem()->text(); + QString file_path = file_dir_.filePath(file_name_); + message_label_->setText("Building..."); + glWidget_->build(file_path); + message_label_->setText("Double click the item to build voronoi diagram:"); + setWindowTitle(tr("Voronoi Visualizer - ") + file_path); + } + + void print_scr() { + if (!file_name_.isEmpty()) { + QImage screenshot = glWidget_->grabFrameBuffer(true); + QString output_file = file_dir_.absolutePath() + tr("/") + + file_name_.left(file_name_.indexOf('.')) + tr(".png"); + screenshot.save(output_file, 0, -1); + } + } + + private: + QGridLayout* create_file_layout() { + QGridLayout* file_layout = new QGridLayout; + + message_label_ = new QLabel("Double click item to build voronoi diagram:"); + + file_list_ = new QListWidget(); + file_list_->connect(file_list_, + SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this, + SLOT(build())); + + QCheckBox* primary_checkbox = new QCheckBox("Show primary edges only."); + connect(primary_checkbox, SIGNAL(clicked()), + this, SLOT(primary_edges_only())); + + QCheckBox* internal_checkbox = new QCheckBox("Show internal edges only."); + connect(internal_checkbox, SIGNAL(clicked()), + this, SLOT(internal_edges_only())); + + QPushButton* browse_button = + new QPushButton(tr("Browse Input Directory")); + connect(browse_button, SIGNAL(clicked()), this, SLOT(browse())); + browse_button->setMinimumHeight(50); + + QPushButton* print_scr_button = new QPushButton(tr("Make Screenshot")); + connect(print_scr_button, SIGNAL(clicked()), this, SLOT(print_scr())); + print_scr_button->setMinimumHeight(50); + + file_layout->addWidget(message_label_, 0, 0); + file_layout->addWidget(file_list_, 1, 0); + file_layout->addWidget(primary_checkbox, 2, 0); + file_layout->addWidget(internal_checkbox, 3, 0); + file_layout->addWidget(browse_button, 4, 0); + file_layout->addWidget(print_scr_button, 5, 0); + + return file_layout; + } + + void update_file_list() { + QFileInfoList list = file_dir_.entryInfoList(); + file_list_->clear(); + if (file_dir_.count() == 0) { + return; + } + QFileInfoList::const_iterator it; + for (it = list.begin(); it != list.end(); it++) { + file_list_->addItem(it->fileName()); + } + file_list_->setCurrentRow(0); + } + + QDir file_dir_; + QString file_name_; + GLWidget* glWidget_; + QListWidget* file_list_; + QLabel* message_label_; +}; + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + MainWindow window; + window.show(); + return app.exec(); +} + +#include "voronoi_visualizer.moc" diff --git a/include/boost/polygon/detail/boolean_op.hpp b/include/boost/polygon/detail/boolean_op.hpp index 400825e..d3e3614 100644 --- a/include/boost/polygon/detail/boolean_op.hpp +++ b/include/boost/polygon/detail/boolean_op.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -30,8 +30,8 @@ namespace boolean_op { inline BooleanOp (T nullT) : scanData_(), nextItr_(), nullT_(nullT) { nextItr_ = scanData_.end(); } inline BooleanOp (const BooleanOp& that) : scanData_(that.scanData_), nextItr_(), nullT_(that.nullT_) { nextItr_ = scanData_.begin(); } - inline BooleanOp& operator=(const BooleanOp& that); - + inline BooleanOp& operator=(const BooleanOp& that); + //moves scanline forward inline void advanceScan() { nextItr_ = scanData_.begin(); } @@ -39,7 +39,7 @@ namespace boolean_op { //appends output edges to cT template inline void processInterval(cT& outputContainer, interval_data ivl, T deltaCount); - + private: inline typename ScanData::iterator lookup_(Unit pos){ if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { @@ -47,9 +47,9 @@ namespace boolean_op { } return nextItr_ = scanData_.lower_bound(pos); } - inline typename ScanData::iterator insert_(Unit pos, T count){ - return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count)); - } + inline typename ScanData::iterator insert_(Unit pos, T count){ + return nextItr_ = scanData_.insert(nextItr_, ElementType(pos, count)); + } template inline void evaluateInterval_(cT& outputContainer, interval_data ivl, T beforeCount, T afterCount); }; @@ -78,29 +78,29 @@ namespace boolean_op { //BinaryCount is an array of two deltaCounts coming from two different layers //of scan event data. It is the merged count of the two suitable for consumption //as the template argument of the BooleanOp algorithm because BinaryCount casts to int. - //T is a binary functor object that evaluates the array of counts and returns a logical + //T is a binary functor object that evaluates the array of counts and returns a logical //result of some operation on those values. //BinaryCount supports many of the operators that work with int, particularly the //binary operators, but cannot support less than or increment. template class BinaryCount { public: - inline BinaryCount() -#ifndef BOOST_POLYGON_MSVC - : counts_() + inline BinaryCount() +#ifndef BOOST_POLYGON_MSVC + : counts_() #endif { counts_[0] = counts_[1] = 0; } // constructs from two integers - inline BinaryCount(int countL, int countR) -#ifndef BOOST_POLYGON_MSVC - : counts_() + inline BinaryCount(int countL, int countR) +#ifndef BOOST_POLYGON_MSVC + : counts_() #endif { counts_[0] = countL, counts_[1] = countR; } inline BinaryCount& operator=(int count) { counts_[0] = count, counts_[1] = count; return *this; } - inline BinaryCount& operator=(const BinaryCount& that); + inline BinaryCount& operator=(const BinaryCount& that); inline BinaryCount(const BinaryCount& that) #ifndef BOOST_POLYGON_MSVC - : counts_() + : counts_() #endif { *this = that; } inline bool operator==(const BinaryCount& that) const; @@ -141,13 +141,13 @@ namespace boolean_op { }; template - inline BooleanOp& BooleanOp::operator=(const BooleanOp& that) { - scanData_ = that.scanData_; + inline BooleanOp& BooleanOp::operator=(const BooleanOp& that) { + scanData_ = that.scanData_; nextItr_ = scanData_.begin(); nullT_ = that.nullT_; return *this; } - + //appends output edges to cT template template @@ -214,7 +214,7 @@ namespace boolean_op { template template - inline void BooleanOp::evaluateInterval_(cT& outputContainer, interval_data ivl, + inline void BooleanOp::evaluateInterval_(cT& outputContainer, interval_data ivl, T beforeCount, T afterCount) { bool before = (int)beforeCount > 0; bool after = (int)afterCount > 0; @@ -225,13 +225,13 @@ namespace boolean_op { } template - inline BinaryCount& BinaryCount::operator=(const BinaryCount& that) { + inline BinaryCount& BinaryCount::operator=(const BinaryCount& that) { counts_[0] = that.counts_[0]; counts_[1] = that.counts_[1]; return *this; } template - inline bool BinaryCount::operator==(const BinaryCount& that) const { + inline bool BinaryCount::operator==(const BinaryCount& that) const { return counts_[0] == that.counts_[0] && counts_[1] == that.counts_[1]; } @@ -290,7 +290,7 @@ namespace boolean_op { count[0] += (*itr1).second.second; } if(itr2 != itr2_end) { - if((*itr2).first < prevCoord || + if((*itr2).first < prevCoord || ((*itr2).first == prevCoord && (*itr2).second.first < prevPosition)) { prevCoord = (*itr2).first; prevPosition = (*itr2).second.first; @@ -307,7 +307,7 @@ namespace boolean_op { } else { if(itr1 != itr1_end) ++itr1; } - + while(itr1 != itr1_end || itr2 != itr2_end) { Unit curCoord = UnitMax; Unit curPosition = UnitMax; @@ -318,7 +318,7 @@ namespace boolean_op { curCount[0] += (*itr1).second.second; } if(itr2 != itr2_end) { - if((*itr2).first < curCoord || + if((*itr2).first < curCoord || ((*itr2).first == curCoord && (*itr2).second.first < curPosition)) { curCoord = (*itr2).first; curPosition = (*itr2).second.first; @@ -349,15 +349,15 @@ namespace boolean_op { boolean.processInterval(container, ivl, count); for(std::size_t i = 0; i < container.size(); ++i) { std::pair, int>& element = container[i]; - if(!output.empty() && output.back().first == prevCoord && + if(!output.empty() && output.back().first == prevCoord && output.back().second.first == element.first.low() && output.back().second.second == element.second * -1) { output.pop_back(); } else { - output.push_back(std::pair >(prevCoord, std::pair(element.first.low(), + output.push_back(std::pair >(prevCoord, std::pair(element.first.low(), element.second))); } - output.push_back(std::pair >(prevCoord, std::pair(element.first.high(), + output.push_back(std::pair >(prevCoord, std::pair(element.first.high(), element.second * -1))); } } @@ -379,11 +379,11 @@ namespace boolean_op { } inputOutput.insert(inputOutput.end(), output.begin(), output.end()); } - + template inline void applyUnaryXOr(std::vector > >& input) { BooleanOp booleanXOr; - + } template @@ -416,15 +416,15 @@ namespace boolean_op { booleanOr.processInterval(container, ivl, count_type(count)); for(std::size_t i = 0; i < container.size(); ++i) { std::pair, int>& element = container[i]; - if(!output.empty() && output.back().first == prevPos && + if(!output.empty() && output.back().first == prevPos && output.back().second.first == element.first.low() && output.back().second.second == element.second * -1) { output.pop_back(); } else { - output.push_back(std::pair >(prevPos, std::pair(element.first.low(), + output.push_back(std::pair >(prevPos, std::pair(element.first.low(), element.second))); } - output.push_back(std::pair >(prevPos, std::pair(element.first.high(), + output.push_back(std::pair >(prevPos, std::pair(element.first.high(), element.second * -1))); } } @@ -435,7 +435,7 @@ namespace boolean_op { input = std::vector > >(); } else { input.clear(); - } + } input.insert(input.end(), output.begin(), output.end()); } }; diff --git a/include/boost/polygon/detail/boolean_op_45.hpp b/include/boost/polygon/detail/boolean_op_45.hpp index b4a82d8..fd64eff 100644 --- a/include/boost/polygon/detail/boolean_op_45.hpp +++ b/include/boost/polygon/detail/boolean_op_45.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -16,20 +16,20 @@ namespace boost { namespace polygon{ class Count2 { public: - inline Count2() -#ifndef BOOST_POLYGON_MSVC - : counts() + inline Count2() +#ifndef BOOST_POLYGON_MSVC + : counts() #endif { counts[0] = counts[1] = 0; } //inline Count2(int count) { counts[0] = counts[1] = count; } - inline Count2(int count1, int count2) -#ifndef BOOST_POLYGON_MSVC - : counts() + inline Count2(int count1, int count2) +#ifndef BOOST_POLYGON_MSVC + : counts() #endif { counts[0] = count1; counts[1] = count2; } - inline Count2(const Count2& count) -#ifndef BOOST_POLYGON_MSVC - : counts() + inline Count2(const Count2& count) +#ifndef BOOST_POLYGON_MSVC + : counts() #endif { counts[0] = count.counts[0]; counts[1] = count.counts[1]; } inline bool operator==(const Count2& count) const { return counts[0] == count.counts[0] && counts[1] == count.counts[1]; } @@ -108,7 +108,7 @@ namespace boost { namespace polygon{ inline Scan45ElementT(const Scan45ElementT& that) : x(that.x), y(that.y), rise(that.rise), count(that.count) {} inline Scan45ElementT& operator=(const Scan45ElementT& that) { - x = that.x; y = that.y; rise = that.rise; count = that.count; + x = that.x; y = that.y; rise = that.rise; count = that.count; return *this; } inline Unit evalAtX(Unit xIn) const { @@ -142,7 +142,7 @@ namespace boost { namespace polygon{ return true; } }; - + typedef Scan45ElementT Scan45Element; // inline std::ostream& operator<< (std::ostream& o, const Scan45Element& c) { @@ -168,7 +168,7 @@ namespace boost { namespace polygon{ inline lessScan45Element(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} inline lessScan45Element(const lessScan45Element& that) : x_(that.x_), justBefore_(that.justBefore_) {} inline lessScan45Element& operator=(const lessScan45Element& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } - inline bool operator () (const Scan45ElementT& elm1, + inline bool operator () (const Scan45ElementT& elm1, const Scan45ElementT& elm2) const { Unit y1 = elm1.evalAtX(*x_); Unit y2 = elm2.evalAtX(*x_); @@ -190,42 +190,42 @@ namespace boost { namespace polygon{ public: inline Scan45CountT() : counts() {} //counts[0] = counts[1] = counts[2] = counts[3] = 0; } inline Scan45CountT(CountType count) : counts() { counts[0] = counts[1] = counts[2] = counts[3] = count; } - inline Scan45CountT(const CountType& count1, const CountType& count2, const CountType& count3, - const CountType& count4) : counts() { - counts[0] = count1; - counts[1] = count2; + inline Scan45CountT(const CountType& count1, const CountType& count2, const CountType& count3, + const CountType& count4) : counts() { + counts[0] = count1; + counts[1] = count2; counts[2] = count3; - counts[3] = count4; + counts[3] = count4; } - inline Scan45CountT(const Scan45CountT& count) : counts() { + inline Scan45CountT(const Scan45CountT& count) : counts() { (*this) = count; } - inline bool operator==(const Scan45CountT& count) const { + inline bool operator==(const Scan45CountT& count) const { for(unsigned int i = 0; i < 4; ++i) { - if(counts[i] != count.counts[i]) return false; + if(counts[i] != count.counts[i]) return false; } return true; } inline bool operator!=(const Scan45CountT& count) const { return !((*this) == count); } - inline Scan45CountT& operator=(CountType count) { + inline Scan45CountT& operator=(CountType count) { counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } inline Scan45CountT& operator=(const Scan45CountT& count) { for(unsigned int i = 0; i < 4; ++i) { - counts[i] = count.counts[i]; + counts[i] = count.counts[i]; } - return *this; + return *this; } inline CountType& operator[](int index) { return counts[index]; } inline CountType operator[](int index) const {return counts[index]; } inline Scan45CountT& operator+=(const Scan45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { - counts[i] += count.counts[i]; + counts[i] += count.counts[i]; } return *this; } inline Scan45CountT& operator-=(const Scan45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { - counts[i] -= count.counts[i]; + counts[i] -= count.counts[i]; } return *this; } @@ -270,7 +270,7 @@ namespace boost { namespace polygon{ inline Vertex45T() : pt(), rise(), count() {} inline Vertex45T(const Point& point, int riseIn, ct countIn) : pt(point), rise(riseIn), count(countIn) {} inline Vertex45T(const Vertex45T& vertex) : pt(vertex.pt), rise(vertex.rise), count(vertex.count) {} - inline Vertex45T& operator=(const Vertex45T& vertex){ + inline Vertex45T& operator=(const Vertex45T& vertex){ pt = vertex.pt; rise = vertex.rise; count = vertex.count; return *this; } inline Vertex45T(const std::pair& vertex) : pt(), rise(), count() {} inline Vertex45T& operator=(const std::pair& vertex){ return *this; } @@ -307,13 +307,13 @@ namespace boost { namespace polygon{ int *justBefore_; public: inline lessVertex45() : x_(0), justBefore_() {} - + inline lessVertex45(Unit *x, int *justBefore) : x_(x), justBefore_(justBefore) {} - + inline lessVertex45(const lessVertex45& that) : x_(that.x_), justBefore_(that.justBefore_) {} - + inline lessVertex45& operator=(const lessVertex45& that) { x_ = that.x_; justBefore_ = that.justBefore_; return *this; } - + template inline bool operator () (const Vertex45T& elm1, const Vertex45T& elm2) const { Unit y1 = elm1.evalAtX(*x_); @@ -390,7 +390,7 @@ namespace boost { namespace polygon{ template struct boolean_op_45_output_functor { template - void operator()(cT& output, const Count2& count1, const Count2& count2, + void operator()(cT& output, const Count2& count1, const Count2& count2, const Point& pt, int rise, direction_1d end) { int edgeType = applyLogic(count1, count2); if(edgeType) { @@ -423,7 +423,7 @@ namespace boost { namespace polygon{ template struct unary_op_45_output_functor { template - void operator()(cT& output, const Count1& count1, const Count1& count2, + void operator()(cT& output, const Count1& count1, const Count1& count2, const Point& pt, int rise, direction_1d end) { int edgeType = applyLogic(count1, count2); if(edgeType) { @@ -445,7 +445,7 @@ namespace boost { namespace polygon{ }; template static inline void sortScan45Vector(S45V& vec) { - gtlsort(vec.begin(), vec.end(), lessScan45Vertex()); + polygon_sort(vec.begin(), vec.end(), lessScan45Vertex()); } template @@ -453,12 +453,12 @@ namespace boost { namespace polygon{ public: typedef Scan45CountT Scan45Count; typedef std::pair Scan45Vertex; - + //index is the index into the vertex static inline Scan45Element getElement(const Scan45Vertex& vertex, int index) { return Scan45Element(vertex.first.x(), vertex.first.y(), index - 1, vertex.second[index]); } - + class lessScan45Point : public std::binary_function { public: inline lessScan45Point() {} //default constructor is only constructor @@ -466,7 +466,7 @@ namespace boost { namespace polygon{ return (v1.x() < v2.x()) || (v1.x() == v2.x() && v1.y() < v2.y()); } }; - + typedef std::vector Scan45Vector; //definitions @@ -474,7 +474,7 @@ namespace boost { namespace polygon{ typedef typename Scan45Data::iterator iterator; typedef typename Scan45Data::const_iterator const_iterator; typedef std::set CrossQueue; - + //data Scan45Data scanData_; CrossQueue crossQueue_; @@ -482,19 +482,19 @@ namespace boost { namespace polygon{ Unit x_; int justBefore_; public: - inline Scan45() : scanData_(), crossQueue_(), crossVector_(), + inline Scan45() : scanData_(), crossQueue_(), crossVector_(), x_((std::numeric_limits::min)()), justBefore_(false) { lessScan45Element lessElm(&x_, &justBefore_); scanData_ = std::set, lessScan45Element >(lessElm); } - inline Scan45(const Scan45& that) : scanData_(), crossQueue_(), crossVector_(), + inline Scan45(const Scan45& that) : scanData_(), crossQueue_(), crossVector_(), x_((std::numeric_limits::min)()), justBefore_(false) { (*this) = that; } inline Scan45& operator=(const Scan45& that) { x_ = that.x_; justBefore_ = that.justBefore_; - crossQueue_ = that.crossQueue_; - crossVector_ = that.crossVector_; + crossQueue_ = that.crossQueue_; + crossVector_ = that.crossVector_; lessScan45Element lessElm(&x_, &justBefore_); scanData_ = std::set, lessScan45Element >(lessElm); for(const_iterator itr = that.scanData_.begin(); itr != that.scanData_.end(); ++itr){ @@ -502,7 +502,7 @@ namespace boost { namespace polygon{ } return *this; } - + //cT is an output container of Vertex45 //iT is an iterator over Scan45Vertex elements template @@ -623,7 +623,7 @@ namespace boost { namespace polygon{ for(std::size_t i = 0; i < numEdges; ++i) { eraseVec.push_back(eraseItrs[i]); } - + //take the derivative wrt theta of the count at the crossing point vertex.second[2] = count[2] - countBelow; vertex.second[1] = count[1] - count[2]; @@ -650,7 +650,7 @@ namespace boost { namespace polygon{ findCross_(searchVec[i]); } } - + template inline iT mergeCross_(iT inputBegin, iT inputEnd) { Scan45Vector vec; @@ -677,7 +677,7 @@ namespace boost { namespace polygon{ } return inputBegin; } - + template inline iT processEvent_(cT& output, iT inputBegin, iT inputEnd) { //std::cout << "processEvent_\n"; @@ -695,12 +695,12 @@ namespace boost { namespace polygon{ prevIter->evalAtX(x_) < vertex.first.y())) { //std::cout << "faking null event\n"; vertex = Scan45Vertex(Point(x_, prevIter->evalAtX(x_)), Scan45Count()); - } else { - ++inputBegin; + } else { + ++inputBegin; //std::cout << "after increment\n"; //accumulate overlapping changes in Scan45Count while(inputBegin != inputEnd && - (*inputBegin).first.x() == x_ && + (*inputBegin).first.x() == x_ && (*inputBegin).first.y() == vertex.first.y()) { //std::cout << "accumulate\n"; vertex.second += (*inputBegin).second; @@ -715,7 +715,7 @@ namespace boost { namespace polygon{ } //std::cout << vertex.second << std::endl; //vertex represents the change in state at this point - + //get counts at current vertex CountType countBelow; iterator lowIter = lookUp_(vertex.first.y()); @@ -764,15 +764,15 @@ namespace boost { namespace polygon{ //std::cout << "ADD\n"; vertex.second += countAt; //std::cout << vertex.second << std::endl; - + //add elements to the scanline for(int i = 0; i < 3; ++i) { if(vertex.second[i] != countBelow) { //std::cout << "insert: " << vertex.first.x() << " " << vertex.first.y() << " " << i-1 << // " " << vertex.second[i][0] << " " << vertex.second[i][1] << std::endl; - iterator insertIter = scanData_.insert(scanData_.end(), - Scan45ElementT(vertex.first.x(), - vertex.first.y(), + iterator insertIter = scanData_.insert(scanData_.end(), + Scan45ElementT(vertex.first.x(), + vertex.first.y(), i - 1, vertex.second[i])); findCross_(insertIter); output_functor f; @@ -784,7 +784,7 @@ namespace boost { namespace polygon{ //std::cout << "end processEvent\n"; return inputBegin; } - + //iter1 is horizontal inline void scheduleCross0_(iterator iter1, iterator iter2) { //std::cout << "0, "; @@ -815,7 +815,7 @@ namespace boost { namespace polygon{ throw(msg); } else { //note that result of this subtraction is always positive because itr1 is above itr2 in scanline - LongUnit halfDelta2 = (LongUnit)((((LongUnit)y1) - y2)/2); + LongUnit halfDelta2 = (LongUnit)((((LongUnit)y1) - y2)/2); //note that halfDelta2 has been truncated if(halfDelta2 + x_ <= UnitMax && halfDelta2 + y2 <= UnitMax) { crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast(halfDelta2), y2+static_cast(halfDelta2))); @@ -823,13 +823,13 @@ namespace boost { namespace polygon{ } } } else { - LongUnit halfDelta = (LongUnit)((((LongUnit)y1) - y2)/2); + LongUnit halfDelta = (LongUnit)((((LongUnit)y1) - y2)/2); if(halfDelta + x_ <= UnitMax && halfDelta + y2 <= UnitMax) crossQueue_.insert(crossQueue_.end(), Point(x_+static_cast(halfDelta), y2+static_cast(halfDelta))); //std::cout << Point(x_+halfDelta, y2+halfDelta); } } - + inline void findCross_(iterator iter) { //std::cout << "find cross "; iterator iteratorBelow = iter; @@ -839,7 +839,7 @@ namespace boost { namespace polygon{ if(iter->rise == 0){ if(iteratorBelow->rise == 1) { scheduleCross0_(iter, iteratorBelow); - } + } } else { //iter->rise == -1 if(iteratorBelow->rise == 1) { @@ -863,10 +863,10 @@ namespace boost { namespace polygon{ scheduleCross0_(iteratorAbove, iter); } } - } - //std::cout << std::endl; - } - + } + //std::cout << std::endl; + } + inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Scan45ElementT(x_, y, -1+2*justBefore_)); @@ -874,7 +874,7 @@ namespace boost { namespace polygon{ }; //template - //static inline void print45Data(const std::set, + //static inline void print45Data(const std::set, // lessScan45Element >& data) { // typename std::set, lessScan45Element >::const_iterator iter; // for(iter = data.begin(); iter != data.end(); ++iter) { @@ -920,7 +920,7 @@ namespace boost { namespace polygon{ stdcout << "done testing Scan45Data\n"; return true; } - + template static inline bool testScan45Rect(stream_type& stdcout) { stdcout << "testing Scan45Rect\n"; @@ -1306,7 +1306,7 @@ namespace boost { namespace polygon{ return true; } - + template static inline bool testScan45Star4(stream_type& stdcout) { stdcout << "testing Scan45Star4\n"; diff --git a/include/boost/polygon/detail/iterator_compact_to_points.hpp b/include/boost/polygon/detail/iterator_compact_to_points.hpp index 9634e6f..bed03d3 100644 --- a/include/boost/polygon/detail/iterator_compact_to_points.hpp +++ b/include/boost/polygon/detail/iterator_compact_to_points.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -24,7 +24,7 @@ public: typedef const point_type& reference; //immutable inline iterator_compact_to_points() : iter_(), iter_end_(), pt_(), firstX_(), orient_() {} - inline iterator_compact_to_points(iterator_type iter, iterator_type iter_end) : + inline iterator_compact_to_points(iterator_type iter, iterator_type iter_end) : iter_(iter), iter_end_(iter_end), pt_(), firstX_(), orient_(HORIZONTAL) { if(iter_ != iter_end_) { firstX_ = *iter_; @@ -66,4 +66,3 @@ public: } } #endif - diff --git a/include/boost/polygon/detail/iterator_geometry_to_set.hpp b/include/boost/polygon/detail/iterator_geometry_to_set.hpp index 4f62873..95840e2 100644 --- a/include/boost/polygon/detail/iterator_geometry_to_set.hpp +++ b/include/boost/polygon/detail/iterator_geometry_to_set.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -28,8 +28,8 @@ private: bool is_hole_; public: iterator_geometry_to_set() : rectangle_(), vertex_(), corner_(4), orient_(), is_hole_() {} - iterator_geometry_to_set(const rectangle_type& rectangle, direction_1d dir, - orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + iterator_geometry_to_set(const rectangle_type& rectangle, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : rectangle_(), vertex_(), corner_(0), orient_(orient), is_hole_(is_hole) { assign(rectangle_, rectangle); if(dir == HIGH) corner_ = 4; @@ -67,7 +67,7 @@ public: vertex_.second.second = 1; if(is_hole_) vertex_.second.second *= -1; } - return vertex_; + return vertex_; } }; @@ -93,9 +93,9 @@ private: int polygon_index; public: iterator_geometry_to_set() : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) {} - iterator_geometry_to_set(const polygon_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool winding_override = false, direction_1d w = CLOCKWISE) : - vertex_(), itrb(), itre(), last_vertex_(), - is_hole_(is_hole), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), + iterator_geometry_to_set(const polygon_type& polygon, direction_1d dir, orientation_2d orient = HORIZONTAL, bool is_hole = false, bool winding_override = false, direction_1d w = CLOCKWISE) : + vertex_(), itrb(), itre(), last_vertex_(), + is_hole_(is_hole), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(orient), polygon_index(0) { itrb = begin_points(polygon); itre = end_points(polygon); @@ -116,7 +116,7 @@ public: evaluate_(); } } - iterator_geometry_to_set(const iterator_geometry_to_set& that) : + iterator_geometry_to_set(const iterator_geometry_to_set& that) : vertex_(), itrb(), itre(), last_vertex_(), is_hole_(), multiplier_(), first_pt(), second_pt(), pts(), use_wrap(), orient_(), polygon_index(-1) { vertex_ = that.vertex_; @@ -176,7 +176,7 @@ public: return !(*this == that); } inline reference operator*() const { - return vertex_; + return vertex_; } inline void evaluate_() { @@ -185,7 +185,7 @@ public: if(pts[1] == pts[2]) { vertex_.second.second = 0; } else if(pts[0].get(HORIZONTAL) != pts[1].get(HORIZONTAL)) { - vertex_.second.second = -1; + vertex_.second.second = -1; } else if(pts[0].get(VERTICAL) != pts[1].get(VERTICAL)) { vertex_.second.second = 1; } else { @@ -213,8 +213,8 @@ private: bool started_holes; public: iterator_geometry_to_set() : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() {} - iterator_geometry_to_set(const polygon_with_holes_type& polygon, direction_1d dir, - orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : + iterator_geometry_to_set(const polygon_with_holes_type& polygon, direction_1d dir, + orientation_2d orient = HORIZONTAL, bool is_hole = false, bool = false, direction_1d = CLOCKWISE) : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(orient), is_hole_(is_hole), started_holes() { itre = iterator_geometry_to_set(polygon, HIGH, orient, is_hole_); itrhe = end_holes(polygon); @@ -228,7 +228,7 @@ public: started_holes = false; } } - iterator_geometry_to_set(const iterator_geometry_to_set& that) : + iterator_geometry_to_set(const iterator_geometry_to_set& that) : itrb(), itre(), itrhib(), itrhie(), itrhb(), itrhe(), orient_(), is_hole_(), started_holes() { itrb = that.itrb; itre = that.itre; @@ -247,9 +247,9 @@ public: if(itrb == itre) { if(itrhib == itrhie) { if(itrhb != itrhe) { - itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); - itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { @@ -258,21 +258,21 @@ public: //both point to end of the previous hole processed //no need to explicitly reset them, and it causes an stl debug assertion to use //the default constructed iterator this way - //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } else { ++itrhib; if(itrhib == itrhie) { if(itrhb != itrhe) { - itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); - itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { //this is the same case as above - //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } @@ -281,9 +281,9 @@ public: ++itrb; if(itrb == itre) { if(itrhb != itrhe) { - itrhib = iterator_geometry_to_set::hole_type>(*itrhb, LOW, orient_, !is_hole_); - itrhie = iterator_geometry_to_set::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } @@ -312,4 +312,3 @@ public: } } #endif - diff --git a/include/boost/polygon/detail/max_cover.hpp b/include/boost/polygon/detail/max_cover.hpp index 343e29a..e61725c 100644 --- a/include/boost/polygon/detail/max_cover.hpp +++ b/include/boost/polygon/detail/max_cover.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -35,7 +35,7 @@ namespace boost { namespace polygon{ }; typedef std::pair, Node* > EdgeAssociation; - + class lessEdgeAssociation : public std::binary_function { public: inline lessEdgeAssociation() {} @@ -83,7 +83,7 @@ namespace boost { namespace polygon{ }; template - static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, Rectangle rect) { //std::cout << "New Root\n"; std::vector stack; @@ -170,7 +170,7 @@ namespace boost { namespace polygon{ Because the code is so much simpler than the loop algorithm I retain it for clarity template - static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, + static inline void getMaxCover(cT& outputContainer, Node* node, orientation_2d orient, const Rectangle& rect) { Interval rectIvl = rect.get(orient); Interval nodeIvl = node->rect.get(orient); @@ -205,7 +205,7 @@ namespace boost { namespace polygon{ template static inline void computeDag(iT beginNode, iT endNode, orientation_2d orient, std::size_t size) { - std::vector leadingEdges; + std::vector leadingEdges; leadingEdges.reserve(size); for(iT iter = beginNode; iter != endNode; ++iter) { Node* nodep = &(*iter); @@ -213,7 +213,7 @@ namespace boost { namespace polygon{ Interval rectIvl = nodep->rect.get(orient); leadingEdges.push_back(EdgeAssociation(std::pair(leading, rectIvl), nodep)); } - gtlsort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); + polygon_sort(leadingEdges.begin(), leadingEdges.end(), lessEdgeAssociation()); typename std::vector::iterator leadingBegin = leadingEdges.begin(); iT trailingBegin = beginNode; while(leadingBegin != leadingEdges.end()) { diff --git a/include/boost/polygon/detail/minkowski.hpp b/include/boost/polygon/detail/minkowski.hpp index 312d9a2..ce34947 100644 --- a/include/boost/polygon/detail/minkowski.hpp +++ b/include/boost/polygon/detail/minkowski.hpp @@ -1,4 +1,10 @@ +/* + Copyright 2008 Intel Corporation + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ namespace boost { namespace polygon { namespace detail { template @@ -62,11 +68,11 @@ struct minkowski_offset { a.get(a_polygons); b.get(b_polygons); for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { - convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), + convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), end_points(a_polygons[ai]), b_polygons); for(typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); itrh != end_holes(a_polygons[ai]); ++itrh) { - convolve_point_sequence_with_polygons(result, begin_points(*itrh), + convolve_point_sequence_with_polygons(result, begin_points(*itrh), end_points(*itrh), b_polygons); } for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { @@ -100,9 +106,9 @@ struct minkowski_offset { ::boost::polygon::bloat(rect, 10); (*this) = rect - (*this); //invert } - //make_arc(std::vector >& return_points, + //make_arc(std::vector >& return_points, //point_data< double> start, point_data< double> end, - //point_data< double> center, double r, unsigned int num_circle_segments) + //point_data< double> center, double r, unsigned int num_circle_segments) std::vector > circle; point_data center(0.0, 0.0), start(0.0, (double)resizing); make_arc(circle, start, start, center, std::abs((double)resizing), diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp index e814a15..8ad30f1 100644 --- a/include/boost/polygon/detail/polygon_45_formation.hpp +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -30,7 +30,7 @@ namespace boost { namespace polygon{ typedef std::pair Scan45Vertex; typedef typename boolean_op_45::template Scan45::template boolean_op_45_output_functor<0> > Scan45; - + class PolyLine45 { public: typedef typename std::list::const_iterator iterator; @@ -52,7 +52,7 @@ namespace boost { namespace polygon{ // copy constructor (since we have dynamic memory) inline PolyLine45(const PolyLine45& that) : points(that.points) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline PolyLine45& operator=(const PolyLine45& that) { points = that.points; @@ -68,31 +68,31 @@ namespace boost { namespace polygon{ inline std::size_t size() const { return points.size(); } //public data member - std::list points; + std::list points; }; class ActiveTail45 { private: //data - PolyLine45* tailp_; + PolyLine45* tailp_; ActiveTail45 *otherTailp_; std::list holesList_; bool head_; public: - + /** * @brief iterator over coordinates of the figure */ typedef typename PolyLine45::iterator iterator; - + /** * @brief iterator over holes contained within the figure */ typedef typename std::list::const_iterator iteratorHoles; - + //default constructor inline ActiveTail45() : tailp_(0), otherTailp_(0), holesList_(), head_(0) {} - + //constructor inline ActiveTail45(const Vertex45& vertex, ActiveTail45* otherTailp = 0) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { @@ -110,7 +110,7 @@ namespace boost { namespace polygon{ tailp_->points.push_back(point); head_ = head; otherTailp_ = otherTailp; - + } inline ActiveTail45(ActiveTail45* otherTailp) : tailp_(0), otherTailp_(0), holesList_(), head_(0) { @@ -155,7 +155,7 @@ namespace boost { namespace polygon{ * @brief get the pointer to the activetail at the other end of the chain */ inline ActiveTail45* getOtherActiveTail() const { return otherTailp_; } - + /** * @brief test if another active tail is the other end of the chain */ @@ -298,7 +298,7 @@ namespace boost { namespace polygon{ */ template - static inline ActiveTail45* joinChains(Point point, ActiveTail45* at1, ActiveTail45* at2, bool solid, + static inline ActiveTail45* joinChains(Point point, ActiveTail45* at1, ActiveTail45* at2, bool solid, cT& output) { if(at1->otherTailp_ == at2) { //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; @@ -370,7 +370,7 @@ namespace boost { namespace polygon{ // std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; // } - static inline std::pair createActiveTail45sAsPair(Point point, bool solid, + static inline std::pair createActiveTail45sAsPair(Point point, bool solid, ActiveTail45* phole, bool fractureHoles) { ActiveTail45* at1 = 0; ActiveTail45* at2 = 0; @@ -386,7 +386,7 @@ namespace boost { namespace polygon{ at2 = new ActiveTail45(at1); at1->otherTailp_ = at2; at2->head_ = !solid; - if(phole) + if(phole) at2->addHole(phole); //assert fractureHoles == false } return std::pair(at1, at2); @@ -398,64 +398,64 @@ namespace boost { namespace polygon{ class Vertex45CountT { public: typedef ct count_type; - inline Vertex45CountT() -#ifndef BOOST_POLYGON_MSVC - : counts() + inline Vertex45CountT() +#ifndef BOOST_POLYGON_MSVC + : counts() #endif { counts[0] = counts[1] = counts[2] = counts[3] = 0; } //inline Vertex45CountT(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; } - inline Vertex45CountT(const ct& count1, const ct& count2, const ct& count3, + inline Vertex45CountT(const ct& count1, const ct& count2, const ct& count3, const ct& count4) -#ifndef BOOST_POLYGON_MSVC - : counts() -#endif - { - counts[0] = count1; - counts[1] = count2; +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { + counts[0] = count1; + counts[1] = count2; counts[2] = count3; - counts[3] = count4; + counts[3] = count4; } inline Vertex45CountT(const Vertex45& vertex) -#ifndef BOOST_POLYGON_MSVC - : counts() -#endif - { +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { counts[0] = counts[1] = counts[2] = counts[3] = 0; (*this) += vertex; } inline Vertex45CountT(const Vertex45CountT& count) -#ifndef BOOST_POLYGON_MSVC - : counts() -#endif - { +#ifndef BOOST_POLYGON_MSVC + : counts() +#endif + { (*this) = count; } - inline bool operator==(const Vertex45CountT& count) const { + inline bool operator==(const Vertex45CountT& count) const { for(unsigned int i = 0; i < 4; ++i) { - if(counts[i] != count.counts[i]) return false; + if(counts[i] != count.counts[i]) return false; } return true; } inline bool operator!=(const Vertex45CountT& count) const { return !((*this) == count); } - inline Vertex45CountT& operator=(ct count) { + inline Vertex45CountT& operator=(ct count) { counts[0] = counts[1] = counts[2] = counts[3] = count; return *this; } inline Vertex45CountT& operator=(const Vertex45CountT& count) { for(unsigned int i = 0; i < 4; ++i) { - counts[i] = count.counts[i]; + counts[i] = count.counts[i]; } - return *this; + return *this; } inline ct& operator[](int index) { return counts[index]; } inline ct operator[](int index) const {return counts[index]; } inline Vertex45CountT& operator+=(const Vertex45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { - counts[i] += count.counts[i]; + counts[i] += count.counts[i]; } return *this; } inline Vertex45CountT& operator-=(const Vertex45CountT& count){ for(unsigned int i = 0; i < 4; ++i) { - counts[i] -= count.counts[i]; + counts[i] -= count.counts[i]; } return *this; } @@ -501,7 +501,7 @@ namespace boost { namespace polygon{ count[vertex.rise+1] = vertex.count; } inline Vertex45CompactT(const Vertex45CompactT& vertex) : pt(vertex.pt), count(vertex.count) {} - inline Vertex45CompactT& operator=(const Vertex45CompactT& vertex){ + inline Vertex45CompactT& operator=(const Vertex45CompactT& vertex){ pt = vertex.pt; count = vertex.count; return *this; } inline bool operator==(const Vertex45CompactT& vertex) const { return pt == vertex.pt && count == vertex.count; } @@ -536,12 +536,12 @@ namespace boost { namespace polygon{ typedef std::map Polygon45FormationData; typedef typename Polygon45FormationData::iterator iterator; typedef typename Polygon45FormationData::const_iterator const_iterator; - + //data Polygon45FormationData scanData_; Unit x_; int justBefore_; - int fractureHoles_; + int fractureHoles_; public: inline Polygon45Formation() : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { lessVertex45 lessElm(&x_, &justBefore_); @@ -564,7 +564,7 @@ namespace boost { namespace polygon{ } return *this; } - + //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over Vertex45 elements //inputBegin - inputEnd is a range of sorted iT that represents @@ -585,8 +585,8 @@ namespace boost { namespace polygon{ private: //functions template - inline std::pair processPoint_(cT& output, cT2& elements, Point point, - Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + inline std::pair processPoint_(cT& output, cT2& elements, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { //std::cout << point << std::endl; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; @@ -609,7 +609,7 @@ namespace boost { namespace polygon{ if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << std::endl; //if a figure is closed it will be written out by this function to output - ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; @@ -632,7 +632,7 @@ namespace boost { namespace polygon{ if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << std::endl; //std::cout << "creating active tail pair\n"; - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); @@ -740,7 +740,7 @@ namespace boost { namespace polygon{ } break; } - } + } //find beginning of a hole for(int i = 0; i < 3; ++i) { if(incoming[i] != 0) { @@ -750,7 +750,7 @@ namespace boost { namespace polygon{ //we are beginning a empty space ActiveTail45* holep = 0; if(counts[3] == 0) holep = tails[3]; - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, false, holep, fractureHoles_ != 0); if(j == 3) { returnValue = tailPair.first; @@ -839,7 +839,7 @@ namespace boost { namespace polygon{ //we got a hole out of the point we just processed //iter is still at the next y element above the current y value in the tree //std::cout << "checking whether ot handle hole\n"; - if(currentIter == inputEnd || + if(currentIter == inputEnd || currentIter->pt.x() != x_ || currentIter->pt.y() >= iter->first.evalAtX(x_)) { //std::cout << "handle hole here\n"; @@ -882,12 +882,12 @@ namespace boost { namespace polygon{ //std::cout << "end processEvent\n"; return currentIter; } - + inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); } - + }; template @@ -904,7 +904,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -928,14 +928,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } //polygon45set class @@ -952,15 +952,15 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 1, 1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); - data.push_back(Vertex45(Point(20, 10), 0, 1)); - gtlsort(data.begin(), data.end()); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } //polygon45set class @@ -1018,14 +1018,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } template @@ -1050,15 +1050,15 @@ namespace boost { namespace polygon{ sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); - - gtlsort(result.begin(), result.end()); + + polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } template @@ -1123,14 +1123,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } template @@ -1195,14 +1195,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } template @@ -1211,7 +1211,7 @@ namespace boost { namespace polygon{ Polygon45Formation pf(false); std::vector polys; std::vector data; - + data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 100), 2, -1)); @@ -1239,14 +1239,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon formation\n"; - return true; + return true; } @@ -1256,7 +1256,7 @@ namespace boost { namespace polygon{ typedef std::map Polygon45FormationData; typedef typename Polygon45FormationData::iterator iterator; typedef typename Polygon45FormationData::const_iterator const_iterator; - + //data Polygon45FormationData scanData_; Unit x_; @@ -1266,7 +1266,7 @@ namespace boost { namespace polygon{ lessVertex45 lessElm(&x_, &justBefore_); scanData_ = Polygon45FormationData(lessElm); } - inline Polygon45Tiling(const Polygon45Tiling& that) : + inline Polygon45Tiling(const Polygon45Tiling& that) : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false) { (*this) = that; } inline Polygon45Tiling& operator=(const Polygon45Tiling& that) { x_ = that.x_; @@ -1278,7 +1278,7 @@ namespace boost { namespace polygon{ } return *this; } - + //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over Vertex45 elements //inputBegin - inputEnd is a range of sorted iT that represents @@ -1298,13 +1298,13 @@ namespace boost { namespace polygon{ private: //functions - - inline void getVerticalPair_(std::pair& verticalPair, + + inline void getVerticalPair_(std::pair& verticalPair, iterator previter) { ActiveTail45* iterTail = (*previter).second; Point prevPoint(x_, previter->first.evalAtX(x_)); iterTail->pushPoint(prevPoint); - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(prevPoint, true, 0, false); verticalPair.first = iterTail; verticalPair.second = tailPair.first; @@ -1312,10 +1312,10 @@ namespace boost { namespace polygon{ } template - inline std::pair processPoint_(cT& output, cT2& elements, - std::pair& verticalPair, - iterator previter, Point point, - Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { + inline std::pair processPoint_(cT& output, cT2& elements, + std::pair& verticalPair, + iterator previter, Point point, + Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { //std::cout << point << std::endl; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; @@ -1341,7 +1341,7 @@ namespace boost { namespace polygon{ if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << std::endl; //if a figure is closed it will be written out by this function to output - ActiveTail45::joinChains(point, tails[i], tails[j], true, output); + ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; @@ -1364,7 +1364,7 @@ namespace boost { namespace polygon{ if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << std::endl; //std::cout << "creating active tail pair\n"; - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); //tailPair.first->print(); //tailPair.second->print(); @@ -1412,10 +1412,10 @@ namespace boost { namespace polygon{ returnCount = -1; } else { verticalPairOut.first = tails[i]; - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); verticalPairOut.second = tailPair.first; - elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.second)); } tails[i] = 0; @@ -1452,16 +1452,16 @@ namespace boost { namespace polygon{ if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } - ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); returnValue = verticalPair.second; returnCount = 1; } else { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } - ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); + ActiveTail45::joinChains(point, tails[i], verticalPair.first, true, output); verticalPair.second->pushPoint(point); - elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), + elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), verticalPair.second)); } tails[i] = 0; @@ -1493,7 +1493,7 @@ namespace boost { namespace polygon{ if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } - ActiveTail45::joinChains(point, tails[j], verticalPair.first, true, output); + ActiveTail45::joinChains(point, tails[j], verticalPair.first, true, output); verticalPairOut.second = verticalPair.second; } tails[i] = 0; @@ -1505,7 +1505,7 @@ namespace boost { namespace polygon{ } break; } - } + } //find beginning of a hole for(int i = 0; i < 3; ++i) { if(incoming[i] != 0) { @@ -1521,7 +1521,7 @@ namespace boost { namespace polygon{ returnValue = verticalPair.first; returnCount = -1; } else { - std::pair tailPair = + std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.second)); @@ -1646,12 +1646,12 @@ namespace boost { namespace polygon{ //std::cout << "end processEvent\n"; return currentIter; } - + inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 return scanData_.lower_bound(Vertex45(Point(x_, y), -1+2*justBefore_, 0)); } - + }; template @@ -1668,7 +1668,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 0), 2, -1)); data.push_back(Vertex45(Point(10, 10), 2, 1)); data.push_back(Vertex45(Point(10, 10), 0, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1692,14 +1692,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 2, -1)); data.push_back(Vertex45(Point(10, 20), 2, 1)); data.push_back(Vertex45(Point(10, 20), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -1715,15 +1715,15 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 1, 1)); data.push_back(Vertex45(Point(10, 10), 0, -1)); data.push_back(Vertex45(Point(20, 10), 1, -1)); - data.push_back(Vertex45(Point(20, 10), 0, 1)); - gtlsort(data.begin(), data.end()); + data.push_back(Vertex45(Point(20, 10), 0, 1)); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -1742,14 +1742,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, 1)); data.push_back(Vertex45(Point(20, 20), 1, 1)); data.push_back(Vertex45(Point(20, 20), 2, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -1768,14 +1768,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, 10), 0, 1)); data.push_back(Vertex45(Point(20, -10), -1, -1)); data.push_back(Vertex45(Point(20, -10), 2, -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -1800,8 +1800,8 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(2, 2), 1, -1)); data.push_back(Vertex45(Point(2, 2), 0, 1)); data.push_back(Vertex45(Point(3, 2), 1, 1)); - data.push_back(Vertex45(Point(3, 2), 0, -1)); - gtlsort(data.begin(), data.end()); + data.push_back(Vertex45(Point(3, 2), 0, -1)); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1835,7 +1835,7 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(2, 2), 2, -1)); data.push_back(Vertex45(Point(2, 2), 0, -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1899,14 +1899,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), 1, -1)); // result == 12 8 -1 1 data.push_back(Vertex45(Point(12, 8), -1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -1932,15 +1932,15 @@ namespace boost { namespace polygon{ sortScan45Vector(vertices); stdcout << "scanning\n"; scan45.scan(result, vertices.begin(), vertices.end()); - - gtlsort(result.begin(), result.end()); + + polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -2005,14 +2005,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(8, 6), -1, -1)); data.push_back(Vertex45(Point(8, 6), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -2077,14 +2077,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 8), -1, -1)); data.push_back(Vertex45(Point(10, 8), 1, 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } template @@ -2093,7 +2093,7 @@ namespace boost { namespace polygon{ Polygon45Tiling pf; std::vector polys; std::vector data; - + data.push_back(Vertex45(Point(0, 0), 0, 1)); data.push_back(Vertex45(Point(0, 0), 2, 1)); data.push_back(Vertex45(Point(0, 100), 2, -1)); @@ -2121,14 +2121,14 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 22), 2, -1)); data.push_back(Vertex45(Point(10, 22), 0, -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { stdcout << polys[i] << std::endl; } stdcout << "done testing polygon tiling\n"; - return true; + return true; } }; @@ -2137,7 +2137,7 @@ namespace boost { namespace polygon{ public: typedef typename polygon_45_formation::ActiveTail45 ActiveTail45; typedef typename ActiveTail45::iterator iterator; - + typedef polygon_45_concept geometry_type; typedef Unit coordinate_type; typedef point_data Point; @@ -2145,7 +2145,7 @@ namespace boost { namespace polygon{ // typedef iterator_points_to_compact compact_iterator_type; typedef iterator iterator_type; typedef typename coordinate_traits::area_type area_type; - + inline PolyLine45HoleData() : p_(0) {} inline PolyLine45HoleData(ActiveTail45* p) : p_(p) {} //use default copy and assign @@ -2166,7 +2166,7 @@ namespace boost { namespace polygon{ typedef typename polygon_45_formation::ActiveTail45 ActiveTail45; typedef typename ActiveTail45::iterator iterator; typedef PolyLine45HoleData holeType; - + typedef polygon_45_with_holes_concept geometry_type; typedef Unit coordinate_type; typedef point_data Point; @@ -2187,7 +2187,7 @@ namespace boost { namespace polygon{ typedef const value_type& reference; //immutable inline iteratorHoles() : itr_() {} inline iteratorHoles(typename ActiveTail45::iteratorHoles itr) : itr_(itr) {} - inline iteratorHoles(const iteratorHoles& that) : itr_(that.itr_) {} + inline iteratorHoles(const iteratorHoles& that) : itr_(that.itr_) {} inline iteratorHoles& operator=(const iteratorHoles& that) { itr_ = that.itr_; return *this; @@ -2208,8 +2208,8 @@ namespace boost { namespace polygon{ } }; typedef iteratorHoles iterator_holes_type; - - + + inline PolyLine45PolygonData() : p_(0) {} inline PolyLine45PolygonData(ActiveTail45* p) : p_(p) {} //use default copy and assign @@ -2225,7 +2225,7 @@ namespace boost { namespace polygon{ inline PolyLine45PolygonData& set(iT inputBegin, iT inputEnd) { return *this; } - + // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template diff --git a/include/boost/polygon/detail/polygon_45_set_view.hpp b/include/boost/polygon/detail/polygon_45_set_view.hpp index 3442386..caf4c62 100644 --- a/include/boost/polygon/detail/polygon_45_set_view.hpp +++ b/include/boost/polygon/detail/polygon_45_set_view.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -18,11 +18,11 @@ namespace boost { namespace polygon{ typedef typename polygon_45_set_view::iterator_type iterator_type; typedef typename polygon_45_set_view::operator_arg_type operator_arg_type; - static inline iterator_type begin(const polygon_45_set_view& polygon_45_set); + static inline iterator_type begin(const polygon_45_set_view& polygon_45_set); static inline iterator_type end(const polygon_45_set_view& polygon_45_set); template - static inline void set(polygon_45_set_view& polygon_45_set, + static inline void set(polygon_45_set_view& polygon_45_set, input_iterator_type input_begin, input_iterator_type input_end); static inline bool clean(const polygon_45_set_view& polygon_45_set); @@ -114,12 +114,12 @@ namespace boost { namespace polygon{ bool sorted() const { return value().sorted(); } //result of a boolean is sorted // template - // void set(input_iterator_type input_begin, input_iterator_type input_end, + // void set(input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) const { // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); - // gtlsort(output_.begin(), output_.end()); + // polygon_sort(output_.begin(), output_.end()); // } }; @@ -137,7 +137,7 @@ namespace boost { namespace polygon{ } template bool polygon_45_set_traits >:: - clean(const polygon_45_set_view& polygon_45_set) { + clean(const polygon_45_set_view& polygon_45_set) { return polygon_45_set.value().clean(); } template @@ -194,32 +194,32 @@ namespace boost { namespace polygon{ typename is_polygon_45_or_90_set_type::type, typename is_polygon_45_or_90_set_type::type, typename is_either_polygon_45_set_type::type>::type, - polygon_45_set_view >::type + polygon_45_set_view >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); } - + struct y_ps45_p : gtl_yes {}; template typename enable_if< typename gtl_and_4< y_ps45_p, - typename gtl_if::type>::type, - typename gtl_if::type>::type, - typename gtl_if::type>::type>::type, - polygon_45_set_view >::type + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_45_set_view >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); } - + struct y_ps45_s : gtl_yes {}; template typename enable_if< typename gtl_and_4< y_ps45_s, typename is_polygon_45_or_90_set_type::type, typename is_polygon_45_or_90_set_type::type, typename is_either_polygon_45_set_type::type>::type, - polygon_45_set_view >::type + polygon_45_set_view >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); @@ -231,7 +231,7 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and_4< y_ps45_a, typename is_polygon_45_or_90_set_type::type, typename is_polygon_45_or_90_set_type::type, typename is_either_polygon_45_set_type::type>::type, - polygon_45_set_view >::type + polygon_45_set_view >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); @@ -243,30 +243,30 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and_4< y_ps45_x, typename is_polygon_45_or_90_set_type::type, typename is_polygon_45_or_90_set_type::type, typename is_either_polygon_45_set_type::type>::type, - polygon_45_set_view >::type + polygon_45_set_view >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); } - + struct y_ps45_m : gtl_yes {}; template typename enable_if< typename gtl_and_4< y_ps45_m, - typename gtl_if::type>::type, - typename gtl_if::type>::type, - typename gtl_if::type>::type>::type, - polygon_45_set_view >::type + typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type>::type, + polygon_45_set_view >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_45_set_view (lvalue, rvalue); } - + struct y_ps45_pe : gtl_yes {}; template typename enable_if< typename gtl_and_4::type, gtl_yes, - typename is_polygon_45_or_90_set_type::type>::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -275,8 +275,8 @@ namespace boost { namespace polygon{ struct y_ps45_be : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_45_or_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -286,8 +286,8 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3< y_ps45_se, - typename is_mutable_polygon_45_set_type::type, - typename is_polygon_45_or_90_set_type::type>::type, + typename is_mutable_polygon_45_set_type::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -296,8 +296,8 @@ namespace boost { namespace polygon{ struct y_ps45_ae : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_45_or_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -306,9 +306,9 @@ namespace boost { namespace polygon{ struct y_ps45_xe : gtl_yes {}; template - typename enable_if< - typename gtl_and_3::type, - typename is_polygon_45_or_90_set_type::type>::type, + typename enable_if< + typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -317,8 +317,8 @@ namespace boost { namespace polygon{ struct y_ps45_me : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_45_or_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_45_or_90_set_type::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op_45(lvalue, rvalue); @@ -327,8 +327,8 @@ namespace boost { namespace polygon{ struct y_ps45_rpe : gtl_yes {}; template - typename enable_if< typename gtl_and_3< y_ps45_rpe, typename is_mutable_polygon_45_set_type::type, - typename gtl_same_type::type, + typename enable_if< typename gtl_and_3< y_ps45_rpe, typename is_mutable_polygon_45_set_type::type, + typename gtl_same_type::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -338,8 +338,8 @@ namespace boost { namespace polygon{ struct y_ps45_rme : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, - typename gtl_same_type::type, + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -349,8 +349,8 @@ namespace boost { namespace polygon{ struct y_ps45_rp : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, - typename gtl_same_type::type, + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -362,8 +362,8 @@ namespace boost { namespace polygon{ struct y_ps45_rm : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, - typename gtl_same_type::type, + typename enable_if< typename gtl_and_3::type>::type, + typename gtl_same_type::type, coordinate_concept>::type> ::type, geometry_type_1>::type operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -375,4 +375,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/detail/polygon_45_touch.hpp b/include/boost/polygon/detail/polygon_45_touch.hpp index e50912a..5da606b 100644 --- a/include/boost/polygon/detail/polygon_45_touch.hpp +++ b/include/boost/polygon/detail/polygon_45_touch.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -32,7 +32,7 @@ namespace boost { namespace polygon{ } else { int count = mp[i].second; if(subtract) count -= mp2[j].second; - else count += mp2[j].second; + else count += mp2[j].second; if(count) { newmp.push_back(mp[i]); newmp.back().second = count; @@ -63,7 +63,7 @@ namespace boost { namespace polygon{ inline bool operator!=(const CountTouch& count) const { return !((*this) == count); } //inline CountTouch& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } - inline int& operator[](int index) { + inline int& operator[](int index) { std::vector >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; @@ -102,8 +102,8 @@ namespace boost { namespace polygon{ std::vector > counts; }; - typedef std::pair > >, std::map > > map_graph_o; - typedef std::pair > >, std::vector > > vector_graph_o; + typedef std::pair > >, std::map > > map_graph_o; + typedef std::pair > >, std::vector > > vector_graph_o; template static void process_previous_x(cT& output) { @@ -124,10 +124,10 @@ namespace boost { namespace polygon{ } y_prop_map.clear(); } - + struct touch_45_output_functor { template - void operator()(cT& output, const CountTouch& count1, const CountTouch& count2, + void operator()(cT& output, const CountTouch& count1, const CountTouch& count2, const Point& pt, int , direction_1d ) { Unit& x = output.first.first; std::map >& y_prop_map = output.first.second; @@ -138,7 +138,7 @@ namespace boost { namespace polygon{ itr1 != count1.counts.end(); ++itr1) { if(itr1->second > 0) { output_set.insert(output_set.end(), itr1->first); - } + } } for(std::vector >::const_iterator itr2 = count2.counts.begin(); itr2 != count2.counts.end(); ++itr2) { @@ -148,16 +148,16 @@ namespace boost { namespace polygon{ } } }; - typedef typename std::pair::template Scan45CountT > Vertex45Compact; typedef std::vector TouchSetData; - + struct lessVertex45Compact { bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { return l.first < r.first; } }; - + // template // static void print_tsd(TSD& tsd) { // for(std::size_t i = 0; i < tsd.size(); ++i) { @@ -185,8 +185,8 @@ namespace boost { namespace polygon{ template static void performTouch(graph_type& graph, TouchSetData& tsd) { - - gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); + + polygon_sort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector::template Scan45CountT > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); @@ -227,10 +227,10 @@ namespace boost { namespace polygon{ } } } - + }; } } -#endif +#endif diff --git a/include/boost/polygon/detail/polygon_90_set_view.hpp b/include/boost/polygon/detail/polygon_90_set_view.hpp index 53beec8..f6ee36c 100644 --- a/include/boost/polygon/detail/polygon_90_set_view.hpp +++ b/include/boost/polygon/detail/polygon_90_set_view.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -23,7 +23,7 @@ namespace boost { namespace polygon{ typedef typename polygon_90_set_view::iterator_type iterator_type; typedef typename polygon_90_set_view::operator_arg_type operator_arg_type; - static inline iterator_type begin(const polygon_90_set_view& polygon_set); + static inline iterator_type begin(const polygon_90_set_view& polygon_set); static inline iterator_type end(const polygon_90_set_view& polygon_set); static inline orientation_2d orient(const polygon_90_set_view& polygon_set); @@ -46,7 +46,7 @@ namespace boost { namespace polygon{ insert_into_view_arg(linput_, lvalue_, orient_l); insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); } }; @@ -65,23 +65,23 @@ namespace boost { namespace polygon{ lvalue_.sort(); rvalue_.sort(); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), - rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); }else if((orient_ != orient_l) && (orient_!= orient_r)){ // both the orientations are not equal to input // easier way is to ignore the input orientation and use the input data's orientation, but not done so insert_into_view_arg(linput_, lvalue_, orient_l); insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); }else if(orient_ != orient_l){ // left hand side orientation is different insert_into_view_arg(linput_, lvalue_, orient_l); rvalue_.sort(); output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); } else if(orient_ != orient_r){ // right hand side orientation is different insert_into_view_arg(rinput_, rvalue_, orient_r); lvalue_.sort(); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); } } }; @@ -98,7 +98,7 @@ namespace boost { namespace polygon{ // << "," << orient_.to_int() << std::endl; insert_into_view_arg(rinput_, rvalue_, orient_r); output_.applyBooleanBinaryOp(lvalue_.begin(), lvalue_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); } }; @@ -115,7 +115,7 @@ namespace boost { namespace polygon{ // << "," << orient_.to_int() << std::endl; output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); + rvalue_.begin(), rvalue_.end(), boolean_op::BinaryCount()); } }; @@ -159,12 +159,12 @@ namespace boost { namespace polygon{ bool sorted() const { return true; } //result of a boolean is sorted // template -// void set(input_iterator_type input_begin, input_iterator_type input_end, +// void set(input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) const { // orient_ = orient; // output_.clear(); // output_.insert(output_.end(), input_begin, input_end); -// gtlsort(output_.begin(), output_.end()); +// polygon_sort(output_.begin(), output_.end()); // } void sort() const {} //is always sorted }; @@ -189,22 +189,22 @@ namespace boost { namespace polygon{ // template // template // void polygon_90_set_traits >:: -// set(polygon_90_set_view& polygon_set, +// set(polygon_90_set_view& polygon_set, // input_iterator_type input_begin, input_iterator_type input_end, // orientation_2d orient) { // polygon_set.set(input_begin, input_end, orient); // } template orientation_2d polygon_90_set_traits >:: - orient(const polygon_90_set_view& polygon_set) { + orient(const polygon_90_set_view& polygon_set) { return polygon_set.orient(); } template bool polygon_90_set_traits >:: - clean(const polygon_90_set_view& polygon_set) { + clean(const polygon_90_set_view& polygon_set) { return true; } template bool polygon_90_set_traits >:: - sorted(const polygon_90_set_view& polygon_set) { + sorted(const polygon_90_set_view& polygon_set) { return true; } template @@ -216,7 +216,7 @@ namespace boost { namespace polygon{ dest.insert(itr1, itr2, orient); dest.sort(); } - + template template inline polygon_90_set_data& polygon_90_set_data::operator=(const polygon_90_set_view& that) { @@ -225,22 +225,22 @@ namespace boost { namespace polygon{ unsorted_ = false; return *this; } - + template template inline polygon_90_set_data::polygon_90_set_data(const polygon_90_set_view& that) : orient_(that.orient()), data_(that.begin(), that.end()), dirty_(false), unsorted_(false) {} - + template struct self_assign_operator_lvalue { typedef geometry_type_1& type; }; - + template struct by_value_binary_operator { typedef type_1 type; }; - + template geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; @@ -257,7 +257,7 @@ namespace boost { namespace polygon{ // to be same as linput value_type rinput_(orient_); //BM: The output dataset's scanline orient is set as equal to first input dataset's (lvalue_) orientation - value_type output_(orient_); + value_type output_(orient_); insert_into_view_arg(linput_, lvalue_, orient_); // BM: The last argument orient_r is the user initialized scanline orientation for rvalue_ data set. // But since rinput (see above) is initialized to scanline orientation consistent with the lvalue_ @@ -265,11 +265,11 @@ namespace boost { namespace polygon{ insert_into_view_arg(rinput_, rvalue_, orient_r); // BM: boolean operation and output uses lvalue_ dataset's scanline orientation. output_.applyBooleanBinaryOp(linput_.begin(), linput_.end(), - rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); + rinput_.begin(), rinput_.end(), boolean_op::BinaryCount()); polygon_90_set_mutable_traits::set(lvalue_, output_.begin(), output_.end(), orient_); return lvalue_; } - + namespace operators { struct y_ps90_b : gtl_yes {}; @@ -279,27 +279,27 @@ namespace boost { namespace polygon{ typename is_polygon_90_set_type::type>::type, polygon_90_set_view >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryOr()); } - + struct y_ps90_p : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3< y_ps90_p, typename gtl_if::type>::type, typename gtl_if::type>::type>::type, polygon_90_set_view >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryOr()); } - + struct y_ps90_s : gtl_yes {}; template @@ -308,12 +308,12 @@ namespace boost { namespace polygon{ typename is_polygon_90_set_type::type>::type, polygon_90_set_view >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryAnd()); } - + struct y_ps90_a : gtl_yes {}; template @@ -322,8 +322,8 @@ namespace boost { namespace polygon{ typename is_polygon_90_set_type::type>::type, polygon_90_set_view >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryAnd()); } @@ -336,12 +336,12 @@ namespace boost { namespace polygon{ typename is_polygon_90_set_type::type>::type, polygon_90_set_view >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryXor()); } - + struct y_ps90_m : gtl_yes {}; template @@ -350,12 +350,12 @@ namespace boost { namespace polygon{ typename gtl_if::type>::type>::type, polygon_90_set_view >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { - return polygon_90_set_view - (lvalue, rvalue, + return polygon_90_set_view + (lvalue, rvalue, polygon_90_set_traits::orient(lvalue), boolean_op::BinaryNot()); } - + struct y_ps90_pe : gtl_yes {}; template @@ -366,11 +366,11 @@ namespace boost { namespace polygon{ polygon_90_set_traits::orient(rvalue)); return lvalue; } - + struct y_ps90_be : gtl_yes {}; // template - typename enable_if< typename gtl_and< y_ps90_be, typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and< y_ps90_be, typename is_polygon_90_set_type::type>::type, polygon_90_set_data >::type & operator|=(polygon_90_set_data& lvalue, const geometry_type_2& rvalue) { return lvalue += rvalue; @@ -380,8 +380,8 @@ namespace boost { namespace polygon{ //normal self assignment boolean operations template - typename enable_if< typename gtl_and_3< y_ps90_pe2, typename is_mutable_polygon_90_set_type::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3< y_ps90_pe2, typename is_mutable_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -390,8 +390,8 @@ namespace boost { namespace polygon{ struct y_ps90_be2 : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -400,18 +400,18 @@ namespace boost { namespace polygon{ struct y_ps90_se : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); } - + struct y_ps90_ae : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -420,8 +420,8 @@ namespace boost { namespace polygon{ struct y_ps90_xe : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -430,8 +430,8 @@ namespace boost { namespace polygon{ struct y_ps90_me : gtl_yes {}; template - typename enable_if< typename gtl_and_3< y_ps90_me, typename is_mutable_polygon_90_set_type::type, - typename is_polygon_90_set_type::type>::type, + typename enable_if< typename gtl_and_3< y_ps90_me, typename is_mutable_polygon_90_set_type::type, + typename is_polygon_90_set_type::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -441,7 +441,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type, + typename is_mutable_polygon_90_set_type::type, typename gtl_same_type::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -452,7 +452,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type, + typename is_mutable_polygon_90_set_type::type, typename gtl_same_type::type, coordinate_concept>::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -463,7 +463,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, + typename gtl_if::type>::type, typename gtl_if::type, coordinate_concept>::type>::type>::type, geometry_type_1>::type operator+(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -476,7 +476,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, + typename gtl_if::type>::type, typename gtl_if::type, coordinate_concept>::type>::type>::type, geometry_type_1>::type operator-(const geometry_type_1& lvalue, coordinate_type_1 rvalue) { @@ -488,4 +488,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/detail/polygon_90_touch.hpp b/include/boost/polygon/detail/polygon_90_touch.hpp index 7671602..77a516b 100644 --- a/include/boost/polygon/detail/polygon_90_touch.hpp +++ b/include/boost/polygon/detail/polygon_90_touch.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -30,7 +30,7 @@ namespace boost { namespace polygon{ bool incremented_; public: inline iterator() : itr_(), ivlIds_(), incremented_(false) {} - inline iterator(typename EventData::const_iterator itr, + inline iterator(typename EventData::const_iterator itr, Unit prevPos, Unit curPos, const std::set& ivlIds) : itr_(itr), ivlIds_(), incremented_(false) { ivlIds_.second = ivlIds; ivlIds_.first = Interval(prevPos, curPos); @@ -61,7 +61,7 @@ namespace boost { namespace polygon{ } else { ivlIds_.second.insert(*itr); } - } + } //std::cout << std::endl; //std::cout << "new state\n"; //for(std::set::iterator itr = ivlIds_.second.begin(); itr != ivlIds_.second.end(); ++itr) { @@ -77,7 +77,7 @@ namespace boost { namespace polygon{ ++(*this); return tmpItr; } - inline std::pair >& operator*() { + inline std::pair >& operator*() { if(incremented_) ivlIds_.first = Interval(ivlIds_.first.get(HIGH), itr_->first); incremented_ = false; if(ivlIds_.second.empty())(++(*this)); @@ -98,13 +98,13 @@ namespace boost { namespace polygon{ eventData_ = that.eventData_; return *this; } - + //Insert an interval polygon id into the EventData inline void insert(const std::pair& intervalId){ insert(intervalId.first.low(), intervalId.second); insert(intervalId.first.high(), intervalId.second); } - + //Insert an position and polygon id into EventData inline void insert(Unit pos, int id) { typename EventData::iterator lb = eventData_.lower_bound(pos); @@ -121,7 +121,7 @@ namespace boost { namespace polygon{ (*lb).second.insert(id); } } - + //merge this scan event with that by inserting its data inline void insert(const TouchScanEvent& that){ typename EventData::const_iterator itr; @@ -129,9 +129,9 @@ namespace boost { namespace polygon{ eventData_[(*itr).first].insert(itr->second.begin(), itr->second.end()); } } - + //Get the begin iterator over event data - inline iterator begin() const { + inline iterator begin() const { //std::cout << "begin\n"; if(eventData_.empty()) return end(); typename EventData::const_iterator itr = eventData_.begin(); @@ -140,18 +140,18 @@ namespace boost { namespace polygon{ ++itr; return iterator(itr, pos, itr->first, idr); } - + //Get the end iterator over event data inline iterator end() const { return iterator(eventData_.end(), 0, 0, std::set()); } - + inline void clear() { eventData_.clear(); } - - inline Interval extents() const { + + inline Interval extents() const { if(eventData_.empty()) return Interval(); return Interval((*(eventData_.begin())).first, (*(eventData_.rbegin())).first); } }; - + //declaration of a map of scan events by coordinate value used to store all the //polygon data for a single layer input into the scanline algorithm typedef std::pair, std::map > TouchSetData; @@ -166,8 +166,8 @@ namespace boost { namespace polygon{ public: inline TouchOp () : scanData_(), nextItr_() { nextItr_ = scanData_.end(); } inline TouchOp (const TouchOp& that) : scanData_(that.scanData_), nextItr_() { nextItr_ = scanData_.begin(); } - inline TouchOp& operator=(const TouchOp& that); - + inline TouchOp& operator=(const TouchOp& that); + //moves scanline forward inline void advanceScan() { nextItr_ = scanData_.begin(); } @@ -252,7 +252,7 @@ namespace boost { namespace polygon{ //std::cout << "case7" << std::endl; scanData_.erase(lowItr); } - } + } //merge the top interval with the one above if they have the same count if(highItr != scanData_.begin()) { //std::cout << "case8" << std::endl; @@ -279,7 +279,7 @@ namespace boost { namespace polygon{ // std::cout << std::endl; // } // } - + private: inline typename ScanData::iterator lookup_(Unit pos){ if(nextItr_ != scanData_.end() && nextItr_->first >= pos) { @@ -294,7 +294,7 @@ namespace boost { namespace polygon{ } template - inline void evaluateInterval_(graphT& outputContainer, std::set& ids, + inline void evaluateInterval_(graphT& outputContainer, std::set& ids, const std::set& changingIds, bool leadingEdge) { for(std::set::const_iterator ciditr = changingIds.begin(); ciditr != changingIds.end(); ++ciditr){ //std::cout << "evaluateInterval " << (*ciditr) << std::endl; diff --git a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp index 5adabb8..8c45617 100644 --- a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp +++ b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -40,7 +40,7 @@ namespace boost { namespace polygon{ return lp(pt, pt2) && lp(pt1, pt); return lp(pt, pt1) && lp(pt2, pt); } - + template static inline Unit compute_intercept(const area_type& dy2, const area_type& dx1, @@ -96,7 +96,7 @@ namespace boost { namespace polygon{ dy2 *= -1; dx2 *= -1; } else if(dx2 == 0) { - //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal return dx1 != 0; } typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; @@ -173,9 +173,9 @@ namespace boost { namespace polygon{ return false; } - static inline Unit evalAtXforYlazy(Unit xIn, Point pt, Point other_pt) { + static inline Unit evalAtXforYlazy(Unit xIn, Point pt, Point other_pt) { long double - evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y @@ -190,16 +190,16 @@ namespace boost { namespace polygon{ if(evalAtXforYdx1 == evalAtXforY0) return (Unit)evalAtXforYy1; evalAtXforYx2 = other_pt.get(HORIZONTAL); evalAtXforYy2 = other_pt.get(VERTICAL); - + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); return (Unit)evalAtXforYret; } - static inline typename high_precision_type::type evalAtXforY(Unit xIn, Point pt, Point other_pt) { + static inline typename high_precision_type::type evalAtXforY(Unit xIn, Point pt, Point other_pt) { typename high_precision_type::type - evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y @@ -215,18 +215,18 @@ namespace boost { namespace polygon{ if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); - + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); return evalAtXforYret; } - + struct evalAtXforYPack { typename high_precision_type::type - evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, + evalAtXforYret, evalAtXforYxIn, evalAtXforYx1, evalAtXforYy1, evalAtXforYdx1, evalAtXforYdx, evalAtXforYdy, evalAtXforYx2, evalAtXforYy2, evalAtXforY0; - inline const typename high_precision_type::type& evalAtXforY(Unit xIn, Point pt, Point other_pt) { + inline const typename high_precision_type::type& evalAtXforY(Unit xIn, Point pt, Point other_pt) { //y = (x - x1)dy/dx + y1 //y = (xIn - pt.x)*(other_pt.y-pt.y)/(other_pt.x-pt.x) + pt.y //assert pt.x != other_pt.x @@ -243,7 +243,7 @@ namespace boost { namespace polygon{ if(evalAtXforYdx1 == evalAtXforY0) return evalAtXforYret = evalAtXforYy1; evalAtXforYx2 = (high_precision)other_pt.get(HORIZONTAL); evalAtXforYy2 = (high_precision)other_pt.get(VERTICAL); - + evalAtXforYdx = evalAtXforYx2 - evalAtXforYx1; evalAtXforYdy = evalAtXforYy2 - evalAtXforYy1; evalAtXforYret = ((evalAtXforYdx1) * evalAtXforYdy / evalAtXforYdx + evalAtXforYy1); @@ -254,7 +254,7 @@ namespace boost { namespace polygon{ static inline bool is_vertical(const half_edge& he) { return he.first.get(HORIZONTAL) == he.second.get(HORIZONTAL); } - + static inline bool is_horizontal(const half_edge& he) { return he.first.get(VERTICAL) == he.second.get(VERTICAL); } @@ -274,10 +274,10 @@ namespace boost { namespace polygon{ inline less_half_edge(Unit *x, int *justBefore, evalAtXforYPack * packIn) : x_(x), justBefore_(justBefore), pack_(packIn) {} inline less_half_edge(const less_half_edge& that) : x_(that.x_), justBefore_(that.justBefore_), pack_(that.pack_){} - inline less_half_edge& operator=(const less_half_edge& that) { - x_ = that.x_; - justBefore_ = that.justBefore_; - pack_ = that.pack_; + inline less_half_edge& operator=(const less_half_edge& that) { + x_ = that.x_; + justBefore_ = that.justBefore_; + pack_ = that.pack_; return *this; } inline bool operator () (const half_edge& elm1, const half_edge& elm2) const { if((std::max)(elm1.first.y(), elm1.second.y()) < (std::min)(elm2.first.y(), elm2.second.y())) @@ -346,8 +346,8 @@ namespace boost { namespace polygon{ template static inline void unsigned_add(unsigned_product_type& result, int& result_sign, unsigned_product_type a, int a_sign, unsigned_product_type b, int b_sign) { int switcher = 0; - if(a_sign < 0) switcher += 1; - if(b_sign < 0) switcher += 2; + if(a_sign < 0) switcher += 1; + if(b_sign < 0) switcher += 2; if(a < b) switcher += 4; switch (switcher) { case 0: //both positive @@ -388,7 +388,7 @@ namespace boost { namespace polygon{ struct compute_intersection_pack { typedef typename high_precision_type::type high_precision; high_precision y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; - static inline bool compute_lazy_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + static inline bool compute_lazy_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { long double y_high, dx1, dy1, dx2, dy2, x11, x21, y11, y21, x_num, y_num, x_den, y_den, x, y; typedef rectangle_data Rectangle; @@ -419,13 +419,13 @@ namespace boost { namespace polygon{ } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point - dy2 = (he2.second.get(VERTICAL)) - + dy2 = (he2.second.get(VERTICAL)) - (he2.first.get(VERTICAL)); - dy1 = (he1.second.get(VERTICAL)) - + dy1 = (he1.second.get(VERTICAL)) - (he1.first.get(VERTICAL)); - dx2 = (he2.second.get(HORIZONTAL)) - + dx2 = (he2.second.get(HORIZONTAL)) - (he2.first.get(HORIZONTAL)); - dx1 = (he1.second.get(HORIZONTAL)) - + dx1 = (he1.second.get(HORIZONTAL)) - (he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes @@ -436,7 +436,7 @@ namespace boost { namespace polygon{ y21 = (he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); - x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); x_den = (dy1 * dx2 - dy2 * dx1); y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); y_den = (dx1 * dy2 - dx2 * dy1); @@ -468,9 +468,9 @@ namespace boost { namespace polygon{ if(!projected && !contains(rect1, result, true)) return false; if(!projected && !contains(rect2, result, true)) return false; if(projected) { - rectangle_data inf_rect(-(long double)(std::numeric_limits::max)(), - -(long double) (std::numeric_limits::max)(), - (long double)(std::numeric_limits::max)(), + rectangle_data inf_rect(-(long double)(std::numeric_limits::max)(), + -(long double) (std::numeric_limits::max)(), + (long double)(std::numeric_limits::max)(), (long double) (std::numeric_limits::max)() ); if(contains(inf_rect, point_data(x, y), true)) { intersection = result; @@ -482,11 +482,11 @@ namespace boost { namespace polygon{ return true; } - inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) return false; - bool lazy_success = compute_lazy_intersection(intersection, he1, he2, projected); + bool lazy_success = compute_lazy_intersection(intersection, he1, he2, projected); if(!projected) { if(lazy_success) { if(intersects_grid(intersection, he1) && @@ -499,7 +499,7 @@ namespace boost { namespace polygon{ return compute_exact_intersection(intersection, he1, he2, projected, round_closest); } - inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) return false; @@ -531,13 +531,13 @@ namespace boost { namespace polygon{ } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point - dy2 = (high_precision)(he2.second.get(VERTICAL)) - + dy2 = (high_precision)(he2.second.get(VERTICAL)) - (high_precision)(he2.first.get(VERTICAL)); - dy1 = (high_precision)(he1.second.get(VERTICAL)) - + dy1 = (high_precision)(he1.second.get(VERTICAL)) - (high_precision)(he1.first.get(VERTICAL)); - dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - (high_precision)(he2.first.get(HORIZONTAL)); - dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - (high_precision)(he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes @@ -548,13 +548,13 @@ namespace boost { namespace polygon{ y21 = (high_precision)(he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); - x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); x_den = (dy1 * dx2 - dy2 * dx1); y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; - //std::cout << x << " " << y << std::endl; + //std::cout << x << " " << y << std::endl; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); @@ -621,13 +621,13 @@ namespace boost { namespace polygon{ } } //the bounding boxes of the two line segments intersect, so we check closer to find the intersection point - high_precision dy2 = (high_precision)(he2.second.get(VERTICAL)) - + high_precision dy2 = (high_precision)(he2.second.get(VERTICAL)) - (high_precision)(he2.first.get(VERTICAL)); - high_precision dy1 = (high_precision)(he1.second.get(VERTICAL)) - + high_precision dy1 = (high_precision)(he1.second.get(VERTICAL)) - (high_precision)(he1.first.get(VERTICAL)); - high_precision dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - + high_precision dx2 = (high_precision)(he2.second.get(HORIZONTAL)) - (high_precision)(he2.first.get(HORIZONTAL)); - high_precision dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - + high_precision dx1 = (high_precision)(he1.second.get(HORIZONTAL)) - (high_precision)(he1.first.get(HORIZONTAL)); if(equal_slope_hp(dx1, dy1, dx2, dy2)) return false; //the line segments have different slopes @@ -638,7 +638,7 @@ namespace boost { namespace polygon{ high_precision y21 = (high_precision)(he2.first.get(VERTICAL)); //Unit exp_x = ((at)x11 * (at)dy1 * (at)dx2 - (at)x21 * (at)dy2 * (at)dx1 + (at)y21 * (at)dx1 * (at)dx2 - (at)y11 * (at)dx1 * (at)dx2) / ((at)dy1 * (at)dx2 - (at)dy2 * (at)dx1); //Unit exp_y = ((at)y11 * (at)dx1 * (at)dy2 - (at)y21 * (at)dx2 * (at)dy1 + (at)x21 * (at)dy1 * (at)dy2 - (at)x11 * (at)dy1 * (at)dy2) / ((at)dx1 * (at)dy2 - (at)dx2 * (at)dy1); - high_precision x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); + high_precision x_num = (x11 * dy1 * dx2 - x21 * dy2 * dx1 + y21 * dx1 * dx2 - y11 * dx1 * dx2); high_precision x_den = (dy1 * dx2 - dy2 * dx1); high_precision y_num = (y11 * dx1 * dy2 - y21 * dx2 * dy1 + x21 * dy1 * dy2 - x11 * dy1 * dy2); high_precision y_den = (dx1 * dy2 - dx2 * dy1); @@ -708,14 +708,14 @@ namespace boost { namespace polygon{ } } int oab1 = on_above_or_below(he1.first, he2); - if(oab1 == 0 && between(he1.first, he2.first, he2.second)) return true; + if(oab1 == 0 && between(he1.first, he2.first, he2.second)) return true; int oab2 = on_above_or_below(he1.second, he2); - if(oab2 == 0 && between(he1.second, he2.first, he2.second)) return true; + if(oab2 == 0 && between(he1.second, he2.first, he2.second)) return true; if(oab1 == oab2 && oab1 != 0) return false; //both points of he1 are on same side of he2 int oab3 = on_above_or_below(he2.first, he1); - if(oab3 == 0 && between(he2.first, he1.first, he1.second)) return true; + if(oab3 == 0 && between(he2.first, he1.first, he1.second)) return true; int oab4 = on_above_or_below(he2.second, he1); - if(oab4 == 0 && between(he2.second, he1.first, he1.second)) return true; + if(oab4 == 0 && between(he2.second, he1.first, he1.second)) return true; if(oab3 == oab4) return false; //both points of he2 are on same side of he1 return true; //they must cross } @@ -737,7 +737,7 @@ namespace boost { namespace polygon{ inline vertex_half_edge() : pt(), other_pt(), count() {} inline vertex_half_edge(const Point& point, const Point& other_point, int countIn) : pt(point), other_pt(other_point), count(countIn) {} inline vertex_half_edge(const vertex_half_edge& vertex) : pt(vertex.pt), other_pt(vertex.other_pt), count(vertex.count) {} - inline vertex_half_edge& operator=(const vertex_half_edge& vertex){ + inline vertex_half_edge& operator=(const vertex_half_edge& vertex){ pt = vertex.pt; other_pt = vertex.other_pt; count = vertex.count; return *this; } inline vertex_half_edge(const std::pair& vertex) : pt(), other_pt(), count() {} inline vertex_half_edge& operator=(const std::pair& vertex){ return *this; } @@ -846,7 +846,7 @@ namespace boost { namespace polygon{ typedef typename scanline_base::half_edge half_edge; typedef typename scanline_base::vertex_half_edge vertex_half_edge; typedef typename scanline_base::less_vertex_half_edge less_vertex_half_edge; - + class poly_line_arbitrary { public: typedef typename std::list::const_iterator iterator; @@ -868,7 +868,7 @@ namespace boost { namespace polygon{ // copy constructor (since we have dynamic memory) inline poly_line_arbitrary(const poly_line_arbitrary& that) : points(that.points) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline poly_line_arbitrary& operator=(const poly_line_arbitrary& that) { points = that.points; @@ -884,31 +884,31 @@ namespace boost { namespace polygon{ inline std::size_t size() const { return points.size(); } //public data member - std::list points; + std::list points; }; class active_tail_arbitrary { protected: //data - poly_line_arbitrary* tailp_; + poly_line_arbitrary* tailp_; active_tail_arbitrary *otherTailp_; std::list holesList_; bool head_; public: - + /** * @brief iterator over coordinates of the figure */ typedef typename poly_line_arbitrary::iterator iterator; - + /** * @brief iterator over holes contained within the figure */ typedef typename std::list::const_iterator iteratorHoles; - + //default constructor inline active_tail_arbitrary() : tailp_(), otherTailp_(), holesList_(), head_() {} - + //constructor inline active_tail_arbitrary(const vertex_half_edge& vertex, active_tail_arbitrary* otherTailp = 0) : tailp_(), otherTailp_(), holesList_(), head_() { tailp_ = new poly_line_arbitrary; @@ -925,7 +925,7 @@ namespace boost { namespace polygon{ tailp_->points.push_back(point); head_ = head; otherTailp_ = otherTailp; - + } inline active_tail_arbitrary(active_tail_arbitrary* otherTailp) : tailp_(), otherTailp_(), holesList_(), head_() { @@ -970,7 +970,7 @@ namespace boost { namespace polygon{ * @brief get the pointer to the activetail at the other end of the chain */ inline active_tail_arbitrary* getOtherActiveTail() const { return otherTailp_; } - + /** * @brief test if another active tail is the other end of the chain */ @@ -1107,7 +1107,7 @@ namespace boost { namespace polygon{ * returns a handle to a hole if one is closed */ template - static inline active_tail_arbitrary* joinChains(Point point, active_tail_arbitrary* at1, active_tail_arbitrary* at2, bool solid, + static inline active_tail_arbitrary* joinChains(Point point, active_tail_arbitrary* at1, active_tail_arbitrary* at2, bool solid, cT& output) { if(at1->otherTailp_ == at2) { //if(at2->otherTailp_ != at1) std::cout << "half closed error\n"; @@ -1179,7 +1179,7 @@ namespace boost { namespace polygon{ //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; } - static inline std::pair createActiveTailsAsPair(Point point, bool solid, + static inline std::pair createActiveTailsAsPair(Point point, bool solid, active_tail_arbitrary* phole, bool fractureHoles) { active_tail_arbitrary* at1 = 0; active_tail_arbitrary* at2 = 0; @@ -1195,7 +1195,7 @@ namespace boost { namespace polygon{ at2 = new active_tail_arbitrary(at1); at1->otherTailp_ = at2; at2->head_ = !solid; - if(phole) + if(phole) at2->addHole(phole); //assert fractureHoles == false } return std::pair(at1, at2); @@ -1219,19 +1219,19 @@ namespace boost { namespace polygon{ static inline void sort_vertex_arbitrary_count(vertex_arbitrary_count& count, const Point& pt) { less_half_edge_count lfec(pt); - gtlsort(count.begin(), count.end(), lfec); + polygon_sort(count.begin(), count.end(), lfec); } typedef std::vector, int>, active_tail_arbitrary*> > incoming_count; - class less_incoming_count : public std::binary_function, int>, active_tail_arbitrary*>, + class less_incoming_count : public std::binary_function, int>, active_tail_arbitrary*>, std::pair, int>, active_tail_arbitrary*>, bool> { private: Point pt_; public: inline less_incoming_count() : pt_() {} inline less_incoming_count(Point point) : pt_(point) {} - inline bool operator () (const std::pair, int>, active_tail_arbitrary*>& elm1, + inline bool operator () (const std::pair, int>, active_tail_arbitrary*>& elm1, const std::pair, int>, active_tail_arbitrary*>& elm2) const { Unit dx1 = elm1.first.first.first.get(HORIZONTAL) - elm1.first.first.second.get(HORIZONTAL); Unit dx2 = elm2.first.first.first.get(HORIZONTAL) - elm2.first.first.second.get(HORIZONTAL); @@ -1243,7 +1243,7 @@ namespace boost { namespace polygon{ static inline void sort_incoming_count(incoming_count& count, const Point& pt) { less_incoming_count lfec(pt); - gtlsort(count.begin(), count.end(), lfec); + polygon_sort(count.begin(), count.end(), lfec); } static inline void compact_vertex_arbitrary_count(const Point& pt, vertex_arbitrary_count &count) { @@ -1282,7 +1282,7 @@ namespace boost { namespace polygon{ count.push_back(std::pair(vertex.other_pt, vertex.count)); } inline vertex_arbitrary_compact(const vertex_arbitrary_compact& vertex) : pt(vertex.pt), count(vertex.count) {} - inline vertex_arbitrary_compact& operator=(const vertex_arbitrary_compact& vertex){ + inline vertex_arbitrary_compact& operator=(const vertex_arbitrary_compact& vertex){ pt = vertex.pt; count = vertex.count; return *this; } //inline vertex_arbitrary_compact(const std::pair& vertex) {} inline vertex_arbitrary_compact& operator=(const std::pair& vertex){ return *this; } @@ -1315,24 +1315,24 @@ namespace boost { namespace polygon{ typedef std::map scanline_data; typedef typename scanline_data::iterator iterator; typedef typename scanline_data::const_iterator const_iterator; - + //data scanline_data scanData_; Unit x_; int justBefore_; - int fractureHoles_; + int fractureHoles_; public: - inline polygon_arbitrary_formation() : + inline polygon_arbitrary_formation() : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { less_vertex_half_edge lessElm(&x_, &justBefore_); scanData_ = scanline_data(lessElm); } - inline polygon_arbitrary_formation(bool fractureHoles) : + inline polygon_arbitrary_formation(bool fractureHoles) : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(fractureHoles) { less_vertex_half_edge lessElm(&x_, &justBefore_); scanData_ = scanline_data(lessElm); } - inline polygon_arbitrary_formation(const polygon_arbitrary_formation& that) : + inline polygon_arbitrary_formation(const polygon_arbitrary_formation& that) : scanData_(), x_((std::numeric_limits::min)()), justBefore_(false), fractureHoles_(0) { (*this) = that; } inline polygon_arbitrary_formation& operator=(const polygon_arbitrary_formation& that) { x_ = that.x_; @@ -1345,7 +1345,7 @@ namespace boost { namespace polygon{ } return *this; } - + //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over vertex_half_edge elements //inputBegin - inputEnd is a range of sorted iT that represents @@ -1367,8 +1367,8 @@ namespace boost { namespace polygon{ protected: //functions template - inline std::pair, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, - incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { + inline std::pair, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, + incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { //std::cout << "\nAT POINT: " << point << std::endl; //join any closing solid corners std::vector counts; @@ -1387,7 +1387,7 @@ namespace boost { namespace polygon{ incoming.back() = 0; } } - + active_tail_arbitrary* returnValue = 0; std::pair returnCount(Point(0, 0), 0); int i_size_less_1 = (int)(incoming.size()) -1; @@ -1421,7 +1421,7 @@ namespace boost { namespace polygon{ if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << std::endl; //if a figure is closed it will be written out by this function to output - active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; @@ -1447,7 +1447,7 @@ namespace boost { namespace polygon{ if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << std::endl; //std::cout << "creating active tail pair\n"; - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); @@ -1459,13 +1459,13 @@ namespace boost { namespace polygon{ } else { //std::cout << "new element " << j-1 << " " << -1 << std::endl; //std::cout << point << " " << incoming_count[j].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << std::endl; //std::cout << point << " " << incoming_count[i].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); incoming[i] = 0; @@ -1501,8 +1501,8 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = -1; } else { - elements.push_back(std::pair(vertex_half_edge(point, + elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); } tails[i] = 0; @@ -1575,7 +1575,7 @@ namespace boost { namespace polygon{ } break; } - } + } } //find beginning of a hole { @@ -1586,14 +1586,14 @@ namespace boost { namespace polygon{ //std::cout << "case6: " << i << " " << j << std::endl; //we are beginning a empty space active_tail_arbitrary* holep = 0; - //if(c_size && counts[c_size_less_1] == 0 && - // counts_from_scanline[c_size_less_1].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) + //if(c_size && counts[c_size_less_1] == 0 && + // counts_from_scanline[c_size_less_1].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) if(have_vertical_tail_from_below) { holep = tails[c_size_less_1]; tails[c_size_less_1] = 0; have_vertical_tail_from_below = false; } - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, false, holep, fractureHoles_ != 0); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //std::cout << "vertical element " << point << std::endl; @@ -1604,13 +1604,13 @@ namespace boost { namespace polygon{ } else { //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; //std::cout << point << " " << incoming_count[j].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.first)); } //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; //std::cout << point << " " << incoming_count[i].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, incoming[i]), tailPair.second)); incoming[i] = 0; @@ -1682,7 +1682,7 @@ namespace boost { namespace polygon{ elementIters.push_back(iter); counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> (std::pair, int>(std::pair(iter->first.pt, - iter->first.other_pt), + iter->first.other_pt), iter->first.count), iter->second)); ++iter; @@ -1722,8 +1722,8 @@ namespace boost { namespace polygon{ //std::cout << "adding vertical tail to counts from scanline\n"; //std::cout << -verticalCount.second << std::endl; counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> - (std::pair, int>(std::pair(verticalCount.first, - currentPoint), + (std::pair, int>(std::pair(verticalCount.first, + currentPoint), -verticalCount.second), verticalTail)); } @@ -1743,7 +1743,7 @@ namespace boost { namespace polygon{ //we got a hole out of the point we just processed //iter is still at the next y element above the current y value in the tree //std::cout << "checking whether ot handle hole\n"; - if(currentIter == inputEnd || + if(currentIter == inputEnd || currentIter->pt.get(HORIZONTAL) != x_ || scanline_base::on_above_or_below(currentIter->pt, half_edge(iter->first.pt, iter->first.other_pt)) != -1) { //(high_precision)(currentIter->pt.get(VERTICAL)) >= iter->first.evalAtX(x_)) { @@ -1791,15 +1791,15 @@ namespace boost { namespace polygon{ //std::cout << "end processEvent\n"; return currentIter; } - + inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 //std::cout << "just before " << justBefore_ << std::endl; return scanData_.lower_bound(vertex_half_edge(Point(x_, y), Point(x_, y+1), 0)); } - + public: //test functions - + template static inline bool testPolygonArbitraryFormationRect(stream_type& stdcout) { stdcout << "testing polygon formation\n"; @@ -1814,7 +1814,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1838,7 +1838,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1862,7 +1862,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1908,7 +1908,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1943,19 +1943,19 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); - + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); - + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); - + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); - - gtlsort(data.begin(), data.end()); + + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -1985,17 +1985,17 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(5, 10), Point(4, 1), -1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); - + data.push_back(vertex_half_edge(Point(4, 1), Point(5, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); - + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); - + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); - - gtlsort(data.begin(), data.end()); + + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2025,17 +2025,17 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(6, 10), Point(4, 1), -1)); data.push_back(vertex_half_edge(Point(6, 10), Point(0, 10), 1)); - + data.push_back(vertex_half_edge(Point(4, 1), Point(6, 10), 1)); data.push_back(vertex_half_edge(Point(4, 1), Point(7, 2), -1)); - + data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); - + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(4, 1), 1)); - - gtlsort(data.begin(), data.end()); + + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2063,7 +2063,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(-1, 4), Point(0, 2), -1)); data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2120,7 +2120,7 @@ namespace boost { namespace polygon{ return b; } - + }; template @@ -2134,7 +2134,7 @@ namespace boost { namespace polygon{ typedef Unit coordinate_type; typedef typename active_tail_arbitrary::iterator iterator_type; //typedef iterator_points_to_compact compact_iterator_type; - + typedef iterator_type iterator; inline poly_line_arbitrary_hole_data() : p_(0) {} inline poly_line_arbitrary_hole_data(active_tail_arbitrary* p) : p_(p) {} @@ -2174,7 +2174,7 @@ namespace boost { namespace polygon{ typedef poly_line_arbitrary_hole_data holeType; mutable holeType hole_; typename active_tail_arbitrary::iteratorHoles itr_; - + public: typedef std::forward_iterator_tag iterator_category; typedef holeType value_type; @@ -2183,7 +2183,7 @@ namespace boost { namespace polygon{ typedef const holeType& reference; //immutable inline iterator_holes_type() : hole_(), itr_() {} inline iterator_holes_type(typename active_tail_arbitrary::iteratorHoles itr) : hole_(), itr_(itr) {} - inline iterator_holes_type(const iterator_holes_type& that) : hole_(that.hole_), itr_(that.itr_) {} + inline iterator_holes_type(const iterator_holes_type& that) : hole_(that.hole_), itr_(that.itr_) {} inline iterator_holes_type& operator=(const iterator_holes_type& that) { itr_ = that.itr_; return *this; @@ -2241,7 +2241,7 @@ namespace boost { namespace polygon{ typedef typename scanline_base::half_edge half_edge; typedef typename scanline_base::vertex_half_edge vertex_half_edge; typedef typename scanline_base::less_vertex_half_edge less_vertex_half_edge; - + typedef typename polygon_arbitrary_formation::poly_line_arbitrary poly_line_arbitrary; typedef typename polygon_arbitrary_formation::active_tail_arbitrary active_tail_arbitrary; @@ -2261,7 +2261,7 @@ namespace boost { namespace polygon{ typedef std::map scanline_data; typedef typename scanline_data::iterator iterator; typedef typename scanline_data::const_iterator const_iterator; - + //data public: inline trapezoid_arbitrary_formation() : polygon_arbitrary_formation() {} @@ -2270,7 +2270,7 @@ namespace boost { namespace polygon{ * static_cast*>(this) = * static_cast*>(&that); return *this; } - + //cT is an output container of Polygon45 or Polygon45WithHoles //iT is an iterator over vertex_half_edge elements //inputBegin - inputEnd is a range of sorted iT that represents @@ -2291,14 +2291,14 @@ namespace boost { namespace polygon{ private: //functions - inline void getVerticalPair_(std::pair& verticalPair, + inline void getVerticalPair_(std::pair& verticalPair, iterator previter) { active_tail_arbitrary* iterTail = (*previter).second; - Point prevPoint(polygon_arbitrary_formation::x_, + Point prevPoint(polygon_arbitrary_formation::x_, convert_high_precision_type(previter->first.evalAtX(polygon_arbitrary_formation::x_))); iterTail->pushPoint(prevPoint); - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(prevPoint, true, 0, false); verticalPair.first = iterTail; verticalPair.second = tailPair.first; @@ -2306,11 +2306,11 @@ namespace boost { namespace polygon{ } template - inline std::pair, active_tail_arbitrary*> - processPoint_(cT& output, cT2& elements, + inline std::pair, active_tail_arbitrary*> + processPoint_(cT& output, cT2& elements, std::pair& verticalPair, - iterator previter, Point point, incoming_count& counts_from_scanline, - vertex_arbitrary_count& incoming_count) { + iterator previter, Point point, incoming_count& counts_from_scanline, + vertex_arbitrary_count& incoming_count) { //std::cout << "\nAT POINT: " << point << std::endl; //join any closing solid corners std::vector counts; @@ -2329,7 +2329,7 @@ namespace boost { namespace polygon{ incoming.back() = 0; } } - + active_tail_arbitrary* returnValue = 0; std::pair verticalPairOut; verticalPairOut.first = 0; @@ -2366,7 +2366,7 @@ namespace boost { namespace polygon{ if(counts[j] == 1) { //std::cout << "case1: " << i << " " << j << std::endl; //if a figure is closed it will be written out by this function to output - active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); + active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; counts[j] = 0; tails[i] = 0; @@ -2392,7 +2392,7 @@ namespace boost { namespace polygon{ if(incoming[j] == -1) { //std::cout << "case2: " << i << " " << j << std::endl; //std::cout << "creating active tail pair\n"; - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, polygon_arbitrary_formation::fractureHoles_ != 0); //tailPair.first->print(); //tailPair.second->print(); @@ -2404,13 +2404,13 @@ namespace boost { namespace polygon{ } else { //std::cout << "new element " << j-1 << " " << -1 << std::endl; //std::cout << point << " " << incoming_count[j].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } //std::cout << "new element " << i-1 << " " << 1 << std::endl; //std::cout << point << " " << incoming_count[i].first << std::endl; - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); incoming[i] = 0; @@ -2446,12 +2446,12 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = -1; } else { - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, false); verticalPairOut.first = tails[i]; verticalPairOut.second = tailPair.first; - elements.push_back(std::pair(vertex_half_edge(point, + elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.second)); } tails[i] = 0; @@ -2478,13 +2478,13 @@ namespace boost { namespace polygon{ if(incoming[j] == -1) { //std::cout << "case4: " << i << " " << j << std::endl; //pass through solid on bottom - + //if count from scanline is vertical - if(i == c_size_less_1 && - counts_from_scanline[i].first.first.first.get(HORIZONTAL) == + if(i == c_size_less_1 && + counts_from_scanline[i].first.first.first.get(HORIZONTAL) == point.get(HORIZONTAL)) { //if incoming count is vertical - if(j == i_size_less_1 && + if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { returnValue = tails[i]; returnCount.first = point; @@ -2495,13 +2495,13 @@ namespace boost { namespace polygon{ active_tail_arbitrary*>(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); } - } else if(j == i_size_less_1 && - incoming_count[j].first.get(HORIZONTAL) == + } else if(j == i_size_less_1 && + incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } - active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); returnValue = verticalPair.second; returnCount.first = point; returnCount.second = 1; @@ -2510,7 +2510,7 @@ namespace boost { namespace polygon{ if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); } - active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); + active_tail_arbitrary::joinChains(point, tails[i], verticalPair.first, true, output); verticalPair.second->pushPoint(point); elements.push_back(std::pair(vertex_half_edge(point, @@ -2541,8 +2541,8 @@ namespace boost { namespace polygon{ tails[i]->pushPoint(point); verticalPairOut.first = tails[i]; if(j == c_size_less_1 && - counts_from_scanline[j].first.first.first.get(HORIZONTAL) == - point.get(HORIZONTAL)) { + counts_from_scanline[j].first.first.first.get(HORIZONTAL) == + point.get(HORIZONTAL)) { verticalPairOut.second = tails[j]; } else { //need to close a trapezoid below @@ -2561,7 +2561,7 @@ namespace boost { namespace polygon{ } break; } - } + } } //find beginning of a hole { @@ -2581,15 +2581,15 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = -1; } else { - std::pair tailPair = + std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, false, 0, false); - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.second)); verticalPairOut.second = tailPair.first; verticalPairOut.first = verticalPair.first; } - elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, incoming[i]), verticalPair.second)); incoming[i] = 0; @@ -2668,7 +2668,7 @@ namespace boost { namespace polygon{ elementIters.push_back(iter); counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> (std::pair, int>(std::pair(iter->first.pt, - iter->first.other_pt), + iter->first.other_pt), iter->first.count), iter->second)); ++iter; @@ -2708,8 +2708,8 @@ namespace boost { namespace polygon{ //std::cout << "adding vertical tail to counts from scanline\n"; //std::cout << -verticalCount.second << std::endl; counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> - (std::pair, int>(std::pair(verticalCount.first, - currentPoint), + (std::pair, int>(std::pair(verticalCount.first, + currentPoint), -verticalCount.second), verticalTail)); } @@ -2769,7 +2769,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 0), Point(10, 10), -1)); data.push_back(vertex_half_edge(Point(10, 10), Point(10, 0), 1)); data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2792,7 +2792,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(10, 20), -1)); data.push_back(vertex_half_edge(Point(10, 20), Point(10, 10), 1)); data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2815,7 +2815,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, -4), Point(2, 4), -1)); data.push_back(vertex_half_edge(Point(2, 4), Point(-2, 2), 1)); data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2860,7 +2860,7 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 22), Point(10, 12), -1)); data.push_back(vertex_half_edge(Point(10, 22), Point(2, 22), -1)); - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2895,19 +2895,19 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(5, 10), Point(5, 5), 1)); data.push_back(vertex_half_edge(Point(5, 10), Point(0, 10), 1)); - + data.push_back(vertex_half_edge(Point(5, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(5, 2), Point(7, 2), -1)); - + data.push_back(vertex_half_edge(Point(5, 5), Point(5, 10), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(5, 2), 1)); data.push_back(vertex_half_edge(Point(5, 5), Point(10, 5), -1)); data.push_back(vertex_half_edge(Point(5, 5), Point(7, 2), 1)); - + data.push_back(vertex_half_edge(Point(7, 2), Point(5, 5), -1)); data.push_back(vertex_half_edge(Point(7, 2), Point(5, 2), 1)); - - gtlsort(data.begin(), data.end()); + + polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); stdcout << "result size: " << polys.size() << std::endl; for(std::size_t i = 0; i < polys.size(); ++i) { @@ -2917,7 +2917,7 @@ namespace boost { namespace polygon{ return true; } }; - + template struct PolyLineArbitraryByConcept { typedef poly_line_arbitrary_polygon_data type; }; template diff --git a/include/boost/polygon/detail/polygon_formation.hpp b/include/boost/polygon/detail/polygon_formation.hpp index 0129962..a9490ce 100644 --- a/include/boost/polygon/detail/polygon_formation.hpp +++ b/include/boost/polygon/detail/polygon_formation.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -25,24 +25,24 @@ namespace polygon_formation { * TAIL End is represented by true because TAIL comes after head and 1 after 0 */ const End TAIL = true; - + /* * 2D turning direction, left and right sides (is a boolean value since it has two states.) */ typedef bool Side; - + /* * LEFT Side is 0 because we inuitively think left to right; left < right */ const Side LEFT = false; - + /* * RIGHT Side is 1 so that right > left */ const Side RIGHT = true; /* - * The PolyLine class is data storage and services for building and representing partial polygons. + * The PolyLine class is data storage and services for building and representing partial polygons. * As the polyline is added to it extends its storage to accomodate the data. * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are * part of the same polygon. @@ -59,20 +59,20 @@ namespace polygon_formation { class PolyLine { private: //data - + /* * ptdata_ a vector of coordiantes * if VERTICAL_HEAD, first coordiante is an X * else first coordinate is a Y */ std::vector ptdata_; - + /* * head and tail points to other polylines before and after this in a chain */ PolyLine* headp_; PolyLine* tailp_; - + /* * state bitmask * bit zero is orientation, 0 H, 1 V @@ -81,24 +81,24 @@ namespace polygon_formation { * bit 3 is solid to left of PolyLine when 1, right when 0 */ int state_; - + public: /* * default constructor (for preallocation) */ PolyLine(); - + /* * constructor that takes the orientation, coordiante and side to which there is solid */ PolyLine(orientation_2d orient, Unit coord, Side side); - + //copy constructor PolyLine(const PolyLine& pline); - + //destructor ~PolyLine(); - + //assignment operator PolyLine& operator=(const PolyLine& that); @@ -118,18 +118,18 @@ namespace polygon_formation { /* * returns true if first coordinate is an X value (first segment is vertical) */ - bool verticalHead() const; + bool verticalHead() const; /* * returns the orientation_2d fo the tail */ orientation_2d tailOrient() const; - + /* * returns true if last coordinate is an X value (last segment is vertical) */ bool verticalTail() const; - + /* * retrun true if PolyLine has odd number of coordiantes */ @@ -157,7 +157,7 @@ namespace polygon_formation { * retrun true if the tail of this polyline is connect to the head of a polyline */ bool tailToHead() const; - + /* * retrun the side on which there is solid for this polyline */ @@ -177,12 +177,12 @@ namespace polygon_formation { * adds a coordinate value to the end of the polyline changing the tail orientation */ PolyLine& pushCoordinate(Unit coord); - + /* * removes a coordinate value at the end of the polyline changing the tail orientation */ PolyLine& popCoordinate(); - + /* * extends the tail of the polyline to include the point, changing orientation if needed */ @@ -299,7 +299,7 @@ namespace polygon_formation { * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon - * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete + * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, @@ -314,7 +314,7 @@ namespace polygon_formation { class ActiveTail { private: //data - PolyLine* tailp_; + PolyLine* tailp_; ActiveTail *otherTailp_; std::list holesList_; public: @@ -331,7 +331,7 @@ namespace polygon_formation { End startEnd_; public: inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} - inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : + inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal //we want to use this active tail, otherwise we want to use the other active tail @@ -560,7 +560,7 @@ namespace polygon_formation { /* deallocate an activetail object */ template void destroyActiveTail(ActiveTail* aTail); - + template class PolyLineHoleData { private: @@ -586,7 +586,7 @@ namespace polygon_formation { inline PolyLineHoleData& set_compact(iT inputBegin, iT inputEnd) { return *this; } - + }; template @@ -646,7 +646,7 @@ namespace polygon_formation { inline PolyLinePolygonWithHolesData& set_compact(iT inputBegin, iT inputEnd) { return *this; } - + // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template @@ -679,18 +679,18 @@ namespace polygon_formation { std::vector outputPolygons_; bool fractureHoles_; public: - typedef typename std::vector::iterator iterator; + typedef typename std::vector::iterator iterator; inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} /* construct a scanline with the proper offsets, protocol and options */ inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} - + ~ScanLineToPolygonItrs() { clearOutput_(); } - + /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ - void processEdges(iterator& beginOutput, iterator& endOutput, - Unit currentX, std::vector >& leftEdges, + void processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, std::vector >& rightEdges); - + private: void clearOutput_(); }; @@ -706,9 +706,9 @@ namespace polygon_formation { // inline ScanLineToPolygons() : scanline_() {} // /* construct a scanline with the proper offsets, protocol and options */ // inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} - + // /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ -// inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, +// inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, // std::vector >& rightEdges) { // typename ScanLineToPolygonItrs::iterator itr, endItr; // scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); @@ -754,7 +754,7 @@ namespace polygon_formation { //constructor template - inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : + inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : ptdata_(1, coord), headp_(0), tailp_(0), @@ -796,7 +796,7 @@ namespace polygon_formation { //valid PolyLine template - inline bool PolyLine::isValid() const { + inline bool PolyLine::isValid() const { return state_ > -1; } //first coordinate is an X value @@ -818,7 +818,7 @@ namespace polygon_formation { inline bool PolyLine::verticalTail() const { return to_bool(verticalHead() ^ oddLength()); } - + template inline orientation_2d PolyLine::tailOrient() const { return (verticalTail() ? VERTICAL : HORIZONTAL); @@ -850,16 +850,16 @@ namespace polygon_formation { inline bool PolyLine::tailToHead() const { return to_bool(!tailToTail()); } - + template inline bool PolyLine::tailToTail() const { return to_bool(state_ & TAIL_TO_TAIL); } template - inline Side PolyLine::solidSide() const { + inline Side PolyLine::solidSide() const { return solidToRight(); } - + template inline bool PolyLine::solidToRight() const { return to_bool(state_ & SOLID_TO_RIGHT) != 0; @@ -1010,14 +1010,14 @@ namespace polygon_formation { inline ActiveTail::ActiveTail() : tailp_(0), otherTailp_(0), holesList_() {} template - inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : + inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : tailp_(0), otherTailp_(0), holesList_() { tailp_ = createPolyLine(orient, coord, solidToRight); otherTailp_ = otherTailp; } template - inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : + inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : tailp_(active), otherTailp_(otherTailp), holesList_() {} //copy constructor @@ -1026,9 +1026,9 @@ namespace polygon_formation { //destructor template - inline ActiveTail::~ActiveTail() { + inline ActiveTail::~ActiveTail() { //clear them in case the memory is read later - tailp_ = 0; otherTailp_ = 0; + tailp_ = 0; otherTailp_ = 0; } template @@ -1050,33 +1050,33 @@ namespace polygon_formation { } template - inline bool ActiveTail::operator<=(const ActiveTail& b) const { + inline bool ActiveTail::operator<=(const ActiveTail& b) const { return !(*this > b); } - + template - inline bool ActiveTail::operator>(const ActiveTail& b) const { + inline bool ActiveTail::operator>(const ActiveTail& b) const { return b < (*this); } - + template - inline bool ActiveTail::operator>=(const ActiveTail& b) const { + inline bool ActiveTail::operator>=(const ActiveTail& b) const { return !(*this < b); } template - inline PolyLine* ActiveTail::getTail() const { + inline PolyLine* ActiveTail::getTail() const { return tailp_; } template - inline PolyLine* ActiveTail::getOtherTail() const { + inline PolyLine* ActiveTail::getOtherTail() const { return otherTailp_->tailp_; } template - inline ActiveTail* ActiveTail::getOtherActiveTail() const { + inline ActiveTail* ActiveTail::getOtherActiveTail() const { return otherTailp_; } template inline bool ActiveTail::isOtherTail(const ActiveTail& b) { // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || - // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) + // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) // ("ActiveTail: Active tails out of sync"); return otherTailp_ == &b; } @@ -1100,7 +1100,7 @@ namespace polygon_formation { if(other->getOrient() == VERTICAL) { //assert that hole.getOrient() == HORIZONTAL //this case should never happen - h = hole; + h = hole; v = other; } else { //assert that hole.getOrient() == VERTICAL @@ -1128,23 +1128,23 @@ namespace polygon_formation { } template - inline bool ActiveTail::solidToRight() const { + inline bool ActiveTail::solidToRight() const { return getTail()->solidToRight(); } template - inline Unit ActiveTail::getCoord() const { + inline Unit ActiveTail::getCoord() const { return getTail()->getEndCoord(); } - - template - inline Unit ActiveTail::getCoordinate() const { - return getCoord(); } template - inline orientation_2d ActiveTail::getOrient() const { + inline Unit ActiveTail::getCoordinate() const { + return getCoord(); } + + template + inline orientation_2d ActiveTail::getOrient() const { return getTail()->tailOrient(); } template - inline void ActiveTail::pushCoordinate(Unit coord) { + inline void ActiveTail::pushCoordinate(Unit coord) { //appropriately handle any co-linear polyline segments by calling push point internally point_data p; p.set(HORIZONTAL, coord); @@ -1241,16 +1241,16 @@ namespace polygon_formation { if((getOrient() == HORIZONTAL) ^ !isHole) { //our first coordinate is a y value, so we need to rotate it to the end typename std::vector::iterator tmpItr = outVec.begin(); - tmpItr += size; + tmpItr += size; outVec.erase(++tmpItr); //erase the 2nd element } End startEnd = tailp_->endConnectivity(HEAD); if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); while(nextPolyLinep) { bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); - nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); + nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); startEnd = nextStartEnd; - } + } if((getOrient() == HORIZONTAL) ^ !isHole) { //we want to push the y value onto the end since we ought to have ended with an x outVec.push_back(firsty); //should never be executed because we want first value to be an x @@ -1284,7 +1284,7 @@ namespace polygon_formation { //solid indicates if it was joined by a solit or a space template - inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ @@ -1298,7 +1298,7 @@ namespace polygon_formation { //because otherwise it would have to have another vertex to the right of this one //and would not be closed at this point return at1; - } else { + } else { //assert pG != 0 //the figure that was closed is a shell at1->writeOutFigure(outBufferTmp); @@ -1334,7 +1334,7 @@ namespace polygon_formation { //solid indicates if it was joined by a solit or a space template template - inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ @@ -1348,7 +1348,7 @@ namespace polygon_formation { //because otherwise it would have to have another vertex to the right of this one //and would not be closed at this point return at1; - } else { + } else { //assert pG != 0 //the figure that was closed is a shell outBufferTmp.push_back(at1); @@ -1367,8 +1367,8 @@ namespace polygon_formation { return 0; } - template inline typename std::map::iterator findAtNext(std::map& theMap, - typename std::map::iterator pos, const TKey& key) + template inline typename std::map::iterator findAtNext(std::map& theMap, + typename std::map::iterator pos, const TKey& key) { if(pos == theMap.end()) return theMap.find(key); //if they match the mapItr is pointing to the correct position @@ -1377,22 +1377,22 @@ namespace polygon_formation { } if(pos->first > key) { return theMap.end(); - } + } //else they are equal and no need to do anything to the iterator return pos; } // createActiveTailsAsPair is called in these two end cases of geometry // 1. lower left concave corner - // ###| // ###| - // ###|### + // ###| + // ###|### // ###|### // 2. lower left convex corner - // |### - // |### - // | - // | + // |### + // |### + // | + // | // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled // the two active tails that form the filament fracture line edges can become the new active tail pair // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails @@ -1408,7 +1408,7 @@ namespace polygon_formation { (*at2) = ActiveTail(HORIZONTAL, y, !solid, at1); //provide a function through activeTail class to provide this at1->getTail()->joinHeadToHead(*(at2->getTail())); - if(phole) + if(phole) at1->addHole(phole, fractureHoles); //assert fractureHoles == false return std::pair*, ActiveTail*>(at1, at2); } @@ -1427,105 +1427,105 @@ namespace polygon_formation { at2->pushCoordinate(y); return std::pair*, ActiveTail*>(at1, at2); } - + //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. // - //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique + //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique //actions to take: // 1. Solid on both sides of the vertical partition after the current position and space on both sides before - // ###|### - // ###|### - // | - // | + // ###|### + // ###|### + // | + // | // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 2. Solid on both sides of the vertical partition before the current position and space on both sides after - // | - // | - // ###|### - // ###|### + // | + // | + // ###|### + // ###|### // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 3. Solid on the left of the vertical partition after the current position and space elsewhere - // ###| - // ###| - // | - // | + // ###| + // ###| + // | + // | // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 4. Solid on the left of the vertical partion before the current position and space elsewhere - // | - // | - // ###| + // | + // | + // ###| // ###| // The horizontal edge from the left is found and joined to the currently active vertical edge. // // 5. Solid to the right above and below and solid to the left above current position. - // ###|### - // ###|### - // |### - // |### + // ###|### + // ###|### + // |### + // |### // The horizontal edge from the left is found and joined to the currently active vertical edge, // potentially closing a hole. // // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below // |### - // |### - // ###|### + // |### + // ###|### // ###|### // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 7. Solid on the right of the vertical partition after the current position and space elsewhere - // |### - // |### - // | - // | + // |### + // |### + // | + // | // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail // // 8. Solid on the right of the vertical partion before the current position and space elsewhere - // | - // | - // |### + // | + // | + // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data // // 9. Solid to the right above and solid to the left above and below current position. - // ###|### - // ###|### - // ###| + // ###|### + // ###|### + // ###| // ###| // The currentTail vertical edge turns right and is added to the horizontal edges data // // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below - // ###| // ###| - // ###|### + // ###| + // ###|### // ###|### // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 11. Solid to the right above and solid to the left below current position. - // |### // |### - // ###| + // |### + // ###| // ###| // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 12. Solid on the left of the vertical partion above the current position and solid to the right below - // ###| // ###| - // |### + // ###| + // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data. // The horizontal edge from the left turns upward and becomes the currentTail vertical edge // template inline void ScanLineToPolygonItrs:: - processEdges(iterator& beginOutput, iterator& endOutput, - Unit currentX, std::vector >& leftEdges, + processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, std::vector >& rightEdges) { clearOutput_(); typename std::map*>::iterator nextMapItr = tailMap_.begin(); @@ -1551,7 +1551,7 @@ namespace polygon_formation { interval_data & nextEdge = edges[!trailingEdge]; //process this edge if(!bottomAlreadyProcessed) { - //assert currentTail = 0 + //assert currentTail = 0 //process the bottom end of this edge typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); @@ -1578,7 +1578,7 @@ namespace polygon_formation { //we need to create one and another one to be the current vertical tail //if this is a trailing edge then there is space to the right of the vertical edge //so pass the inverse of trailingEdge to indicate solid to the right - std::pair*, ActiveTail*> tailPair = + std::pair*, ActiveTail*> tailPair = createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); currentTail = tailPair.first; tailMap_.insert(nextMapItr, std::pair*>(edge.get(LOW), tailPair.second)); @@ -1606,7 +1606,7 @@ namespace polygon_formation { //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail //pass true becuase they are created at the lower left corner of some solid //pass null because there is no hole pointer possible - std::pair*, ActiveTail*> tailPair = + std::pair*, ActiveTail*> tailPair = createActiveTailsAsPair(currentX, edge.get(HIGH), true, 0, fractureHoles_); currentTail = tailPair.first; thisMapItr->second = tailPair.second; @@ -1662,7 +1662,7 @@ namespace polygon_formation { //set current tail to null currentTail = 0; } - } + } //delete thisMapItr from the map tailMap_.erase(thisMapItr); } else { @@ -1675,7 +1675,7 @@ namespace polygon_formation { //leave nextMapItr unchanged, it is still next } } - + //increment index leftIndex += !trailingEdge; rightIndex += trailingEdge; @@ -1804,4 +1804,3 @@ namespace polygon_formation { } } #endif - diff --git a/include/boost/polygon/detail/polygon_set_view.hpp b/include/boost/polygon/detail/polygon_set_view.hpp index 693acc4..661884a 100644 --- a/include/boost/polygon/detail/polygon_set_view.hpp +++ b/include/boost/polygon/detail/polygon_set_view.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -8,8 +8,8 @@ #ifndef BOOST_POLYGON_POLYGON_SET_VIEW_HPP #define BOOST_POLYGON_POLYGON_SET_VIEW_HPP namespace boost { namespace polygon{ - - + + template inline void polygon_set_data::clean() const { if(dirty_) { @@ -20,24 +20,24 @@ namespace boost { namespace polygon{ //that vertices be "linearly consistent" //therefore it doesn't work to fall back on 45-degree //booleans for arbitrary angle polygons - if(0) { //downcast(tmp) ) { - tmp.clean(); - data_.clear(); - is_45_ = true; - polygon_set_data tmp2; - tmp2.insert(tmp); - data_.swap(tmp2.data_); - dirty_ = false; - sort(); - } else { - sort(); - arbitrary_boolean_op abo; - polygon_set_data tmp2; - abo.execute(tmp2, begin(), end(), end(), end(), 0); - data_.swap(tmp2.data_); - is_45_ = tmp2.is_45_; - dirty_ = false; - } + //if(0) { //downcast(tmp) ) { + // tmp.clean(); + // data_.clear(); + // is_45_ = true; + // polygon_set_data tmp2; + // tmp2.insert(tmp); + // data_.swap(tmp2.data_); + // dirty_ = false; + // sort(); + //} else { + sort(); + arbitrary_boolean_op abo; + polygon_set_data tmp2; + abo.execute(tmp2, begin(), end(), end(), end(), 0); + data_.swap(tmp2.data_); + is_45_ = tmp2.is_45_; + dirty_ = false; + //} } } @@ -66,7 +66,7 @@ namespace boost { namespace polygon{ typedef typename polygon_set_view::iterator_type iterator_type; typedef typename polygon_set_view::operator_arg_type operator_arg_type; - static inline iterator_type begin(const polygon_set_view& polygon_set); + static inline iterator_type begin(const polygon_set_view& polygon_set); static inline iterator_type end(const polygon_set_view& polygon_set); static inline bool clean(const polygon_set_view& polygon_set); @@ -99,26 +99,26 @@ namespace boost { namespace polygon{ insert_into_view_arg(linput_, lvalue_); insert_into_view_arg(rinput_, rvalue_); polygon_45_set_data l45, r45, o45; - if(linput_.downcast(l45) && rinput_.downcast(r45)) { - //the op codes are screwed up between 45 and arbitrary -#ifdef BOOST_POLYGON_MSVC -#pragma warning (disable: 4127) -#endif - if(op_type < 2) - l45.template applyAdaptiveBoolean_(o45, r45); - else if(op_type == 2) - l45.template applyAdaptiveBoolean_<3>(o45, r45); - else - l45.template applyAdaptiveBoolean_<2>(o45, r45); -#ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) -#endif - output_.insert(o45); - } else { +// if(linput_.downcast(l45) && rinput_.downcast(r45)) { +// //the op codes are screwed up between 45 and arbitrary +//#ifdef BOOST_POLYGON_MSVC +//#pragma warning (disable: 4127) +//#endif +// if(op_type < 2) +// l45.template applyAdaptiveBoolean_(o45, r45); +// else if(op_type == 2) +// l45.template applyAdaptiveBoolean_<3>(o45, r45); +// else +// l45.template applyAdaptiveBoolean_<2>(o45, r45); +//#ifdef BOOST_POLYGON_MSVC +//#pragma warning (default: 4127) +//#endif +// output_.insert(o45); +// } else { arbitrary_boolean_op abo; abo.execute(output_, linput_.begin(), linput_.end(), rinput_.begin(), rinput_.end(), op_type); - } +// } } template @@ -172,11 +172,11 @@ namespace boost { namespace polygon{ } template bool polygon_set_traits >:: - clean(const polygon_set_view& ) { + clean(const polygon_set_view& ) { return true; } template bool polygon_set_traits >:: - sort(const polygon_set_view& ) { + sort(const polygon_set_view& ) { return true; } template @@ -187,7 +187,7 @@ namespace boost { namespace polygon{ itr2 = polygon_set_traits::end(arg); dest.insert(itr1, itr2); } - + template geometry_type_1& self_assignment_boolean_op(geometry_type_1& lvalue_, const geometry_type_2& rvalue_) { typedef geometry_type_1 ltype; @@ -201,13 +201,21 @@ namespace boost { namespace polygon{ // copy constructor template - template + template polygon_set_data::polygon_set_data(const polygon_set_view& that) : data_(that.value().data_), dirty_(that.value().dirty_), unsorted_(that.value().unsorted_), is_45_(that.value().is_45_) {} + // equivalence operator + template + inline bool polygon_set_data::operator==(const polygon_set_data& p) const { + typedef polygon_set_data value_type; + value_type output_; + execute_boolean_op(output_, (*this), p); + return output_.data_.empty(); + } + template struct geometry_concept > { typedef polygon_set_concept type; }; } } #endif - diff --git a/include/boost/polygon/detail/polygon_simplify.hpp b/include/boost/polygon/detail/polygon_simplify.hpp index c9a92f3..4871f50 100644 --- a/include/boost/polygon/detail/polygon_simplify.hpp +++ b/include/boost/polygon/detail/polygon_simplify.hpp @@ -8,19 +8,19 @@ #include namespace boost { namespace polygon { namespace detail { namespace simplify_detail { - + // Does a simplification/optimization pass on the polygon. If a given // vertex lies within "len" of the line segment joining its neighbor // vertices, it is removed. template //T is a model of point concept - std::size_t simplify(std::vector& dst, const std::vector& src, + std::size_t simplify(std::vector& dst, const std::vector& src, typename coordinate_traits< typename point_traits::coordinate_type >::coordinate_distance len) { using namespace boost::polygon; typedef typename point_traits::coordinate_type coordinate_type; - typedef typename coordinate_traits::area_type ftype; + typedef typename coordinate_traits::area_type ftype; typedef typename std::vector::const_iterator iter; std::vector out; @@ -33,7 +33,7 @@ namespace boost { namespace polygon { namespace detail { namespace simplify_deta bool closed = equivalence(src.front(), src.back()); //we need to keep smoothing until we don't find points to remove - //because removing points in the first iteration through the + //because removing points in the first iteration through the //polygon may leave it in a state where more removal is possible bool not_done = true; while(not_done) { @@ -41,7 +41,7 @@ namespace boost { namespace polygon { namespace detail { namespace simplify_deta dst.clear(); return orig_size; } - + // Start with the second, test for the last point // explicitly, and exit after looping back around to the first. ftype len2 = ftype(len) * ftype(len); @@ -49,47 +49,47 @@ namespace boost { namespace polygon { namespace detail { namespace simplify_deta next = i+1; if(next == dst.end()) next = dst.begin(); - + // points A, B, C ftype ax = x(*prev), ay = y(*prev); ftype bx = x(*i), by = y(*i); ftype cx = x(*next), cy = y(*next); - + // vectors AB, BC and AC: ftype abx = bx-ax, aby = by-ay; ftype bcx = cx-bx, bcy = cy-by; ftype acx = cx-ax, acy = cy-ay; - + // dot products ftype ab_ab = abx*abx + aby*aby; ftype bc_bc = bcx*bcx + bcy*bcy; ftype ac_ac = acx*acx + acy*acy; ftype ab_ac = abx*acx + aby*acy; - + // projection of AB along AC ftype projf = ab_ac / ac_ac; ftype projx = acx * projf, projy = acy * projf; - + // perpendicular vector from the line AC to point B (i.e. AB - proj) ftype perpx = abx - projx, perpy = aby - projy; - + // Squared fractional distance of projection. FIXME: can // remove this division, the decisions below can be made with // just the sign of the quotient and a check to see if // abs(numerator) is greater than abs(divisor). ftype f2 = (projx*acx + projy*acx) / ac_ac; - + // Square of the relevant distance from point B: ftype dist2; if (f2 < 0) dist2 = ab_ab; else if(f2 > 1) dist2 = bc_bc; else dist2 = perpx*perpx + perpy*perpy; - + if(dist2 > len2) { prev = i; // bump prev, we didn't remove the segment out.push_back(*i); } - + if(i == dst.begin()) break; } diff --git a/include/boost/polygon/detail/polygon_sort_adaptor.hpp b/include/boost/polygon/detail/polygon_sort_adaptor.hpp old mode 100755 new mode 100644 index 40f16a7..b3561f8 --- a/include/boost/polygon/detail/polygon_sort_adaptor.hpp +++ b/include/boost/polygon/detail/polygon_sort_adaptor.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -14,22 +14,22 @@ #include -//! @brief gtlsort_adaptor default implementation that calls std::sort +//! @brief polygon_sort_adaptor default implementation that calls std::sort namespace boost { namespace polygon { template struct dummy_to_delay_instantiation{ - typedef int unit_type; // default GTL unit + typedef int unit_type; // default GTL unit }; - //! @brief gtlsort_adaptor default implementation that calls std::sort + //! @brief polygon_sort_adaptor default implementation that calls std::sort template - struct gtlsort_adaptor { + struct polygon_sort_adaptor { //! @brief wrapper that mimics std::sort() function and takes // the same arguments template - static void sort(RandomAccessIterator_Type _First, + static void sort(RandomAccessIterator_Type _First, RandomAccessIterator_Type _Last) { std::sort(_First, _Last); @@ -37,31 +37,31 @@ namespace boost { //! @brief wrapper that mimics std::sort() function overload and takes // the same arguments template - static void sort(RandomAccessIterator_Type _First, - RandomAccessIterator_Type _Last, + static void sort(RandomAccessIterator_Type _First, + RandomAccessIterator_Type _Last, const Pred_Type& _Comp) { std::sort(_First, _Last, _Comp); } }; - //! @brief user level wrapper for sorting quantities + //! @brief user level wrapper for sorting quantities template - void gtlsort(iter_type _b_, iter_type _e_) + void polygon_sort(iter_type _b_, iter_type _e_) { - gtlsort_adaptor::unit_type>::sort(_b_, _e_); + polygon_sort_adaptor::unit_type>::sort(_b_, _e_); } //! @brief user level wrapper for sorting quantities that takes predicate // as additional argument template - void gtlsort(iter_type _b_, iter_type _e_, const pred_type& _pred_) + void polygon_sort(iter_type _b_, iter_type _e_, const pred_type& _pred_) { - gtlsort_adaptor::unit_type>::sort(_b_, _e_, _pred_); + polygon_sort_adaptor::unit_type>::sort(_b_, _e_, _pred_); } - + } // namespace polygon -} // namespace boost +} // namespace boost #endif diff --git a/include/boost/polygon/detail/property_merge.hpp b/include/boost/polygon/detail/property_merge.hpp index 77f2614..b0c843b 100644 --- a/include/boost/polygon/detail/property_merge.hpp +++ b/include/boost/polygon/detail/property_merge.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -70,8 +70,8 @@ public: //static public member functions template - static inline void - populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end, + static inline void + populate_property_merge_data(property_merge_data& pmd, iT input_begin, iT input_end, const property_type& property, orientation_2d_type orient) { for( ; input_begin != input_end; ++input_begin) { std::pair, std::pair > element; @@ -112,7 +112,7 @@ public: inline void perform_merge(result_type& result, property_merge_data& data) { if(data.empty()) return; //sort - gtlsort(data.begin(), data.end(), less_vertex_data()); + polygon_sort(data.begin(), data.end(), less_vertex_data()); //scanline bool firstIteration = true; scanlinePosition = scanline.end(); @@ -175,7 +175,7 @@ private: //private static member functions static inline void mergeProperty(property_map& lvalue, std::pair& rvalue) { - typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue, + typename property_map::iterator itr = std::lower_bound(lvalue.begin(), lvalue.end(), rvalue, lessPropertyCount >()); if(itr == lvalue.end() || (*itr).first != rvalue.first) { @@ -286,7 +286,7 @@ private: inline void processVertex(edge_property_vector& output) { if(!countFromBelow.empty()) { //we are processing an interval of change in scanline state between - //previous vertex position and current vertex position where + //previous vertex position and current vertex position where //count from below represents the change on the interval //foreach scanline element from previous to current we //write the interval on the scanline that is changing @@ -333,7 +333,7 @@ private: if((*tmpitr).second == (*previousScanlinePosition).second) scanline.erase(previousScanlinePosition); } - + } else if(currentY < currentInterval.high()){ //elementY > currentInterval.high() //split the interval between previous and current scanline elements @@ -354,7 +354,7 @@ private: std::pair elementScan; elementScan.first = currentInterval.high(); scanlinePosition = scanline.insert(scanline.end(), elementScan); - } + } } if(scanlinePosition == scanline.end() && currentY < currentInterval.high()) { @@ -423,7 +423,7 @@ private: template inline int assertRedundant(T& t) { if(t.empty()) return 0; - int count = 0; + int count = 0; typename T::iterator itr = t.begin(); if((*itr).second.empty()) ++count; @@ -442,8 +442,8 @@ private: inline void performExtract(T& result, property_merge_data& data) { if(data.empty()) return; //sort - gtlsort(data.begin(), data.end(), less_vertex_data()); - + polygon_sort(data.begin(), data.end(), less_vertex_data()); + //scanline bool firstIteration = true; scanlinePosition = scanline.end(); @@ -528,7 +528,7 @@ private: insertEdges(graph, edge.second.second, previousEdge.second.first); } else { if(!firstIteration){ - //look up regions above previous edge + //look up regions above previous edge propertySetAbove(previousEdge.first.high(), ps, scanline); insertEdges(graph, ps, previousEdge.second.first); insertEdges(graph, ps, previousEdge.second.second); diff --git a/include/boost/polygon/detail/property_merge_45.hpp b/include/boost/polygon/detail/property_merge_45.hpp index b85baf7..c2feffc 100644 --- a/include/boost/polygon/detail/property_merge_45.hpp +++ b/include/boost/polygon/detail/property_merge_45.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -30,7 +30,7 @@ namespace boost { namespace polygon{ inline bool operator!=(const CountMerge& count) const { return !((*this) == count); } //inline CountMerge& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline CountMerge& operator=(const CountMerge& count) { counts = count.counts; return *this; } - inline int& operator[](property_type index) { + inline int& operator[](property_type index) { std::vector >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; @@ -72,7 +72,7 @@ namespace boost { namespace polygon{ //output is a std::map, polygon_45_set_data > struct merge_45_output_functor { template - void operator()(cT& output, const CountMerge& count1, const CountMerge& count2, + void operator()(cT& output, const CountMerge& count1, const CountMerge& count2, const Point& pt, int rise, direction_1d end) { typedef typename cT::key_type keytype; keytype left; @@ -98,20 +98,20 @@ namespace boost { namespace polygon{ } }; - typedef typename std::pair::template Scan45CountT > Vertex45Compact; typedef std::vector MergeSetData; - + struct lessVertex45Compact { bool operator()(const Vertex45Compact& l, const Vertex45Compact& r) { return l.first < r.first; } }; - + template static void performMerge(output_type& result, MergeSetData& tsd) { - - gtlsort(tsd.begin(), tsd.end(), lessVertex45Compact()); + + polygon_sort(tsd.begin(), tsd.end(), lessVertex45Compact()); typedef std::vector::template Scan45CountT > > TSD; TSD tsd_; tsd_.reserve(tsd.size()); @@ -149,7 +149,7 @@ namespace boost { namespace polygon{ } } } - + }; diff --git a/include/boost/polygon/detail/rectangle_formation.hpp b/include/boost/polygon/detail/rectangle_formation.hpp index d0ae180..22d0f38 100644 --- a/include/boost/polygon/detail/rectangle_formation.hpp +++ b/include/boost/polygon/detail/rectangle_formation.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -10,14 +10,14 @@ namespace boost { namespace polygon{ namespace rectangle_formation { - template + template class ScanLineToRects { public: typedef T rectangle_type; typedef typename rectangle_traits::coordinate_type coordinate_type; typedef rectangle_data scan_rect_type; private: - + typedef std::set > ScanData; ScanData scanData_; bool haveCurrentRect_; @@ -26,17 +26,17 @@ namespace rectangle_formation { typename rectangle_traits::coordinate_type currentCoordinate_; public: inline ScanLineToRects() : scanData_(), haveCurrentRect_(), currentRect_(), orient_(), currentCoordinate_() {} - + inline ScanLineToRects(orientation_2d orient, rectangle_type model) : scanData_(orientation_2d(orient.to_int() ? VERTICAL : HORIZONTAL)), haveCurrentRect_(false), currentRect_(), orient_(orient), currentCoordinate_() { assign(currentRect_, model); currentCoordinate_ = (std::numeric_limits::max)(); } - + template inline ScanLineToRects& processEdge(CT& rectangles, const interval_data& edge); - + inline ScanLineToRects& nextMajorCoordinate(coordinate_type currentCoordinate) { if(haveCurrentRect_) { scanData_.insert(scanData_.end(), currentRect_); @@ -45,12 +45,12 @@ namespace rectangle_formation { currentCoordinate_ = currentCoordinate; return *this; } - + }; - template inline CT& - processEdge_(CT& rectangles, ST& scanData, const interval_type& edge, - bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient) + template inline CT& + processEdge_(CT& rectangles, ST& scanData, const interval_type& edge, + bool& haveCurrentRect, rectangle_type& currentRect, coordinate_type currentCoordinate, orientation_2d orient) { typedef typename CT::value_type result_type; bool edgeProcessed = false; @@ -59,15 +59,15 @@ namespace rectangle_formation { //process all rectangles in the scanData that touch the edge typename ST::iterator dataIter = scanData.lower_bound(rectangle_type(edge, edge)); //decrement beginIter until its low is less than edge's low - while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) && + while((dataIter == scanData.end() || (*dataIter).get(orient).get(LOW) > edge.get(LOW)) && dataIter != scanData.begin()) { --dataIter; } - //process each rectangle until the low end of the rectangle + //process each rectangle until the low end of the rectangle //is greater than the high end of the edge while(dataIter != scanData.end() && - (*dataIter).get(orient).get(LOW) <= edge.get(HIGH)) + (*dataIter).get(orient).get(LOW) <= edge.get(HIGH)) { const rectangle_type& rect = *dataIter; //if the rectangle data intersects the edge at all @@ -111,7 +111,7 @@ namespace rectangle_formation { scanData.insert(nextIter, highRect); } //we are done with this edge - edgeProcessed = true; + edgeProcessed = true; break; } else { //it must be an opening edge @@ -145,8 +145,8 @@ namespace rectangle_formation { } } else { //extend the top of current rect - currentRect.set(orient.get_direction(HIGH), - (std::max)(edge.get(HIGH), + currentRect.set(orient.get_direction(HIGH), + (std::max)(edge.get(HIGH), tmpRect.get(orient.get_direction(HIGH)))); } } else { @@ -155,7 +155,7 @@ namespace rectangle_formation { //create a new current rect currentRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, currentCoordinate)); - currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), + currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), edge.get(LOW)), (std::max)(tmpRect.get(orient).get(HIGH), edge.get(HIGH)))); @@ -164,7 +164,7 @@ namespace rectangle_formation { haveCurrentRect = true; currentRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, currentCoordinate)); - currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), + currentRect.set(orient, interval_data((std::min)(tmpRect.get(orient).get(LOW), edge.get(LOW)), (std::max)(tmpRect.get(orient).get(HIGH), edge.get(HIGH)))); @@ -176,22 +176,22 @@ namespace rectangle_formation { //edgeProcessed = true; } ++dataIter; - } //end while edge intersects rectangle data + } //end while edge intersects rectangle data } if(!edgeProcessed) { if(haveCurrentRect) { - if(currentRect.get(orient.get_perpendicular().get_direction(HIGH)) + if(currentRect.get(orient.get_perpendicular().get_direction(HIGH)) == currentCoordinate && - currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW)) + currentRect.get(orient.get_direction(HIGH)) >= edge.get(LOW)) { if(currentRect.get(orient.get_direction(HIGH)) > edge.get(LOW)){ rectangle_type tmpRect(currentRect); tmpRect.set(orient.get_direction(HIGH), edge.get(LOW)); scanData.insert(scanData.end(), tmpRect); if(currentRect.get(orient.get_direction(HIGH)) > edge.get(HIGH)) { - currentRect.set(orient, - interval_data(edge.get(HIGH), + currentRect.set(orient, + interval_data(edge.get(HIGH), currentRect.get(orient.get_direction(HIGH)))); return rectangles; } else { @@ -205,7 +205,7 @@ namespace rectangle_formation { } scanData.insert(scanData.end(), currentRect); haveCurrentRect = false; - } + } rectangle_type tmpRect(currentRect); tmpRect.set(orient.get_perpendicular(), interval_data(currentCoordinate, currentCoordinate)); @@ -214,13 +214,13 @@ namespace rectangle_formation { return rectangles; } return rectangles; - + } - template - template - inline - ScanLineToRects& ScanLineToRects::processEdge(CT& rectangles, const interval_data& edge) + template + template + inline + ScanLineToRects& ScanLineToRects::processEdge(CT& rectangles, const interval_data& edge) { processEdge_(rectangles, scanData_, edge, haveCurrentRect_, currentRect_, currentCoordinate_, orient_); return *this; @@ -264,4 +264,3 @@ namespace rectangle_formation { } } #endif - diff --git a/include/boost/polygon/detail/scan_arbitrary.hpp b/include/boost/polygon/detail/scan_arbitrary.hpp index 1933eee..0c82fcf 100644 --- a/include/boost/polygon/detail/scan_arbitrary.hpp +++ b/include/boost/polygon/detail/scan_arbitrary.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -17,11 +17,11 @@ namespace boost { namespace polygon{ class line_intersection : public scanline_base { private: typedef typename scanline_base::Point Point; - + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair half_edge; typedef typename scanline_base::half_edge half_edge; - + //scanline comparator functor typedef typename scanline_base::less_half_edge less_half_edge; typedef typename scanline_base::less_point less_point; @@ -51,7 +51,7 @@ namespace boost { namespace polygon{ // x_ = that.x_; // just_before_ = that.just_before_; // segment_id_ = that.segment_id_; - + // //I cannot simply copy that.edge_scanline_ to this edge_scanline_ becuase the functor store pointers to other members! // less_half_edge lessElm(&x_, &just_before_); // edge_scanline_ = edge_scanline(lessElm); @@ -76,7 +76,7 @@ namespace boost { namespace polygon{ ends.push_back(std::make_pair((*itr).first.first.y(), count)); ends.push_back(std::make_pair((*itr).first.second.y(), -count)); } - gtlsort(ends.begin(), ends.end()); + polygon_sort(ends.begin(), ends.end()); histogram.reserve(ends.size()); histogram.push_back(std::make_pair(ends.front().first, std::make_pair(0, 0))); for(typename std::vector >::iterator itr = ends.begin(); itr != ends.end(); ++itr) { @@ -128,11 +128,11 @@ namespace boost { namespace polygon{ bins[*itr] = std::vector >(); } for(iT itr = begin; itr != end; ++itr) { - typename std::map > >::iterator lb = + typename std::map > >::iterator lb = bins.lower_bound((std::min)((*itr).first.first.y(), (*itr).first.second.y())); if(lb != bins.begin()) --lb; - typename std::map > >::iterator ub = + typename std::map > >::iterator ub = bins.upper_bound((std::max)((*itr).first.first.y(), (*itr).first.second.y())); for( ; lb != ub; ++lb) { (*lb).second.push_back(*itr); @@ -161,7 +161,7 @@ namespace boost { namespace polygon{ } } typename scanline_base::compute_intersection_pack pack_; - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); //find all intersection points for(typename std::vector >::iterator outer = data.begin(); outer != data.end(); ++outer) { @@ -182,7 +182,7 @@ namespace boost { namespace polygon{ //at least one segment has a low y value within the range if(he1 == he2) continue; if((std::min)(he2. first.get(HORIZONTAL), - he2.second.get(HORIZONTAL)) >= + he2.second.get(HORIZONTAL)) >= (std::max)(he1.second.get(HORIZONTAL), he1.first.get(HORIZONTAL))) break; @@ -194,11 +194,11 @@ namespace boost { namespace polygon{ pts.push_back(intersection); intersection_points[(*inner).second].insert(intersection); intersection_points[(*outer).second].insert(intersection); - } + } } } } - gtlsort(pts.begin(), pts.end()); + polygon_sort(pts.begin(), pts.end()); typename std::vector::iterator newend = std::unique(pts.begin(), pts.end()); typename std::vector::iterator lfinger = pts.begin(); //find all segments that interact with intersection points @@ -217,7 +217,7 @@ namespace boost { namespace polygon{ //while(itr2 != newend && (*itr2).get(HORIZONTAL) <= (std::max)(he1.first.get(HORIZONTAL), he1.second.get(HORIZONTAL))) ++itr2; //itr = pts.begin(); //itr2 = pts.end(); - while(lfinger != newend && (*lfinger).x() < startpt.x()) ++lfinger; + while(lfinger != newend && (*lfinger).x() < startpt.x()) ++lfinger; for(typename std::vector::iterator itr = lfinger ; itr != newend && (*itr).x() <= stoppt.x(); ++itr) { if(scanline_base::intersects_grid(*itr, he1)) intersection_points[id1].insert(*itr); @@ -289,7 +289,7 @@ namespace boost { namespace polygon{ std::swap(data[i].first.first, data[i].first.second); } } - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); for(typename std::vector >::iterator outer = data.begin(); outer != data.end(); ++outer) { const half_edge& he1 = (*outer).first; @@ -299,7 +299,7 @@ namespace boost { namespace polygon{ const half_edge& he2 = (*inner).first; if(he1 == he2) continue; if((std::min)(he2. first.get(HORIZONTAL), - he2.second.get(HORIZONTAL)) > + he2.second.get(HORIZONTAL)) > (std::max)(he1.second.get(HORIZONTAL), he1.first.get(HORIZONTAL))) break; @@ -359,7 +359,7 @@ namespace boost { namespace polygon{ tmpPts.reserve(pts.size()); tmpPts.insert(tmpPts.end(), pts.begin(), pts.end()); less_point_down_slope lpds; - gtlsort(tmpPts.begin(), tmpPts.end(), lpds); + polygon_sort(tmpPts.begin(), tmpPts.end(), lpds); segment_edge(output_segments, he, id, tmpPts.begin(), tmpPts.end()); } else { segment_edge(output_segments, he, id, pts.begin(), pts.end()); @@ -432,7 +432,7 @@ namespace boost { namespace polygon{ // edge_scanline_.erase(remove_iter); // } -// static inline void update_segments(std::map >& intersection_points, +// static inline void update_segments(std::map >& intersection_points, // const std::set& segments, Point pt) { // for(std::set::const_iterator itr = segments.begin(); itr != segments.end(); ++itr) { // intersection_points[*itr].insert(pt); @@ -479,7 +479,7 @@ namespace boost { namespace polygon{ // std::vector insertion_edges; // insertion_edges.reserve(intersecting_elements.size()); // std::vector > sloping_ends; -// //do all the work of updating the output of all intersecting +// //do all the work of updating the output of all intersecting // for(typename std::set::iterator inter_iter = intersecting_elements.begin(); // inter_iter != intersecting_elements.end(); ++inter_iter) { // //if it is horizontal update it now and continue @@ -491,7 +491,7 @@ namespace boost { namespace polygon{ // //insert its end points into the vector of sloping ends // const half_edge& he = (*inter_iter).first; // Unit y = evalAtXforY(x_, he.first, he.second); -// Unit y2 = evalAtXforY(x_+1, he.first, he.second); +// Unit y2 = evalAtXforY(x_+1, he.first, he.second); // if(y2 >= y) y2 +=1; //we round up, in exact case we don't worry about overbite of one // else y += 1; //downward sloping round up // sloping_ends.push_back(std::make_pair(y, inter_iter)); @@ -499,9 +499,9 @@ namespace boost { namespace polygon{ // } // } // } - + // //merge sloping element data -// gtlsort(sloping_ends.begin(), sloping_ends.end()); +// polygon_sort(sloping_ends.begin(), sloping_ends.end()); // std::map > sloping_elements; // std::set merge_elements; // for(typename std::vector >::iterator slop_iter = sloping_ends.begin(); @@ -574,7 +574,7 @@ namespace boost { namespace polygon{ // inline void process_scan_event(std::map >& intersection_points) { // just_before_ = true; -// //process end events by removing those segments from the scanline +// //process end events by removing those segments from the scanline // //and insert vertices of all events into intersection queue // Point prev_point((std::numeric_limits::min)(), (std::numeric_limits::min)()); // less_point lp; @@ -591,7 +591,7 @@ namespace boost { namespace polygon{ // lookup_and_remove(he, id); // } else { // //half edge is begin event -// insert_into_scanline(he, id); +// insert_into_scanline(he, id); // //note that they will be immediately removed and reinserted after // //handling their intersection (vertex) // //an optimization would allow them to be processed specially to avoid the redundant @@ -787,7 +787,7 @@ namespace boost { namespace polygon{ print(edges); return false; } - //3 3 2 2: 0; 4 2 0 6: 1; 0 3 6 3: 2; 4 1 5 5: 3; + //3 3 2 2: 0; 4 2 0 6: 1; 0 3 6 3: 2; 4 1 5 5: 3; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(3, 3), Point(2, 2)), 0)); @@ -801,7 +801,7 @@ namespace boost { namespace polygon{ print(edges); return false; } - //5 7 1 3: 0; 4 5 2 1: 1; 2 5 2 1: 2; 4 1 5 3: 3; + //5 7 1 3: 0; 4 5 2 1: 1; 2 5 2 1: 2; 4 1 5 3: 3; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(5, 7), Point(1, 3)), 0)); @@ -815,7 +815,7 @@ namespace boost { namespace polygon{ print(edges); return false; } - //1 0 -4 -1: 0; 0 0 2 -1: 1; + //1 0 -4 -1: 0; 0 0 2 -1: 1; input.clear(); edges.clear(); input.push_back(std::make_pair(half_edge(Point(1, 0), Point(-4, -1)), 0)); @@ -875,7 +875,7 @@ namespace boost { namespace polygon{ static void print(const std::vector >& vec) { for(std::size_t i = 0; i < vec.size(); ++ i) { // print(vec[i]); - } + } //std::cout << std::endl; } @@ -940,14 +940,14 @@ namespace boost { namespace polygon{ }; //scanline consumes the "flattened" fully intersected line segments produced by - //a pass of line_intersection along with property and count information and performs a + //a pass of line_intersection along with property and count information and performs a //useful operation like booleans or property merge or connectivity extraction template > class scanline : public scanline_base { public: //definitions typedef typename scanline_base::Point Point; - + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair half_edge; typedef typename scanline_base::half_edge half_edge; @@ -970,7 +970,7 @@ namespace boost { namespace polygon{ //this is the output data type that is created by the scanline before it is post processed based on content of property sets typedef std::pair > half_edge_property; - + //this is the scanline data structure typedef std::map scanline_type; typedef std::pair scanline_element; @@ -987,12 +987,12 @@ namespace boost { namespace polygon{ int just_before_; typename scanline_base::evalAtXforYPack evalAtXforYPack_; public: - inline scanline() : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + inline scanline() : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), x_((std::numeric_limits::max)()), y_((std::numeric_limits::max)()), just_before_(false), evalAtXforYPack_() { less_half_edge lessElm(&x_, &just_before_, &evalAtXforYPack_); scan_data_ = scanline_type(lessElm); } - inline scanline(const scanline& that) : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), + inline scanline(const scanline& that) : scan_data_(), removal_set_(), insertion_set_(), end_point_queue_(), x_((std::numeric_limits::max)()), y_((std::numeric_limits::max)()), just_before_(false), evalAtXforYPack_() { (*this) = that; } inline scanline& operator=(const scanline& that) { @@ -1037,11 +1037,11 @@ namespace boost { namespace polygon{ Unit y = (std::numeric_limits::min)(); bool first_iteration = true; //we want to return from inside the loop when we hit end or new x -#ifdef BOOST_POLYGON_MSVC +#ifdef BOOST_POLYGON_MSVC #pragma warning( disable: 4127 ) #endif while(true) { - if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || + if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || (*begin).first.first.get(HORIZONTAL) != x_))) { //lookup iterator range in scanline for elements coming in from the left //that end at this y @@ -1062,7 +1062,7 @@ namespace boost { namespace polygon{ } if(current_iter != scan_data_.end()) { //get the bottom iterator for elements at this point - //while(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y && + //while(evalAtXforY(x_, (*current_iter).first.first, (*current_iter).first.second) >= (high_precision)y && while(scanline_base::on_above_or_below(Point(x_, y), (*current_iter).first) != 1 && current_iter != scan_data_.begin()) { --current_iter; @@ -1145,7 +1145,7 @@ namespace boost { namespace polygon{ ++begin; } } -#ifdef BOOST_POLYGON_MSVC +#ifdef BOOST_POLYGON_MSVC #pragma warning( default: 4127 ) #endif @@ -1247,7 +1247,7 @@ namespace boost { namespace polygon{ ++j; } else { int count = mp[i].second; - count += mp2[j].second; + count += mp2[j].second; if(count) { newmp.push_back(mp[i]); newmp.back().second = count; @@ -1313,7 +1313,7 @@ namespace boost { namespace polygon{ output.push_back(vertex_half_edge(he.first, he.second, count)); output.push_back(vertex_half_edge(he.second, he.first, -count)); } - gtlsort(output.begin(), output.end()); + polygon_sort(output.begin(), output.end()); } class test_functor { @@ -1484,12 +1484,12 @@ namespace boost { namespace polygon{ } }; - template , + template , typename output_functor_type = merge_output_functor > class property_merge : public scanline_base { protected: typedef typename scanline_base::Point Point; - + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair half_edge; typedef typename scanline_base::half_edge half_edge; @@ -1531,7 +1531,7 @@ namespace boost { namespace polygon{ inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - gtlsort(pmd.begin(), pmd.end(), lvd); + polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline property_merge_data& get_property_merge_data() { return pmd; } @@ -1576,7 +1576,7 @@ namespace boost { namespace polygon{ pts.push_back(lines[i].first.first); pts.push_back(lines[i].first.second); } - gtlsort(pts.begin(), pts.end()); + polygon_sort(pts.begin(), pts.end()); for(std::size_t i = 0; i < pts.size(); i+=2) { if(pts[i] != pts[i+1]) { //stdcout << "Non-closed figures after line intersection!\n"; @@ -1590,7 +1590,7 @@ namespace boost { namespace polygon{ protected: template - void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole, + void insert(const polygon_type& polygon_object, const property_type& property_value, bool is_hole, polygon_concept ) { bool first_iteration = true; bool second_iteration = true; @@ -1638,10 +1638,10 @@ namespace boost { namespace polygon{ } template - void insert(const polygon_with_holes_type& polygon_with_holes_object, const property_type& property_value, bool is_hole, + void insert(const polygon_with_holes_type& polygon_with_holes_object, const property_type& property_value, bool is_hole, polygon_with_holes_concept tag) { insert(polygon_with_holes_object, property_value, is_hole, polygon_concept()); - for(typename polygon_with_holes_traits::iterator_holes_type itr = + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon_with_holes_object); itr != end_holes(polygon_with_holes_object); ++itr) { insert(*itr, property_value, !is_hole, polygon_concept()); @@ -1649,7 +1649,7 @@ namespace boost { namespace polygon{ } template - void insert(const rectangle_type& rectangle_object, const property_type& property_value, bool is_hole, + void insert(const rectangle_type& rectangle_object, const property_type& property_value, bool is_hole, rectangle_concept ) { polygon_90_data poly; assign(poly, rectangle_object); @@ -1658,9 +1658,9 @@ namespace boost { namespace polygon{ public: //change to private when done testing - static inline void create_vertex(property_merge_data& pmd, - const Point& current_point, - const Point& next_point, + static inline void create_vertex(property_merge_data& pmd, + const Point& current_point, + const Point& next_point, direction_1d winding, bool is_hole, const property_type& property) { if(current_point == next_point) return; @@ -1669,7 +1669,7 @@ namespace boost { namespace polygon{ current_vertex.first.second = next_point; current_vertex.second.first = property; int multiplier = 1; - if(winding == CLOCKWISE) + if(winding == CLOCKWISE) multiplier = -1; if(is_hole) multiplier *= -1; @@ -1686,7 +1686,7 @@ namespace boost { namespace polygon{ static inline void sort_vertex_half_edges(vertex_data& vertex) { less_half_edge_pair lessF(vertex.first); - gtlsort(vertex.second.begin(), vertex.second.end(), lessF); + polygon_sort(vertex.second.begin(), vertex.second.end(), lessF); } class less_half_edge_pair { @@ -1697,12 +1697,12 @@ namespace boost { namespace polygon{ bool operator()(const half_edge& e1, const half_edge& e2) { const Point& pt1 = e1.first; const Point& pt2 = e2.first; - if(get(pt1, HORIZONTAL) == + if(get(pt1, HORIZONTAL) == get(pt_, HORIZONTAL)) { //vertical edge is always largest return false; } - if(get(pt2, HORIZONTAL) == + if(get(pt2, HORIZONTAL) == get(pt_, HORIZONTAL)) { //if half edge 1 is not vertical its slope is less than that of half edge 2 return get(pt1, HORIZONTAL) != get(pt2, HORIZONTAL); @@ -1791,7 +1791,7 @@ namespace boost { namespace polygon{ si.insert(rect, 333); print(stdcout, si.pmd) << std::endl; - + Point pts[4] = {Point(0, 0), Point(10,-3), Point(13, 8), Point(0, 0) }; polygon_data poly; property_merge si2; @@ -1817,7 +1817,7 @@ namespace boost { namespace polygon{ si5.insert(poly, 444); si5.sort_property_merge_data(); stdcout << (si2.pmd == si5.pmd) << std::endl; - + return true; } @@ -1867,8 +1867,8 @@ namespace boost { namespace polygon{ stdcout << "fail merge 2\n"; return false; } - //Polygon { -4 -1, 3 3, -2 3 } - //Polygon { 0 -4, -4 -2, -2 1 } + //Polygon { -4 -1, 3 3, -2 3 } + //Polygon { 0 -4, -4 -2, -2 1 } si.clear(); pts.clear(); pts.push_back(Point(-4, -1)); @@ -2069,89 +2069,89 @@ stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; //pts.push_back(Point(5624841,9125000)); //pts.push_back(Point(17616200,9125000)); //pts.push_back(Point(17616200,75000)); -pts.push_back(Point(12262940, 6652520 )); pts.push_back(Point(12125750, 6652520 )); pts.push_back(Point(12121272, 6652961 )); pts.push_back(Point(12112981, 6656396 )); pts.push_back(Point(12106636, 6662741 )); pts.push_back(Point(12103201, 6671032 )); pts.push_back(Point(12103201, 6680007 )); pts.push_back(Point(12106636, 6688298 )); -pts.push_back(Point(12109500, 6691780 )); pts.push_back(Point(12748600, 7330890 )); pts.push_back(Point(15762600, 7330890 )); pts.push_back(Point(15904620, 7472900 )); pts.push_back(Point(15909200, 7473030 )); pts.push_back(Point(15935830, 7476006 )); pts.push_back(Point(15992796, 7499602 )); pts.push_back(Point(16036397, 7543203 )); -pts.push_back(Point(16059993, 7600169 )); pts.push_back(Point(16059993, 7661830 )); pts.push_back(Point(16036397, 7718796 )); pts.push_back(Point(15992796, 7762397 )); pts.push_back(Point(15935830, 7785993 )); pts.push_back(Point(15874169, 7785993 )); pts.push_back(Point(15817203, 7762397 )); pts.push_back(Point(15773602, 7718796 )); -pts.push_back(Point(15750006, 7661830 )); pts.push_back(Point(15747030, 7635200 )); pts.push_back(Point(15746900, 7630620 )); pts.push_back(Point(15670220, 7553930 )); pts.push_back(Point(14872950, 7553930 )); pts.push_back(Point(14872950, 7626170 )); -pts.push_back(Point(14869973, 7661280 )); pts.push_back(Point(14846377, 7718246 )); pts.push_back(Point(14802776, 7761847 )); pts.push_back(Point(14745810, 7785443 )); pts.push_back(Point(14684149, 7785443 )); pts.push_back(Point(14627183, 7761847 )); pts.push_back(Point(14583582, 7718246 )); -pts.push_back(Point(14559986, 7661280 )); pts.push_back(Point(14557070, 7636660 )); pts.push_back(Point(14556670, 7625570 )); pts.push_back(Point(13703330, 7625570 )); pts.push_back(Point(13702930, 7636660 )); pts.push_back(Point(13699993, 7661830 )); pts.push_back(Point(13676397, 7718796 )); -pts.push_back(Point(13632796, 7762397 )); pts.push_back(Point(13575830, 7785993 )); pts.push_back(Point(13514169, 7785993 )); pts.push_back(Point(13457203, 7762397 )); pts.push_back(Point(13436270, 7745670 )); pts.push_back(Point(13432940, 7742520 )); pts.push_back(Point(12963760, 7742520 )); -pts.push_back(Point(12959272, 7742961 )); pts.push_back(Point(12950981, 7746396 )); pts.push_back(Point(12944636, 7752741 )); pts.push_back(Point(12941201, 7761032 )); pts.push_back(Point(12941201, 7770007 )); pts.push_back(Point(12944636, 7778298 )); pts.push_back(Point(12947490, 7781780 )); -pts.push_back(Point(13425330, 8259620 )); pts.push_back(Point(15601330, 8259620 )); pts.push_back(Point(15904620, 8562900 )); pts.push_back(Point(15909200, 8563030 )); pts.push_back(Point(15935830, 8566006 )); pts.push_back(Point(15992796, 8589602 )); pts.push_back(Point(16036397, 8633203 )); -pts.push_back(Point(16059993, 8690169 )); pts.push_back(Point(16059993, 8751830 )); pts.push_back(Point(16036397, 8808796 )); pts.push_back(Point(15992796, 8852397 )); pts.push_back(Point(15935830, 8875993 )); pts.push_back(Point(15874169, 8875993 )); pts.push_back(Point(15817203, 8852397 )); pts.push_back(Point(15773602, 8808796 )); -pts.push_back(Point(15750006, 8751830 )); pts.push_back(Point(15747030, 8725200 )); pts.push_back(Point(15746900, 8720620 )); pts.push_back(Point(15508950, 8482660 )); pts.push_back(Point(14689890, 8482660 )); pts.push_back(Point(14685412, 8483101 )); pts.push_back(Point(14677121, 8486536 )); -pts.push_back(Point(14670776, 8492881 )); pts.push_back(Point(14667341, 8501172 )); pts.push_back(Point(14667341, 8510147 )); pts.push_back(Point(14670776, 8518438 )); pts.push_back(Point(14673630, 8521920 )); pts.push_back(Point(14714620, 8562900 )); pts.push_back(Point(14719200, 8563030 )); pts.push_back(Point(14745830, 8566006 )); -pts.push_back(Point(14802796, 8589602 )); pts.push_back(Point(14846397, 8633203 )); pts.push_back(Point(14869993, 8690169 )); pts.push_back(Point(14869993, 8751830 )); pts.push_back(Point(14846397, 8808796 )); pts.push_back(Point(14802796, 8852397 )); pts.push_back(Point(14745830, 8875993 )); pts.push_back(Point(14684169, 8875993 )); -pts.push_back(Point(14627203, 8852397 )); pts.push_back(Point(14583602, 8808796 )); pts.push_back(Point(14560006, 8751830 )); pts.push_back(Point(14557030, 8725200 )); pts.push_back(Point(14556900, 8720620 )); pts.push_back(Point(14408270, 8571980 )); pts.push_back(Point(13696320, 8571980 )); pts.push_back(Point(13696320, 8675520 )); -pts.push_back(Point(13699963, 8690161 )); pts.push_back(Point(13699963, 8751818 )); pts.push_back(Point(13676368, 8808781 )); pts.push_back(Point(13632771, 8852378 )); pts.push_back(Point(13575808, 8875973 )); pts.push_back(Point(13514151, 8875973 )); pts.push_back(Point(13457188, 8852378 )); pts.push_back(Point(13436270, 8835670 )); pts.push_back(Point(13432940, 8832520 )); -pts.push_back(Point(13281760, 8832520 )); pts.push_back(Point(13277272, 8832961 )); pts.push_back(Point(13268981, 8836396 )); pts.push_back(Point(13262636, 8842741 )); pts.push_back(Point(13259201, 8851032 )); pts.push_back(Point(13259201, 8860007 )); pts.push_back(Point(13262636, 8868298 )); pts.push_back(Point(13265500, 8871780 )); -pts.push_back(Point(13518710, 9125000 )); pts.push_back(Point(16270720, 9125000 )); pts.push_back(Point(16270720, 8939590 )); pts.push_back(Point(17120780, 8939590 )); pts.push_back(Point(17120780, 9125000 )); pts.push_back(Point(17616200, 9125000 )); pts.push_back(Point(17616200, 75000 )); pts.push_back(Point(16024790, 75000 )); -pts.push_back(Point(16021460, 80700 )); pts.push_back(Point(16016397, 88796 )); pts.push_back(Point(15972796, 132397 )); pts.push_back(Point(15915830, 155993 )); pts.push_back(Point(15908730, 157240 )); pts.push_back(Point(15905000, 157800 )); pts.push_back(Point(15516800, 546000 )); pts.push_back(Point(15905000, 934200 )); -pts.push_back(Point(15908730, 934760 )); pts.push_back(Point(15915830, 936006 )); pts.push_back(Point(15972796, 959602 )); pts.push_back(Point(16016397, 1003203 )); pts.push_back(Point(16039993, 1060169 )); pts.push_back(Point(16039993, 1121830 )); pts.push_back(Point(16016397, 1178796 )); pts.push_back(Point(15972796, 1222397 )); -pts.push_back(Point(15915830, 1245993 )); pts.push_back(Point(15854169, 1245993 )); pts.push_back(Point(15797203, 1222397 )); pts.push_back(Point(15753602, 1178796 )); pts.push_back(Point(15730006, 1121830 )); pts.push_back(Point(15728760, 1114730 )); pts.push_back(Point(15728200, 1111000 )); pts.push_back(Point(15363500, 746300 )); -pts.push_back(Point(14602620, 746300 )); pts.push_back(Point(14598142, 746741 )); pts.push_back(Point(14589851, 750176 )); pts.push_back(Point(14583506, 756521 )); pts.push_back(Point(14580071, 764812 )); pts.push_back(Point(14580071, 773787 )); pts.push_back(Point(14583506, 782078 )); pts.push_back(Point(14586360, 785560 )); -pts.push_back(Point(14586370, 785560 )); pts.push_back(Point(14735000, 934200 )); pts.push_back(Point(14738730, 934760 )); pts.push_back(Point(14745830, 936006 )); pts.push_back(Point(14802796, 959602 )); pts.push_back(Point(14846397, 1003203 )); pts.push_back(Point(14869993, 1060169 )); -pts.push_back(Point(14870450, 1062550 )); pts.push_back(Point(14872170, 1071980 )); pts.push_back(Point(14972780, 1071980 )); pts.push_back(Point(15925000, 2024200 )); pts.push_back(Point(15928730, 2024760 )); pts.push_back(Point(15935830, 2026006 )); pts.push_back(Point(15992796, 2049602 )); -pts.push_back(Point(16036397, 2093203 )); pts.push_back(Point(16059993, 2150169 )); pts.push_back(Point(16059993, 2211830 )); pts.push_back(Point(16036397, 2268796 )); pts.push_back(Point(15992796, 2312397 )); pts.push_back(Point(15935830, 2335993 )); pts.push_back(Point(15874169, 2335993 )); -pts.push_back(Point(15817203, 2312397 )); pts.push_back(Point(15773602, 2268796 )); pts.push_back(Point(15750006, 2211830 )); pts.push_back(Point(15748760, 2204730 )); pts.push_back(Point(15748200, 2201000 )); pts.push_back(Point(14869220, 1322020 )); pts.push_back(Point(14088350, 1322020 )); -pts.push_back(Point(14083862, 1322461 )); pts.push_back(Point(14075571, 1325896 )); pts.push_back(Point(14069226, 1332241 )); pts.push_back(Point(14065791, 1340532 )); pts.push_back(Point(14065791, 1349507 )); pts.push_back(Point(14069226, 1357798 )); pts.push_back(Point(14072080, 1361280 )); -pts.push_back(Point(14072090, 1361280 )); pts.push_back(Point(14735000, 2024200 )); pts.push_back(Point(14738730, 2024760 )); pts.push_back(Point(14745830, 2026006 )); pts.push_back(Point(14802796, 2049602 )); pts.push_back(Point(14846397, 2093203 )); pts.push_back(Point(14869993, 2150169 )); -pts.push_back(Point(14869993, 2211830 )); pts.push_back(Point(14846397, 2268796 )); pts.push_back(Point(14802796, 2312397 )); pts.push_back(Point(14745830, 2335993 )); pts.push_back(Point(14684169, 2335993 )); pts.push_back(Point(14627203, 2312397 )); pts.push_back(Point(14583602, 2268796 )); pts.push_back(Point(14560006, 2211830 )); -pts.push_back(Point(14558760, 2204730 )); pts.push_back(Point(14558200, 2201000 )); pts.push_back(Point(13752220, 1395020 )); pts.push_back(Point(12991340, 1395020 )); pts.push_back(Point(12986862, 1395461 )); pts.push_back(Point(12978571, 1398896 )); pts.push_back(Point(12972226, 1405241 )); -pts.push_back(Point(12968791, 1413532 )); pts.push_back(Point(12968791, 1422507 )); pts.push_back(Point(12972226, 1430798 )); pts.push_back(Point(12975080, 1434280 )); pts.push_back(Point(12975090, 1434280 )); pts.push_back(Point(13565000, 2024200 )); pts.push_back(Point(13568730, 2024760 )); pts.push_back(Point(13575830, 2026006 )); -pts.push_back(Point(13632796, 2049602 )); pts.push_back(Point(13676397, 2093203 )); pts.push_back(Point(13699993, 2150169 )); pts.push_back(Point(13699993, 2211830 )); pts.push_back(Point(13676397, 2268796 )); pts.push_back(Point(13632796, 2312397 )); pts.push_back(Point(13575830, 2335993 )); -pts.push_back(Point(13514169, 2335993 )); pts.push_back(Point(13457203, 2312397 )); pts.push_back(Point(13413602, 2268796 )); pts.push_back(Point(13390006, 2211830 )); pts.push_back(Point(13388760, 2204730 )); pts.push_back(Point(13388200, 2201000 )); pts.push_back(Point(12655220, 1468020 )); -pts.push_back(Point(11894340, 1468020 )); pts.push_back(Point(11889862, 1468461 )); pts.push_back(Point(11881571, 1471896 )); pts.push_back(Point(11875226, 1478241 )); pts.push_back(Point(11871791, 1486532 )); pts.push_back(Point(11871791, 1495507 )); -pts.push_back(Point(11875226, 1503798 )); pts.push_back(Point(11878090, 1507280 )); pts.push_back(Point(12395000, 2024200 )); pts.push_back(Point(12398730, 2024760 )); pts.push_back(Point(12405830, 2026006 )); pts.push_back(Point(12462796, 2049602 )); pts.push_back(Point(12506397, 2093203 )); -pts.push_back(Point(12529993, 2150169 )); pts.push_back(Point(12529993, 2211830 )); pts.push_back(Point(12506397, 2268796 )); pts.push_back(Point(12462796, 2312397 )); pts.push_back(Point(12405830, 2335993 )); pts.push_back(Point(12344169, 2335993 )); -pts.push_back(Point(12287203, 2312397 )); pts.push_back(Point(12243602, 2268796 )); pts.push_back(Point(12220006, 2211830 )); pts.push_back(Point(12218760, 2204730 )); pts.push_back(Point(12218200, 2201000 )); pts.push_back(Point(11558220, 1541020 )); -pts.push_back(Point(10797340, 1541020 )); pts.push_back(Point(10792862, 1541461 )); pts.push_back(Point(10784571, 1544896 )); pts.push_back(Point(10778226, 1551241 )); pts.push_back(Point(10774791, 1559532 )); pts.push_back(Point(10774791, 1568507 )); pts.push_back(Point(10778226, 1576798 )); pts.push_back(Point(10781080, 1580280 )); -pts.push_back(Point(10781090, 1580280 )); pts.push_back(Point(11225000, 2024200 )); pts.push_back(Point(11228730, 2024760 )); pts.push_back(Point(11235830, 2026006 )); pts.push_back(Point(11292796, 2049602 )); pts.push_back(Point(11336397, 2093203 )); pts.push_back(Point(11359993, 2150169 )); -pts.push_back(Point(11359993, 2211830 )); pts.push_back(Point(11336397, 2268796 )); pts.push_back(Point(11292796, 2312397 )); pts.push_back(Point(11235830, 2335993 )); pts.push_back(Point(11174169, 2335993 )); pts.push_back(Point(11117203, 2312397 )); pts.push_back(Point(11073602, 2268796 )); pts.push_back(Point(11050006, 2211830 )); -pts.push_back(Point(11048760, 2204730 )); pts.push_back(Point(11048200, 2201000 )); pts.push_back(Point(10461220, 1614020 )); pts.push_back(Point( 5647400, 1614020 )); pts.push_back(Point( 5642912, 1614461 )); -pts.push_back(Point( 5634621, 1617896 )); pts.push_back(Point( 5628276, 1624241 )); pts.push_back(Point( 5624841, 1632532 )); pts.push_back(Point( 5624841, 1641507 )); pts.push_back(Point( 5628276, 1649798 )); pts.push_back(Point( 5631130, 1653280 )); -pts.push_back(Point( 5688490, 1710640 )); pts.push_back(Point( 9722350, 1710640 )); pts.push_back(Point(10034620, 2022900 )); pts.push_back(Point(10039200, 2023030 )); pts.push_back(Point(10065830, 2026006 )); pts.push_back(Point(10122796, 2049602 )); -pts.push_back(Point(10166397, 2093203 )); pts.push_back(Point(10189993, 2150169 )); pts.push_back(Point(10189993, 2211830 )); pts.push_back(Point(10166397, 2268796 )); pts.push_back(Point(10158620, 2279450 )); pts.push_back(Point(10158620, 2404900 )); pts.push_back(Point(10548950, 2795240 )); -pts.push_back(Point(15586950, 2795240 )); pts.push_back(Point(15904620, 3112900 )); pts.push_back(Point(15909200, 3113030 )); pts.push_back(Point(15935830, 3116006 )); pts.push_back(Point(15992796, 3139602 )); pts.push_back(Point(16036397, 3183203 )); pts.push_back(Point(16059993, 3240169 )); pts.push_back(Point(16059993, 3301830 )); -pts.push_back(Point(16036397, 3358796 )); pts.push_back(Point(15992796, 3402397 )); pts.push_back(Point(15935830, 3425993 )); pts.push_back(Point(15874169, 3425993 )); pts.push_back(Point(15817203, 3402397 )); pts.push_back(Point(15773602, 3358796 )); pts.push_back(Point(15750006, 3301830 )); pts.push_back(Point(15747030, 3275200 )); -pts.push_back(Point(15746900, 3270620 )); pts.push_back(Point(15494570, 3018280 )); pts.push_back(Point(14675510, 3018280 )); pts.push_back(Point(14671032, 3018721 )); pts.push_back(Point(14662741, 3022156 )); pts.push_back(Point(14656396, 3028501 )); pts.push_back(Point(14652961, 3036792 )); -pts.push_back(Point(14652961, 3045767 )); pts.push_back(Point(14656396, 3054058 )); pts.push_back(Point(14659260, 3057540 )); pts.push_back(Point(14714620, 3112900 )); pts.push_back(Point(14719200, 3113030 )); pts.push_back(Point(14745830, 3116006 )); pts.push_back(Point(14802796, 3139602 )); -pts.push_back(Point(14846397, 3183203 )); pts.push_back(Point(14869993, 3240169 )); pts.push_back(Point(14869993, 3301830 )); pts.push_back(Point(14846397, 3358796 )); pts.push_back(Point(14802796, 3402397 )); pts.push_back(Point(14745830, 3425993 )); pts.push_back(Point(14684169, 3425993 )); pts.push_back(Point(14627203, 3402397 )); -pts.push_back(Point(14583602, 3358796 )); pts.push_back(Point(14560006, 3301830 )); pts.push_back(Point(14557030, 3275200 )); pts.push_back(Point(14556900, 3270620 )); pts.push_back(Point(14370700, 3084410 )); pts.push_back(Point(13702830, 3084410 )); pts.push_back(Point(13702830, 3263160 )); -pts.push_back(Point(13700003, 3302210 )); pts.push_back(Point(13676407, 3359176 )); pts.push_back(Point(13632806, 3402777 )); pts.push_back(Point(13575840, 3426373 )); pts.push_back(Point(13514179, 3426373 )); pts.push_back(Point(13457213, 3402777 )); pts.push_back(Point(13413612, 3359176 )); -pts.push_back(Point(13390016, 3302210 )); pts.push_back(Point(13387030, 3275200 )); pts.push_back(Point(13386900, 3270620 )); pts.push_back(Point(13266840, 3150550 )); pts.push_back(Point(12532920, 3150550 )); pts.push_back(Point(12532920, 3264990 )); pts.push_back(Point(12529993, 3301820 )); -pts.push_back(Point(12506397, 3358786 )); pts.push_back(Point(12462796, 3402387 )); pts.push_back(Point(12405830, 3425983 )); pts.push_back(Point(12344169, 3425983 )); pts.push_back(Point(12287203, 3402387 )); pts.push_back(Point(12243602, 3358786 )); pts.push_back(Point(12220006, 3301820 )); pts.push_back(Point(12217030, 3275200 )); -pts.push_back(Point(12216900, 3270620 )); pts.push_back(Point(12157460, 3211170 )); pts.push_back(Point(11362030, 3211170 )); pts.push_back(Point(11360250, 3220520 )); pts.push_back(Point(11359993, 3221830 )); pts.push_back(Point(11336397, 3278796 )); -pts.push_back(Point(11292796, 3322397 )); pts.push_back(Point(11235830, 3345993 )); pts.push_back(Point(11174169, 3345993 )); pts.push_back(Point(11117203, 3322397 )); pts.push_back(Point(11096270, 3305670 )); pts.push_back(Point(11092940, 3302520 )); pts.push_back(Point(10680760, 3302520 )); -pts.push_back(Point(10676272, 3302961 )); pts.push_back(Point(10667981, 3306396 )); pts.push_back(Point(10661636, 3312741 )); pts.push_back(Point(10658201, 3321032 )); pts.push_back(Point(10658201, 3330007 )); pts.push_back(Point(10661636, 3338298 )); pts.push_back(Point(10664500, 3341780 )); -pts.push_back(Point(11264260, 3941550 )); pts.push_back(Point(15643260, 3941550 )); pts.push_back(Point(15904620, 4202900 )); pts.push_back(Point(15909200, 4203030 )); pts.push_back(Point(15935830, 4206006 )); pts.push_back(Point(15992796, 4229602 )); -pts.push_back(Point(16036397, 4273203 )); pts.push_back(Point(16059993, 4330169 )); pts.push_back(Point(16059993, 4391830 )); pts.push_back(Point(16036397, 4448796 )); pts.push_back(Point(15992796, 4492397 )); -pts.push_back(Point(15935830, 4515993 )); pts.push_back(Point(15874169, 4515993 )); pts.push_back(Point(15817203, 4492397 )); pts.push_back(Point(15773602, 4448796 )); pts.push_back(Point(15750006, 4391830 )); pts.push_back(Point(15747030, 4365200 )); pts.push_back(Point(15746900, 4360620 )); -pts.push_back(Point(15550880, 4164590 )); pts.push_back(Point(14825070, 4164590 )); pts.push_back(Point(14825070, 4247610 )); pts.push_back(Point(14846397, 4273213 )); pts.push_back(Point(14869993, 4330179 )); pts.push_back(Point(14869993, 4391840 )); pts.push_back(Point(14846397, 4448806 )); -pts.push_back(Point(14802796, 4492407 )); pts.push_back(Point(14745830, 4516003 )); pts.push_back(Point(14684169, 4516003 )); pts.push_back(Point(14627203, 4492407 )); pts.push_back(Point(14583602, 4448806 )); pts.push_back(Point(14560006, 4391840 )); pts.push_back(Point(14557030, 4365200 )); -pts.push_back(Point(14556900, 4360620 )); pts.push_back(Point(14432520, 4236230 )); pts.push_back(Point(13702830, 4236230 )); pts.push_back(Point(13702830, 4352930 )); pts.push_back(Point(13699993, 4391750 )); pts.push_back(Point(13676397, 4448716 )); -pts.push_back(Point(13632796, 4492317 )); pts.push_back(Point(13575830, 4515913 )); pts.push_back(Point(13514169, 4515913 )); pts.push_back(Point(13457203, 4492317 )); pts.push_back(Point(13413602, 4448716 )); pts.push_back(Point(13390006, 4391750 )); pts.push_back(Point(13387030, 4365200 )); -pts.push_back(Point(13386900, 4360620 )); pts.push_back(Point(13334170, 4307880 )); pts.push_back(Point(12532990, 4307880 )); pts.push_back(Point(12532990, 4357550 )); pts.push_back(Point(12529993, 4391760 )); pts.push_back(Point(12506397, 4448726 )); pts.push_back(Point(12462796, 4492327 )); -pts.push_back(Point(12405830, 4515923 )); pts.push_back(Point(12344169, 4515923 )); pts.push_back(Point(12287203, 4492327 )); pts.push_back(Point(12243602, 4448726 )); pts.push_back(Point(12220006, 4391760 )); pts.push_back(Point(12217970, 4378710 )); pts.push_back(Point(12216810, 4368500 )); -pts.push_back(Point(11363190, 4368500 )); pts.push_back(Point(11362030, 4378710 )); pts.push_back(Point(11359983, 4391828 )); pts.push_back(Point(11336388, 4448791 )); pts.push_back(Point(11292791, 4492388 )); pts.push_back(Point(11235828, 4515983 )); pts.push_back(Point(11174171, 4515983 )); pts.push_back(Point(11117208, 4492388 )); -pts.push_back(Point(11096270, 4475670 )); pts.push_back(Point(11092940, 4472520 )); pts.push_back(Point(11057750, 4472520 )); pts.push_back(Point(11053272, 4472961 )); pts.push_back(Point(11044981, 4476396 )); pts.push_back(Point(11038636, 4482741 )); pts.push_back(Point(11035201, 4491032 )); -pts.push_back(Point(11035201, 4500007 )); pts.push_back(Point(11038636, 4508298 )); pts.push_back(Point(11041490, 4511780 )); pts.push_back(Point(11573490, 5043780 )); pts.push_back(Point(15655490, 5043780 )); pts.push_back(Point(15904620, 5292900 )); -pts.push_back(Point(15909200, 5293030 )); pts.push_back(Point(15935830, 5296006 )); pts.push_back(Point(15992796, 5319602 )); pts.push_back(Point(16036397, 5363203 )); pts.push_back(Point(16059993, 5420169 )); pts.push_back(Point(16059993, 5481830 )); pts.push_back(Point(16036397, 5538796 )); -pts.push_back(Point(15992796, 5582397 )); pts.push_back(Point(15935830, 5605993 )); pts.push_back(Point(15874169, 5605993 )); pts.push_back(Point(15817203, 5582397 )); pts.push_back(Point(15773602, 5538796 )); pts.push_back(Point(15750006, 5481830 )); pts.push_back(Point(15747030, 5455200 )); -pts.push_back(Point(15746900, 5450620 )); pts.push_back(Point(15563110, 5266820 )); pts.push_back(Point(14857380, 5266820 )); pts.push_back(Point(14857380, 5382430 )); pts.push_back(Point(14869993, 5420179 )); pts.push_back(Point(14869993, 5481840 )); pts.push_back(Point(14846397, 5538806 )); pts.push_back(Point(14802796, 5582407 )); -pts.push_back(Point(14745830, 5606003 )); pts.push_back(Point(14684169, 5606003 )); pts.push_back(Point(14627203, 5582407 )); pts.push_back(Point(14583602, 5538806 )); pts.push_back(Point(14560006, 5481840 )); pts.push_back(Point(14557030, 5455200 )); pts.push_back(Point(14556900, 5450620 )); pts.push_back(Point(14444750, 5338460 )); -pts.push_back(Point(13702890, 5338460 )); pts.push_back(Point(13702890, 5364400 )); pts.push_back(Point(13699993, 5401800 )); pts.push_back(Point(13676397, 5458766 )); pts.push_back(Point(13632796, 5502367 )); pts.push_back(Point(13575830, 5525963 )); pts.push_back(Point(13514169, 5525963 )); pts.push_back(Point(13457203, 5502367 )); -pts.push_back(Point(13413602, 5458766 )); pts.push_back(Point(13390006, 5401800 )); pts.push_back(Point(13389230, 5397620 )); pts.push_back(Point(13387590, 5388060 )); pts.push_back(Point(12532960, 5388060 )); pts.push_back(Point(12532960, 5446220 )); pts.push_back(Point(12529993, 5481820 )); -pts.push_back(Point(12506397, 5538786 )); pts.push_back(Point(12462796, 5582387 )); pts.push_back(Point(12405830, 5605983 )); pts.push_back(Point(12344169, 5605983 )); pts.push_back(Point(12287203, 5582387 )); pts.push_back(Point(12266270, 5565670 )); pts.push_back(Point(12262940, 5562520 )); pts.push_back(Point(11737750, 5562520 )); -pts.push_back(Point(11733272, 5562961 )); pts.push_back(Point(11724981, 5566396 )); pts.push_back(Point(11718636, 5572741 )); pts.push_back(Point(11715201, 5581032 )); pts.push_back(Point(11715201, 5590007 )); pts.push_back(Point(11718636, 5598298 )); pts.push_back(Point(11721500, 5601780 )); -pts.push_back(Point(12287760, 6168050 )); pts.push_back(Point(15689760, 6168050 )); pts.push_back(Point(15904620, 6382900 )); pts.push_back(Point(15909200, 6383030 )); pts.push_back(Point(15935830, 6386006 )); pts.push_back(Point(15992796, 6409602 )); -pts.push_back(Point(16036397, 6453203 )); pts.push_back(Point(16059993, 6510169 )); pts.push_back(Point(16059993, 6571830 )); pts.push_back(Point(16036397, 6628796 )); pts.push_back(Point(15992796, 6672397 )); pts.push_back(Point(15935830, 6695993 )); pts.push_back(Point(15874169, 6695993 )); -pts.push_back(Point(15817203, 6672397 )); pts.push_back(Point(15773602, 6628796 )); pts.push_back(Point(15750006, 6571830 )); pts.push_back(Point(15747030, 6545200 )); pts.push_back(Point(15746900, 6540620 )); pts.push_back(Point(15597380, 6391090 )); pts.push_back(Point(14858060, 6391090 )); -pts.push_back(Point(14858060, 6473860 )); pts.push_back(Point(14869993, 6510179 )); pts.push_back(Point(14869993, 6571840 )); pts.push_back(Point(14846397, 6628806 )); pts.push_back(Point(14802796, 6672407 )); pts.push_back(Point(14745830, 6696003 )); pts.push_back(Point(14684169, 6696003 )); -pts.push_back(Point(14627203, 6672407 )); pts.push_back(Point(14583602, 6628806 )); pts.push_back(Point(14560006, 6571840 )); pts.push_back(Point(14557030, 6545200 )); pts.push_back(Point(14556900, 6540620 )); pts.push_back(Point(14479020, 6462730 )); -pts.push_back(Point(13702990, 6462730 )); pts.push_back(Point(13702990, 6537170 )); pts.push_back(Point(13700003, 6571840 )); pts.push_back(Point(13676407, 6628806 )); pts.push_back(Point(13632806, 6672407 )); pts.push_back(Point(13575840, 6696003 )); -pts.push_back(Point(13514179, 6696003 )); pts.push_back(Point(13457213, 6672407 )); pts.push_back(Point(13413612, 6628806 )); pts.push_back(Point(13390016, 6571840 )); pts.push_back(Point(13387040, 6545550 )); pts.push_back(Point(13386710, 6534380 )); -pts.push_back(Point(12533290, 6534380 )); pts.push_back(Point(12532960, 6545550 )); pts.push_back(Point(12529983, 6571828 )); pts.push_back(Point(12506388, 6628791 )); pts.push_back(Point(12462791, 6672388 )); pts.push_back(Point(12405828, 6695983 )); +pts.push_back(Point(12262940, 6652520 )); pts.push_back(Point(12125750, 6652520 )); pts.push_back(Point(12121272, 6652961 )); pts.push_back(Point(12112981, 6656396 )); pts.push_back(Point(12106636, 6662741 )); pts.push_back(Point(12103201, 6671032 )); pts.push_back(Point(12103201, 6680007 )); pts.push_back(Point(12106636, 6688298 )); +pts.push_back(Point(12109500, 6691780 )); pts.push_back(Point(12748600, 7330890 )); pts.push_back(Point(15762600, 7330890 )); pts.push_back(Point(15904620, 7472900 )); pts.push_back(Point(15909200, 7473030 )); pts.push_back(Point(15935830, 7476006 )); pts.push_back(Point(15992796, 7499602 )); pts.push_back(Point(16036397, 7543203 )); +pts.push_back(Point(16059993, 7600169 )); pts.push_back(Point(16059993, 7661830 )); pts.push_back(Point(16036397, 7718796 )); pts.push_back(Point(15992796, 7762397 )); pts.push_back(Point(15935830, 7785993 )); pts.push_back(Point(15874169, 7785993 )); pts.push_back(Point(15817203, 7762397 )); pts.push_back(Point(15773602, 7718796 )); +pts.push_back(Point(15750006, 7661830 )); pts.push_back(Point(15747030, 7635200 )); pts.push_back(Point(15746900, 7630620 )); pts.push_back(Point(15670220, 7553930 )); pts.push_back(Point(14872950, 7553930 )); pts.push_back(Point(14872950, 7626170 )); +pts.push_back(Point(14869973, 7661280 )); pts.push_back(Point(14846377, 7718246 )); pts.push_back(Point(14802776, 7761847 )); pts.push_back(Point(14745810, 7785443 )); pts.push_back(Point(14684149, 7785443 )); pts.push_back(Point(14627183, 7761847 )); pts.push_back(Point(14583582, 7718246 )); +pts.push_back(Point(14559986, 7661280 )); pts.push_back(Point(14557070, 7636660 )); pts.push_back(Point(14556670, 7625570 )); pts.push_back(Point(13703330, 7625570 )); pts.push_back(Point(13702930, 7636660 )); pts.push_back(Point(13699993, 7661830 )); pts.push_back(Point(13676397, 7718796 )); +pts.push_back(Point(13632796, 7762397 )); pts.push_back(Point(13575830, 7785993 )); pts.push_back(Point(13514169, 7785993 )); pts.push_back(Point(13457203, 7762397 )); pts.push_back(Point(13436270, 7745670 )); pts.push_back(Point(13432940, 7742520 )); pts.push_back(Point(12963760, 7742520 )); +pts.push_back(Point(12959272, 7742961 )); pts.push_back(Point(12950981, 7746396 )); pts.push_back(Point(12944636, 7752741 )); pts.push_back(Point(12941201, 7761032 )); pts.push_back(Point(12941201, 7770007 )); pts.push_back(Point(12944636, 7778298 )); pts.push_back(Point(12947490, 7781780 )); +pts.push_back(Point(13425330, 8259620 )); pts.push_back(Point(15601330, 8259620 )); pts.push_back(Point(15904620, 8562900 )); pts.push_back(Point(15909200, 8563030 )); pts.push_back(Point(15935830, 8566006 )); pts.push_back(Point(15992796, 8589602 )); pts.push_back(Point(16036397, 8633203 )); +pts.push_back(Point(16059993, 8690169 )); pts.push_back(Point(16059993, 8751830 )); pts.push_back(Point(16036397, 8808796 )); pts.push_back(Point(15992796, 8852397 )); pts.push_back(Point(15935830, 8875993 )); pts.push_back(Point(15874169, 8875993 )); pts.push_back(Point(15817203, 8852397 )); pts.push_back(Point(15773602, 8808796 )); +pts.push_back(Point(15750006, 8751830 )); pts.push_back(Point(15747030, 8725200 )); pts.push_back(Point(15746900, 8720620 )); pts.push_back(Point(15508950, 8482660 )); pts.push_back(Point(14689890, 8482660 )); pts.push_back(Point(14685412, 8483101 )); pts.push_back(Point(14677121, 8486536 )); +pts.push_back(Point(14670776, 8492881 )); pts.push_back(Point(14667341, 8501172 )); pts.push_back(Point(14667341, 8510147 )); pts.push_back(Point(14670776, 8518438 )); pts.push_back(Point(14673630, 8521920 )); pts.push_back(Point(14714620, 8562900 )); pts.push_back(Point(14719200, 8563030 )); pts.push_back(Point(14745830, 8566006 )); +pts.push_back(Point(14802796, 8589602 )); pts.push_back(Point(14846397, 8633203 )); pts.push_back(Point(14869993, 8690169 )); pts.push_back(Point(14869993, 8751830 )); pts.push_back(Point(14846397, 8808796 )); pts.push_back(Point(14802796, 8852397 )); pts.push_back(Point(14745830, 8875993 )); pts.push_back(Point(14684169, 8875993 )); +pts.push_back(Point(14627203, 8852397 )); pts.push_back(Point(14583602, 8808796 )); pts.push_back(Point(14560006, 8751830 )); pts.push_back(Point(14557030, 8725200 )); pts.push_back(Point(14556900, 8720620 )); pts.push_back(Point(14408270, 8571980 )); pts.push_back(Point(13696320, 8571980 )); pts.push_back(Point(13696320, 8675520 )); +pts.push_back(Point(13699963, 8690161 )); pts.push_back(Point(13699963, 8751818 )); pts.push_back(Point(13676368, 8808781 )); pts.push_back(Point(13632771, 8852378 )); pts.push_back(Point(13575808, 8875973 )); pts.push_back(Point(13514151, 8875973 )); pts.push_back(Point(13457188, 8852378 )); pts.push_back(Point(13436270, 8835670 )); pts.push_back(Point(13432940, 8832520 )); +pts.push_back(Point(13281760, 8832520 )); pts.push_back(Point(13277272, 8832961 )); pts.push_back(Point(13268981, 8836396 )); pts.push_back(Point(13262636, 8842741 )); pts.push_back(Point(13259201, 8851032 )); pts.push_back(Point(13259201, 8860007 )); pts.push_back(Point(13262636, 8868298 )); pts.push_back(Point(13265500, 8871780 )); +pts.push_back(Point(13518710, 9125000 )); pts.push_back(Point(16270720, 9125000 )); pts.push_back(Point(16270720, 8939590 )); pts.push_back(Point(17120780, 8939590 )); pts.push_back(Point(17120780, 9125000 )); pts.push_back(Point(17616200, 9125000 )); pts.push_back(Point(17616200, 75000 )); pts.push_back(Point(16024790, 75000 )); +pts.push_back(Point(16021460, 80700 )); pts.push_back(Point(16016397, 88796 )); pts.push_back(Point(15972796, 132397 )); pts.push_back(Point(15915830, 155993 )); pts.push_back(Point(15908730, 157240 )); pts.push_back(Point(15905000, 157800 )); pts.push_back(Point(15516800, 546000 )); pts.push_back(Point(15905000, 934200 )); +pts.push_back(Point(15908730, 934760 )); pts.push_back(Point(15915830, 936006 )); pts.push_back(Point(15972796, 959602 )); pts.push_back(Point(16016397, 1003203 )); pts.push_back(Point(16039993, 1060169 )); pts.push_back(Point(16039993, 1121830 )); pts.push_back(Point(16016397, 1178796 )); pts.push_back(Point(15972796, 1222397 )); +pts.push_back(Point(15915830, 1245993 )); pts.push_back(Point(15854169, 1245993 )); pts.push_back(Point(15797203, 1222397 )); pts.push_back(Point(15753602, 1178796 )); pts.push_back(Point(15730006, 1121830 )); pts.push_back(Point(15728760, 1114730 )); pts.push_back(Point(15728200, 1111000 )); pts.push_back(Point(15363500, 746300 )); +pts.push_back(Point(14602620, 746300 )); pts.push_back(Point(14598142, 746741 )); pts.push_back(Point(14589851, 750176 )); pts.push_back(Point(14583506, 756521 )); pts.push_back(Point(14580071, 764812 )); pts.push_back(Point(14580071, 773787 )); pts.push_back(Point(14583506, 782078 )); pts.push_back(Point(14586360, 785560 )); +pts.push_back(Point(14586370, 785560 )); pts.push_back(Point(14735000, 934200 )); pts.push_back(Point(14738730, 934760 )); pts.push_back(Point(14745830, 936006 )); pts.push_back(Point(14802796, 959602 )); pts.push_back(Point(14846397, 1003203 )); pts.push_back(Point(14869993, 1060169 )); +pts.push_back(Point(14870450, 1062550 )); pts.push_back(Point(14872170, 1071980 )); pts.push_back(Point(14972780, 1071980 )); pts.push_back(Point(15925000, 2024200 )); pts.push_back(Point(15928730, 2024760 )); pts.push_back(Point(15935830, 2026006 )); pts.push_back(Point(15992796, 2049602 )); +pts.push_back(Point(16036397, 2093203 )); pts.push_back(Point(16059993, 2150169 )); pts.push_back(Point(16059993, 2211830 )); pts.push_back(Point(16036397, 2268796 )); pts.push_back(Point(15992796, 2312397 )); pts.push_back(Point(15935830, 2335993 )); pts.push_back(Point(15874169, 2335993 )); +pts.push_back(Point(15817203, 2312397 )); pts.push_back(Point(15773602, 2268796 )); pts.push_back(Point(15750006, 2211830 )); pts.push_back(Point(15748760, 2204730 )); pts.push_back(Point(15748200, 2201000 )); pts.push_back(Point(14869220, 1322020 )); pts.push_back(Point(14088350, 1322020 )); +pts.push_back(Point(14083862, 1322461 )); pts.push_back(Point(14075571, 1325896 )); pts.push_back(Point(14069226, 1332241 )); pts.push_back(Point(14065791, 1340532 )); pts.push_back(Point(14065791, 1349507 )); pts.push_back(Point(14069226, 1357798 )); pts.push_back(Point(14072080, 1361280 )); +pts.push_back(Point(14072090, 1361280 )); pts.push_back(Point(14735000, 2024200 )); pts.push_back(Point(14738730, 2024760 )); pts.push_back(Point(14745830, 2026006 )); pts.push_back(Point(14802796, 2049602 )); pts.push_back(Point(14846397, 2093203 )); pts.push_back(Point(14869993, 2150169 )); +pts.push_back(Point(14869993, 2211830 )); pts.push_back(Point(14846397, 2268796 )); pts.push_back(Point(14802796, 2312397 )); pts.push_back(Point(14745830, 2335993 )); pts.push_back(Point(14684169, 2335993 )); pts.push_back(Point(14627203, 2312397 )); pts.push_back(Point(14583602, 2268796 )); pts.push_back(Point(14560006, 2211830 )); +pts.push_back(Point(14558760, 2204730 )); pts.push_back(Point(14558200, 2201000 )); pts.push_back(Point(13752220, 1395020 )); pts.push_back(Point(12991340, 1395020 )); pts.push_back(Point(12986862, 1395461 )); pts.push_back(Point(12978571, 1398896 )); pts.push_back(Point(12972226, 1405241 )); +pts.push_back(Point(12968791, 1413532 )); pts.push_back(Point(12968791, 1422507 )); pts.push_back(Point(12972226, 1430798 )); pts.push_back(Point(12975080, 1434280 )); pts.push_back(Point(12975090, 1434280 )); pts.push_back(Point(13565000, 2024200 )); pts.push_back(Point(13568730, 2024760 )); pts.push_back(Point(13575830, 2026006 )); +pts.push_back(Point(13632796, 2049602 )); pts.push_back(Point(13676397, 2093203 )); pts.push_back(Point(13699993, 2150169 )); pts.push_back(Point(13699993, 2211830 )); pts.push_back(Point(13676397, 2268796 )); pts.push_back(Point(13632796, 2312397 )); pts.push_back(Point(13575830, 2335993 )); +pts.push_back(Point(13514169, 2335993 )); pts.push_back(Point(13457203, 2312397 )); pts.push_back(Point(13413602, 2268796 )); pts.push_back(Point(13390006, 2211830 )); pts.push_back(Point(13388760, 2204730 )); pts.push_back(Point(13388200, 2201000 )); pts.push_back(Point(12655220, 1468020 )); +pts.push_back(Point(11894340, 1468020 )); pts.push_back(Point(11889862, 1468461 )); pts.push_back(Point(11881571, 1471896 )); pts.push_back(Point(11875226, 1478241 )); pts.push_back(Point(11871791, 1486532 )); pts.push_back(Point(11871791, 1495507 )); +pts.push_back(Point(11875226, 1503798 )); pts.push_back(Point(11878090, 1507280 )); pts.push_back(Point(12395000, 2024200 )); pts.push_back(Point(12398730, 2024760 )); pts.push_back(Point(12405830, 2026006 )); pts.push_back(Point(12462796, 2049602 )); pts.push_back(Point(12506397, 2093203 )); +pts.push_back(Point(12529993, 2150169 )); pts.push_back(Point(12529993, 2211830 )); pts.push_back(Point(12506397, 2268796 )); pts.push_back(Point(12462796, 2312397 )); pts.push_back(Point(12405830, 2335993 )); pts.push_back(Point(12344169, 2335993 )); +pts.push_back(Point(12287203, 2312397 )); pts.push_back(Point(12243602, 2268796 )); pts.push_back(Point(12220006, 2211830 )); pts.push_back(Point(12218760, 2204730 )); pts.push_back(Point(12218200, 2201000 )); pts.push_back(Point(11558220, 1541020 )); +pts.push_back(Point(10797340, 1541020 )); pts.push_back(Point(10792862, 1541461 )); pts.push_back(Point(10784571, 1544896 )); pts.push_back(Point(10778226, 1551241 )); pts.push_back(Point(10774791, 1559532 )); pts.push_back(Point(10774791, 1568507 )); pts.push_back(Point(10778226, 1576798 )); pts.push_back(Point(10781080, 1580280 )); +pts.push_back(Point(10781090, 1580280 )); pts.push_back(Point(11225000, 2024200 )); pts.push_back(Point(11228730, 2024760 )); pts.push_back(Point(11235830, 2026006 )); pts.push_back(Point(11292796, 2049602 )); pts.push_back(Point(11336397, 2093203 )); pts.push_back(Point(11359993, 2150169 )); +pts.push_back(Point(11359993, 2211830 )); pts.push_back(Point(11336397, 2268796 )); pts.push_back(Point(11292796, 2312397 )); pts.push_back(Point(11235830, 2335993 )); pts.push_back(Point(11174169, 2335993 )); pts.push_back(Point(11117203, 2312397 )); pts.push_back(Point(11073602, 2268796 )); pts.push_back(Point(11050006, 2211830 )); +pts.push_back(Point(11048760, 2204730 )); pts.push_back(Point(11048200, 2201000 )); pts.push_back(Point(10461220, 1614020 )); pts.push_back(Point( 5647400, 1614020 )); pts.push_back(Point( 5642912, 1614461 )); +pts.push_back(Point( 5634621, 1617896 )); pts.push_back(Point( 5628276, 1624241 )); pts.push_back(Point( 5624841, 1632532 )); pts.push_back(Point( 5624841, 1641507 )); pts.push_back(Point( 5628276, 1649798 )); pts.push_back(Point( 5631130, 1653280 )); +pts.push_back(Point( 5688490, 1710640 )); pts.push_back(Point( 9722350, 1710640 )); pts.push_back(Point(10034620, 2022900 )); pts.push_back(Point(10039200, 2023030 )); pts.push_back(Point(10065830, 2026006 )); pts.push_back(Point(10122796, 2049602 )); +pts.push_back(Point(10166397, 2093203 )); pts.push_back(Point(10189993, 2150169 )); pts.push_back(Point(10189993, 2211830 )); pts.push_back(Point(10166397, 2268796 )); pts.push_back(Point(10158620, 2279450 )); pts.push_back(Point(10158620, 2404900 )); pts.push_back(Point(10548950, 2795240 )); +pts.push_back(Point(15586950, 2795240 )); pts.push_back(Point(15904620, 3112900 )); pts.push_back(Point(15909200, 3113030 )); pts.push_back(Point(15935830, 3116006 )); pts.push_back(Point(15992796, 3139602 )); pts.push_back(Point(16036397, 3183203 )); pts.push_back(Point(16059993, 3240169 )); pts.push_back(Point(16059993, 3301830 )); +pts.push_back(Point(16036397, 3358796 )); pts.push_back(Point(15992796, 3402397 )); pts.push_back(Point(15935830, 3425993 )); pts.push_back(Point(15874169, 3425993 )); pts.push_back(Point(15817203, 3402397 )); pts.push_back(Point(15773602, 3358796 )); pts.push_back(Point(15750006, 3301830 )); pts.push_back(Point(15747030, 3275200 )); +pts.push_back(Point(15746900, 3270620 )); pts.push_back(Point(15494570, 3018280 )); pts.push_back(Point(14675510, 3018280 )); pts.push_back(Point(14671032, 3018721 )); pts.push_back(Point(14662741, 3022156 )); pts.push_back(Point(14656396, 3028501 )); pts.push_back(Point(14652961, 3036792 )); +pts.push_back(Point(14652961, 3045767 )); pts.push_back(Point(14656396, 3054058 )); pts.push_back(Point(14659260, 3057540 )); pts.push_back(Point(14714620, 3112900 )); pts.push_back(Point(14719200, 3113030 )); pts.push_back(Point(14745830, 3116006 )); pts.push_back(Point(14802796, 3139602 )); +pts.push_back(Point(14846397, 3183203 )); pts.push_back(Point(14869993, 3240169 )); pts.push_back(Point(14869993, 3301830 )); pts.push_back(Point(14846397, 3358796 )); pts.push_back(Point(14802796, 3402397 )); pts.push_back(Point(14745830, 3425993 )); pts.push_back(Point(14684169, 3425993 )); pts.push_back(Point(14627203, 3402397 )); +pts.push_back(Point(14583602, 3358796 )); pts.push_back(Point(14560006, 3301830 )); pts.push_back(Point(14557030, 3275200 )); pts.push_back(Point(14556900, 3270620 )); pts.push_back(Point(14370700, 3084410 )); pts.push_back(Point(13702830, 3084410 )); pts.push_back(Point(13702830, 3263160 )); +pts.push_back(Point(13700003, 3302210 )); pts.push_back(Point(13676407, 3359176 )); pts.push_back(Point(13632806, 3402777 )); pts.push_back(Point(13575840, 3426373 )); pts.push_back(Point(13514179, 3426373 )); pts.push_back(Point(13457213, 3402777 )); pts.push_back(Point(13413612, 3359176 )); +pts.push_back(Point(13390016, 3302210 )); pts.push_back(Point(13387030, 3275200 )); pts.push_back(Point(13386900, 3270620 )); pts.push_back(Point(13266840, 3150550 )); pts.push_back(Point(12532920, 3150550 )); pts.push_back(Point(12532920, 3264990 )); pts.push_back(Point(12529993, 3301820 )); +pts.push_back(Point(12506397, 3358786 )); pts.push_back(Point(12462796, 3402387 )); pts.push_back(Point(12405830, 3425983 )); pts.push_back(Point(12344169, 3425983 )); pts.push_back(Point(12287203, 3402387 )); pts.push_back(Point(12243602, 3358786 )); pts.push_back(Point(12220006, 3301820 )); pts.push_back(Point(12217030, 3275200 )); +pts.push_back(Point(12216900, 3270620 )); pts.push_back(Point(12157460, 3211170 )); pts.push_back(Point(11362030, 3211170 )); pts.push_back(Point(11360250, 3220520 )); pts.push_back(Point(11359993, 3221830 )); pts.push_back(Point(11336397, 3278796 )); +pts.push_back(Point(11292796, 3322397 )); pts.push_back(Point(11235830, 3345993 )); pts.push_back(Point(11174169, 3345993 )); pts.push_back(Point(11117203, 3322397 )); pts.push_back(Point(11096270, 3305670 )); pts.push_back(Point(11092940, 3302520 )); pts.push_back(Point(10680760, 3302520 )); +pts.push_back(Point(10676272, 3302961 )); pts.push_back(Point(10667981, 3306396 )); pts.push_back(Point(10661636, 3312741 )); pts.push_back(Point(10658201, 3321032 )); pts.push_back(Point(10658201, 3330007 )); pts.push_back(Point(10661636, 3338298 )); pts.push_back(Point(10664500, 3341780 )); +pts.push_back(Point(11264260, 3941550 )); pts.push_back(Point(15643260, 3941550 )); pts.push_back(Point(15904620, 4202900 )); pts.push_back(Point(15909200, 4203030 )); pts.push_back(Point(15935830, 4206006 )); pts.push_back(Point(15992796, 4229602 )); +pts.push_back(Point(16036397, 4273203 )); pts.push_back(Point(16059993, 4330169 )); pts.push_back(Point(16059993, 4391830 )); pts.push_back(Point(16036397, 4448796 )); pts.push_back(Point(15992796, 4492397 )); +pts.push_back(Point(15935830, 4515993 )); pts.push_back(Point(15874169, 4515993 )); pts.push_back(Point(15817203, 4492397 )); pts.push_back(Point(15773602, 4448796 )); pts.push_back(Point(15750006, 4391830 )); pts.push_back(Point(15747030, 4365200 )); pts.push_back(Point(15746900, 4360620 )); +pts.push_back(Point(15550880, 4164590 )); pts.push_back(Point(14825070, 4164590 )); pts.push_back(Point(14825070, 4247610 )); pts.push_back(Point(14846397, 4273213 )); pts.push_back(Point(14869993, 4330179 )); pts.push_back(Point(14869993, 4391840 )); pts.push_back(Point(14846397, 4448806 )); +pts.push_back(Point(14802796, 4492407 )); pts.push_back(Point(14745830, 4516003 )); pts.push_back(Point(14684169, 4516003 )); pts.push_back(Point(14627203, 4492407 )); pts.push_back(Point(14583602, 4448806 )); pts.push_back(Point(14560006, 4391840 )); pts.push_back(Point(14557030, 4365200 )); +pts.push_back(Point(14556900, 4360620 )); pts.push_back(Point(14432520, 4236230 )); pts.push_back(Point(13702830, 4236230 )); pts.push_back(Point(13702830, 4352930 )); pts.push_back(Point(13699993, 4391750 )); pts.push_back(Point(13676397, 4448716 )); +pts.push_back(Point(13632796, 4492317 )); pts.push_back(Point(13575830, 4515913 )); pts.push_back(Point(13514169, 4515913 )); pts.push_back(Point(13457203, 4492317 )); pts.push_back(Point(13413602, 4448716 )); pts.push_back(Point(13390006, 4391750 )); pts.push_back(Point(13387030, 4365200 )); +pts.push_back(Point(13386900, 4360620 )); pts.push_back(Point(13334170, 4307880 )); pts.push_back(Point(12532990, 4307880 )); pts.push_back(Point(12532990, 4357550 )); pts.push_back(Point(12529993, 4391760 )); pts.push_back(Point(12506397, 4448726 )); pts.push_back(Point(12462796, 4492327 )); +pts.push_back(Point(12405830, 4515923 )); pts.push_back(Point(12344169, 4515923 )); pts.push_back(Point(12287203, 4492327 )); pts.push_back(Point(12243602, 4448726 )); pts.push_back(Point(12220006, 4391760 )); pts.push_back(Point(12217970, 4378710 )); pts.push_back(Point(12216810, 4368500 )); +pts.push_back(Point(11363190, 4368500 )); pts.push_back(Point(11362030, 4378710 )); pts.push_back(Point(11359983, 4391828 )); pts.push_back(Point(11336388, 4448791 )); pts.push_back(Point(11292791, 4492388 )); pts.push_back(Point(11235828, 4515983 )); pts.push_back(Point(11174171, 4515983 )); pts.push_back(Point(11117208, 4492388 )); +pts.push_back(Point(11096270, 4475670 )); pts.push_back(Point(11092940, 4472520 )); pts.push_back(Point(11057750, 4472520 )); pts.push_back(Point(11053272, 4472961 )); pts.push_back(Point(11044981, 4476396 )); pts.push_back(Point(11038636, 4482741 )); pts.push_back(Point(11035201, 4491032 )); +pts.push_back(Point(11035201, 4500007 )); pts.push_back(Point(11038636, 4508298 )); pts.push_back(Point(11041490, 4511780 )); pts.push_back(Point(11573490, 5043780 )); pts.push_back(Point(15655490, 5043780 )); pts.push_back(Point(15904620, 5292900 )); +pts.push_back(Point(15909200, 5293030 )); pts.push_back(Point(15935830, 5296006 )); pts.push_back(Point(15992796, 5319602 )); pts.push_back(Point(16036397, 5363203 )); pts.push_back(Point(16059993, 5420169 )); pts.push_back(Point(16059993, 5481830 )); pts.push_back(Point(16036397, 5538796 )); +pts.push_back(Point(15992796, 5582397 )); pts.push_back(Point(15935830, 5605993 )); pts.push_back(Point(15874169, 5605993 )); pts.push_back(Point(15817203, 5582397 )); pts.push_back(Point(15773602, 5538796 )); pts.push_back(Point(15750006, 5481830 )); pts.push_back(Point(15747030, 5455200 )); +pts.push_back(Point(15746900, 5450620 )); pts.push_back(Point(15563110, 5266820 )); pts.push_back(Point(14857380, 5266820 )); pts.push_back(Point(14857380, 5382430 )); pts.push_back(Point(14869993, 5420179 )); pts.push_back(Point(14869993, 5481840 )); pts.push_back(Point(14846397, 5538806 )); pts.push_back(Point(14802796, 5582407 )); +pts.push_back(Point(14745830, 5606003 )); pts.push_back(Point(14684169, 5606003 )); pts.push_back(Point(14627203, 5582407 )); pts.push_back(Point(14583602, 5538806 )); pts.push_back(Point(14560006, 5481840 )); pts.push_back(Point(14557030, 5455200 )); pts.push_back(Point(14556900, 5450620 )); pts.push_back(Point(14444750, 5338460 )); +pts.push_back(Point(13702890, 5338460 )); pts.push_back(Point(13702890, 5364400 )); pts.push_back(Point(13699993, 5401800 )); pts.push_back(Point(13676397, 5458766 )); pts.push_back(Point(13632796, 5502367 )); pts.push_back(Point(13575830, 5525963 )); pts.push_back(Point(13514169, 5525963 )); pts.push_back(Point(13457203, 5502367 )); +pts.push_back(Point(13413602, 5458766 )); pts.push_back(Point(13390006, 5401800 )); pts.push_back(Point(13389230, 5397620 )); pts.push_back(Point(13387590, 5388060 )); pts.push_back(Point(12532960, 5388060 )); pts.push_back(Point(12532960, 5446220 )); pts.push_back(Point(12529993, 5481820 )); +pts.push_back(Point(12506397, 5538786 )); pts.push_back(Point(12462796, 5582387 )); pts.push_back(Point(12405830, 5605983 )); pts.push_back(Point(12344169, 5605983 )); pts.push_back(Point(12287203, 5582387 )); pts.push_back(Point(12266270, 5565670 )); pts.push_back(Point(12262940, 5562520 )); pts.push_back(Point(11737750, 5562520 )); +pts.push_back(Point(11733272, 5562961 )); pts.push_back(Point(11724981, 5566396 )); pts.push_back(Point(11718636, 5572741 )); pts.push_back(Point(11715201, 5581032 )); pts.push_back(Point(11715201, 5590007 )); pts.push_back(Point(11718636, 5598298 )); pts.push_back(Point(11721500, 5601780 )); +pts.push_back(Point(12287760, 6168050 )); pts.push_back(Point(15689760, 6168050 )); pts.push_back(Point(15904620, 6382900 )); pts.push_back(Point(15909200, 6383030 )); pts.push_back(Point(15935830, 6386006 )); pts.push_back(Point(15992796, 6409602 )); +pts.push_back(Point(16036397, 6453203 )); pts.push_back(Point(16059993, 6510169 )); pts.push_back(Point(16059993, 6571830 )); pts.push_back(Point(16036397, 6628796 )); pts.push_back(Point(15992796, 6672397 )); pts.push_back(Point(15935830, 6695993 )); pts.push_back(Point(15874169, 6695993 )); +pts.push_back(Point(15817203, 6672397 )); pts.push_back(Point(15773602, 6628796 )); pts.push_back(Point(15750006, 6571830 )); pts.push_back(Point(15747030, 6545200 )); pts.push_back(Point(15746900, 6540620 )); pts.push_back(Point(15597380, 6391090 )); pts.push_back(Point(14858060, 6391090 )); +pts.push_back(Point(14858060, 6473860 )); pts.push_back(Point(14869993, 6510179 )); pts.push_back(Point(14869993, 6571840 )); pts.push_back(Point(14846397, 6628806 )); pts.push_back(Point(14802796, 6672407 )); pts.push_back(Point(14745830, 6696003 )); pts.push_back(Point(14684169, 6696003 )); +pts.push_back(Point(14627203, 6672407 )); pts.push_back(Point(14583602, 6628806 )); pts.push_back(Point(14560006, 6571840 )); pts.push_back(Point(14557030, 6545200 )); pts.push_back(Point(14556900, 6540620 )); pts.push_back(Point(14479020, 6462730 )); +pts.push_back(Point(13702990, 6462730 )); pts.push_back(Point(13702990, 6537170 )); pts.push_back(Point(13700003, 6571840 )); pts.push_back(Point(13676407, 6628806 )); pts.push_back(Point(13632806, 6672407 )); pts.push_back(Point(13575840, 6696003 )); +pts.push_back(Point(13514179, 6696003 )); pts.push_back(Point(13457213, 6672407 )); pts.push_back(Point(13413612, 6628806 )); pts.push_back(Point(13390016, 6571840 )); pts.push_back(Point(13387040, 6545550 )); pts.push_back(Point(13386710, 6534380 )); +pts.push_back(Point(12533290, 6534380 )); pts.push_back(Point(12532960, 6545550 )); pts.push_back(Point(12529983, 6571828 )); pts.push_back(Point(12506388, 6628791 )); pts.push_back(Point(12462791, 6672388 )); pts.push_back(Point(12405828, 6695983 )); pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 )); pts.push_back(Point(12266270, 6655670 )); poly.set(pts.begin(), pts.end()); si.insert(poly, 444); @@ -2168,7 +2168,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 outpts.push_back((*itr).first.first); outpts.push_back((*itr).first.second); } - gtlsort(outpts.begin(), outpts.end()); + polygon_sort(outpts.begin(), outpts.end()); for(std::size_t i = 0; i < outpts.size(); i+=2) { if(outpts[i] != outpts[i+1]) { stdcout << "Polygon set not a closed figure\n"; @@ -2486,10 +2486,10 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 template class arbitrary_boolean_op : public scanline_base { private: - + typedef int property_type; typedef typename scanline_base::Point Point; - + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair half_edge; typedef typename scanline_base::half_edge half_edge; @@ -2567,7 +2567,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 if((*(left.begin())) == 0) { result.insert_clean(elem); } - } + } #ifdef BOOST_POLYGON_MSVC #pragma warning (default: 4127) #endif @@ -2583,7 +2583,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - gtlsort(pmd.begin(), pmd.end(), lvd); + polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_boolean_op() : pmd(), evalAtXforYPack_() {} @@ -2593,7 +2593,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 enum BOOLEAN_OP_TYPE { BOOLEAN_OR = 0, BOOLEAN_AND = 1, - BOOLEAN_XOR = 2, + BOOLEAN_XOR = 2, BOOLEAN_NOT = 3 }; template @@ -2627,17 +2627,17 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 } else if(op == BOOLEAN_NOT) { boolean_output_functor, 3> bof; sl.scan(result, bof, pmd.begin(), pmd.end()); - } + } } - + inline void clear() {*this = arbitrary_boolean_op();} private: template void insert(iT b, iT e, int id) { - for(; + for(; b != e; ++b) { - pmd.push_back(vertex_property(half_edge((*b).first.first, (*b).first.second), + pmd.push_back(vertex_property(half_edge((*b).first.first, (*b).first.second), std::pair(id, (*b).second))); } } @@ -2705,9 +2705,9 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 template class arbitrary_connectivity_extraction : public scanline_base { private: - + typedef typename scanline_base::Point Point; - + //the first point is the vertex and and second point establishes the slope of an edge eminating from the vertex //typedef std::pair half_edge; typedef typename scanline_base::half_edge half_edge; @@ -2752,7 +2752,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 std::map, std::set >& y_prop_map = output.first.second; if(y_prop_map.empty()) return; Unit x = output.first.first; - for(typename std::map, std::set >::iterator itr = + for(typename std::map, std::set >::iterator itr = y_prop_map.begin(); itr != y_prop_map.end(); ++itr) { if((*itr).first.x() < x) { y_prop_map.erase(y_prop_map.begin(), itr); @@ -2771,7 +2771,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 } } } - + template class connectivity_extraction_output_functor { public: @@ -2784,21 +2784,21 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 x = pt.x(); std::set& output_set = y_prop_map[pt]; { - for(typename key_type::const_iterator itr1 = + for(typename key_type::const_iterator itr1 = left.begin(); itr1 != left.end(); ++itr1) { output_set.insert(output_set.end(), *itr1); } - for(typename key_type::const_iterator itr2 = + for(typename key_type::const_iterator itr2 = right.begin(); itr2 != right.end(); ++itr2) { output_set.insert(output_set.end(), *itr2); } } std::set& output_set2 = y_prop_map[edge.second]; - for(typename key_type::const_iterator itr1 = + for(typename key_type::const_iterator itr1 = left.begin(); itr1 != left.end(); ++itr1) { output_set2.insert(output_set2.end(), *itr1); } - for(typename key_type::const_iterator itr2 = + for(typename key_type::const_iterator itr2 = right.begin(); itr2 != right.end(); ++itr2) { output_set2.insert(output_set2.end(), *itr2); } @@ -2807,7 +2807,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 inline void sort_property_merge_data() { less_vertex_data lvd(&evalAtXforYPack_); - gtlsort(pmd.begin(), pmd.end(), lvd); + polygon_sort(pmd.begin(), pmd.end(), lvd); } public: inline arbitrary_connectivity_extraction() : pmd(), evalAtXforYPack_() {} @@ -2824,13 +2824,13 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pmd.swap(tmp_pmd); sort_property_merge_data(); scanline > sl; - std::pair, std::set > >, + std::pair, std::set > >, result_type*> output - (std::make_pair(std::make_pair((std::numeric_limits::max)(), - std::map, + (std::make_pair(std::make_pair((std::numeric_limits::max)(), + std::map, std::set >()), &result)); - connectivity_extraction_output_functor, std::set > >, result_type*>, + connectivity_extraction_output_functor, std::set > >, result_type*>, std::vector > ceof; sl.scan(output, ceof, pmd.begin(), pmd.end()); process_previous_x(output); @@ -2839,17 +2839,16 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 inline void clear() {*this = arbitrary_connectivity_extraction();} template - void populateTouchSetData(iT begin, iT end, + void populateTouchSetData(iT begin, iT end, property_type property) { for( ; begin != end; ++begin) { - pmd.push_back(vertex_property(half_edge((*begin).first.first, (*begin).first.second), + pmd.push_back(vertex_property(half_edge((*begin).first.first, (*begin).first.second), std::pair(property, (*begin).second))); } } }; -} +} } #endif - diff --git a/include/boost/polygon/detail/transform_detail.hpp b/include/boost/polygon/detail/transform_detail.hpp index 2cd3400..daba231 100644 --- a/include/boost/polygon/detail/transform_detail.hpp +++ b/include/boost/polygon/detail/transform_detail.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -54,7 +54,7 @@ namespace boost { namespace polygon{ }; atr_ = tmp[orient.to_int()]; } - + inline axis_transformation::axis_transformation(const orientation_2d& orient) : atr_(NULL_TRANSFORM) { const ATR tmp[3] = { NORTH_EAST_UP, //sort by z, then x, then y @@ -62,7 +62,7 @@ namespace boost { namespace polygon{ }; atr_ = tmp[orient.to_int()]; } - + inline axis_transformation::axis_transformation(const direction_3d& dir) : atr_(NULL_TRANSFORM) { const ATR tmp[6] = { DOWN_EAST_NORTH, //sort by -x, then z, then y @@ -74,7 +74,7 @@ namespace boost { namespace polygon{ }; atr_ = tmp[dir.to_int()]; } - + inline axis_transformation::axis_transformation(const direction_2d& dir) : atr_(NULL_TRANSFORM) { const ATR tmp[4] = { SOUTH_EAST_UP, //sort by z, then x, then y @@ -84,7 +84,7 @@ namespace boost { namespace polygon{ }; atr_ = tmp[dir.to_int()]; } - + inline axis_transformation& axis_transformation::operator=(const axis_transformation& a) { atr_ = a.atr_; return *this; @@ -113,13 +113,13 @@ namespace boost { namespace polygon{ bool abit3 = (a.atr_ & 8) != 0; bool abit2 = (a.atr_ & 4) != 0; bool abit1 = (a.atr_ & 2) != 0; - bool abit0 = (a.atr_ & 1) != 0; + bool abit0 = (a.atr_ & 1) != 0; bool bit5 = (atr_ & 32) != 0; bool bit4 = (atr_ & 16) != 0; bool bit3 = (atr_ & 8) != 0; bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; + bool bit0 = (atr_ & 1) != 0; int indexes[2][3] = { { ((int)((bit5 & bit2) | (bit4 & !bit2)) << 1) + @@ -127,7 +127,7 @@ namespace boost { namespace polygon{ ((int)((bit4 & bit2) | (bit5 & !bit2)) << 1) + (int)(!bit5 & !bit2), ((int)(!bit4 & !bit5) << 1) + - (int)(bit5) + (int)(bit5) }, { ((int)((abit5 & abit2) | (abit4 & !abit2)) << 1) + @@ -135,7 +135,7 @@ namespace boost { namespace polygon{ ((int)((abit4 & abit2) | (abit5 & !abit2)) << 1) + (int)(!abit5 & !abit2), ((int)(!abit4 & !abit5) << 1) + - (int)(abit5) + (int)(abit5) } }; int zero_bits[2][3] = { @@ -153,19 +153,19 @@ namespace boost { namespace polygon{ int nbit2 = (!(nbit5 | nbit4) & (bool)(indexes[0][0] & 1)) | //swap xy (nbit5 & ((indexes[0][0] & 2) >> 1)) | //z->y x->z (nbit4 & ((indexes[0][1] & 2) >> 1)); //z->x y->z - atr_ = (ATR)((nbit5 << 5) + - (nbit4 << 4) + - (nbit3 << 3) + - (nbit2 << 2) + + atr_ = (ATR)((nbit5 << 5) + + (nbit4 << 4) + + (nbit3 << 3) + + (nbit2 << 2) + (nbit1 << 1) + nbit0); return *this; } - + inline axis_transformation axis_transformation::operator+(const axis_transformation& a) const { axis_transformation retval(*this); return retval+=a; } - + // populate_axis_array writes the three INDIVIDUAL_AXIS values that the // ATR enum value of 'this' represent into axis_array inline void axis_transformation::populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { @@ -174,24 +174,24 @@ namespace boost { namespace polygon{ bool bit3 = (atr_ & 8) != 0; bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; - axis_array[2] = + bool bit0 = (atr_ & 1) != 0; + axis_array[2] = (INDIVIDUAL_AXIS)((((int)(!bit4 & !bit5)) << 2) + - ((int)(bit5) << 1) + + ((int)(bit5) << 1) + bit3); - axis_array[1] = + axis_array[1] = (INDIVIDUAL_AXIS)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ - ((int)(!bit5 & !bit2) << 1) + + ((int)(!bit5 & !bit2) << 1) + bit1); - axis_array[0] = + axis_array[0] = (INDIVIDUAL_AXIS)((((int)((bit5 & bit2) | (bit4 & !bit2))) << 2) + - ((int)(bit2 & !bit5) << 1) + + ((int)(bit2 & !bit5) << 1) + bit0); } - + // combine_axis_arrays concatenates this_array and that_array overwriting // the result into this_array - inline void + inline void axis_transformation::combine_axis_arrays (INDIVIDUAL_AXIS this_array[], const INDIVIDUAL_AXIS that_array[]){ int indexes[3] = {this_array[0] >> 1, @@ -203,21 +203,21 @@ namespace boost { namespace polygon{ }; this_array[0] = that_array[indexes[0]]; this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] & (int)((int)PZ+(int)PY)); - this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | - ((int)zero_bits[0][0] ^ + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | + ((int)zero_bits[0][0] ^ (int)zero_bits[1][indexes[0]])); this_array[1] = that_array[indexes[1]]; this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] & (int)((int)PZ+(int)PY)); - this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | - ((int)zero_bits[0][1] ^ + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | + ((int)zero_bits[0][1] ^ (int)zero_bits[1][indexes[1]])); this_array[2] = that_array[indexes[2]]; this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] & (int)((int)PZ+(int)PY)); - this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] | - ((int)zero_bits[0][2] ^ + this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] | + ((int)zero_bits[0][2] ^ (int)zero_bits[1][indexes[2]])); } - + // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values // to the ATR enum value and sets 'this' to that value inline void axis_transformation::write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { @@ -230,16 +230,16 @@ namespace boost { namespace polygon{ (bit4 & (((int)this_array[1] & 4) >> 2)); //z->x y->z int bit1 = ((int)this_array[1] & 1); int bit0 = ((int)this_array[0] & 1); - atr_ = ATR((bit5 << 5) + - (bit4 << 4) + - (bit3 << 3) + - (bit2 << 2) + + atr_ = ATR((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + (bit1 << 1) + bit0); } - + // behavior is deterministic but undefined in the case where illegal - // combinations of directions are passed in. - inline axis_transformation& + // combinations of directions are passed in. + inline axis_transformation& axis_transformation::set_directions(const direction_2d& horizontalDir, const direction_2d& verticalDir){ int bit2 = (static_cast(horizontalDir).to_int()) != 0; @@ -248,42 +248,39 @@ namespace boost { namespace polygon{ atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); return *this; } - + // behavior is deterministic but undefined in the case where illegal // combinations of directions are passed in. - inline axis_transformation& axis_transformation::set_directions(const direction_3d& horizontalDir, - const direction_3d& verticalDir, - const direction_3d& proximalDir){ - int this_array[3] = {horizontalDir.to_int(), - verticalDir.to_int(), - proximalDir.to_int()}; - int bit5 = (this_array[2] & 2) != 0; - int bit4 = !(((this_array[2] & 4) != 0) | ((this_array[2] & 2) != 0)); - int bit3 = !((this_array[2] & 1) != 0); + inline axis_transformation& axis_transformation::set_directions( + const direction_3d& horizontalDir, + const direction_3d& verticalDir, + const direction_3d& proximalDir){ + unsigned int this_array[3] = {horizontalDir.to_int(), + verticalDir.to_int(), + proximalDir.to_int()}; + unsigned int bit5 = (this_array[2] & 2) != 0; + unsigned int bit4 = !(((this_array[2] & 4) != 0) | ((this_array[2] & 2) != 0)); + unsigned int bit3 = !((this_array[2] & 1) != 0); //bit 2 is the tricky bit - int bit2 = (!(bit5 | bit4) & ((this_array[0] & 2) != 0 )) | //swap xy - (bit5 & ((this_array[0] & 4) >> 2)) | //z->y x->z - (bit4 & ((this_array[1] & 4) >> 2)); //z->x y->z - int bit1 = !(this_array[1] & 1); - int bit0 = !(this_array[0] & 1); - atr_ = ATR((bit5 << 5) + - (bit4 << 4) + - (bit3 << 3) + - (bit2 << 2) + - (bit1 << 1) + bit0); + unsigned int bit2 = (!(bit5 | bit4) & ((this_array[0] & 2) != 0 )) | //swap xy + (bit5 & ((this_array[0] & 4) >> 2)) | //z->y x->z + (bit4 & ((this_array[1] & 4) >> 2)); //z->x y->z + unsigned int bit1 = !(this_array[1] & 1); + unsigned int bit0 = !(this_array[0] & 1); + atr_ = ATR((bit5 << 5) | (bit4 << 4) | (bit3 << 3) | (bit2 << 2) | (bit1 << 1) | bit0); return *this; } - + template inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y) const { int bit2 = (atr_ & 4) != 0; int bit1 = (atr_ & 2) != 0; int bit0 = (atr_ & 1) != 0; x *= -((bit0 << 1) - 1); - y *= -((bit1 << 1) - 1); + y *= -((bit1 << 1) - 1); predicated_swap(bit2 != 0,x,y); } - + template inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { int bit5 = (atr_ & 32) != 0; @@ -293,13 +290,13 @@ namespace boost { namespace polygon{ int bit1 = (atr_ & 2) != 0; int bit0 = (atr_ & 1) != 0; x *= -((bit0 << 1) - 1); - y *= -((bit1 << 1) - 1); + y *= -((bit1 << 1) - 1); z *= -((bit3 << 1) - 1); predicated_swap(bit2 != 0, x, y); predicated_swap(bit5 != 0, y, z); predicated_swap(bit4 != 0, x, z); } - + inline axis_transformation& axis_transformation::invert_2d() { int bit2 = ((atr_ & 4) != 0); int bit1 = ((atr_ & 2) != 0); @@ -311,15 +308,15 @@ namespace boost { namespace polygon{ atr_ = (ATR)(atr_ | bit0 | bit1); return *this; } - + inline axis_transformation axis_transformation::inverse_2d() const { axis_transformation retval(*this); return retval.invert_2d(); } - + inline axis_transformation& axis_transformation::invert() { int bit5 = ((atr_ & 32) != 0); - int bit4 = ((atr_ & 16) != 0); + int bit4 = ((atr_ & 16) != 0); int bit3 = ((atr_ & 8) != 0); int bit2 = ((atr_ & 4) != 0); int bit1 = ((atr_ & 2) != 0); @@ -328,24 +325,24 @@ namespace boost { namespace polygon{ predicated_swap(bit4 != 0, bit0, bit3); predicated_swap(bit5 != 0, bit1, bit3); predicated_swap(bit2 != 0, bit0, bit1); - atr_ = (ATR)((bit5 << 5) + - (bit4 << 4) + - (bit3 << 3) + - (bit2 << 2) + + atr_ = (ATR)((bit5 << 5) + + (bit4 << 4) + + (bit3 << 3) + + (bit2 << 2) + (bit1 << 1) + bit0); return *this; } - + inline axis_transformation axis_transformation::inverse() const { axis_transformation retval(*this); return retval.invert(); } - + template inline scale_factor_type anisotropic_scale_factor::get(orientation_3d orient) const { return scale_[orient.to_int()]; } - + template inline void anisotropic_scale_factor::set(orientation_3d orient, scale_factor_type value) { scale_[orient.to_int()] = value; @@ -363,14 +360,14 @@ namespace boost { namespace polygon{ inline void anisotropic_scale_factor::y(scale_factor_type value) { scale_[VERTICAL] = value; } template inline void anisotropic_scale_factor::z(scale_factor_type value) { scale_[PROXIMAL] = value; } - + //concatenation operator (convolve scale factors) template inline anisotropic_scale_factor anisotropic_scale_factor::operator+(const anisotropic_scale_factor& s) const { anisotropic_scale_factor retval(*this); return retval+=s; } - + //concatenate this with that template inline const anisotropic_scale_factor& anisotropic_scale_factor::operator+=(const anisotropic_scale_factor& s){ @@ -379,7 +376,7 @@ namespace boost { namespace polygon{ scale_[2] *= s.scale_[2]; return *this; } - + //transform template inline anisotropic_scale_factor& anisotropic_scale_factor::transform(axis_transformation atr){ @@ -453,30 +450,30 @@ namespace boost { namespace polygon{ } template - inline transformation::transformation(const transformation& tr) : + inline transformation::transformation(const transformation& tr) : atr_(tr.atr_), p_(tr.p_) {;} - + template inline bool transformation::operator==(const transformation& tr) const { return atr_ == tr.atr_ && p_ == tr.p_; } - + template inline bool transformation::operator!=(const transformation& tr) const { return !(*this == tr); } - + template inline bool transformation::operator<(const transformation& tr) const { - return atr_ < tr.atr_ || atr_ == tr.atr_ && p_ < tr.p_; + return atr_ < tr.atr_ || (atr_ == tr.atr_ && p_ < tr.p_); } - + template inline transformation transformation::operator+(const transformation& tr) const { transformation retval(*this); return retval+=tr; } - + template inline const transformation& transformation::operator+=(const transformation& tr){ //apply the inverse transformation of this to the translation point of that @@ -491,24 +488,24 @@ namespace boost { namespace polygon{ atr_ += tr.atr_; return *this; } - + template inline void transformation::set_axis_transformation(const axis_transformation& atr) { atr_ = atr; } - + template template inline void transformation::get_translation(point_type& p) const { assign(p, p_); } - + template template inline void transformation::set_translation(const point_type& p) { assign(p_, p); } - + template inline void transformation::transform(coordinate_type& x, coordinate_type& y) const { //subtract each component of new origin point @@ -525,7 +522,7 @@ namespace boost { namespace polygon{ x -= p_.get(HORIZONTAL); atr_.transform(x,y,z); } - + // sets the axis_transform portion to its inverse // transforms the tranlastion portion by that inverse axis_transform // multiplies the translation portion by -1 to reverse it @@ -540,7 +537,7 @@ namespace boost { namespace polygon{ atr_.invert(); return *this; } - + template inline transformation transformation::inverse() const { transformation retval(*this); @@ -549,5 +546,3 @@ namespace boost { namespace polygon{ } } #endif - - diff --git a/include/boost/polygon/detail/voronoi_ctypes.hpp b/include/boost/polygon/detail/voronoi_ctypes.hpp new file mode 100644 index 0000000..63e42a9 --- /dev/null +++ b/include/boost/polygon/detail/voronoi_ctypes.hpp @@ -0,0 +1,650 @@ +// Boost.Polygon library detail/voronoi_ctypes.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_DETAIL_VORONOI_CTYPES +#define BOOST_POLYGON_DETAIL_VORONOI_CTYPES + +#include + +#include +#include +#include +#include + +namespace boost { +namespace polygon { +namespace detail { + +typedef boost::int32_t int32; +typedef boost::int64_t int64; +typedef boost::uint32_t uint32; +typedef boost::uint64_t uint64; +typedef double fpt64; + +// If two floating-point numbers in the same format are ordered (x < y), +// then they are ordered the same way when their bits are reinterpreted as +// sign-magnitude integers. Values are considered to be almost equal if +// their integer bits reinterpretations differ in not more than maxUlps units. +template +struct ulp_comparison; + +template <> +struct ulp_comparison { + enum Result { + LESS = -1, + EQUAL = 0, + MORE = 1 + }; + + Result operator()(fpt64 a, fpt64 b, unsigned int maxUlps) const { + uint64 ll_a, ll_b; + + // Reinterpret double bits as 64-bit signed integer. + std::memcpy(&ll_a, &a, sizeof(fpt64)); + std::memcpy(&ll_b, &b, sizeof(fpt64)); + + // Positive 0.0 is integer zero. Negative 0.0 is 0x8000000000000000. + // Map negative zero to an integer zero representation - making it + // identical to positive zero - the smallest negative number is + // represented by negative one, and downwards from there. + if (ll_a < 0x8000000000000000ULL) + ll_a = 0x8000000000000000ULL - ll_a; + if (ll_b < 0x8000000000000000ULL) + ll_b = 0x8000000000000000ULL - ll_b; + + // Compare 64-bit signed integer representations of input values. + // Difference in 1 Ulp is equivalent to a relative error of between + // 1/4,000,000,000,000,000 and 1/8,000,000,000,000,000. + if (ll_a > ll_b) + return (ll_a - ll_b <= maxUlps) ? EQUAL : LESS; + return (ll_b - ll_a <= maxUlps) ? EQUAL : MORE; + } +}; + +template +struct extened_exponent_fpt_traits; + +template <> +class extened_exponent_fpt_traits { + public: + typedef int exp_type; + static const int kMaxSignificantExpDif; +}; + +const int extened_exponent_fpt_traits::kMaxSignificantExpDif = 54; + +// Floating point type wrapper. Allows to extend exponent boundaries to the +// integer type range. This class does not handle division by zero, subnormal +// numbers or NaNs. +template > +class extended_exponent_fpt { + public: + typedef _fpt fpt_type; + typedef typename _traits::exp_type exp_type; + + explicit extended_exponent_fpt(fpt_type val) { + val_ = std::frexp(val, &exp_); + } + + extended_exponent_fpt(fpt_type val, exp_type exp) { + val_ = std::frexp(val, &exp_); + exp_ += exp; + } + + bool is_pos() const { + return val_ > 0; + } + + bool is_neg() const { + return val_ < 0; + } + + bool is_zero() const { + return val_ == 0; + } + + extended_exponent_fpt operator-() const { + return extended_exponent_fpt(-val_, exp_); + } + + extended_exponent_fpt operator+(const extended_exponent_fpt& that) const { + if (this->val_ == 0.0 || + that.exp_ > this->exp_ + _traits::kMaxSignificantExpDif) { + return that; + } + if (that.val_ == 0.0 || + this->exp_ > that.exp_ + _traits::kMaxSignificantExpDif) { + return *this; + } + if (this->exp_ >= that.exp_) { + exp_type exp_dif = this->exp_ - that.exp_; + fpt_type val = std::ldexp(this->val_, exp_dif) + that.val_; + return extended_exponent_fpt(val, that.exp_); + } else { + exp_type exp_dif = that.exp_ - this->exp_; + fpt_type val = std::ldexp(that.val_, exp_dif) + this->val_; + return extended_exponent_fpt(val, this->exp_); + } + } + + extended_exponent_fpt operator-(const extended_exponent_fpt& that) const { + if (this->val_ == 0.0 || + that.exp_ > this->exp_ + _traits::kMaxSignificantExpDif) { + return extended_exponent_fpt(-that.val_, that.exp_); + } + if (that.val_ == 0.0 || + this->exp_ > that.exp_ + _traits::kMaxSignificantExpDif) { + return *this; + } + if (this->exp_ >= that.exp_) { + exp_type exp_dif = this->exp_ - that.exp_; + fpt_type val = std::ldexp(this->val_, exp_dif) - that.val_; + return extended_exponent_fpt(val, that.exp_); + } else { + exp_type exp_dif = that.exp_ - this->exp_; + fpt_type val = std::ldexp(-that.val_, exp_dif) + this->val_; + return extended_exponent_fpt(val, this->exp_); + } + } + + extended_exponent_fpt operator*(const extended_exponent_fpt& that) const { + fpt_type val = this->val_ * that.val_; + exp_type exp = this->exp_ + that.exp_; + return extended_exponent_fpt(val, exp); + } + + extended_exponent_fpt operator/(const extended_exponent_fpt& that) const { + fpt_type val = this->val_ / that.val_; + exp_type exp = this->exp_ - that.exp_; + return extended_exponent_fpt(val, exp); + } + + extended_exponent_fpt& operator+=(const extended_exponent_fpt& that) { + return *this = *this + that; + } + + extended_exponent_fpt& operator-=(const extended_exponent_fpt& that) { + return *this = *this - that; + } + + extended_exponent_fpt& operator*=(const extended_exponent_fpt& that) { + return *this = *this * that; + } + + extended_exponent_fpt& operator/=(const extended_exponent_fpt& that) { + return *this = *this / that; + } + + extended_exponent_fpt sqrt() const { + fpt_type val = val_; + exp_type exp = exp_; + if (exp & 1) { + val *= 2.0; + --exp; + } + return extended_exponent_fpt(std::sqrt(val), exp >> 1); + } + + fpt_type d() const { + return std::ldexp(val_, exp_); + } + + private: + fpt_type val_; + exp_type exp_; +}; +typedef extended_exponent_fpt efpt64; + +template +extended_exponent_fpt<_fpt> get_sqrt(const extended_exponent_fpt<_fpt>& that) { + return that.sqrt(); +} + +template +bool is_pos(const extended_exponent_fpt<_fpt>& that) { + return that.is_pos(); +} + +template +bool is_neg(const extended_exponent_fpt<_fpt>& that) { + return that.is_neg(); +} + +template +bool is_zero(const extended_exponent_fpt<_fpt>& that) { + return that.is_zero(); +} + +// Very efficient stack allocated big integer class. +// Supports next set of arithmetic operations: +, -, *. +template +class extended_int { + public: + static const uint64 kUInt64LowMask; + static const uint64 kUInt64HighMask; + + extended_int() {} + + extended_int(int32 that) { + if (that > 0) { + this->chunks_[0] = that; + this->count_ = 1; + } else if (that < 0) { + this->chunks_[0] = -that; + this->count_ = -1; + } else { + this->count_ = 0; + } + } + + extended_int(int64 that) { + if (that > 0) { + this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[1] = that >> 32; + this->count_ = this->chunks_[1] ? 2 : 1; + } else if (that < 0) { + that = -that; + this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[1] = that >> 32; + this->count_ = this->chunks_[1] ? -2 : -1; + } else { + this->count_ = 0; + } + } + + extended_int(const std::vector& chunks, bool plus = true) { + this->count_ = static_cast((std::min)(N, chunks.size())); + for (int i = 0; i < this->count_; ++i) + this->chunks_[i] = chunks[chunks.size() - i - 1]; + if (!plus) + this->count_ = -this->count_; + } + + template + extended_int(const extended_int& that) { + this->count_ = that.count(); + std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); + } + + extended_int& operator=(int32 that) { + if (that > 0) { + this->chunks_[0] = that; + this->count_ = 1; + } else if (that < 0) { + this->chunks_[0] = -that; + this->count_ = -1; + } else { + this->count_ = 0; + } + return *this; + } + + extended_int& operator=(int64 that) { + if (that > 0) { + this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[1] = that >> 32; + this->count_ = this->chunks_[1] ? 2 : 1; + } else if (that < 0) { + that = -that; + this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[1] = that >> 32; + this->count_ = this->chunks_[1] ? -2 : -1; + } else { + this->count_ = 0; + } + return *this; + } + + template + extended_int& operator=(const extended_int& that) { + this->count_ = that.count(); + std::memcpy(this->chunks_, that.chunks(), that.size() * sizeof(uint32)); + return *this; + } + + bool is_pos() const { + return this->count_ > 0; + } + + bool is_neg() const { + return this->count_ < 0; + } + + bool is_zero() const { + return this->count_ == 0; + } + + bool operator==(const extended_int& that) const { + if (this->count_ != that.count()) + return false; + for (std::size_t i = 0; i < this->size(); ++i) + if (this->chunks_[i] != that.chunks()[i]) + return false; + return true; + } + + bool operator!=(const extended_int& that) const { + return !(*this == that); + } + + bool operator<(const extended_int& that) const { + if (this->count_ != that.count()) + return this->count_ < that.count(); + std::size_t i = this->size(); + if (!i) + return false; + do { + --i; + if (this->chunks_[i] != that.chunks()[i]) + return (this->chunks_[i] < that.chunks()[i]) ^ (this->count_ < 0); + } while (i); + return false; + } + + bool operator>(const extended_int& that) const { + return that < *this; + } + + bool operator<=(const extended_int& that) const { + return !(that < *this); + } + + bool operator>=(const extended_int& that) const { + return !(*this < that); + } + + extended_int operator-() const { + extended_int ret_val = *this; + ret_val.neg(); + return ret_val; + } + + void neg() { + this->count_ = -this->count_; + } + + extended_int operator+(const extended_int& that) const { + extended_int ret_val; + ret_val.add(*this, that); + return ret_val; + } + + void add(const extended_int& e1, const extended_int& e2) { + if (!e1.count()) { + *this = e2; + return; + } + if (!e2.count()) { + *this = e1; + return; + } + if ((e1.count() > 0) ^ (e2.count() > 0)) { + dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); + } else { + add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); + } + if (e1.count() < 0) + this->count_ = -this->count_; + } + + extended_int operator-(const extended_int& that) const { + extended_int ret_val; + ret_val.dif(*this, that); + return ret_val; + } + + void dif(const extended_int& e1, const extended_int& e2) { + if (!e1.count()) { + *this = e2; + this->count_ = -this->count_; + return; + } + if (!e2.count()) { + *this = e1; + return; + } + if ((e1.count() > 0) ^ (e2.count() > 0)) { + add(e1.chunks(), e1.size(), e2.chunks(), e2.size()); + } else { + dif(e1.chunks(), e1.size(), e2.chunks(), e2.size()); + } + if (e1.count() < 0) + this->count_ = -this->count_; + } + + extended_int operator*(int32 that) const { + extended_int temp(that); + return (*this) * temp; + } + + extended_int operator*(int64 that) const { + extended_int temp(that); + return (*this) * temp; + } + + extended_int operator*(const extended_int& that) const { + extended_int ret_val; + ret_val.mul(*this, that); + return ret_val; + } + + void mul(const extended_int& e1, const extended_int& e2) { + if (!e1.count() || !e2.count()) { + this->count_ = 0; + return; + } + mul(e1.chunks(), e1.size(), e2.chunks(), e2.size()); + if ((e1.count() > 0) ^ (e2.count() > 0)) + this->count_ = -this->count_; + } + + const uint32* chunks() const { + return chunks_; + } + + int32 count() const { + return count_; + } + + std::size_t size() const { + return (std::abs)(count_); + } + + std::pair p() const { + std::pair ret_val(0, 0); + std::size_t sz = this->size(); + if (!sz) { + return ret_val; + } else { + if (sz == 1) { + ret_val.first = static_cast(this->chunks_[0]); + } else if (sz == 2) { + ret_val.first = static_cast(this->chunks_[1]) * + static_cast(0x100000000LL) + + static_cast(this->chunks_[0]); + } else { + for (std::size_t i = 1; i <= 3; ++i) { + ret_val.first *= static_cast(0x100000000LL); + ret_val.first += static_cast(this->chunks_[sz - i]); + } + ret_val.second = (sz - 3) << 5; + } + } + if (this->count_ < 0) + ret_val.first = -ret_val.first; + return ret_val; + } + + fpt64 d() const { + std::pair p = this->p(); + return std::ldexp(p.first, p.second); + } + + private: + void add(const uint32* c1, std::size_t sz1, + const uint32* c2, std::size_t sz2) { + if (sz1 < sz2) { + add(c2, sz2, c1, sz1); + return; + } + this->count_ = sz1; + uint64 temp = 0; + for (std::size_t i = 0; i < sz2; ++i) { + temp += static_cast(c1[i]) + static_cast(c2[i]); + this->chunks_[i] = static_cast(temp & kUInt64LowMask); + temp >>= 32; + } + for (std::size_t i = sz2; i < sz1; ++i) { + temp += static_cast(c1[i]); + this->chunks_[i] = static_cast(temp & kUInt64LowMask); + temp >>= 32; + } + if (temp && (this->count_ != N)) { + this->chunks_[this->count_] = static_cast(temp & kUInt64LowMask); + ++this->count_; + } + } + + void dif(const uint32* c1, std::size_t sz1, + const uint32* c2, std::size_t sz2, + bool rec = false) { + if (sz1 < sz2) { + dif(c2, sz2, c1, sz1, true); + this->count_ = -this->count_; + return; + } else if ((sz1 == sz2) && !rec) { + do { + --sz1; + if (c1[sz1] < c2[sz1]) { + ++sz1; + dif(c2, sz1, c1, sz1, true); + this->count_ = -this->count_; + return; + } else if (c1[sz1] > c2[sz1]) { + ++sz1; + break; + } + } while (sz1); + if (!sz1) { + this->count_ = 0; + return; + } + sz2 = sz1; + } + this->count_ = sz1-1; + bool flag = false; + for (std::size_t i = 0; i < sz2; ++i) { + this->chunks_[i] = c1[i] - c2[i] - (flag?1:0); + flag = (c1[i] < c2[i]) || ((c1[i] == c2[i]) && flag); + } + for (std::size_t i = sz2; i < sz1; ++i) { + this->chunks_[i] = c1[i] - (flag?1:0); + flag = !c1[i] && flag; + } + if (this->chunks_[this->count_]) + ++this->count_; + } + + void mul(const uint32* c1, std::size_t sz1, + const uint32* c2, std::size_t sz2) { + uint64 cur = 0, nxt, tmp; + this->count_ = static_cast((std::min)(N, sz1 + sz2 - 1)); + for (std::size_t shift = 0; shift < static_cast(this->count_); + ++shift) { + nxt = 0; + for (std::size_t first = 0; first <= shift; ++first) { + if (first >= sz1) + break; + std::size_t second = shift - first; + if (second >= sz2) + continue; + tmp = static_cast(c1[first]) * static_cast(c2[second]); + cur += tmp & kUInt64LowMask; + nxt += tmp >> 32; + } + this->chunks_[shift] = static_cast(cur & kUInt64LowMask); + cur = nxt + (cur >> 32); + } + if (cur && (this->count_ != N)) { + this->chunks_[this->count_] = static_cast(cur & kUInt64LowMask); + ++this->count_; + } + } + + uint32 chunks_[N]; + int32 count_; +}; + +template +const uint64 extended_int::kUInt64LowMask = 0x00000000ffffffffULL; +template +const uint64 extended_int::kUInt64HighMask = 0xffffffff00000000ULL; + +template +bool is_pos(const extended_int& that) { + return that.count() > 0; +} + +template +bool is_neg(const extended_int& that) { + return that.count() < 0; +} + +template +bool is_zero(const extended_int& that) { + return !that.count(); +} + +struct type_converter_fpt { + template + fpt64 operator()(const T& that) const { + return static_cast(that); + } + + template + fpt64 operator()(const extended_int& that) const { + return that.d(); + } + + fpt64 operator()(const extended_exponent_fpt& that) const { + return that.d(); + } +}; + +struct type_converter_efpt { + template + extended_exponent_fpt operator()(const extended_int& that) const { + std::pair p = that.p(); + return extended_exponent_fpt(p.first, p.second); + } +}; + +// Voronoi coordinate type traits make it possible to extend algorithm +// input coordinate range to any user provided integer type and algorithm +// output coordinate range to any ieee-754 like floating point type. +template +struct voronoi_ctype_traits; + +template <> +struct voronoi_ctype_traits { + typedef int32 int_type; + typedef int64 int_x2_type; + typedef uint64 uint_x2_type; + typedef extended_int<64> big_int_type; + typedef fpt64 fpt_type; + typedef extended_exponent_fpt efpt_type; + typedef ulp_comparison ulp_cmp_type; + typedef type_converter_fpt to_fpt_converter_type; + typedef type_converter_efpt to_efpt_converter_type; +}; +} // detail +} // polygon +} // boost + +#endif // BOOST_POLYGON_DETAIL_VORONOI_CTYPES diff --git a/include/boost/polygon/detail/voronoi_predicates.hpp b/include/boost/polygon/detail/voronoi_predicates.hpp new file mode 100644 index 0000000..a1a3fad --- /dev/null +++ b/include/boost/polygon/detail/voronoi_predicates.hpp @@ -0,0 +1,1520 @@ +// Boost.Polygon library detail/voronoi_predicates.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_DETAIL_VORONOI_PREDICATES +#define BOOST_POLYGON_DETAIL_VORONOI_PREDICATES + +#include + +#include "voronoi_robust_fpt.hpp" + +namespace boost { +namespace polygon { +namespace detail { + +// Predicate utilities. Operates with the coordinate types that could +// be converted to the 32-bit signed integer without precision loss. +template +class voronoi_predicates { + public: + typedef typename CTYPE_TRAITS::int_type int_type; + typedef typename CTYPE_TRAITS::int_x2_type int_x2_type; + typedef typename CTYPE_TRAITS::uint_x2_type uint_x2_type; + typedef typename CTYPE_TRAITS::big_int_type big_int_type; + typedef typename CTYPE_TRAITS::fpt_type fpt_type; + typedef typename CTYPE_TRAITS::efpt_type efpt_type; + typedef typename CTYPE_TRAITS::ulp_cmp_type ulp_cmp_type; + typedef typename CTYPE_TRAITS::to_fpt_converter_type to_fpt_converter; + typedef typename CTYPE_TRAITS::to_efpt_converter_type to_efpt_converter; + + enum { + ULPS = 64, + ULPSx2 = 128 + }; + + template + static bool is_vertical(const Point& point1, const Point& point2) { + return point1.x() == point2.x(); + } + + template + static bool is_vertical(const Site& site) { + return is_vertical(site.point0(), site.point1()); + } + + // Compute robust cross_product: a1 * b2 - b1 * a2. + // It was mathematically proven that the result is correct + // with epsilon relative error equal to 1EPS. + static fpt_type robust_cross_product(int_x2_type a1_, + int_x2_type b1_, + int_x2_type a2_, + int_x2_type b2_) { + static to_fpt_converter to_fpt; + uint_x2_type a1 = static_cast(is_neg(a1_) ? -a1_ : a1_); + uint_x2_type b1 = static_cast(is_neg(b1_) ? -b1_ : b1_); + uint_x2_type a2 = static_cast(is_neg(a2_) ? -a2_ : a2_); + uint_x2_type b2 = static_cast(is_neg(b2_) ? -b2_ : b2_); + + uint_x2_type l = a1 * b2; + uint_x2_type r = b1 * a2; + + if (is_neg(a1_) ^ is_neg(b2_)) { + if (is_neg(a2_) ^ is_neg(b1_)) + return (l > r) ? -to_fpt(l - r) : to_fpt(r - l); + else + return -to_fpt(l + r); + } else { + if (is_neg(a2_) ^ is_neg(b1_)) + return to_fpt(l + r); + else + return (l < r) ? -to_fpt(r - l) : to_fpt(l - r); + } + } + + typedef struct orientation_test { + public: + // Represents orientation test result. + enum Orientation { + RIGHT = -1, + COLLINEAR = 0, + LEFT = 1 + }; + + // Value is a determinant of two vectors (e.g. x1 * y2 - x2 * y1). + // Return orientation based on the sign of the determinant. + template + static Orientation eval(T value) { + if (is_zero(value)) return COLLINEAR; + return (is_neg(value)) ? RIGHT : LEFT; + } + + static Orientation eval(int_x2_type dif_x1_, + int_x2_type dif_y1_, + int_x2_type dif_x2_, + int_x2_type dif_y2_) { + return eval(robust_cross_product(dif_x1_, dif_y1_, dif_x2_, dif_y2_)); + } + + template + static Orientation eval(const Point& point1, + const Point& point2, + const Point& point3) { + int_x2_type dx1 = static_cast(point1.x()) - + static_cast(point2.x()); + int_x2_type dx2 = static_cast(point2.x()) - + static_cast(point3.x()); + int_x2_type dy1 = static_cast(point1.y()) - + static_cast(point2.y()); + int_x2_type dy2 = static_cast(point2.y()) - + static_cast(point3.y()); + return eval(robust_cross_product(dx1, dy1, dx2, dy2)); + } + } ot; + + template + class point_comparison_predicate { + public: + typedef Point point_type; + + bool operator()(const point_type& lhs, const point_type& rhs) const { + if (lhs.x() == rhs.x()) + return lhs.y() < rhs.y(); + return lhs.x() < rhs.x(); + } + }; + + template + class event_comparison_predicate { + public: + typedef Site site_type; + typedef Circle circle_type; + + bool operator()(const site_type& lhs, const site_type& rhs) const { + if (lhs.x0() != rhs.x0()) + return lhs.x0() < rhs.x0(); + if (!lhs.is_segment()) { + if (!rhs.is_segment()) + return lhs.y0() < rhs.y0(); + if (is_vertical(rhs)) + return lhs.y0() <= rhs.y0(); + return true; + } else { + if (is_vertical(rhs)) { + if (is_vertical(lhs)) + return lhs.y0() < rhs.y0(); + return false; + } + if (is_vertical(lhs)) + return true; + if (lhs.y0() != rhs.y0()) + return lhs.y0() < rhs.y0(); + return ot::eval(lhs.point1(), lhs.point0(), rhs.point1()) == ot::LEFT; + } + } + + bool operator()(const site_type& lhs, const circle_type& rhs) const { + typename ulp_cmp_type::Result xCmp = + ulp_cmp(to_fpt(lhs.x()), to_fpt(rhs.lower_x()), ULPS); + if (xCmp != ulp_cmp_type::EQUAL) + return xCmp == ulp_cmp_type::LESS; + typename ulp_cmp_type::Result yCmp = + ulp_cmp(to_fpt(lhs.y()), to_fpt(rhs.lower_y()), ULPS); + return yCmp == ulp_cmp_type::LESS; + } + + bool operator()(const circle_type& lhs, const site_type& rhs) const { + typename ulp_cmp_type::Result xCmp = + ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x()), ULPS); + if (xCmp != ulp_cmp_type::EQUAL) + return xCmp == ulp_cmp_type::LESS; + typename ulp_cmp_type::Result yCmp = + ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y()), ULPS); + return yCmp == ulp_cmp_type::LESS; + } + + bool operator()(const circle_type& lhs, const circle_type& rhs) const { + typename ulp_cmp_type::Result xCmp = + ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.lower_x()), ULPSx2); + if (xCmp != ulp_cmp_type::EQUAL) + return xCmp == ulp_cmp_type::LESS; + typename ulp_cmp_type::Result yCmp = + ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.lower_y()), ULPSx2); + return yCmp == ulp_cmp_type::LESS; + } + + private: + ulp_cmp_type ulp_cmp; + to_fpt_converter to_fpt; + }; + + template + class distance_predicate { + public: + typedef Site site_type; + + // Returns true if a horizontal line going through a new site intersects + // right arc at first, else returns false. If horizontal line goes + // through intersection point of the given two arcs returns false also. + bool operator()(const site_type& left_site, + const site_type& right_site, + const site_type& new_site) const { + if (!left_site.is_segment()) { + if (!right_site.is_segment()) { + return pp(left_site, right_site, new_site); + } else { + return ps(left_site, right_site, new_site, false); + } + } else { + if (!right_site.is_segment()) { + return ps(right_site, left_site, new_site, true); + } else { + return ss(left_site, right_site, new_site); + } + } + } + + private: + // Represents the result of the epsilon robust predicate. If the + // result is undefined some further processing is usually required. + enum kPredicateResult { + LESS = -1, + UNDEFINED = 0, + MORE = 1 + }; + + typedef typename Site::point_type point_type; + + // Robust predicate, avoids using high-precision libraries. + // Returns true if a horizontal line going through the new point site + // intersects right arc at first, else returns false. If horizontal line + // goes through intersection point of the given two arcs returns false. + bool pp(const site_type& left_site, + const site_type& right_site, + const site_type& new_site) const { + const point_type& left_point = left_site.point0(); + const point_type& right_point = right_site.point0(); + const point_type& new_point = new_site.point0(); + if (left_point.x() > right_point.x()) { + if (new_point.y() <= left_point.y()) + return false; + } else if (left_point.x() < right_point.x()) { + if (new_point.y() >= right_point.y()) + return true; + } else { + return static_cast(left_point.y()) + + static_cast(right_point.y()) < + static_cast(new_point.y()) * 2; + } + + fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); + fpt_type dist2 = find_distance_to_point_arc(right_site, new_point); + + // The undefined ulp range is equal to 3EPS + 3EPS <= 6ULP. + return dist1 < dist2; + } + + bool ps(const site_type& left_site, const site_type& right_site, + const site_type& new_site, bool reverse_order) const { + kPredicateResult fast_res = fast_ps( + left_site, right_site, new_site, reverse_order); + if (fast_res != UNDEFINED) + return (fast_res == LESS); + + fpt_type dist1 = find_distance_to_point_arc( + left_site, new_site.point0()); + fpt_type dist2 = find_distance_to_segment_arc( + right_site, new_site.point0()); + + // The undefined ulp range is equal to 3EPS + 7EPS <= 10ULP. + return reverse_order ^ (dist1 < dist2); + } + + bool ss(const site_type& left_site, + const site_type& right_site, + const site_type& new_site) const { + // Handle temporary segment sites. + if (left_site.point0() == right_site.point0() && + left_site.point1() == right_site.point1()) { + return ot::eval(left_site.point0(), + left_site.point1(), + new_site.point0()) == ot::LEFT; + } + + fpt_type dist1 = find_distance_to_segment_arc( + left_site, new_site.point0()); + fpt_type dist2 = find_distance_to_segment_arc( + right_site, new_site.point0()); + + // The undefined ulp range is equal to 7EPS + 7EPS <= 14ULP. + return dist1 < dist2; + } + + fpt_type find_distance_to_point_arc( + const site_type& site, const point_type& point) const { + fpt_type dx = to_fpt(site.x()) - to_fpt(point.x()); + fpt_type dy = to_fpt(site.y()) - to_fpt(point.y()); + // The relative error is at most 3EPS. + return (dx * dx + dy * dy) / (to_fpt(2.0) * dx); + } + + fpt_type find_distance_to_segment_arc( + const site_type& site, const point_type& point) const { + if (is_vertical(site)) { + return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5); + } else { + const point_type& segment0 = site.point0(true); + const point_type& segment1 = site.point1(true); + fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x()); + fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y()); + fpt_type k = get_sqrt(a1 * a1 + b1 * b1); + // Avoid subtraction while computing k. + if (!is_neg(b1)) { + k = to_fpt(1.0) / (b1 + k); + } else { + k = (k - b1) / (a1 * a1); + } + // The relative error is at most 7EPS. + return k * robust_cross_product( + static_cast(segment1.x()) - + static_cast(segment0.x()), + static_cast(segment1.y()) - + static_cast(segment0.y()), + static_cast(point.x()) - + static_cast(segment0.x()), + static_cast(point.y()) - + static_cast(segment0.y())); + } + } + + kPredicateResult fast_ps( + const site_type& left_site, const site_type& right_site, + const site_type& new_site, bool reverse_order) const { + const point_type& site_point = left_site.point0(); + const point_type& segment_start = right_site.point0(true); + const point_type& segment_end = right_site.point1(true); + const point_type& new_point = new_site.point0(); + + if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT) + return (!right_site.is_inverse()) ? LESS : MORE; + + fpt_type dif_x = to_fpt(new_point.x()) - to_fpt(site_point.x()); + fpt_type dif_y = to_fpt(new_point.y()) - to_fpt(site_point.y()); + fpt_type a = to_fpt(segment_end.x()) - to_fpt(segment_start.x()); + fpt_type b = to_fpt(segment_end.y()) - to_fpt(segment_start.y()); + + if (is_vertical(right_site)) { + if (new_point.y() < site_point.y() && !reverse_order) + return MORE; + else if (new_point.y() > site_point.y() && reverse_order) + return LESS; + return UNDEFINED; + } else { + typename ot::Orientation orientation = ot::eval( + static_cast(segment_end.x()) - + static_cast(segment_start.x()), + static_cast(segment_end.y()) - + static_cast(segment_start.y()), + static_cast(new_point.x()) - + static_cast(site_point.x()), + static_cast(new_point.y()) - + static_cast(site_point.y())); + if (orientation == ot::LEFT) { + if (!right_site.is_inverse()) + return reverse_order ? LESS : UNDEFINED; + return reverse_order ? UNDEFINED : MORE; + } + } + + fpt_type fast_left_expr = a * (dif_y + dif_x) * (dif_y - dif_x); + fpt_type fast_right_expr = (to_fpt(2.0) * b) * dif_x * dif_y; + typename ulp_cmp_type::Result expr_cmp = + ulp_cmp(fast_left_expr, fast_right_expr, 4); + if (expr_cmp != ulp_cmp_type::EQUAL) { + if ((expr_cmp == ulp_cmp_type::MORE) ^ reverse_order) + return reverse_order ? LESS : MORE; + return UNDEFINED; + } + return UNDEFINED; + } + + private: + ulp_cmp_type ulp_cmp; + to_fpt_converter to_fpt; + }; + + template + class node_comparison_predicate { + public: + typedef Node node_type; + typedef typename Node::site_type site_type; + typedef typename site_type::coordinate_type coordinate_type; + typedef distance_predicate distance_predicate_type; + + // Compares nodes in the balanced binary search tree. Nodes are + // compared based on the y coordinates of the arcs intersection points. + // Nodes with less y coordinate of the intersection point go first. + // Comparison is only called during the new site events processing. + // That's why one of the nodes will always lie on the sweepline and may + // be represented as a straight horizontal line. + bool operator() (const node_type& node1, + const node_type& node2) const { + // Get x coordinate of the rightmost site from both nodes. + const site_type& site1 = get_comparison_site(node1); + const site_type& site2 = get_comparison_site(node2); + + if (site1.x() < site2.x()) { + // The second node contains a new site. + return predicate_(node1.left_site(), node1.right_site(), site2); + } else if (site1.x() > site2.x()) { + // The first node contains a new site. + return !predicate_(node2.left_site(), node2.right_site(), site1); + } else { + // This checks were evaluated experimentally. + if (site1.sorted_index() == site2.sorted_index()) { + // Both nodes are new (inserted during same site event processing). + return get_comparison_y(node1) < get_comparison_y(node2); + } else if (site1.sorted_index() < site2.sorted_index()) { + std::pair y1 = get_comparison_y(node1, false); + std::pair y2 = get_comparison_y(node2, true); + if (y1.first != y2.first) return y1.first < y2.first; + return (!site1.is_segment()) ? (y1.second < 0) : false; + } else { + std::pair y1 = get_comparison_y(node1, true); + std::pair y2 = get_comparison_y(node2, false); + if (y1.first != y2.first) return y1.first < y2.first; + return (!site2.is_segment()) ? (y2.second > 0) : true; + } + } + } + + private: + // Get the newer site. + const site_type& get_comparison_site(const node_type& node) const { + if (node.left_site().sorted_index() > node.right_site().sorted_index()) { + return node.left_site(); + } + return node.right_site(); + } + + // Get comparison pair: y coordinate and direction of the newer site. + std::pair get_comparison_y( + const node_type& node, bool is_new_node = true) const { + if (node.left_site().sorted_index() == + node.right_site().sorted_index()) { + return std::make_pair(node.left_site().y(), 0); + } + if (node.left_site().sorted_index() > node.right_site().sorted_index()) { + if (!is_new_node && + node.left_site().is_segment() && + is_vertical(node.left_site())) { + return std::make_pair(node.left_site().y1(), 1); + } + return std::make_pair(node.left_site().y(), 1); + } + return std::make_pair(node.right_site().y(), -1); + } + + distance_predicate_type predicate_; + }; + + template + class circle_existence_predicate { + public: + typedef typename Site::point_type point_type; + typedef Site site_type; + + bool ppp(const site_type& site1, + const site_type& site2, + const site_type& site3) const { + return ot::eval(site1.point0(), site2.point0(), site3.point0()) == + ot::RIGHT; + } + + bool pps(const site_type& site1, + const site_type& site2, + const site_type& site3, + int segment_index) const { + if (segment_index != 2) { + typename ot::Orientation orient1 = ot::eval(site1.point0(), + site2.point0(), site3.point0(true)); + typename ot::Orientation orient2 = ot::eval(site1.point0(), + site2.point0(), site3.point1(true)); + if (segment_index == 1 && site1.x0() >= site2.x0()) { + if (orient1 != ot::RIGHT) + return false; + } else if (segment_index == 3 && site2.x0() >= site1.x0()) { + if (orient2 != ot::RIGHT) + return false; + } else if (orient1 != ot::RIGHT && orient2 != ot::RIGHT) { + return false; + } + } else { + if (site3.point0(true) == site1.point0() && + site3.point1(true) == site2.point0()) + return false; + } + return true; + } + + bool pss(const site_type& site1, + const site_type& site2, + const site_type& site3, + int point_index) const { + if (site2.point0() == site3.point0() && + site2.point1() == site3.point1()) { + return false; + } + if (point_index == 2) { + if (!site2.is_inverse() && site3.is_inverse()) + return false; + if (site2.is_inverse() == site3.is_inverse() && + ot::eval(site2.point0(true), + site1.point0(), + site3.point1(true)) != ot::RIGHT) + return false; + } + return true; + } + + bool sss(const site_type& site1, + const site_type& site2, + const site_type& site3) const { + if (site1.point0() == site2.point0() && site1.point1() == site2.point1()) + return false; + if (site2.point0() == site3.point0() && site2.point1() == site3.point1()) + return false; + return true; + } + }; + + template + class mp_circle_formation_functor { + public: + typedef typename Site::point_type point_type; + typedef Site site_type; + typedef Circle circle_type; + typedef robust_sqrt_expr + robust_sqrt_expr_type; + + void ppp(const site_type& site1, + const site_type& site2, + const site_type& site3, + circle_type& circle, + bool recompute_c_x = true, + bool recompute_c_y = true, + bool recompute_lower_x = true) { + big_int_type dif_x[3], dif_y[3], sum_x[2], sum_y[2]; + dif_x[0] = static_cast(site1.x()) - + static_cast(site2.x()); + dif_x[1] = static_cast(site2.x()) - + static_cast(site3.x()); + dif_x[2] = static_cast(site1.x()) - + static_cast(site3.x()); + dif_y[0] = static_cast(site1.y()) - + static_cast(site2.y()); + dif_y[1] = static_cast(site2.y()) - + static_cast(site3.y()); + dif_y[2] = static_cast(site1.y()) - + static_cast(site3.y()); + sum_x[0] = static_cast(site1.x()) + + static_cast(site2.x()); + sum_x[1] = static_cast(site2.x()) + + static_cast(site3.x()); + sum_y[0] = static_cast(site1.y()) + + static_cast(site2.y()); + sum_y[1] = static_cast(site2.y()) + + static_cast(site3.y()); + fpt_type inv_denom = to_fpt(0.5) / to_fpt(static_cast( + dif_x[0] * dif_y[1] - dif_x[1] * dif_y[0])); + big_int_type numer1 = dif_x[0] * sum_x[0] + dif_y[0] * sum_y[0]; + big_int_type numer2 = dif_x[1] * sum_x[1] + dif_y[1] * sum_y[1]; + + if (recompute_c_x || recompute_lower_x) { + big_int_type c_x = numer1 * dif_y[1] - numer2 * dif_y[0]; + circle.x(to_fpt(c_x) * inv_denom); + + if (recompute_lower_x) { + // Evaluate radius of the circle. + big_int_type sqr_r = (dif_x[0] * dif_x[0] + dif_y[0] * dif_y[0]) * + (dif_x[1] * dif_x[1] + dif_y[1] * dif_y[1]) * + (dif_x[2] * dif_x[2] + dif_y[2] * dif_y[2]); + fpt_type r = get_sqrt(to_fpt(sqr_r)); + + // If c_x >= 0 then lower_x = c_x + r, + // else lower_x = (c_x * c_x - r * r) / (c_x - r). + // To guarantee epsilon relative error. + if (!is_neg(circle.x())) { + if (!is_neg(inv_denom)) { + circle.lower_x(circle.x() + r * inv_denom); + } else { + circle.lower_x(circle.x() - r * inv_denom); + } + } else { + big_int_type numer = c_x * c_x - sqr_r; + fpt_type lower_x = to_fpt(numer) * inv_denom / (to_fpt(c_x) + r); + circle.lower_x(lower_x); + } + } + } + + if (recompute_c_y) { + big_int_type c_y = numer2 * dif_x[0] - numer1 * dif_x[1]; + circle.y(to_fpt(c_y) * inv_denom); + } + } + + // Recompute parameters of the circle event using high-precision library. + void pps(const site_type& site1, + const site_type& site2, + const site_type& site3, + int segment_index, + circle_type& c_event, + bool recompute_c_x = true, + bool recompute_c_y = true, + bool recompute_lower_x = true) { + big_int_type cA[4], cB[4]; + big_int_type line_a = static_cast(site3.point1(true).y()) - + static_cast(site3.point0(true).y()); + big_int_type line_b = static_cast(site3.point0(true).x()) - + static_cast(site3.point1(true).x()); + big_int_type segm_len = line_a * line_a + line_b * line_b; + big_int_type vec_x = static_cast(site2.y()) - + static_cast(site1.y()); + big_int_type vec_y = static_cast(site1.x()) - + static_cast(site2.x()); + big_int_type sum_x = static_cast(site1.x()) + + static_cast(site2.x()); + big_int_type sum_y = static_cast(site1.y()) + + static_cast(site2.y()); + big_int_type teta = line_a * vec_x + line_b * vec_y; + big_int_type denom = vec_x * line_b - vec_y * line_a; + + big_int_type dif0 = static_cast(site3.point1().y()) - + static_cast(site1.y()); + big_int_type dif1 = static_cast(site1.x()) - + static_cast(site3.point1().x()); + big_int_type A = line_a * dif1 - line_b * dif0; + dif0 = static_cast(site3.point1().y()) - + static_cast(site2.y()); + dif1 = static_cast(site2.x()) - + static_cast(site3.point1().x()); + big_int_type B = line_a * dif1 - line_b * dif0; + big_int_type sum_AB = A + B; + + if (is_zero(denom)) { + big_int_type numer = teta * teta - sum_AB * sum_AB; + big_int_type denom = teta * sum_AB; + cA[0] = denom * sum_x * 2 + numer * vec_x; + cB[0] = segm_len; + cA[1] = denom * sum_AB * 2 + numer * teta; + cB[1] = 1; + cA[2] = denom * sum_y * 2 + numer * vec_y; + fpt_type inv_denom = to_fpt(1.0) / to_fpt(denom); + if (recompute_c_x) + c_event.x(to_fpt(0.25) * to_fpt(cA[0]) * inv_denom); + if (recompute_c_y) + c_event.y(to_fpt(0.25) * to_fpt(cA[2]) * inv_denom); + if (recompute_lower_x) { + c_event.lower_x(to_fpt(0.25) * to_fpt(sqrt_expr_.eval2(cA, cB)) * + inv_denom / get_sqrt(to_fpt(segm_len))); + } + return; + } + + big_int_type det = (teta * teta + denom * denom) * A * B * 4; + fpt_type inv_denom_sqr = to_fpt(1.0) / to_fpt(denom); + inv_denom_sqr *= inv_denom_sqr; + + if (recompute_c_x || recompute_lower_x) { + cA[0] = sum_x * denom * denom + teta * sum_AB * vec_x; + cB[0] = 1; + cA[1] = (segment_index == 2) ? -vec_x : vec_x; + cB[1] = det; + if (recompute_c_x) { + c_event.x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(cA, cB)) * + inv_denom_sqr); + } + } + + if (recompute_c_y || recompute_lower_x) { + cA[2] = sum_y * denom * denom + teta * sum_AB * vec_y; + cB[2] = 1; + cA[3] = (segment_index == 2) ? -vec_y : vec_y; + cB[3] = det; + if (recompute_c_y) { + c_event.y(to_fpt(0.5) * to_fpt(sqrt_expr_.eval2(&cA[2], &cB[2])) * + inv_denom_sqr); + } + } + + if (recompute_lower_x) { + cB[0] = cB[0] * segm_len; + cB[1] = cB[1] * segm_len; + cA[2] = sum_AB * (denom * denom + teta * teta); + cB[2] = 1; + cA[3] = (segment_index == 2) ? -teta : teta; + cB[3] = det; + c_event.lower_x(to_fpt(0.5) * to_fpt(sqrt_expr_.eval4(cA, cB)) * + inv_denom_sqr / get_sqrt(to_fpt(segm_len))); + } + } + + // Recompute parameters of the circle event using high-precision library. + void pss(const site_type& site1, + const site_type& site2, + const site_type& site3, + int point_index, + circle_type& c_event, + bool recompute_c_x = true, + bool recompute_c_y = true, + bool recompute_lower_x = true) { + big_int_type a[2], b[2], c[2], cA[4], cB[4]; + const point_type& segm_start1 = site2.point1(true); + const point_type& segm_end1 = site2.point0(true); + const point_type& segm_start2 = site3.point0(true); + const point_type& segm_end2 = site3.point1(true); + a[0] = static_cast(segm_end1.x()) - + static_cast(segm_start1.x()); + b[0] = static_cast(segm_end1.y()) - + static_cast(segm_start1.y()); + a[1] = static_cast(segm_end2.x()) - + static_cast(segm_start2.x()); + b[1] = static_cast(segm_end2.y()) - + static_cast(segm_start2.y()); + big_int_type orientation = a[1] * b[0] - a[0] * b[1]; + if (is_zero(orientation)) { + fpt_type denom = to_fpt(2.0) * to_fpt( + static_cast(a[0] * a[0] + b[0] * b[0])); + c[0] = b[0] * (static_cast(segm_start2.x()) - + static_cast(segm_start1.x())) - + a[0] * (static_cast(segm_start2.y()) - + static_cast(segm_start1.y())); + big_int_type dx = a[0] * (static_cast(site1.y()) - + static_cast(segm_start1.y())) - + b[0] * (static_cast(site1.x()) - + static_cast(segm_start1.x())); + big_int_type dy = b[0] * (static_cast(site1.x()) - + static_cast(segm_start2.x())) - + a[0] * (static_cast(site1.y()) - + static_cast(segm_start2.y())); + cB[0] = dx * dy; + cB[1] = 1; + + if (recompute_c_y) { + cA[0] = b[0] * ((point_index == 2) ? 2 : -2); + cA[1] = a[0] * a[0] * (static_cast(segm_start1.y()) + + static_cast(segm_start2.y())) - + a[0] * b[0] * (static_cast(segm_start1.x()) + + static_cast(segm_start2.x()) - + static_cast(site1.x()) * 2) + + b[0] * b[0] * (static_cast(site1.y()) * 2); + fpt_type c_y = to_fpt(sqrt_expr_.eval2(cA, cB)); + c_event.y(c_y / denom); + } + + if (recompute_c_x || recompute_lower_x) { + cA[0] = a[0] * ((point_index == 2) ? 2 : -2); + cA[1] = b[0] * b[0] * (static_cast(segm_start1.x()) + + static_cast(segm_start2.x())) - + a[0] * b[0] * (static_cast(segm_start1.y()) + + static_cast(segm_start2.y()) - + static_cast(site1.y()) * 2) + + a[0] * a[0] * (static_cast(site1.x()) * 2); + + if (recompute_c_x) { + fpt_type c_x = to_fpt(sqrt_expr_.eval2(cA, cB)); + c_event.x(c_x / denom); + } + + if (recompute_lower_x) { + cA[2] = is_neg(c[0]) ? -c[0] : c[0]; + cB[2] = a[0] * a[0] + b[0] * b[0]; + fpt_type lower_x = to_fpt(sqrt_expr_.eval3(cA, cB)); + c_event.lower_x(lower_x / denom); + } + } + return; + } + c[0] = b[0] * segm_end1.x() - a[0] * segm_end1.y(); + c[1] = a[1] * segm_end2.y() - b[1] * segm_end2.x(); + big_int_type ix = a[0] * c[1] + a[1] * c[0]; + big_int_type iy = b[0] * c[1] + b[1] * c[0]; + big_int_type dx = ix - orientation * site1.x(); + big_int_type dy = iy - orientation * site1.y(); + if (is_zero(dx) && is_zero(dy)) { + fpt_type denom = to_fpt(orientation); + fpt_type c_x = to_fpt(ix) / denom; + fpt_type c_y = to_fpt(iy) / denom; + c_event = circle_type(c_x, c_y, c_x); + return; + } + + big_int_type sign = ((point_index == 2) ? 1 : -1) * + (is_neg(orientation) ? 1 : -1); + cA[0] = a[1] * -dx + b[1] * -dy; + cA[1] = a[0] * -dx + b[0] * -dy; + cA[2] = sign; + cA[3] = 0; + cB[0] = a[0] * a[0] + b[0] * b[0]; + cB[1] = a[1] * a[1] + b[1] * b[1]; + cB[2] = a[0] * a[1] + b[0] * b[1]; + cB[3] = (a[0] * dy - b[0] * dx) * (a[1] * dy - b[1] * dx) * -2; + fpt_type temp = to_fpt( + sqrt_expr_evaluator_pss4(cA, cB)); + fpt_type denom = temp * to_fpt(orientation); + + if (recompute_c_y) { + cA[0] = b[1] * (dx * dx + dy * dy) - iy * (dx * a[1] + dy * b[1]); + cA[1] = b[0] * (dx * dx + dy * dy) - iy * (dx * a[0] + dy * b[0]); + cA[2] = iy * sign; + fpt_type cy = to_fpt( + sqrt_expr_evaluator_pss4(cA, cB)); + c_event.y(cy / denom); + } + + if (recompute_c_x || recompute_lower_x) { + cA[0] = a[1] * (dx * dx + dy * dy) - ix * (dx * a[1] + dy * b[1]); + cA[1] = a[0] * (dx * dx + dy * dy) - ix * (dx * a[0] + dy * b[0]); + cA[2] = ix * sign; + + if (recompute_c_x) { + fpt_type cx = to_fpt( + sqrt_expr_evaluator_pss4(cA, cB)); + c_event.x(cx / denom); + } + + if (recompute_lower_x) { + cA[3] = orientation * (dx * dx + dy * dy) * (is_neg(temp) ? -1 : 1); + fpt_type lower_x = to_fpt( + sqrt_expr_evaluator_pss4(cA, cB)); + c_event.lower_x(lower_x / denom); + } + } + } + + // Recompute parameters of the circle event using high-precision library. + void sss(const site_type& site1, + const site_type& site2, + const site_type& site3, + circle_type& c_event, + bool recompute_c_x = true, + bool recompute_c_y = true, + bool recompute_lower_x = true) { + big_int_type a[3], b[3], c[3], cA[4], cB[4]; + // cA - corresponds to the cross product. + // cB - corresponds to the squared length. + a[0] = static_cast(site1.x1(true)) - + static_cast(site1.x0(true)); + a[1] = static_cast(site2.x1(true)) - + static_cast(site2.x0(true)); + a[2] = static_cast(site3.x1(true)) - + static_cast(site3.x0(true)); + + b[0] = static_cast(site1.y1(true)) - + static_cast(site1.y0(true)); + b[1] = static_cast(site2.y1(true)) - + static_cast(site2.y0(true)); + b[2] = static_cast(site3.y1(true)) - + static_cast(site3.y0(true)); + + c[0] = static_cast(site1.x0(true)) * + static_cast(site1.y1(true)) - + static_cast(site1.y0(true)) * + static_cast(site1.x1(true)); + c[1] = static_cast(site2.x0(true)) * + static_cast(site2.y1(true)) - + static_cast(site2.y0(true)) * + static_cast(site2.x1(true)); + c[2] = static_cast(site3.x0(true)) * + static_cast(site3.y1(true)) - + static_cast(site3.y0(true)) * + static_cast(site3.x1(true)); + + for (int i = 0; i < 3; ++i) + cB[i] = a[i] * a[i] + b[i] * b[i]; + + for (int i = 0; i < 3; ++i) { + int j = (i+1) % 3; + int k = (i+2) % 3; + cA[i] = a[j] * b[k] - a[k] * b[j]; + } + fpt_type denom = to_fpt(sqrt_expr_.eval3(cA, cB)); + + if (recompute_c_y) { + for (int i = 0; i < 3; ++i) { + int j = (i+1) % 3; + int k = (i+2) % 3; + cA[i] = b[j] * c[k] - b[k] * c[j]; + } + fpt_type c_y = to_fpt(sqrt_expr_.eval3(cA, cB)); + c_event.y(c_y / denom); + } + + if (recompute_c_x || recompute_lower_x) { + cA[3] = 0; + for (int i = 0; i < 3; ++i) { + int j = (i+1) % 3; + int k = (i+2) % 3; + cA[i] = a[j] * c[k] - a[k] * c[j]; + if (recompute_lower_x) { + cA[3] = cA[3] + cA[i] * b[i]; + } + } + + if (recompute_c_x) { + fpt_type c_x = to_fpt(sqrt_expr_.eval3(cA, cB)); + c_event.x(c_x / denom); + } + + if (recompute_lower_x) { + cB[3] = 1; + fpt_type lower_x = to_fpt(sqrt_expr_.eval4(cA, cB)); + c_event.lower_x(lower_x / denom); + } + } + } + + private: + // Evaluates A[3] + A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + + // A[2] * sqrt(B[3] * (sqrt(B[0] * B[1]) + B[2])). + template + _fpt sqrt_expr_evaluator_pss4(_int *A, _int *B) { + _int cA[4], cB[4]; + if (is_zero(A[3])) { + _fpt lh = sqrt_expr_.eval2(A, B); + cA[0] = 1; + cB[0] = B[0] * B[1]; + cA[1] = B[2]; + cB[1] = 1; + _fpt rh = sqrt_expr_.eval1(A+2, B+3) * + get_sqrt(sqrt_expr_.eval2(cA, cB)); + if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) + return lh + rh; + cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - + A[2] * A[2] * B[3] * B[2]; + cB[0] = 1; + cA[1] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; + cB[1] = B[0] * B[1]; + _fpt numer = sqrt_expr_.eval2(cA, cB); + return numer / (lh - rh); + } + cA[0] = 1; + cB[0] = B[0] * B[1]; + cA[1] = B[2]; + cB[1] = 1; + _fpt rh = sqrt_expr_.eval1(A+2, B+3) * get_sqrt(sqrt_expr_.eval2(cA, cB)); + cA[0] = A[0]; + cB[0] = B[0]; + cA[1] = A[1]; + cB[1] = B[1]; + cA[2] = A[3]; + cB[2] = 1; + _fpt lh = sqrt_expr_.eval3(cA, cB); + if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) + return lh + rh; + cA[0] = A[3] * A[0] * 2; + cA[1] = A[3] * A[1] * 2; + cA[2] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] + + A[3] * A[3] - A[2] * A[2] * B[2] * B[3]; + cA[3] = A[0] * A[1] * 2 - A[2] * A[2] * B[3]; + cB[3] = B[0] * B[1]; + _fpt numer = sqrt_expr_evaluator_pss3<_int, _fpt>(cA, cB); + return numer / (lh - rh); + } + + template + // Evaluates A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + + // A[2] + A[3] * sqrt(B[0] * B[1]). + // B[3] = B[0] * B[1]. + _fpt sqrt_expr_evaluator_pss3(_int *A, _int *B) { + _int cA[2], cB[2]; + _fpt lh = sqrt_expr_.eval2(A, B); + _fpt rh = sqrt_expr_.eval2(A+2, B+2); + if ((!is_neg(lh) && !is_neg(rh)) || (!is_pos(lh) && !is_pos(rh))) + return lh + rh; + cA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - + A[2] * A[2] - A[3] * A[3] * B[0] * B[1]; + cB[0] = 1; + cA[1] = (A[0] * A[1] - A[2] * A[3]) * 2; + cB[1] = B[3]; + _fpt numer = sqrt_expr_.eval2(cA, cB); + return numer / (lh - rh); + } + + robust_sqrt_expr_type sqrt_expr_; + to_fpt_converter to_fpt; + }; + + template + class lazy_circle_formation_functor { + public: + typedef robust_fpt robust_fpt_type; + typedef robust_dif robust_dif_type; + typedef typename Site::point_type point_type; + typedef Site site_type; + typedef Circle circle_type; + typedef mp_circle_formation_functor + exact_circle_formation_functor_type; + + void ppp(const site_type& site1, + const site_type& site2, + const site_type& site3, + circle_type& c_event) { + fpt_type dif_x1 = to_fpt(site1.x()) - to_fpt(site2.x()); + fpt_type dif_x2 = to_fpt(site2.x()) - to_fpt(site3.x()); + fpt_type dif_y1 = to_fpt(site1.y()) - to_fpt(site2.y()); + fpt_type dif_y2 = to_fpt(site2.y()) - to_fpt(site3.y()); + fpt_type orientation = robust_cross_product( + static_cast(site1.x()) - + static_cast(site2.x()), + static_cast(site2.x()) - + static_cast(site3.x()), + static_cast(site1.y()) - + static_cast(site2.y()), + static_cast(site2.y()) - + static_cast(site3.y())); + robust_fpt_type inv_orientation(to_fpt(0.5) / orientation, to_fpt(2.0)); + fpt_type sum_x1 = to_fpt(site1.x()) + to_fpt(site2.x()); + fpt_type sum_x2 = to_fpt(site2.x()) + to_fpt(site3.x()); + fpt_type sum_y1 = to_fpt(site1.y()) + to_fpt(site2.y()); + fpt_type sum_y2 = to_fpt(site2.y()) + to_fpt(site3.y()); + fpt_type dif_x3 = to_fpt(site1.x()) - to_fpt(site3.x()); + fpt_type dif_y3 = to_fpt(site1.y()) - to_fpt(site3.y()); + robust_dif_type c_x, c_y; + c_x += robust_fpt_type(dif_x1 * sum_x1 * dif_y2, to_fpt(2.0)); + c_x += robust_fpt_type(dif_y1 * sum_y1 * dif_y2, to_fpt(2.0)); + c_x -= robust_fpt_type(dif_x2 * sum_x2 * dif_y1, to_fpt(2.0)); + c_x -= robust_fpt_type(dif_y2 * sum_y2 * dif_y1, to_fpt(2.0)); + c_y += robust_fpt_type(dif_x2 * sum_x2 * dif_x1, to_fpt(2.0)); + c_y += robust_fpt_type(dif_y2 * sum_y2 * dif_x1, to_fpt(2.0)); + c_y -= robust_fpt_type(dif_x1 * sum_x1 * dif_x2, to_fpt(2.0)); + c_y -= robust_fpt_type(dif_y1 * sum_y1 * dif_x2, to_fpt(2.0)); + robust_dif_type lower_x(c_x); + lower_x -= robust_fpt_type(get_sqrt( + (dif_x1 * dif_x1 + dif_y1 * dif_y1) * + (dif_x2 * dif_x2 + dif_y2 * dif_y2) * + (dif_x3 * dif_x3 + dif_y3 * dif_y3)), to_fpt(5.0)); + c_event = circle_type( + c_x.dif().fpv() * inv_orientation.fpv(), + c_y.dif().fpv() * inv_orientation.fpv(), + lower_x.dif().fpv() * inv_orientation.fpv()); + bool recompute_c_x = c_x.dif().ulp() > ULPS; + bool recompute_c_y = c_y.dif().ulp() > ULPS; + bool recompute_lower_x = lower_x.dif().ulp() > ULPS; + if (recompute_c_x || recompute_c_y || recompute_lower_x) { + exact_circle_formation_functor_.ppp( + site1, site2, site3, c_event, + recompute_c_x, recompute_c_y, recompute_lower_x); + } + } + + void pps(const site_type& site1, + const site_type& site2, + const site_type& site3, + int segment_index, + circle_type& c_event) { + fpt_type line_a = to_fpt(site3.point1(true).y()) - + to_fpt(site3.point0(true).y()); + fpt_type line_b = to_fpt(site3.point0(true).x()) - + to_fpt(site3.point1(true).x()); + fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y()); + fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x()); + robust_fpt_type teta(robust_cross_product( + static_cast(site3.point1(true).y()) - + static_cast(site3.point0(true).y()), + static_cast(site3.point0(true).x()) - + static_cast(site3.point1(true).x()), + static_cast(site2.x()) - + static_cast(site1.x()), + static_cast(site2.y()) - + static_cast(site1.y())), to_fpt(1.0)); + robust_fpt_type A(robust_cross_product( + static_cast(site3.point1(true).y()) - + static_cast(site3.point0(true).y()), + static_cast(site3.point0(true).x()) - + static_cast(site3.point1(true).x()), + static_cast(site3.point1().y()) - + static_cast(site1.y()), + static_cast(site1.x()) - + static_cast(site3.point1().x())), to_fpt(1.0)); + robust_fpt_type B(robust_cross_product( + static_cast(site3.point1(true).y()) - + static_cast(site3.point0(true).y()), + static_cast(site3.point0(true).x()) - + static_cast(site3.point1(true).x()), + static_cast(site3.point1().y()) - + static_cast(site2.y()), + static_cast(site2.x()) - + static_cast(site3.point1().x())), to_fpt(1.0)); + robust_fpt_type denom(robust_cross_product( + static_cast(site2.y()) - + static_cast(site1.y()), + static_cast(site1.x()) - + static_cast(site2.x()), + static_cast(site3.point1(true).y()) - + static_cast(site3.point0(true).y()), + static_cast(site3.point0(true).x()) - + static_cast(site3.point1(true).x())), to_fpt(1.0)); + robust_fpt_type inv_segm_len(to_fpt(1.0) / + get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0)); + robust_dif_type t; + if (ot::eval(denom) == ot::COLLINEAR) { + t += teta / (robust_fpt_type(to_fpt(8.0)) * A); + t -= A / (robust_fpt_type(to_fpt(2.0)) * teta); + } else { + robust_fpt_type det = ((teta * teta + denom * denom) * A * B).sqrt(); + if (segment_index == 2) { + t -= det / (denom * denom); + } else { + t += det / (denom * denom); + } + t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom); + } + robust_dif_type c_x, c_y; + c_x += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.x()) + + to_fpt(site2.x()))); + c_x += robust_fpt_type(vec_x) * t; + c_y += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.y()) + + to_fpt(site2.y()))); + c_y += robust_fpt_type(vec_y) * t; + robust_dif_type r, lower_x(c_x); + r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0()); + r -= robust_fpt_type(line_b) * robust_fpt_type(site3.y0()); + r += robust_fpt_type(line_a) * c_x; + r += robust_fpt_type(line_b) * c_y; + if (r.pos().fpv() < r.neg().fpv()) + r = -r; + lower_x += r * inv_segm_len; + c_event = circle_type( + c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); + bool recompute_c_x = c_x.dif().ulp() > ULPS; + bool recompute_c_y = c_y.dif().ulp() > ULPS; + bool recompute_lower_x = lower_x.dif().ulp() > ULPS; + if (recompute_c_x || recompute_c_y || recompute_lower_x) { + exact_circle_formation_functor_.pps( + site1, site2, site3, segment_index, c_event, + recompute_c_x, recompute_c_y, recompute_lower_x); + } + } + + void pss(const site_type& site1, + const site_type& site2, + const site_type& site3, + int point_index, + circle_type& c_event) { + const point_type& segm_start1 = site2.point1(true); + const point_type& segm_end1 = site2.point0(true); + const point_type& segm_start2 = site3.point0(true); + const point_type& segm_end2 = site3.point1(true); + fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x()); + fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y()); + fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x()); + fpt_type b2 = to_fpt(segm_end2.y()) - to_fpt(segm_start2.y()); + bool recompute_c_x, recompute_c_y, recompute_lower_x; + robust_fpt_type orientation(robust_cross_product( + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end2.y()) - + static_cast(segm_start2.y()), + static_cast(segm_end2.x()) - + static_cast(segm_start2.x())), to_fpt(1.0)); + if (ot::eval(orientation) == ot::COLLINEAR) { + robust_fpt_type a(a1 * a1 + b1 * b1, to_fpt(2.0)); + robust_fpt_type c(robust_cross_product( + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_start2.y()) - + static_cast(segm_start1.y()), + static_cast(segm_start2.x()) - + static_cast(segm_start1.x())), to_fpt(1.0)); + robust_fpt_type det( + robust_cross_product( + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(site1.x()) - + static_cast(segm_start1.x()), + static_cast(site1.y()) - + static_cast(segm_start1.y())) * + robust_cross_product( + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(site1.y()) - + static_cast(segm_start2.y()), + static_cast(site1.x()) - + static_cast(segm_start2.x())), + to_fpt(3.0)); + robust_dif_type t; + t -= robust_fpt_type(a1) * robust_fpt_type(( + to_fpt(segm_start1.x()) + to_fpt(segm_start2.x())) * to_fpt(0.5) - + to_fpt(site1.x())); + t -= robust_fpt_type(b1) * robust_fpt_type(( + to_fpt(segm_start1.y()) + to_fpt(segm_start2.y())) * to_fpt(0.5) - + to_fpt(site1.y())); + if (point_index == 2) { + t += det.sqrt(); + } else { + t -= det.sqrt(); + } + t /= a; + robust_dif_type c_x, c_y; + c_x += robust_fpt_type(to_fpt(0.5) * ( + to_fpt(segm_start1.x()) + to_fpt(segm_start2.x()))); + c_x += robust_fpt_type(a1) * t; + c_y += robust_fpt_type(to_fpt(0.5) * ( + to_fpt(segm_start1.y()) + to_fpt(segm_start2.y()))); + c_y += robust_fpt_type(b1) * t; + robust_dif_type lower_x(c_x); + if (is_neg(c)) { + lower_x -= robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); + } else { + lower_x += robust_fpt_type(to_fpt(0.5)) * c / a.sqrt(); + } + recompute_c_x = c_x.dif().ulp() > ULPS; + recompute_c_y = c_y.dif().ulp() > ULPS; + recompute_lower_x = lower_x.dif().ulp() > ULPS; + c_event = + circle_type(c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); + } else { + robust_fpt_type sqr_sum1(get_sqrt(a1 * a1 + b1 * b1), to_fpt(2.0)); + robust_fpt_type sqr_sum2(get_sqrt(a2 * a2 + b2 * b2), to_fpt(2.0)); + robust_fpt_type a(robust_cross_product( + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_start2.y()) - + static_cast(segm_end2.y()), + static_cast(segm_end2.x()) - + static_cast(segm_start2.x())), to_fpt(1.0)); + if (!is_neg(a)) { + a += sqr_sum1 * sqr_sum2; + } else { + a = (orientation * orientation) / (sqr_sum1 * sqr_sum2 - a); + } + robust_fpt_type or1(robust_cross_product( + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end1.y()) - + static_cast(site1.y()), + static_cast(segm_end1.x()) - + static_cast(site1.x())), to_fpt(1.0)); + robust_fpt_type or2(robust_cross_product( + static_cast(segm_end2.x()) - + static_cast(segm_start2.x()), + static_cast(segm_end2.y()) - + static_cast(segm_start2.y()), + static_cast(segm_end2.x()) - + static_cast(site1.x()), + static_cast(segm_end2.y()) - + static_cast(site1.y())), to_fpt(1.0)); + robust_fpt_type det = robust_fpt_type(to_fpt(2.0)) * a * or1 * or2; + robust_fpt_type c1(robust_cross_product( + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end1.y()), + static_cast(segm_end1.x())), to_fpt(1.0)); + robust_fpt_type c2(robust_cross_product( + static_cast(segm_end2.x()) - + static_cast(segm_start2.x()), + static_cast(segm_end2.y()) - + static_cast(segm_start2.y()), + static_cast(segm_end2.x()), + static_cast(segm_end2.y())), to_fpt(1.0)); + robust_fpt_type inv_orientation = + robust_fpt_type(to_fpt(1.0)) / orientation; + robust_dif_type t, b, ix, iy; + ix += robust_fpt_type(a2) * c1 * inv_orientation; + ix += robust_fpt_type(a1) * c2 * inv_orientation; + iy += robust_fpt_type(b1) * c2 * inv_orientation; + iy += robust_fpt_type(b2) * c1 * inv_orientation; + + b += ix * (robust_fpt_type(a1) * sqr_sum2); + b += ix * (robust_fpt_type(a2) * sqr_sum1); + b += iy * (robust_fpt_type(b1) * sqr_sum2); + b += iy * (robust_fpt_type(b2) * sqr_sum1); + b -= sqr_sum1 * robust_fpt_type(robust_cross_product( + static_cast(segm_end2.x()) - + static_cast(segm_start2.x()), + static_cast(segm_end2.y()) - + static_cast(segm_start2.y()), + static_cast(-site1.y()), + static_cast(site1.x())), to_fpt(1.0)); + b -= sqr_sum2 * robust_fpt_type(robust_cross_product( + static_cast(segm_end1.x()) - + static_cast(segm_start1.x()), + static_cast(segm_end1.y()) - + static_cast(segm_start1.y()), + static_cast(-site1.y()), + static_cast(site1.x())), to_fpt(1.0)); + t -= b; + if (point_index == 2) { + t += det.sqrt(); + } else { + t -= det.sqrt(); + } + t /= (a * a); + robust_dif_type c_x(ix), c_y(iy); + c_x += t * (robust_fpt_type(a1) * sqr_sum2); + c_x += t * (robust_fpt_type(a2) * sqr_sum1); + c_y += t * (robust_fpt_type(b1) * sqr_sum2); + c_y += t * (robust_fpt_type(b2) * sqr_sum1); + if (t.pos().fpv() < t.neg().fpv()) { + t = -t; + } + robust_dif_type lower_x(c_x); + if (is_neg(orientation)) { + lower_x -= t * orientation; + } else { + lower_x += t * orientation; + } + recompute_c_x = c_x.dif().ulp() > ULPS; + recompute_c_y = c_y.dif().ulp() > ULPS; + recompute_lower_x = lower_x.dif().ulp() > ULPS; + c_event = circle_type( + c_x.dif().fpv(), c_y.dif().fpv(), lower_x.dif().fpv()); + } + if (recompute_c_x || recompute_c_y || recompute_lower_x) { + exact_circle_formation_functor_.pss( + site1, site2, site3, point_index, c_event, + recompute_c_x, recompute_c_y, recompute_lower_x); + } + } + + void sss(const site_type& site1, + const site_type& site2, + const site_type& site3, + circle_type& c_event) { + robust_fpt_type a1(to_fpt(site1.x1(true)) - to_fpt(site1.x0(true))); + robust_fpt_type b1(to_fpt(site1.y1(true)) - to_fpt(site1.y0(true))); + robust_fpt_type c1(robust_cross_product( + site1.x0(true), site1.y0(true), + site1.x1(true), site1.y1(true)), to_fpt(1.0)); + + robust_fpt_type a2(to_fpt(site2.x1(true)) - to_fpt(site2.x0(true))); + robust_fpt_type b2(to_fpt(site2.y1(true)) - to_fpt(site2.y0(true))); + robust_fpt_type c2(robust_cross_product( + site2.x0(true), site2.y0(true), + site2.x1(true), site2.y1(true)), to_fpt(1.0)); + + robust_fpt_type a3(to_fpt(site3.x1(true)) - to_fpt(site3.x0(true))); + robust_fpt_type b3(to_fpt(site3.y1(true)) - to_fpt(site3.y0(true))); + robust_fpt_type c3(robust_cross_product( + site3.x0(true), site3.y0(true), + site3.x1(true), site3.y1(true)), to_fpt(1.0)); + + robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt(); + robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt(); + robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt(); + robust_fpt_type cross_12(robust_cross_product( + static_cast(site1.x1(true)) - + static_cast(site1.x0(true)), + static_cast(site1.y1(true)) - + static_cast(site1.y0(true)), + static_cast(site2.x1(true)) - + static_cast(site2.x0(true)), + static_cast(site2.y1(true)) - + static_cast(site2.y0(true))), to_fpt(1.0)); + robust_fpt_type cross_23(robust_cross_product( + static_cast(site2.x1(true)) - + static_cast(site2.x0(true)), + static_cast(site2.y1(true)) - + static_cast(site2.y0(true)), + static_cast(site3.x1(true)) - + static_cast(site3.x0(true)), + static_cast(site3.y1(true)) - + static_cast(site3.y0(true))), to_fpt(1.0)); + robust_fpt_type cross_31(robust_cross_product( + static_cast(site3.x1(true)) - + static_cast(site3.x0(true)), + static_cast(site3.y1(true)) - + static_cast(site3.y0(true)), + static_cast(site1.x1(true)) - + static_cast(site1.x0(true)), + static_cast(site1.y1(true)) - + static_cast(site1.y0(true))), to_fpt(1.0)); + robust_dif_type denom, c_x, c_y, r; + + // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2. + denom += cross_12 * len3; + denom += cross_23 * len1; + denom += cross_31 * len2; + + // denom * r = (b2 * c_x - a2 * c_y - c2 * denom) / len2. + r -= cross_12 * c3; + r -= cross_23 * c1; + r -= cross_31 * c2; + + c_x += a1 * c2 * len3; + c_x -= a2 * c1 * len3; + c_x += a2 * c3 * len1; + c_x -= a3 * c2 * len1; + c_x += a3 * c1 * len2; + c_x -= a1 * c3 * len2; + c_y += b1 * c2 * len3; + c_y -= b2 * c1 * len3; + c_y += b2 * c3 * len1; + c_y -= b3 * c2 * len1; + c_y += b3 * c1 * len2; + c_y -= b1 * c3 * len2; + robust_dif_type lower_x(c_x + r); + bool recompute_c_x = c_x.dif().ulp() > ULPS; + bool recompute_c_y = c_y.dif().ulp() > ULPS; + bool recompute_lower_x = lower_x.dif().ulp() > ULPS; + bool recompute_denom = denom.dif().ulp() > ULPS; + c_event = circle_type( + c_x.dif().fpv() / denom.dif().fpv(), + c_y.dif().fpv() / denom.dif().fpv(), + lower_x.dif().fpv() / denom.dif().fpv()); + if (recompute_c_x || recompute_c_y || + recompute_lower_x || recompute_denom) { + exact_circle_formation_functor_.sss( + site1, site2, site3, c_event, + recompute_c_x, recompute_c_y, recompute_lower_x); + } + } + + private: + exact_circle_formation_functor_type exact_circle_formation_functor_; + to_fpt_converter to_fpt; + }; + + template , + typename CFF = lazy_circle_formation_functor > + class circle_formation_predicate { + public: + typedef Site site_type; + typedef Circle circle_type; + typedef CEP circle_existence_predicate_type; + typedef CFF circle_formation_functor_type; + + // Create a circle event from the given three sites. + // Returns true if the circle event exists, else false. + // If exists circle event is saved into the c_event variable. + bool operator()(const site_type& site1, const site_type& site2, + const site_type& site3, circle_type& circle) { + if (!site1.is_segment()) { + if (!site2.is_segment()) { + if (!site3.is_segment()) { + // (point, point, point) sites. + if (!circle_existence_predicate_.ppp(site1, site2, site3)) + return false; + circle_formation_functor_.ppp(site1, site2, site3, circle); + } else { + // (point, point, segment) sites. + if (!circle_existence_predicate_.pps(site1, site2, site3, 3)) + return false; + circle_formation_functor_.pps(site1, site2, site3, 3, circle); + } + } else { + if (!site3.is_segment()) { + // (point, segment, point) sites. + if (!circle_existence_predicate_.pps(site1, site3, site2, 2)) + return false; + circle_formation_functor_.pps(site1, site3, site2, 2, circle); + } else { + // (point, segment, segment) sites. + if (!circle_existence_predicate_.pss(site1, site2, site3, 1)) + return false; + circle_formation_functor_.pss(site1, site2, site3, 1, circle); + } + } + } else { + if (!site2.is_segment()) { + if (!site3.is_segment()) { + // (segment, point, point) sites. + if (!circle_existence_predicate_.pps(site2, site3, site1, 1)) + return false; + circle_formation_functor_.pps(site2, site3, site1, 1, circle); + } else { + // (segment, point, segment) sites. + if (!circle_existence_predicate_.pss(site2, site1, site3, 2)) + return false; + circle_formation_functor_.pss(site2, site1, site3, 2, circle); + } + } else { + if (!site3.is_segment()) { + // (segment, segment, point) sites. + if (!circle_existence_predicate_.pss(site3, site1, site2, 3)) + return false; + circle_formation_functor_.pss(site3, site1, site2, 3, circle); + } else { + // (segment, segment, segment) sites. + if (!circle_existence_predicate_.sss(site1, site2, site3)) + return false; + circle_formation_functor_.sss(site1, site2, site3, circle); + } + } + } + return true; + } + + private: + circle_existence_predicate_type circle_existence_predicate_; + circle_formation_functor_type circle_formation_functor_; + }; +}; +} // detail +} // polygon +} // boost + +#endif // BOOST_POLYGON_DETAIL_VORONOI_PREDICATES diff --git a/include/boost/polygon/detail/voronoi_robust_fpt.hpp b/include/boost/polygon/detail/voronoi_robust_fpt.hpp new file mode 100644 index 0000000..0d2e62b --- /dev/null +++ b/include/boost/polygon/detail/voronoi_robust_fpt.hpp @@ -0,0 +1,519 @@ +// Boost.Polygon library detail/voronoi_robust_fpt.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT +#define BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT + +#include + +// Geometry predicates with floating-point variables usually require +// high-precision predicates to retrieve the correct result. +// Epsilon robust predicates give the result within some epsilon relative +// error, but are a lot faster than high-precision predicates. +// To make algorithm robust and efficient epsilon robust predicates are +// used at the first step. In case of the undefined result high-precision +// arithmetic is used to produce required robustness. This approach +// requires exact computation of epsilon intervals within which epsilon +// robust predicates have undefined value. +// There are two ways to measure an error of floating-point calculations: +// relative error and ULPs (units in the last place). +// Let EPS be machine epsilon, then next inequalities have place: +// 1 EPS <= 1 ULP <= 2 EPS (1), 0.5 ULP <= 1 EPS <= 1 ULP (2). +// ULPs are good for measuring rounding errors and comparing values. +// Relative errors are good for computation of general relative +// error of formulas or expressions. So to calculate epsilon +// interval within which epsilon robust predicates have undefined result +// next schema is used: +// 1) Compute rounding errors of initial variables using ULPs; +// 2) Transform ULPs to epsilons using upper bound of the (1); +// 3) Compute relative error of the formula using epsilon arithmetic; +// 4) Transform epsilon to ULPs using upper bound of the (2); +// In case two values are inside undefined ULP range use high-precision +// arithmetic to produce the correct result, else output the result. +// Look at almost_equal function to see how two floating-point variables +// are checked to fit in the ULP range. +// If A has relative error of r(A) and B has relative error of r(B) then: +// 1) r(A + B) <= max(r(A), r(B)), for A * B >= 0; +// 2) r(A - B) <= B*r(A)+A*r(B)/(A-B), for A * B >= 0; +// 2) r(A * B) <= r(A) + r(B); +// 3) r(A / B) <= r(A) + r(B); +// In addition rounding error should be added, that is always equal to +// 0.5 ULP or at most 1 epsilon. As you might see from the above formulas +// subtraction relative error may be extremely large, that's why +// epsilon robust comparator class is used to store floating point values +// and compute subtraction as the final step of the evaluation. +// For further information about relative errors and ULPs try this link: +// http://docs.sun.com/source/806-3568/ncg_goldberg.html + +namespace boost { +namespace polygon { +namespace detail { + +template +T get_sqrt(const T& that) { + return (std::sqrt)(that); +} + +template +bool is_pos(const T& that) { + return that > 0; +} + +template +bool is_neg(const T& that) { + return that < 0; +} + +template +bool is_zero(const T& that) { + return that == 0; +} + +template +class robust_fpt { + public: + typedef _fpt floating_point_type; + typedef _fpt relative_error_type; + + // Rounding error is at most 1 EPS. + static const relative_error_type ROUNDING_ERROR; + + robust_fpt() : fpv_(0.0), re_(0.0) {} + explicit robust_fpt(floating_point_type fpv) : + fpv_(fpv), re_(0.0) {} + robust_fpt(floating_point_type fpv, relative_error_type error) : + fpv_(fpv), re_(error) {} + + floating_point_type fpv() const { return fpv_; } + relative_error_type re() const { return re_; } + relative_error_type ulp() const { return re_; } + + robust_fpt& operator=(const robust_fpt& that) { + this->fpv_ = that.fpv_; + this->re_ = that.re_; + return *this; + } + + bool has_pos_value() const { + return is_pos(fpv_); + } + + bool has_neg_value() const { + return is_neg(fpv_); + } + + bool has_zero_value() const { + return is_zero(fpv_); + } + + robust_fpt operator-() const { + return robust_fpt(-fpv_, re_); + } + + robust_fpt& operator+=(const robust_fpt& that) { + floating_point_type fpv = this->fpv_ + that.fpv_; + if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) || + (!is_pos(this->fpv_) && !is_pos(that.fpv_))) { + this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; + } else { + floating_point_type temp = + (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv; + if (is_neg(temp)) + temp = -temp; + this->re_ = temp + ROUNDING_ERROR; + } + this->fpv_ = fpv; + return *this; + } + + robust_fpt& operator-=(const robust_fpt& that) { + floating_point_type fpv = this->fpv_ - that.fpv_; + if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) || + (!is_pos(this->fpv_) && !is_neg(that.fpv_))) { + this->re_ = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; + } else { + floating_point_type temp = + (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv; + if (is_neg(temp)) + temp = -temp; + this->re_ = temp + ROUNDING_ERROR; + } + this->fpv_ = fpv; + return *this; + } + + robust_fpt& operator*=(const robust_fpt& that) { + this->re_ += that.re_ + ROUNDING_ERROR; + this->fpv_ *= that.fpv_; + return *this; + } + + robust_fpt& operator/=(const robust_fpt& that) { + this->re_ += that.re_ + ROUNDING_ERROR; + this->fpv_ /= that.fpv_; + return *this; + } + + robust_fpt operator+(const robust_fpt& that) const { + floating_point_type fpv = this->fpv_ + that.fpv_; + relative_error_type re; + if ((!is_neg(this->fpv_) && !is_neg(that.fpv_)) || + (!is_pos(this->fpv_) && !is_pos(that.fpv_))) { + re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; + } else { + floating_point_type temp = + (this->fpv_ * this->re_ - that.fpv_ * that.re_) / fpv; + if (is_neg(temp)) + temp = -temp; + re = temp + ROUNDING_ERROR; + } + return robust_fpt(fpv, re); + } + + robust_fpt operator-(const robust_fpt& that) const { + floating_point_type fpv = this->fpv_ - that.fpv_; + relative_error_type re; + if ((!is_neg(this->fpv_) && !is_pos(that.fpv_)) || + (!is_pos(this->fpv_) && !is_neg(that.fpv_))) { + re = (std::max)(this->re_, that.re_) + ROUNDING_ERROR; + } else { + floating_point_type temp = + (this->fpv_ * this->re_ + that.fpv_ * that.re_) / fpv; + if (is_neg(temp)) + temp = -temp; + re = temp + ROUNDING_ERROR; + } + return robust_fpt(fpv, re); + } + + robust_fpt operator*(const robust_fpt& that) const { + floating_point_type fpv = this->fpv_ * that.fpv_; + relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR; + return robust_fpt(fpv, re); + } + + robust_fpt operator/(const robust_fpt& that) const { + floating_point_type fpv = this->fpv_ / that.fpv_; + relative_error_type re = this->re_ + that.re_ + ROUNDING_ERROR; + return robust_fpt(fpv, re); + } + + robust_fpt sqrt() const { + return robust_fpt(get_sqrt(fpv_), + re_ * static_cast(0.5) + + ROUNDING_ERROR); + } + + private: + floating_point_type fpv_; + relative_error_type re_; +}; + +template +const typename robust_fpt::relative_error_type + robust_fpt::ROUNDING_ERROR = 1; + +template +robust_fpt get_sqrt(const robust_fpt& that) { + return that.sqrt(); +} + +template +bool is_pos(const robust_fpt& that) { + return that.has_pos_value(); +} + +template +bool is_neg(const robust_fpt& that) { + return that.has_neg_value(); +} + +template +bool is_zero(const robust_fpt& that) { + return that.has_zero_value(); +} + +// robust_dif consists of two not negative values: value1 and value2. +// The resulting expression is equal to the value1 - value2. +// Subtraction of a positive value is equivalent to the addition to value2 +// and subtraction of a negative value is equivalent to the addition to +// value1. The structure implicitly avoids difference computation. +template +class robust_dif { + public: + robust_dif() : + positive_sum_(0), + negative_sum_(0) {} + + explicit robust_dif(const T& value) : + positive_sum_((value > 0)?value:0), + negative_sum_((value < 0)?-value:0) {} + + robust_dif(const T& pos, const T& neg) : + positive_sum_(pos), + negative_sum_(neg) {} + + T dif() const { + return positive_sum_ - negative_sum_; + } + + T pos() const { + return positive_sum_; + } + + T neg() const { + return negative_sum_; + } + + robust_dif operator-() const { + return robust_dif(negative_sum_, positive_sum_); + } + + robust_dif& operator+=(const T& val) { + if (!is_neg(val)) + positive_sum_ += val; + else + negative_sum_ -= val; + return *this; + } + + robust_dif& operator+=(const robust_dif& that) { + positive_sum_ += that.positive_sum_; + negative_sum_ += that.negative_sum_; + return *this; + } + + robust_dif& operator-=(const T& val) { + if (!is_neg(val)) + negative_sum_ += val; + else + positive_sum_ -= val; + return *this; + } + + robust_dif& operator-=(const robust_dif& that) { + positive_sum_ += that.negative_sum_; + negative_sum_ += that.positive_sum_; + return *this; + } + + robust_dif& operator*=(const T& val) { + if (!is_neg(val)) { + positive_sum_ *= val; + negative_sum_ *= val; + } else { + positive_sum_ *= -val; + negative_sum_ *= -val; + swap(); + } + return *this; + } + + robust_dif& operator*=(const robust_dif& that) { + T positive_sum = this->positive_sum_ * that.positive_sum_ + + this->negative_sum_ * that.negative_sum_; + T negative_sum = this->positive_sum_ * that.negative_sum_ + + this->negative_sum_ * that.positive_sum_; + positive_sum_ = positive_sum; + negative_sum_ = negative_sum; + return *this; + } + + robust_dif& operator/=(const T& val) { + if (!is_neg(val)) { + positive_sum_ /= val; + negative_sum_ /= val; + } else { + positive_sum_ /= -val; + negative_sum_ /= -val; + swap(); + } + return *this; + } + + private: + void swap() { + (std::swap)(positive_sum_, negative_sum_); + } + + T positive_sum_; + T negative_sum_; +}; + +template +robust_dif operator+(const robust_dif& lhs, + const robust_dif& rhs) { + return robust_dif(lhs.pos() + rhs.pos(), lhs.neg() + rhs.neg()); +} + +template +robust_dif operator+(const robust_dif& lhs, const T& rhs) { + if (!is_neg(rhs)) { + return robust_dif(lhs.pos() + rhs, lhs.neg()); + } else { + return robust_dif(lhs.pos(), lhs.neg() - rhs); + } +} + +template +robust_dif operator+(const T& lhs, const robust_dif& rhs) { + if (!is_neg(lhs)) { + return robust_dif(lhs + rhs.pos(), rhs.neg()); + } else { + return robust_dif(rhs.pos(), rhs.neg() - lhs); + } +} + +template +robust_dif operator-(const robust_dif& lhs, + const robust_dif& rhs) { + return robust_dif(lhs.pos() + rhs.neg(), lhs.neg() + rhs.pos()); +} + +template +robust_dif operator-(const robust_dif& lhs, const T& rhs) { + if (!is_neg(rhs)) { + return robust_dif(lhs.pos(), lhs.neg() + rhs); + } else { + return robust_dif(lhs.pos() - rhs, lhs.neg()); + } +} + +template +robust_dif operator-(const T& lhs, const robust_dif& rhs) { + if (!is_neg(lhs)) { + return robust_dif(lhs + rhs.neg(), rhs.pos()); + } else { + return robust_dif(rhs.neg(), rhs.pos() - lhs); + } +} + +template +robust_dif operator*(const robust_dif& lhs, + const robust_dif& rhs) { + T res_pos = lhs.pos() * rhs.pos() + lhs.neg() * rhs.neg(); + T res_neg = lhs.pos() * rhs.neg() + lhs.neg() * rhs.pos(); + return robust_dif(res_pos, res_neg); +} + +template +robust_dif operator*(const robust_dif& lhs, const T& val) { + if (!is_neg(val)) { + return robust_dif(lhs.pos() * val, lhs.neg() * val); + } else { + return robust_dif(-lhs.neg() * val, -lhs.pos() * val); + } +} + +template +robust_dif operator*(const T& val, const robust_dif& rhs) { + if (!is_neg(val)) { + return robust_dif(val * rhs.pos(), val * rhs.neg()); + } else { + return robust_dif(-val * rhs.neg(), -val * rhs.pos()); + } +} + +template +robust_dif operator/(const robust_dif& lhs, const T& val) { + if (!is_neg(val)) { + return robust_dif(lhs.pos() / val, lhs.neg() / val); + } else { + return robust_dif(-lhs.neg() / val, -lhs.pos() / val); + } +} + +// Used to compute expressions that operate with sqrts with predefined +// relative error. Evaluates expressions of the next type: +// sum(i = 1 .. n)(A[i] * sqrt(B[i])), 1 <= n <= 4. +template +class robust_sqrt_expr { + public: + static const unsigned int EVAL1_MAX_RELATIVE_ERROR; + static const unsigned int EVAL2_MAX_RELATIVE_ERROR; + static const unsigned int EVAL3_MAX_RELATIVE_ERROR; + static const unsigned int EVAL4_MAX_RELATIVE_ERROR; + + // Evaluates expression (re = 4 EPS): + // A[0] * sqrt(B[0]). + _fpt eval1(_int* A, _int* B) { + _fpt a = convert(A[0]); + _fpt b = convert(B[0]); + return a * get_sqrt(b); + } + + // Evaluates expression (re = 7 EPS): + // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]). + _fpt eval2(_int* A, _int* B) { + _fpt a = eval1(A, B); + _fpt b = eval1(A + 1, B + 1); + if ((!is_neg(a) && !is_neg(b)) || + (!is_pos(a) && !is_pos(b))) + return a + b; + return convert(A[0] * A[0] * B[0] - A[1] * A[1] * B[1]) / (a - b); + } + + // Evaluates expression (re = 16 EPS): + // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + A[2] * sqrt(B[2]). + _fpt eval3(_int* A, _int* B) { + _fpt a = eval2(A, B); + _fpt b = eval1(A + 2, B + 2); + if ((!is_neg(a) && !is_neg(b)) || + (!is_pos(a) && !is_pos(b))) + return a + b; + tA[3] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - A[2] * A[2] * B[2]; + tB[3] = 1; + tA[4] = A[0] * A[1] * 2; + tB[4] = B[0] * B[1]; + return eval2(tA + 3, tB + 3) / (a - b); + } + + + // Evaluates expression (re = 25 EPS): + // A[0] * sqrt(B[0]) + A[1] * sqrt(B[1]) + + // A[2] * sqrt(B[2]) + A[3] * sqrt(B[3]). + _fpt eval4(_int* A, _int* B) { + _fpt a = eval2(A, B); + _fpt b = eval2(A + 2, B + 2); + if ((!is_neg(a) && !is_neg(b)) || + (!is_pos(a) && !is_pos(b))) + return a + b; + tA[0] = A[0] * A[0] * B[0] + A[1] * A[1] * B[1] - + A[2] * A[2] * B[2] - A[3] * A[3] * B[3]; + tB[0] = 1; + tA[1] = A[0] * A[1] * 2; + tB[1] = B[0] * B[1]; + tA[2] = A[2] * A[3] * -2; + tB[2] = B[2] * B[3]; + return eval3(tA, tB) / (a - b); + } + + private: + _int tA[5]; + _int tB[5]; + _converter convert; +}; + +template +const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: + EVAL1_MAX_RELATIVE_ERROR = 4; +template +const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: + EVAL2_MAX_RELATIVE_ERROR = 7; +template +const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: + EVAL3_MAX_RELATIVE_ERROR = 16; +template +const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: + EVAL4_MAX_RELATIVE_ERROR = 25; +} // detail +} // polygon +} // boost + +#endif // BOOST_POLYGON_DETAIL_VORONOI_ROBUST_FPT diff --git a/include/boost/polygon/detail/voronoi_structures.hpp b/include/boost/polygon/detail/voronoi_structures.hpp new file mode 100644 index 0000000..532eb7e --- /dev/null +++ b/include/boost/polygon/detail/voronoi_structures.hpp @@ -0,0 +1,461 @@ +// Boost.Polygon library detail/voronoi_structures.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES +#define BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES + +#include +#include +#include + +#include "boost/polygon/voronoi_geometry_type.hpp" + +namespace boost { +namespace polygon { +namespace detail { +// Cartesian 2D point data structure. +template +class point_2d { + public: + typedef T coordinate_type; + + point_2d() {} + + point_2d(coordinate_type x, coordinate_type y) : + x_(x), + y_(y) {} + + bool operator==(const point_2d& that) const { + return (this->x_ == that.x()) && (this->y_ == that.y()); + } + + bool operator!=(const point_2d& that) const { + return (this->x_ != that.x()) || (this->y_ != that.y()); + } + + coordinate_type x() const { + return x_; + } + + coordinate_type y() const { + return y_; + } + + point_2d& x(coordinate_type x) { + x_ = x; + return *this; + } + + point_2d& y(coordinate_type y) { + y_ = y; + return *this; + } + + private: + coordinate_type x_; + coordinate_type y_; +}; + +// Site event type. +// Occurs when the sweepline sweeps over one of the initial sites: +// 1) point site +// 2) start-point of the segment site +// 3) endpoint of the segment site +// Implicit segment direction is defined: the start-point of +// the segment compares less than its endpoint. +// Each input segment is divided onto two site events: +// 1) One going from the start-point to the endpoint +// (is_inverse() = false) +// 2) Another going from the endpoint to the start-point +// (is_inverse() = true) +// In beach line data structure segment sites of the first +// type precede sites of the second type for the same segment. +// Members: +// point0_ - point site or segment's start-point +// point1_ - segment's endpoint if site is a segment +// sorted_index_ - the last bit encodes information if the site is inverse; +// the other bits encode site event index among the sorted site events +// initial_index_ - site index among the initial input set +// Note: for all sites is_inverse_ flag is equal to false by default. +template +class site_event { + public: + typedef T coordinate_type; + typedef point_2d point_type; + + site_event() : + point0_(0, 0), + point1_(0, 0), + sorted_index_(0), + flags_(0) {} + + site_event(coordinate_type x, coordinate_type y) : + point0_(x, y), + point1_(x, y), + sorted_index_(0), + flags_(0) {} + + explicit site_event(const point_type& point) : + point0_(point), + point1_(point), + sorted_index_(0), + flags_(0) {} + + site_event(coordinate_type x1, coordinate_type y1, + coordinate_type x2, coordinate_type y2): + point0_(x1, y1), + point1_(x2, y2), + sorted_index_(0), + flags_(0) {} + + site_event(const point_type& point1, const point_type& point2) : + point0_(point1), + point1_(point2), + sorted_index_(0), + flags_(0) {} + + bool operator==(const site_event& that) const { + return (this->point0_ == that.point0_) && + (this->point1_ == that.point1_); + } + + bool operator!=(const site_event& that) const { + return (this->point0_ != that.point0_) || + (this->point1_ != that.point1_); + } + + coordinate_type x(bool oriented = false) const { + return x0(oriented); + } + + coordinate_type y(bool oriented = false) const { + return y0(oriented); + } + + coordinate_type x0(bool oriented = false) const { + if (!oriented) + return point0_.x(); + return is_inverse() ? point1_.x() : point0_.x(); + } + + coordinate_type y0(bool oriented = false) const { + if (!oriented) + return point0_.y(); + return is_inverse() ? point1_.y() : point0_.y(); + } + + coordinate_type x1(bool oriented = false) const { + if (!oriented) + return point1_.x(); + return is_inverse() ? point0_.x() : point1_.x(); + } + + coordinate_type y1(bool oriented = false) const { + if (!oriented) + return point1_.y(); + return is_inverse() ? point0_.y() : point1_.y(); + } + + const point_type& point0(bool oriented = false) const { + if (!oriented) + return point0_; + return is_inverse() ? point1_ : point0_; + } + + const point_type& point1(bool oriented = false) const { + if (!oriented) + return point1_; + return is_inverse() ? point0_ : point1_; + } + + std::size_t sorted_index() const { + return sorted_index_; + } + + site_event& sorted_index(std::size_t index) { + sorted_index_ = index; + return *this; + } + + std::size_t initial_index() const { + return initial_index_; + } + + site_event& initial_index(std::size_t index) { + initial_index_ = index; + return *this; + } + + bool is_inverse() const { + return (flags_ & IS_INVERSE) ? true : false; + } + + site_event& inverse() { + flags_ ^= IS_INVERSE; + return *this; + } + + SourceCategory source_category() const { + return static_cast(flags_ & SOURCE_CATEGORY_BITMASK); + } + + site_event& source_category(SourceCategory source_category) { + flags_ |= source_category; + return *this; + } + + bool is_point() const { + return (point0_.x() == point1_.x()) && (point0_.y() == point1_.y()); + } + + bool is_segment() const { + return (point0_.x() != point1_.x()) || (point0_.y() != point1_.y()); + } + + private: + enum Bits { + IS_INVERSE = 0x20 // 32 + }; + + point_type point0_; + point_type point1_; + std::size_t sorted_index_; + std::size_t initial_index_; + std::size_t flags_; +}; + +// Circle event type. +// Occurs when the sweepline sweeps over the rightmost point of the Voronoi +// circle (with the center at the intersection point of the bisectors). +// Circle event is made of the two consecutive nodes in the beach line data +// structure. In case another node was inserted during algorithm execution +// between the given two nodes circle event becomes inactive. +// Variables: +// center_x_ - center x-coordinate; +// center_y_ - center y-coordinate; +// lower_x_ - leftmost x-coordinate; +// is_active_ - states whether circle event is still active. +// NOTE: lower_y coordinate is always equal to center_y. +template +class circle_event { + public: + typedef T coordinate_type; + + circle_event() : is_active_(true) {} + + circle_event(coordinate_type c_x, + coordinate_type c_y, + coordinate_type lower_x) : + center_x_(c_x), + center_y_(c_y), + lower_x_(lower_x), + is_active_(true) {} + + coordinate_type x() const { + return center_x_; + } + + circle_event& x(coordinate_type center_x) { + center_x_ = center_x; + return *this; + } + + coordinate_type y() const { + return center_y_; + } + + circle_event& y(coordinate_type center_y) { + center_y_ = center_y; + return *this; + } + + coordinate_type lower_x() const { + return lower_x_; + } + + circle_event& lower_x(coordinate_type lower_x) { + lower_x_ = lower_x; + return *this; + } + + coordinate_type lower_y() const { + return center_y_; + } + + bool is_active() const { + return is_active_; + } + + circle_event& deactivate() { + is_active_ = false; + return *this; + } + + private: + coordinate_type center_x_; + coordinate_type center_y_; + coordinate_type lower_x_; + bool is_active_; +}; + +// Event queue data structure, holds circle events. +// During algorithm run, some of the circle events disappear (become +// inactive). Priority queue data structure doesn't support +// iterators (there is no direct ability to modify its elements). +// Instead list is used to store all the circle events and priority queue +// of the iterators to the list elements is used to keep the correct circle +// events ordering. +template +class ordered_queue { + public: + ordered_queue() {} + + bool empty() const { + return c_.empty(); + } + + const T &top() const { + return *c_.top(); + } + + void pop() { + list_iterator_type it = c_.top(); + c_.pop(); + c_list_.erase(it); + } + + T &push(const T &e) { + c_list_.push_front(e); + c_.push(c_list_.begin()); + return c_list_.front(); + } + + void clear() { + while (!c_.empty()) + c_.pop(); + c_list_.clear(); + } + + private: + typedef typename std::list::iterator list_iterator_type; + + struct comparison { + bool operator() (const list_iterator_type &it1, + const list_iterator_type &it2) const { + return cmp_(*it1, *it2); + } + Predicate cmp_; + }; + + std::priority_queue< list_iterator_type, + std::vector, + comparison > c_; + std::list c_list_; + + // Disallow copy constructor and operator= + ordered_queue(const ordered_queue&); + void operator=(const ordered_queue&); +}; + +// Represents a bisector node made by two arcs that correspond to the left +// and right sites. Arc is defined as a curve with points equidistant from +// the site and from the sweepline. If the site is a point then arc is +// a parabola, otherwise it's a line segment. A segment site event will +// produce different bisectors based on its direction. +// In general case two sites will create two opposite bisectors. That's +// why the order of the sites is important to define the unique bisector. +// The one site is considered to be newer than the other one if it was +// processed by the algorithm later (has greater index). +template +class beach_line_node_key { + public: + typedef Site site_type; + + // Constructs degenerate bisector, used to search an arc that is above + // the given site. The input to the constructor is the new site point. + explicit beach_line_node_key(const site_type &new_site) : + left_site_(new_site), + right_site_(new_site) {} + + // Constructs a new bisector. The input to the constructor is the two + // sites that create the bisector. The order of sites is important. + beach_line_node_key(const site_type &left_site, + const site_type &right_site) : + left_site_(left_site), + right_site_(right_site) {} + + const site_type &left_site() const { + return left_site_; + } + + site_type &left_site() { + return left_site_; + } + + beach_line_node_key& left_site(const site_type &site) { + left_site_ = site; + return *this; + } + + const site_type &right_site() const { + return right_site_; + } + + site_type &right_site() { + return right_site_; + } + + beach_line_node_key& right_site(const site_type &site) { + right_site_ = site; + return *this; + } + + private: + site_type left_site_; + site_type right_site_; +}; + +// Represents edge data structure from the Voronoi output, that is +// associated as a value with beach line bisector in the beach +// line. Contains pointer to the circle event in the circle event +// queue if the edge corresponds to the right bisector of the circle event. +template +class beach_line_node_data { + public: + explicit beach_line_node_data(Edge* new_edge) : + circle_event_(NULL), + edge_(new_edge) {} + + Circle* circle_event() const { + return circle_event_; + } + + beach_line_node_data& circle_event(Circle* circle_event) { + circle_event_ = circle_event; + return *this; + } + + Edge* edge() const { + return edge_; + } + + beach_line_node_data& edge(Edge* new_edge) { + edge_ = new_edge; + return *this; + } + + private: + Circle* circle_event_; + Edge* edge_; +}; +} // detail +} // polygon +} // boost + +#endif // BOOST_POLYGON_DETAIL_VORONOI_STRUCTURES diff --git a/include/boost/polygon/gmp_override.hpp b/include/boost/polygon/gmp_override.hpp old mode 100755 new mode 100644 index 16cc96f..322e05d --- a/include/boost/polygon/gmp_override.hpp +++ b/include/boost/polygon/gmp_override.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -25,14 +25,14 @@ namespace boost { namespace polygon { v_ = that; return (*this); } - inline operator int() const { + inline operator int() const { std::cout << "cast\n"; mpz_class num = v_.get_num(); mpz_class den = v_.get_den(); num /= den; - return num.get_si(); + return num.get_si(); } - inline double get_d() const { + inline double get_d() const { return v_.get_d(); } inline int get_num() const { @@ -109,7 +109,7 @@ namespace boost { namespace polygon { private: mpq_class v_; }; - + template <> struct high_precision_type { typedef mpq_class type; @@ -120,10 +120,9 @@ namespace boost { namespace polygon { mpz_class num = v.get_num(); mpz_class den = v.get_den(); num /= den; - return num.get_si(); + return num.get_si(); }; } } -//== #endif diff --git a/include/boost/polygon/gtl.hpp b/include/boost/polygon/gtl.hpp old mode 100755 new mode 100644 index cabbb63..048d15d --- a/include/boost/polygon/gtl.hpp +++ b/include/boost/polygon/gtl.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). diff --git a/include/boost/polygon/interval_concept.hpp b/include/boost/polygon/interval_concept.hpp old mode 100755 new mode 100644 index 9fc5257..f5516ad --- a/include/boost/polygon/interval_concept.hpp +++ b/include/boost/polygon/interval_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -13,7 +13,7 @@ namespace boost { namespace polygon{ struct interval_concept {}; - + template struct is_interval_concept { typedef gtl_no type; }; template <> @@ -38,7 +38,7 @@ namespace boost { namespace polygon{ template struct interval_difference_type_by_concept { typedef void type; }; template - struct interval_difference_type_by_concept { + struct interval_difference_type_by_concept { typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; template @@ -47,73 +47,87 @@ namespace boost { namespace polygon{ T, typename is_interval_concept::type>::type>::type type; }; + struct y_i_get : gtl_yes {}; template - typename interval_coordinate_type::type - get(const T& interval, direction_1d dir, - typename enable_if::type>::type>::type>::type * = 0 - ) { - return interval_traits::get(interval, dir); + typename enable_if< typename gtl_and< + y_i_get, + typename is_interval_concept::type>::type>::type, + typename interval_coordinate_type::type>::type + get(const T& interval, direction_1d dir) { + return interval_traits::get(interval, dir); } + struct y_i_set : gtl_yes {}; + template - void - set(T& interval, direction_1d dir, coordinate_type value, - typename enable_if::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and< + y_i_set, + typename is_mutable_interval_concept::type>::type>::type, + void>::type + set(T& interval, direction_1d dir, coordinate_type value) { //this may need to be refined - interval_mutable_traits::set(interval, dir, value); + interval_mutable_traits::set(interval, dir, value); if(high(interval) < low(interval)) interval_mutable_traits::set(interval, dir.backward(), value); } - + + struct y_i_construct : gtl_yes {}; + template - T - construct(T2 low_value, T3 high_value, - typename enable_if::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and< + y_i_construct, + typename is_mutable_interval_concept::type>::type>::type, + T>::type + construct(T2 low_value, T3 high_value) { if(low_value > high_value) std::swap(low_value, high_value); - return interval_mutable_traits::construct(low_value, high_value); - } - - template - T - copy_construct(const T2& interval, - typename enable_if< typename gtl_and::type>::type, - typename is_interval_concept::type>::type>::type>::type * = 0 - ) { - return construct - (get(interval, LOW ), - get(interval, HIGH)); + return interval_mutable_traits::construct(low_value, high_value); } + struct y_i_copy_construct : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3< + y_i_copy_construct, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + T>::type + copy_construct(const T2& interval) { + return construct(get(interval, LOW ), get(interval, HIGH)); + } + + struct y_i_assign : gtl_yes {}; + template - T1 & - assign(T1& lvalue, const T2& rvalue, - typename enable_if< typename gtl_and< typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type>::type * = 0) { + typename enable_if< typename gtl_and_3< + y_i_assign, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + T1>::type & + assign(T1& lvalue, const T2& rvalue) { lvalue = copy_construct(rvalue); return lvalue; } + struct y_i_equivalence : gtl_yes {}; + template - bool - equivalence(const T& interval1, const T2& interval2, - typename enable_if< typename gtl_and< typename is_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type>::type * = 0 - ) { - return get(interval1, LOW) == - get(interval2, LOW) && - get(interval1, HIGH) == - get(interval2, HIGH); + typename enable_if< typename gtl_and_3< + y_i_equivalence, + typename is_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + equivalence(const T& interval1, const T2& interval2) { + return get(interval1, LOW) == get(interval2, LOW) && + get(interval1, HIGH) == get(interval2, HIGH); } - + struct y_i_contains : gtl_yes {}; template - typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept::type>::type >::type, bool>::type + typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept::type>::type >::type, bool>::type contains(const interval_type& interval, - typename interval_traits::coordinate_type value, + typename interval_coordinate_type::type value, bool consider_touch = true ) { if(consider_touch) { return value <= high(interval) && value >= low(interval); @@ -121,63 +135,85 @@ namespace boost { namespace polygon{ return value < high(interval) && value > low(interval); } } - + + struct y_i_contains2 : gtl_yes {}; + template - bool + typename enable_if< typename gtl_and_3< + y_i_contains2, + typename is_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type contains(const interval_type& interval, - const interval_type_2& value, bool consider_touch = true, - typename enable_if< typename gtl_and< typename is_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type>::type * = 0 - ) { + const interval_type_2& value, + bool consider_touch = true) { return contains(interval, get(value, LOW), consider_touch) && contains(interval, get(value, HIGH), consider_touch); } - - // get the low coordinate - template - typename interval_traits::coordinate_type - low(const interval_type& interval, - typename enable_if< typename is_interval_concept::type>::type>::type * = 0 - ) { return get(interval, LOW); } - - // get the high coordinate - template - typename interval_traits::coordinate_type - high(const interval_type& interval, - typename enable_if< typename is_interval_concept::type>::type>::type * = 0 - ) { return get(interval, HIGH); } - - // get the center coordinate - template - typename interval_traits::coordinate_type - center(const interval_type& interval, - typename enable_if< typename is_interval_concept::type>::type>::type * = 0 - ) { return (high(interval) + low(interval))/2; } - struct y_i_low : gtl_yes {}; + // get the low coordinate + template + typename enable_if< typename gtl_and< + y_i_low, + typename is_interval_concept::type>::type>::type, + typename interval_coordinate_type::type>::type + low(const interval_type& interval) { return get(interval, LOW); } + + struct y_i_high : gtl_yes {}; + + // get the high coordinate + template + typename enable_if< typename gtl_and< + y_i_high, + typename is_interval_concept::type>::type>::type, + typename interval_coordinate_type::type>::type + high(const interval_type& interval) { return get(interval, HIGH); } + + struct y_i_center : gtl_yes {}; + + // get the center coordinate + template + typename enable_if< typename gtl_and< + y_i_center, + typename is_interval_concept::type>::type>::type, + typename interval_coordinate_type::type>::type + center(const interval_type& interval) { return (high(interval) + low(interval))/2; } + + + struct y_i_low2 : gtl_yes {}; + // set the low coordinate to v template - typename enable_if::type>::type>::type, void>::type + typename enable_if::type>::type>::type, + void>::type low(interval_type& interval, - typename interval_traits::coordinate_type v) { set(interval, LOW, v); } - - struct y_i_high : gtl_yes {}; + typename interval_coordinate_type::type v) { set(interval, LOW, v); } + + struct y_i_high2 : gtl_yes {}; // set the high coordinate to v template - typename enable_if::type>::type>::type, void>::type + typename enable_if::type>::type>::type, + void>::type high(interval_type& interval, - typename interval_traits::coordinate_type v) { set(interval, HIGH, v); } - + typename interval_coordinate_type::type v) { set(interval, HIGH, v); } + + struct y_i_delta : gtl_yes {}; + // get the magnitude of the interval template - typename interval_difference_type::type - delta(const interval_type& interval, - typename enable_if< typename is_interval_concept::type>::type>::type * = 0 - ) { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference diffT; + typename enable_if< typename gtl_and< + y_i_delta, + typename is_interval_concept::type>::type>::type, + typename interval_difference_type::type >::type + delta(const interval_type& interval) { + typedef typename coordinate_traits::type>::coordinate_difference diffT; return (diffT)high(interval) - (diffT)low(interval); } struct y_i_flip : gtl_yes {}; @@ -186,8 +222,8 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, interval_type>::type & flip(interval_type& interval, - typename interval_traits::coordinate_type axis = 0) { - typename interval_traits::coordinate_type newLow, newHigh; + typename interval_coordinate_type::type axis = 0) { + typename interval_coordinate_type::type newLow, newHigh; newLow = 2 * axis - high(interval); newHigh = 2 * axis - low(interval); low(interval, newLow); @@ -200,9 +236,9 @@ namespace boost { namespace polygon{ // scale interval by factor template typename enable_if::type>::type>::type, interval_type>::type & - scale_up(interval_type& interval, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { - typedef typename interval_traits::coordinate_type Unit; + scale_up(interval_type& interval, + typename coordinate_traits::type>::unsigned_area_type factor) { + typedef typename interval_coordinate_type::type Unit; Unit newHigh = high(interval) * (Unit)factor; low(interval, low(interval) * (Unit)factor); high(interval, (newHigh)); @@ -213,12 +249,12 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, interval_type>::type & - scale_down(interval_type& interval, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { - typedef typename interval_traits::coordinate_type Unit; + scale_down(interval_type& interval, + typename coordinate_traits::type>::unsigned_area_type factor) { + typedef typename interval_coordinate_type::type Unit; typedef typename coordinate_traits::coordinate_distance dt; - Unit newHigh = scaling_policy::round((dt)(high(interval)) / (dt)factor); - low(interval, scaling_policy::round((dt)(low(interval)) / (dt)factor)); + Unit newHigh = scaling_policy::round((dt)(high(interval)) / (dt)factor); + low(interval, scaling_policy::round((dt)(low(interval)) / (dt)factor)); high(interval, (newHigh)); return interval; } @@ -228,36 +264,38 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, interval_type>::type & scale(interval_type& interval, double factor) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit newHigh = scaling_policy::round((double)(high(interval)) * factor); low(interval, scaling_policy::round((double)low(interval)* factor)); high(interval, (newHigh)); return interval; } - + + struct y_i_move : gtl_yes {}; + // move interval by delta template - interval_type& - move(interval_type& interval, - typename interval_difference_type::type displacement, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename interval_traits::coordinate_type ctype; + typename enable_if< typename gtl_and< + y_i_move, + typename is_mutable_interval_concept::type>::type>::type, + interval_type>::type & + move(interval_type& interval, typename interval_difference_type::type displacement) { + typedef typename interval_coordinate_type::type ctype; typedef typename coordinate_traits::coordinate_difference Unit; Unit len = delta(interval); low(interval, static_cast(static_cast(low(interval)) + displacement)); high(interval, static_cast(static_cast(low(interval)) + len)); return interval; } - + struct y_i_convolve : gtl_yes {}; // convolve this with b template typename enable_if::type>::type>::type, interval_type>::type & convolve(interval_type& interval, - typename interval_traits::coordinate_type b) { - typedef typename interval_traits::coordinate_type Unit; + typename interval_coordinate_type::type b) { + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) + b; Unit newHigh = high(interval) + b; low(interval, newLow); @@ -271,8 +309,8 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, interval_type>::type & deconvolve(interval_type& interval, - typename interval_traits::coordinate_type b) { - typedef typename interval_traits::coordinate_type Unit; + typename interval_coordinate_type::type b) { + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) - b; Unit newHigh = high(interval) - b; low(interval, newLow); @@ -284,78 +322,78 @@ namespace boost { namespace polygon{ // convolve this with b template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, + typename is_mutable_interval_concept::type>::type, typename is_interval_concept::type>::type>::type, interval_type>::type & convolve(interval_type& interval, const interval_type_2& b) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) + low(b); Unit newHigh = high(interval) + high(b); low(interval, newLow); high(interval, newHigh); return interval; } - + struct y_i_deconvolve2 : gtl_yes {}; // deconvolve this with b template - typename enable_if< + typename enable_if< typename gtl_and_3< y_i_deconvolve2, typename is_mutable_interval_concept::type>::type, typename is_interval_concept::type>::type>::type, interval_type>::type & deconvolve(interval_type& interval, const interval_type_2& b) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) - low(b); Unit newHigh = high(interval) - high(b); low(interval, newLow); high(interval, newHigh); return interval; } - + struct y_i_reconvolve : gtl_yes {}; // reflected convolve this with b template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, interval_type>::type & reflected_convolve(interval_type& interval, const interval_type_2& b) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) - high(b); Unit newHigh = high(interval) - low(b); low(interval, newLow); high(interval, newHigh); return interval; } - + struct y_i_redeconvolve : gtl_yes {}; // reflected deconvolve this with b template - typename enable_if< + typename enable_if< typename gtl_and_3< y_i_redeconvolve, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, interval_type>::type & reflected_deconvolve(interval_type& interval, const interval_type_2& b) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit newLow = low(interval) + high(b); Unit newHigh = high(interval) + low(b); low(interval, newLow); high(interval, newHigh); return interval; } - + struct y_i_e_dist1 : gtl_yes {}; // distance from a coordinate to an interval @@ -363,38 +401,38 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and::type>::type>::type, typename interval_difference_type::type>::type euclidean_distance(const interval_type& interval, - typename interval_traits::coordinate_type position) { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference Unit; + typename interval_coordinate_type::type position) { + typedef typename coordinate_traits::type>::coordinate_difference Unit; Unit dist[3] = {0, (Unit)low(interval) - (Unit)position, (Unit)position - (Unit)high(interval)}; return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; } struct y_i_e_dist2 : gtl_yes {}; - + // distance between two intervals template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, typename interval_difference_type::type>::type euclidean_distance(const interval_type& interval, const interval_type_2& b) { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference Unit; + typedef typename coordinate_traits::type>::coordinate_difference Unit; Unit dist[3] = {0, (Unit)low(interval) - (Unit)high(b), (Unit)low(b) - (Unit)high(interval)}; return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; } - + struct y_i_e_intersects : gtl_yes {}; // check if Interval b intersects `this` Interval template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type - intersects(const interval_type& interval, const interval_type_2& b, + bool>::type + intersects(const interval_type& interval, const interval_type_2& b, bool consider_touch = true) { - return consider_touch ? + return consider_touch ? (low(interval) <= high(b)) & (high(interval) >= low(b)) : (low(interval) < high(b)) & (high(interval) > low(b)); } @@ -403,15 +441,15 @@ namespace boost { namespace polygon{ // check if Interval b partially overlaps `this` Interval template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type - boundaries_intersect(const interval_type& interval, const interval_type_2& b, + bool>::type + boundaries_intersect(const interval_type& interval, const interval_type_2& b, bool consider_touch = true) { - return (contains(interval, low(b), consider_touch) || + return (contains(interval, low(b), consider_touch) || contains(interval, high(b), consider_touch)) && - (contains(b, low(interval), consider_touch) || + (contains(b, low(interval), consider_touch) || contains(b, high(interval), consider_touch)); } @@ -421,7 +459,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type + bool>::type abuts(const interval_type& interval, const interval_type_2& b, direction_1d dir) { return dir.to_int() ? low(b) == high(interval) : low(interval) == high(b); } @@ -430,13 +468,13 @@ namespace boost { namespace polygon{ // check if they are end to end template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type + bool>::type abuts(const interval_type& interval, const interval_type_2& b) { return abuts(interval, b, HIGH) || abuts(interval, b, LOW); - } + } struct y_i_intersect : gtl_yes {}; @@ -444,9 +482,9 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type + bool>::type intersect(interval_type& interval, const interval_type_2& b, bool consider_touch = true) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit lowVal = (std::max)(low(interval), low(b)); Unit highVal = (std::min)(high(interval), high(b)); bool valid = consider_touch ? @@ -463,15 +501,15 @@ namespace boost { namespace polygon{ // set 'this' interval to the generalized intersection of 'this' and b template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, interval_type>::type & generalized_intersect(interval_type& interval, const interval_type_2& b) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit coords[4] = {low(interval), high(interval), low(b), high(b)}; //consider implementing faster sorting of small fixed length range - gtlsort(coords, coords+4); + polygon_sort(coords, coords+4); low(interval, coords[1]); high(interval, coords[2]); return interval; @@ -483,19 +521,19 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and::type>::type>::type, interval_type>::type & - bloat(interval_type& interval, typename interval_traits::coordinate_type bloating) { + bloat(interval_type& interval, typename interval_coordinate_type::type bloating) { low(interval, low(interval)-bloating); high(interval, high(interval)+bloating); return interval; } - + struct y_i_bloat2 : gtl_yes {}; // bloat the specified side of `this` Interval template typename enable_if< typename gtl_and::type>::type>::type, interval_type>::type & - bloat(interval_type& interval, direction_1d dir, typename interval_traits::coordinate_type bloating) { + bloat(interval_type& interval, direction_1d dir, typename interval_coordinate_type::type bloating) { set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); return interval; } @@ -506,7 +544,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and::type>::type>::type, interval_type>::type & - shrink(interval_type& interval, typename interval_traits::coordinate_type shrinking) { + shrink(interval_type& interval, typename interval_coordinate_type::type shrinking) { return bloat(interval, -shrinking); } @@ -516,44 +554,46 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and::type>::type>::type, interval_type>::type & - shrink(interval_type& interval, direction_1d dir, typename interval_traits::coordinate_type shrinking) { + shrink(interval_type& interval, direction_1d dir, typename interval_coordinate_type::type shrinking) { return bloat(interval, dir, -shrinking); } - // Enlarge `this` Interval to encompass the specified Interval - template - bool - encompass(interval_type& interval, const interval_type_2& b, - typename enable_if< - typename gtl_and< typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type>::type * = 0 - ) { - bool retval = !contains(interval, b, true); - low(interval, (std::min)(low(interval), low(b))); - high(interval, (std::max)(high(interval), high(b))); - return retval; - } - struct y_i_encompass : gtl_yes {}; + // Enlarge `this` Interval to encompass the specified Interval + template + typename enable_if< typename gtl_and_3< + y_i_encompass, + typename is_mutable_interval_concept::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + encompass(interval_type& interval, const interval_type_2& b) { + bool retval = !contains(interval, b, true); + low(interval, (std::min)(low(interval), low(b))); + high(interval, (std::max)(high(interval), high(b))); + return retval; + } + + struct y_i_encompass2 : gtl_yes {}; + // Enlarge `this` Interval to encompass the specified Interval template - typename enable_if< typename gtl_and::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, bool>::type - encompass(interval_type& interval, typename interval_traits::coordinate_type b) { + encompass(interval_type& interval, typename interval_coordinate_type::type b) { bool retval = !contains(interval, b, true); low(interval, (std::min)(low(interval), b)); high(interval, (std::max)(high(interval), b)); return retval; - } + } struct y_i_get_half : gtl_yes {}; // gets the half of the interval as an interval template - typename enable_if::type>::type>::type, interval_type>::type + typename enable_if::type>::type>::type, interval_type>::type get_half(const interval_type& interval, direction_1d d1d) { - typedef typename interval_traits::coordinate_type Unit; + typedef typename interval_coordinate_type::type Unit; Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; return construct((d1d == LOW) ? get(interval, LOW) : c, (d1d == LOW) ? c : get(interval, HIGH)); @@ -564,10 +604,10 @@ namespace boost { namespace polygon{ // returns true if the 2 intervals exactly touch at one value, like in l1 <= h1 == l2 <= h2 // sets the argument to the joined interval template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type + bool>::type join_with(interval_type& interval, const interval_type_2& b) { if(abuts(interval, b)) { encompass(interval, b); diff --git a/include/boost/polygon/interval_data.hpp b/include/boost/polygon/interval_data.hpp old mode 100755 new mode 100644 index cf2aabf..dbb772e --- a/include/boost/polygon/interval_data.hpp +++ b/include/boost/polygon/interval_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -14,31 +14,31 @@ namespace boost { namespace polygon{ public: typedef T coordinate_type; inline interval_data() -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - {} +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif + {} inline interval_data(coordinate_type low, coordinate_type high) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif { - coords_[LOW] = low; coords_[HIGH] = high; + coords_[LOW] = low; coords_[HIGH] = high; } inline interval_data(const interval_data& that) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif +#ifndef BOOST_POLYGON_MSVC + :coords_() +#endif { - (*this) = that; + (*this) = that; } inline interval_data& operator=(const interval_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; } template inline interval_data& operator=(const T2& rvalue); inline coordinate_type get(direction_1d dir) const { - return coords_[dir.to_int()]; + return coords_[dir.to_int()]; } inline coordinate_type low() const { return coords_[0]; } inline coordinate_type high() const { return coords_[1]; } @@ -56,10 +56,10 @@ namespace boost { namespace polygon{ inline bool operator>(const interval_data& that) const { return that < *this; } inline bool operator>=(const interval_data& that) const { return !((*this) < that); } inline void set(direction_1d dir, coordinate_type value) { - coords_[dir.to_int()] = value; + coords_[dir.to_int()] = value; } private: - coordinate_type coords_[2]; + coordinate_type coords_[2]; }; } diff --git a/include/boost/polygon/interval_traits.hpp b/include/boost/polygon/interval_traits.hpp old mode 100755 new mode 100644 index a7d74ef..97f918f --- a/include/boost/polygon/interval_traits.hpp +++ b/include/boost/polygon/interval_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -13,21 +13,20 @@ namespace boost { namespace polygon{ typedef typename T::coordinate_type coordinate_type; static inline coordinate_type get(const T& interval, direction_1d dir) { - return interval.get(dir); + return interval.get(dir); } }; template struct interval_mutable_traits { static inline void set(T& interval, direction_1d dir, typename interval_traits::coordinate_type value) { - interval.set(dir, value); + interval.set(dir, value); } - static inline T construct(typename interval_traits::coordinate_type low_value, + static inline T construct(typename interval_traits::coordinate_type low_value, typename interval_traits::coordinate_type high_value) { - return T(low_value, high_value); + return T(low_value, high_value); } }; } } #endif - diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp old mode 100755 new mode 100644 index 055707c..890595e --- a/include/boost/polygon/isotropy.hpp +++ b/include/boost/polygon/isotropy.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -26,7 +26,7 @@ #ifndef BOOST_POLYGON_NO_DEPS -#include +#include #ifdef BOOST_MSVC #define BOOST_POLYGON_MSVC #endif @@ -58,7 +58,7 @@ typedef boost::ulong_long_type polygon_ulong_long_type; typedef long long polygon_long_long_type; typedef unsigned long long polygon_ulong_long_type; - namespace boost { + namespace boost { template struct enable_if_c { typedef T type; @@ -67,7 +67,7 @@ typedef unsigned long long polygon_ulong_long_type; template struct enable_if_c {}; - template + template struct enable_if : public enable_if_c {}; template @@ -78,7 +78,7 @@ typedef unsigned long long polygon_ulong_long_type; template struct lazy_enable_if_c {}; - template + template struct lazy_enable_if : public lazy_enable_if_c {}; @@ -90,7 +90,7 @@ typedef unsigned long long polygon_ulong_long_type; template struct disable_if_c {}; - template + template struct disable_if : public disable_if_c {}; template @@ -101,7 +101,7 @@ typedef unsigned long long polygon_ulong_long_type; template struct lazy_disable_if_c {}; - template + template struct lazy_disable_if : public lazy_disable_if_c {}; } @@ -129,17 +129,18 @@ namespace boost { namespace polygon{ struct undefined_concept {}; template - struct geometry_concept { typedef undefined_concept type; }; + struct geometry_concept { typedef undefined_concept type; }; template struct view_of {}; template - view_of view_as(const T2& obj) { return view_of(obj); } + view_of view_as(const T2& obj) { return view_of(obj); } template struct coordinate_traits {}; + //used to override long double with an infinite precision datatype template struct high_precision_type { typedef long double type; @@ -150,6 +151,14 @@ namespace boost { namespace polygon{ return T(v); } + //used to override std::sort with an alternative (parallel) algorithm + template + void polygon_sort(iter_type _b_, iter_type _e_); + + template + void polygon_sort(iter_type _b_, iter_type _e_, const pred_type& _pred_); + + template <> struct coordinate_traits { typedef int coordinate_type; @@ -314,13 +323,13 @@ namespace boost { namespace polygon{ template struct area_type_by_domain { typedef typename coordinate_traits::area_type type; }; template - struct area_type_by_domain { + struct area_type_by_domain { typedef typename coordinate_traits::manhattan_area_type type; }; struct y_c_edist : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3::type, coordinate_concept>::type, typename gtl_same_type::type, coordinate_concept>::type>::type, typename coordinate_traits::coordinate_difference>::type @@ -383,7 +392,7 @@ namespace boost { namespace polygon{ inline direction_1d(const direction_1d_enum val) : val_(val) {} explicit inline direction_1d(const direction_2d& that); explicit inline direction_1d(const direction_3d& that); - inline direction_1d& operator = (const direction_1d& d) { + inline direction_1d& operator = (const direction_1d& d) { val_ = d.val_; return * this; } inline bool operator==(direction_1d d) const { return (val_ == d.val_); } inline bool operator!=(direction_1d d) const { return !((*this) == d); } @@ -426,7 +435,7 @@ namespace boost { namespace polygon{ inline direction_2d() : val_(WEST) {} inline direction_2d(const direction_2d& that) : val_(that.val_) {} - + inline direction_2d(const direction_2d_enum val) : val_(val) {} inline direction_2d& operator=(const direction_2d& d) { @@ -489,7 +498,7 @@ namespace boost { namespace polygon{ explicit inline orientation_3d(const direction_2d& that); explicit inline orientation_3d(const direction_3d& that); inline ~orientation_3d() { } - inline orientation_3d& operator=(const orientation_3d& ori) { + inline orientation_3d& operator=(const orientation_3d& ori) { val_ = ori.val_; return * this; } inline bool operator==(orientation_3d that) const { return (val_ == that.val_); } inline bool operator!=(orientation_3d that) const { return (val_ != that.val_); } @@ -507,7 +516,7 @@ namespace boost { namespace polygon{ inline direction_3d(direction_2d that) : val_(that.to_int()) {} inline direction_3d(const direction_3d& that) : val_(that.val_) {} - + inline direction_3d(const direction_2d_enum val) : val_(val) {} inline direction_3d(const direction_3d_enum val) : val_(val) {} @@ -551,4 +560,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/point_3d_concept.hpp b/include/boost/polygon/point_3d_concept.hpp old mode 100755 new mode 100644 index ab7afeb..6183237 --- a/include/boost/polygon/point_3d_concept.hpp +++ b/include/boost/polygon/point_3d_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -12,7 +12,7 @@ #include "point_3d_traits.hpp" namespace boost { namespace polygon{ struct point_3d_concept {}; - + template struct is_point_3d_concept { typedef gtl_no type; }; template <> @@ -38,8 +38,8 @@ namespace boost { namespace polygon{ template struct point_3d_difference_type_by_concept { typedef void type; }; template - struct point_3d_difference_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + struct point_3d_difference_type_by_concept { + typedef typename coordinate_traits::type>::coordinate_difference type; }; template struct point_3d_difference_type { @@ -50,8 +50,8 @@ namespace boost { namespace polygon{ template struct point_3d_distance_type_by_concept { typedef void type; }; template - struct point_3d_distance_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + struct point_3d_distance_type_by_concept { + typedef typename coordinate_traits::type>::coordinate_distance type; }; template struct point_3d_distance_type { @@ -62,10 +62,10 @@ namespace boost { namespace polygon{ struct y_p3d_get : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, - typename point_3d_coordinate_type::type >::type + typename enable_if< typename gtl_and::type>::type>::type, + typename point_3d_coordinate_type::type >::type get(const T& point, orientation_3d orient) { return point_3d_traits::get(point, orient); } - + struct y_p3d_set : gtl_yes {}; template @@ -86,11 +86,11 @@ namespace boost { namespace polygon{ return point_3d_mutable_traits::construct(x_value, y_value, z_value); } struct y_p3d_assign : gtl_yes {}; - + template typename enable_if< - typename gtl_and_3::type>::type, - typename is_point_3d_concept::type>::type>::type, + typename gtl_and_3::type>::type, + typename is_point_3d_concept::type>::type>::type, point_3d_type_1>::type & assign(point_3d_type_1& lvalue, const point_3d_type_2& rvalue) { set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); @@ -102,8 +102,8 @@ namespace boost { namespace polygon{ struct y_p3d_z : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_3d_traits::coordinate_type >::type + typename enable_if< typename gtl_and::type>::type>::type, + typename point_3d_coordinate_type::type >::type z(const point_type& point) { return get(point, PROXIMAL); } struct y_p3d_x : gtl_yes {}; @@ -128,7 +128,7 @@ namespace boost { namespace polygon{ template typename enable_if< - typename gtl_and_3::type>::type, + typename gtl_and_3::type>::type, typename gtl_same_type::type>::type>::type, bool>::type equivalence(const T& point1, const T2& point2) { @@ -138,11 +138,11 @@ namespace boost { namespace polygon{ struct y_p3d_dist : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, - typename is_point_3d_concept::type>::type>::type, + typename enable_if< typename gtl_and_3::type>::type, + typename is_point_3d_concept::type>::type>::type, typename point_3d_difference_type::type>::type euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_3d orient) { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference return_type; + typedef typename coordinate_traits::type>::coordinate_difference return_type; return_type return_value = (return_type)get(point1, orient) - (return_type)get(point2, orient); return return_value < 0 ? -return_value : return_value; @@ -151,33 +151,33 @@ namespace boost { namespace polygon{ struct y_p3d_man_dist : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3::type>::type, typename gtl_same_type::type>::type>::type, typename point_3d_difference_type::type>::type manhattan_distance(const point_type_1& point1, const point_type_2& point2) { - return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL) + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL) + euclidean_distance(point1, point2, PROXIMAL); } struct y_p3d_dist2 : gtl_yes {}; template - typename enable_if< typename gtl_and_3< y_p3d_dist2, - typename gtl_same_type::type>::type, + typename enable_if< typename gtl_and_3< y_p3d_dist2, + typename gtl_same_type::type>::type, typename gtl_same_type::type>::type>::type, typename point_3d_distance_type::type>::type euclidean_distance(const point_type_1& point1, const point_type_2& point2) { - typedef typename coordinate_traits::coordinate_type>::coordinate_distance return_value; + typedef typename coordinate_traits::type>::coordinate_distance return_value; return_value pdist = (return_value)euclidean_distance(point1, point2, PROXIMAL); pdist *= pdist; - return sqrt((double)(distance_squared(point1, point2) + pdist)); + return std::sqrt((double)(distance_squared(point1, point2) + pdist)); } - + struct y_p3d_convolve : gtl_yes {}; template typename enable_if< typename gtl_and_3< y_p3d_convolve, - typename is_mutable_point_3d_concept::type>::type, + typename is_mutable_point_3d_concept::type>::type, typename gtl_same_type::type>::type>::type, point_type_1>::type & convolve(point_type_1& lvalue, const point_type_2& rvalue) { @@ -186,12 +186,12 @@ namespace boost { namespace polygon{ z(lvalue, z(lvalue) + z(rvalue)); return lvalue; } - + struct y_p3d_deconvolve : gtl_yes {}; template typename enable_if< - typename gtl_and_3::type>::type, + typename gtl_and_3::type>::type, typename gtl_same_type::type>::type>::type, point_type_1>::type & deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { @@ -204,39 +204,39 @@ namespace boost { namespace polygon{ struct y_p3d_scale_up : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, point_type>::type & - scale_up(point_type& point, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { - x(point, x(point) * (typename point_3d_traits::coordinate_type)factor); - y(point, y(point) * (typename point_3d_traits::coordinate_type)factor); - z(point, z(point) * (typename point_3d_traits::coordinate_type)factor); + scale_up(point_type& point, + typename coordinate_traits::type>::unsigned_area_type factor) { + x(point, x(point) * (typename point_3d_coordinate_type::type)factor); + y(point, y(point) * (typename point_3d_coordinate_type::type)factor); + z(point, z(point) * (typename point_3d_coordinate_type::type)factor); return point; } struct y_p3d_scale_down : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, point_type>::type & - scale_down(point_type& point, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { - typedef typename point_3d_traits::coordinate_type Unit; + scale_down(point_type& point, + typename coordinate_traits::type>::unsigned_area_type factor) { + typedef typename point_3d_coordinate_type::type Unit; typedef typename coordinate_traits::coordinate_distance dt; - x(point, scaling_policy::round((dt)(x(point)) / (dt)factor)); - y(point, scaling_policy::round((dt)(y(point)) / (dt)factor)); - z(point, scaling_policy::round((dt)(z(point)) / (dt)factor)); + x(point, scaling_policy::round((dt)(x(point)) / (dt)factor)); + y(point, scaling_policy::round((dt)(y(point)) / (dt)factor)); + z(point, scaling_policy::round((dt)(z(point)) / (dt)factor)); return point; } struct y_p3d_scale : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, point_type>::type & - scale(point_type& point, + scale(point_type& point, const scaling_type& scaling) { - typedef typename point_3d_traits::coordinate_type Unit; + typedef typename point_3d_coordinate_type::type Unit; Unit x_(x(point)), y_(y(point)), z_(z(point)); scaling.scale(x_, y_, z_); x(point, x_); @@ -248,10 +248,10 @@ namespace boost { namespace polygon{ struct y_p3d_transform : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, point_type>::type & transform(point_type& point, const transformation_type& transformation) { - typedef typename point_3d_traits::coordinate_type Unit; + typedef typename point_3d_coordinate_type::type Unit; Unit x_(x(point)), y_(y(point)), z_(z(point)); transformation.transform(x_, y_, z_); x(point, x_); diff --git a/include/boost/polygon/point_3d_data.hpp b/include/boost/polygon/point_3d_data.hpp old mode 100755 new mode 100644 index c57097c..24a01af --- a/include/boost/polygon/point_3d_data.hpp +++ b/include/boost/polygon/point_3d_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -12,7 +12,7 @@ namespace boost { namespace polygon{ class point_3d_data { public: typedef T coordinate_type; - inline point_3d_data():coords_(){} + inline point_3d_data():coords_(){} inline point_3d_data(coordinate_type x, coordinate_type y):coords_() { coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = 0; } inline point_3d_data(coordinate_type x, coordinate_type y, coordinate_type z) @@ -23,7 +23,7 @@ namespace boost { namespace polygon{ coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = z; } inline point_3d_data(const point_3d_data& that):coords_() { (*this) = that; } inline point_3d_data& operator=(const point_3d_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; coords_[2] = that.coords_[2]; return *this; } template inline point_3d_data& operator=(const T2& rvalue); @@ -42,10 +42,8 @@ namespace boost { namespace polygon{ inline void set(orientation_3d orient, coordinate_type value) { coords_[orient.to_int()] = value; } private: - coordinate_type coords_[3]; + coordinate_type coords_[3]; }; } } #endif - - diff --git a/include/boost/polygon/point_3d_traits.hpp b/include/boost/polygon/point_3d_traits.hpp old mode 100755 new mode 100644 index 9f6eb9a..3de97cc --- a/include/boost/polygon/point_3d_traits.hpp +++ b/include/boost/polygon/point_3d_traits.hpp @@ -23,7 +23,7 @@ namespace boost { namespace polygon{ struct point_3d_mutable_traits { static inline void set(T& point, orientation_3d orient, typename point_3d_traits::coordinate_type value) { point.set(orient, value); } - + static inline T construct(typename point_3d_traits::coordinate_type x_value, typename point_3d_traits::coordinate_type y_value, typename point_3d_traits::coordinate_type z_value) { @@ -32,4 +32,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/point_concept.hpp b/include/boost/polygon/point_concept.hpp old mode 100755 new mode 100644 index 6e2ce0a..e4f42f9 --- a/include/boost/polygon/point_concept.hpp +++ b/include/boost/polygon/point_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -13,7 +13,7 @@ namespace boost { namespace polygon{ struct point_concept {}; - + template struct is_point_concept { typedef gtl_no type; }; template <> @@ -41,8 +41,8 @@ namespace boost { namespace polygon{ template struct point_difference_type_by_concept { typedef void type; }; template - struct point_difference_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + struct point_difference_type_by_concept { + typedef typename coordinate_traits::type>::coordinate_difference type; }; template struct point_difference_type { @@ -53,8 +53,8 @@ namespace boost { namespace polygon{ template struct point_distance_type_by_concept { typedef void type; }; template - struct point_distance_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + struct point_distance_type_by_concept { + typedef typename coordinate_traits::type>::coordinate_distance type; }; template struct point_distance_type { @@ -62,36 +62,42 @@ namespace boost { namespace polygon{ T, typename is_point_concept::type>::type>::type type; }; + struct y_pt_get : gtl_yes {}; + template - typename point_coordinate_type::type - get(const T& point, orientation_2d orient, - typename enable_if< typename gtl_if::type>::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and::type>::type>::type, + typename point_coordinate_type::type >::type + get(const T& point, orientation_2d orient) { return point_traits::get(point, orient); } - + + struct y_pt_set : gtl_yes {}; + template - void - set(T& point, orientation_2d orient, coordinate_type value, - typename enable_if::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and::type>::type>::type, + void>::type + set(T& point, orientation_2d orient, coordinate_type value) { point_mutable_traits::set(point, orient, value); } - + + struct y_pt_construct : gtl_yes {}; + template - T - construct(coordinate_type1 x_value, coordinate_type2 y_value, - typename enable_if::type>::type>::type * = 0 - ) { - return point_mutable_traits::construct(x_value, y_value); + typename enable_if< typename gtl_and::type>::type>::type, + T>::type + construct(coordinate_type1 x_value, coordinate_type2 y_value) { + return point_mutable_traits::construct(x_value, y_value); } + struct y_pt_assign : gtl_yes {}; + template - T1& - assign(T1& lvalue, const T2& rvalue, - typename enable_if< typename gtl_and< typename is_mutable_point_concept::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { + typename enable_if::type>::type, + typename is_point_concept::type>::type>::type, + T1>::type & + assign(T1& lvalue, const T2& rvalue) { set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); set(lvalue, VERTICAL, get(rvalue, VERTICAL)); return lvalue; @@ -100,8 +106,8 @@ namespace boost { namespace polygon{ struct y_p_x : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_traits::coordinate_type >::type + typename enable_if< typename gtl_and::type>::type>::type, + typename point_coordinate_type::type >::type x(const point_type& point) { return get(point, HORIZONTAL); } @@ -109,8 +115,8 @@ namespace boost { namespace polygon{ struct y_p_y : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_traits::coordinate_type >::type + typename enable_if< typename gtl_and::type>::type>::type, + typename point_coordinate_type::type >::type y(const point_type& point) { return get(point, VERTICAL); } @@ -119,7 +125,7 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, - void>::type + void>::type x(point_type& point, coordinate_type value) { set(point, HORIZONTAL, value); } @@ -128,62 +134,71 @@ namespace boost { namespace polygon{ template typename enable_if::type>::type>::type, - void>::type + void>::type y(point_type& point, coordinate_type value) { set(point, VERTICAL, value); } + struct y_pt_equiv : gtl_yes {}; + template - bool - equivalence(const T& point1, const T2& point2, - typename enable_if< typename gtl_and::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { - typename point_traits::coordinate_type x1 = x(point1); - typename point_traits::coordinate_type x2 = get(point2, HORIZONTAL); - typename point_traits::coordinate_type y1 = get(point1, VERTICAL); - typename point_traits::coordinate_type y2 = y(point2); + typename enable_if::type>::type, + typename is_point_concept::type>::type>::type, + bool>::type + equivalence(const T& point1, const T2& point2) { + typename point_coordinate_type::type x1 = x(point1); + typename point_coordinate_type::type x2 = get(point2, HORIZONTAL); + typename point_coordinate_type::type y1 = get(point1, VERTICAL); + typename point_coordinate_type::type y2 = y(point2); return x1 == x2 && y1 == y2; } - template - typename point_difference_type::type - manhattan_distance(const point_type_1& point1, const point_type_2& point2, - typename enable_if< typename gtl_and::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0) { - return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); - } - - struct y_i_ed1 : gtl_yes {}; + struct y_pt_man_dist : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3< + y_pt_man_dist, + typename gtl_same_type::type>::type, + typename is_point_concept::type>::type>::type, + typename point_difference_type::type>::type + manhattan_distance(const point_type_1& point1, const point_type_2& point2) { + return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); + } + + struct y_pt_ed1 : gtl_yes {}; + + template + typename enable_if< typename gtl_and_3::type>::type, typename is_point_concept::type>::type>::type, typename point_difference_type::type>::type euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_2d orient) { - typename coordinate_traits::coordinate_type>::coordinate_difference return_value = + typename coordinate_traits::type>::coordinate_difference return_value = get(point1, orient) - get(point2, orient); - return return_value < 0 ? (typename coordinate_traits::coordinate_type>::coordinate_difference)-return_value : return_value; + return return_value < 0 ? (typename coordinate_traits::type>::coordinate_difference)-return_value : return_value; } - - struct y_i_ed2 : gtl_yes {}; + + struct y_pt_ed2 : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3::type>::type, typename gtl_same_type::type>::type>::type, typename point_distance_type::type>::type euclidean_distance(const point_type_1& point1, const point_type_2& point2) { - typedef typename point_traits::coordinate_type Unit; - return sqrt((double)(distance_squared(point1, point2))); + typedef typename point_coordinate_type::type Unit; + return std::sqrt((double)(distance_squared(point1, point2))); } - + + struct y_pt_eds : gtl_yes {}; + template - typename point_difference_type::type - distance_squared(const point_type_1& point1, const point_type_2& point2, - typename enable_if< typename gtl_and::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename enable_if< typename gtl_and_3< + y_pt_eds, + typename is_point_concept::type>::type, + typename is_point_concept::type>::type>::type, + typename point_difference_type::type>::type + distance_squared(const point_type_1& point1, const point_type_2& point2) { + typedef typename point_coordinate_type::type Unit; typename coordinate_traits::coordinate_difference dx = euclidean_distance(point1, point2, HORIZONTAL); typename coordinate_traits::coordinate_difference dy = euclidean_distance(point1, point2, VERTICAL); dx *= dx; @@ -191,58 +206,66 @@ namespace boost { namespace polygon{ return dx + dy; } + struct y_pt_convolve : gtl_yes {}; + template - point_type_1 & - convolve(point_type_1& lvalue, const point_type_2& rvalue, - typename enable_if< typename gtl_and::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and_3< + y_pt_convolve, + typename is_mutable_point_concept::type>::type, + typename is_point_concept::type>::type>::type, + point_type_1>::type & + convolve(point_type_1& lvalue, const point_type_2& rvalue) { x(lvalue, x(lvalue) + x(rvalue)); y(lvalue, y(lvalue) + y(rvalue)); return lvalue; } - + + struct y_pt_deconvolve : gtl_yes {}; + template - point_type_1 & - deconvolve(point_type_1& lvalue, const point_type_2& rvalue, - typename enable_if< typename gtl_and::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and_3< + y_pt_deconvolve, + typename is_mutable_point_concept::type>::type, + typename is_point_concept::type>::type>::type, + point_type_1>::type & + deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { x(lvalue, x(lvalue) - x(rvalue)); y(lvalue, y(lvalue) - y(rvalue)); return lvalue; } - + + struct y_pt_scale_up : gtl_yes {}; + template - point_type & - scale_up(point_type& point, coord_type factor, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale_up(point_type& point, coord_type factor) { + typedef typename point_coordinate_type::type Unit; x(point, x(point) * (Unit)factor); y(point, y(point) * (Unit)factor); return point; } + struct y_pt_scale_down : gtl_yes {}; + template - point_type & - scale_down(point_type& point, coord_type factor, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale_down(point_type& point, coord_type factor) { + typedef typename point_coordinate_type::type Unit; typedef typename coordinate_traits::coordinate_distance dt; - x(point, scaling_policy::round((dt)((dt)(x(point)) / (dt)factor))); - y(point, scaling_policy::round((dt)((dt)(y(point)) / (dt)factor))); + x(point, scaling_policy::round((dt)((dt)(x(point)) / (dt)factor))); + y(point, scaling_policy::round((dt)((dt)(y(point)) / (dt)factor))); return point; } + struct y_pt_scale : gtl_yes {}; + template - point_type & - scale(point_type& point, - const scaling_type& scaling, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + scale(point_type& point, const scaling_type& scaling) { + typedef typename point_coordinate_type::type Unit; Unit x_(x(point)), y_(y(point)); scaling.scale(x_, y_); x(point, x_); @@ -250,12 +273,13 @@ namespace boost { namespace polygon{ return point; } + struct y_pt_transform : gtl_yes {}; + template - point_type & - transform(point_type& point, const transformation_type& transformation, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & + transform(point_type& point, const transformation_type& transformation) { + typedef typename point_coordinate_type::type Unit; Unit x_(x(point)), y_(y(point)); transformation.transform(x_, y_); x(point, x_); @@ -266,16 +290,11 @@ namespace boost { namespace polygon{ struct y_pt_move : gtl_yes {}; template - typename enable_if< - typename gtl_and< y_pt_move, - typename is_mutable_point_concept< - typename geometry_concept::type>::type>::type, - point_type>::type & + typename enable_if< typename gtl_and::type>::type>::type, + point_type>::type & move(point_type& point, orientation_2d orient, - typename point_traits::coordinate_type displacement, - typename enable_if::type>::type>::type * = 0 - ) { - typedef typename point_traits::coordinate_type Unit; + typename point_coordinate_type::type displacement) { + typedef typename point_coordinate_type::type Unit; Unit v(get(point, orient)); set(point, orient, v + displacement); return point; @@ -295,4 +314,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/point_data.hpp b/include/boost/polygon/point_data.hpp old mode 100755 new mode 100644 index d181b03..0ed55cf --- a/include/boost/polygon/point_data.hpp +++ b/include/boost/polygon/point_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -18,34 +18,34 @@ namespace boost { namespace polygon{ typedef T coordinate_type; inline point_data() #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif - {} + {} inline point_data(coordinate_type x, coordinate_type y) #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif { - coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; + coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; } inline point_data(const point_data& that) #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif { (*this) = that; } template point_data(const other& that) #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif { (*this) = that; } inline point_data& operator=(const point_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; + coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; } template inline point_data(const T1& x, const T2& y) #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif { coords_[HORIZONTAL] = (coordinate_type)x; @@ -54,7 +54,7 @@ namespace boost { namespace polygon{ template inline point_data(const point_data& rvalue) #ifndef BOOST_POLYGON_MSVC - :coords_() + :coords_() #endif { coords_[HORIZONTAL] = (coordinate_type)(rvalue.x()); @@ -76,10 +76,10 @@ namespace boost { namespace polygon{ inline bool operator>(const point_data& that) const { return that < *this; } inline bool operator>=(const point_data& that) const { return !((*this) < that); } inline coordinate_type get(orientation_2d orient) const { - return coords_[orient.to_int()]; + return coords_[orient.to_int()]; } inline void set(orientation_2d orient, coordinate_type value) { - coords_[orient.to_int()] = value; + coords_[orient.to_int()] = value; } inline coordinate_type x() const { return coords_[HORIZONTAL]; @@ -96,10 +96,9 @@ namespace boost { namespace polygon{ return *this; } private: - coordinate_type coords_[2]; + coordinate_type coords_[2]; }; } } #endif - diff --git a/include/boost/polygon/point_traits.hpp b/include/boost/polygon/point_traits.hpp old mode 100755 new mode 100644 index 504fa35..6604d2c --- a/include/boost/polygon/point_traits.hpp +++ b/include/boost/polygon/point_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -14,22 +14,21 @@ namespace boost { namespace polygon{ template struct point_traits { typedef typename T::coordinate_type coordinate_type; - + static inline coordinate_type get(const T& point, orientation_2d orient) { - return point.get(orient); + return point.get(orient); } }; template struct point_mutable_traits { static inline void set(T& point, orientation_2d orient, typename point_traits::coordinate_type value) { - point.set(orient, value); + point.set(orient, value); } static inline T construct(typename point_traits::coordinate_type x_value, typename point_traits::coordinate_type y_value) { - return T(x_value, y_value); + return T(x_value, y_value); } }; } } #endif - diff --git a/include/boost/polygon/polygon.hpp b/include/boost/polygon/polygon.hpp old mode 100755 new mode 100644 index 4c3e43a..ddbc08d --- a/include/boost/polygon/polygon.hpp +++ b/include/boost/polygon/polygon.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -34,6 +34,11 @@ #include "rectangle_traits.hpp" #include "rectangle_concept.hpp" +//segment +#include "segment_data.hpp" +#include "segment_traits.hpp" +#include "segment_concept.hpp" + //algorithms needed by polygon types #include "detail/iterator_points_to_compact.hpp" #include "detail/iterator_compact_to_points.hpp" @@ -88,4 +93,6 @@ #include "polygon_set_concept.hpp" +#include "segment_utils.hpp" + #endif diff --git a/include/boost/polygon/polygon_45_data.hpp b/include/boost/polygon/polygon_45_data.hpp old mode 100755 new mode 100644 index 86753ec..cdd5c24 --- a/include/boost/polygon/polygon_45_data.hpp +++ b/include/boost/polygon/polygon_45_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -34,7 +34,7 @@ public: // copy constructor (since we have dynamic memory) inline polygon_45_data(const polygon_45_data& that) : coords_(that.coords_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_45_data& operator=(const polygon_45_data& that) { coords_ = that.coords_; @@ -63,11 +63,10 @@ public: inline std::size_t size() const { return coords_.size(); } public: - std::vector > coords_; + std::vector > coords_; }; } } #endif - diff --git a/include/boost/polygon/polygon_45_set_concept.hpp b/include/boost/polygon/polygon_45_set_concept.hpp old mode 100755 new mode 100644 index f22910c..623415f --- a/include/boost/polygon/polygon_45_set_concept.hpp +++ b/include/boost/polygon/polygon_45_set_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -28,14 +28,14 @@ namespace boost { namespace polygon{ begin_45_set_data(const polygon_set_type& polygon_set) { return polygon_45_set_traits::begin(polygon_set); } - + template typename enable_if< typename gtl_if::type>::type, typename polygon_45_set_traits::iterator_type>::type end_45_set_data(const polygon_set_type& polygon_set) { return polygon_45_set_traits::end(polygon_set); } - + template typename enable_if< typename gtl_if::type>::type, bool>::type @@ -79,9 +79,9 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename gtl_if::type>::type, - typename gtl_if::type>::type>::type, - bool>::type + bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_45_set_data::coordinate_type> ps1; @@ -111,14 +111,14 @@ namespace boost { namespace polygon{ ps.clean(); return ps.empty(); } - + //extents template typename enable_if< typename gtl_and< typename gtl_if::type>::type, typename is_mutable_rectangle_concept::type>::type>::type, bool>::type - extents(rectangle_type& extents_rectangle, + extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_45_set_data::coordinate_type> ps; @@ -181,7 +181,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - resize(polygon_set_type& polygon_set, coord_type resizing, + resize(polygon_set_type& polygon_set, coord_type resizing, RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION) { typedef typename polygon_45_set_traits::coordinate_type Unit; clean(polygon_set); @@ -195,7 +195,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - bloat(polygon_set_type& polygon_set, + bloat(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { return resize(polygon_set, static_cast::coordinate_type>(bloating)); } @@ -203,7 +203,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - shrink(polygon_set_type& polygon_set, + shrink(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { return resize(polygon_set, -(typename polygon_45_set_traits::coordinate_type)shrinking); } @@ -211,7 +211,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - grow_and(polygon_set_type& polygon_set, + grow_and(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { typedef typename polygon_45_set_traits::coordinate_type Unit; std::vector > polys; @@ -233,7 +233,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - scale_up(polygon_set_type& polygon_set, + scale_up(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_45_set_traits::coordinate_type Unit; clean(polygon_set); @@ -247,7 +247,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - scale_down(polygon_set_type& polygon_set, + scale_down(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_45_set_traits::coordinate_type Unit; clean(polygon_set); @@ -316,7 +316,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_45_set_type::type, polygon_set_type>::type & - keep(polygon_set_type& polygon_set, + keep(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::area_type min_area, typename coordinate_traits::coordinate_type>::area_type max_area, typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, @@ -408,13 +408,13 @@ namespace boost { namespace polygon{ return polygon_set.end(); } - static inline orientation_2d orient(const view_of& polygon_set) { + static inline orientation_2d orient(const view_of& polygon_set) { return polygon_set.orient(); } - static inline bool clean(const view_of& polygon_set) { + static inline bool clean(const view_of& polygon_set) { return polygon_set.clean(); } - static inline bool sorted(const view_of& polygon_set) { + static inline bool sorted(const view_of& polygon_set) { return polygon_set.sorted(); } }; diff --git a/include/boost/polygon/polygon_45_set_data.hpp b/include/boost/polygon/polygon_45_set_data.hpp old mode 100755 new mode 100644 index e541ee5..cf03518 --- a/include/boost/polygon/polygon_45_set_data.hpp +++ b/include/boost/polygon/polygon_45_set_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -19,7 +19,7 @@ namespace boost { namespace polygon{ template class polygon_45_set_view; - + struct polygon_45_set_concept {}; template @@ -43,8 +43,8 @@ namespace boost { namespace polygon{ } // copy constructor - inline polygon_45_set_data(const polygon_45_set_data& that) : - error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_), + inline polygon_45_set_data(const polygon_45_set_data& that) : + error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_manhattan_(that.is_manhattan_) {} template @@ -123,7 +123,7 @@ namespace boost { namespace polygon{ unsorted_ = true; insert_clean(vertex_45, is_hole); } - + template inline void insert(const polygon_90_set_data& polygon_set, bool is_hole = false) { if(polygon_set.orient() == VERTICAL) { @@ -158,14 +158,14 @@ namespace boost { namespace polygon{ p.data_.insert(p.data_.end(), error_data_.begin(), error_data_.end()); } - // equivalence operator + // equivalence operator inline bool operator==(const polygon_45_set_data& p) const { clean(); p.clean(); return data_ == p.data_; } - // inequivalence operator + // inequivalence operator inline bool operator!=(const polygon_45_set_data& p) const { return !((*this) == p); } @@ -212,7 +212,7 @@ namespace boost { namespace polygon{ void sort() const{ if(unsorted_) { - gtlsort(data_.begin(), data_.end()); + polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -220,6 +220,7 @@ namespace boost { namespace polygon{ template void set(input_iterator_type input_begin, input_iterator_type input_end) { data_.clear(); + reserve(std::distance(input_begin, input_end)); insert(input_begin, input_end); dirty_ = true; unsorted_ = true; @@ -232,7 +233,7 @@ namespace boost { namespace polygon{ } void set(const value_type& value) { - data_ = value; + data_ = value; dirty_ = true; unsorted_ = true; } @@ -242,13 +243,13 @@ namespace boost { namespace polygon{ void get_polygons(cT& container) const { get_dispatch(container, polygon_45_concept()); } - + // append to the container cT with PolygonWithHoles objects template void get_polygons_with_holes(cT& container) const { get_dispatch(container, polygon_45_with_holes_concept()); } - + // append to the container cT with polygons of three or four verticies // slicing orientation is vertical template @@ -288,7 +289,7 @@ namespace boost { namespace polygon{ // snap verticies of set to even,even or odd,odd coordinates void snap() const; - + // |= &= += *= -= ^= binary operators polygon_45_set_data& operator|=(const polygon_45_set_data& b); polygon_45_set_data& operator&=(const polygon_45_set_data& b); @@ -300,7 +301,7 @@ namespace boost { namespace polygon{ // resizing operations polygon_45_set_data& operator+=(Unit delta); polygon_45_set_data& operator-=(Unit delta); - + // shrink the Polygon45Set by shrinking polygon_45_set_data& resize(coordinate_type resizing, RoundingOption rounding = CLOSEST, CornerOption corner = INTERSECTION); @@ -338,14 +339,14 @@ namespace boost { namespace polygon{ bool hole = false) { return insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, typename geometry_concept::type()); } - + private: mutable value_type error_data_; mutable value_type data_; mutable bool dirty_; mutable bool unsorted_; mutable bool is_manhattan_; - + private: //functions template @@ -377,7 +378,7 @@ namespace boost { namespace polygon{ insert(geometry_object.begin(), geometry_object.end(), is_hole); } template - void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag); + void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag); template void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_concept ) { insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole); @@ -417,20 +418,20 @@ namespace boost { namespace polygon{ insert(pl.begin(), pl.end(), is_hole); } - void insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, + void insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, const point_data& pt3, direction_1d wdir); template polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_concept tag); - + // accumulate the bloated polygon with holes template polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, RoundingOption rounding, - CornerOption corner, bool hole, polygon_45_with_holes_concept tag); - + CornerOption corner, bool hole, polygon_45_with_holes_concept tag); + static void snap_vertex_45(Vertex45Compact& vertex); public: @@ -446,7 +447,7 @@ namespace boost { namespace polygon{ struct geometry_concept > { typedef polygon_45_set_concept type; }; - + template void scale_up_vertex_45_compact_range(iT beginr, iT endr, T factor) { for( ; beginr != endr; ++beginr) { @@ -490,17 +491,17 @@ namespace boost { namespace polygon{ template bool insert_vertex_half_edge_45_pair_into_vector(cT& output, - const pT& pt1, pT& pt2, - const pT& pt3, + const pT& pt1, pT& pt2, + const pT& pt3, direction_1d wdir) { int multiplier = wdir == LOW ? -1 : 1; typename cT::value_type vertex(pt2, 0, 0); //std::cout << pt1 << " " << pt2 << " " << pt3 << std::endl; std::pair check; - check = characterizeEdge45(pt1, pt2); + check = characterizeEdge45(pt1, pt2); //std::cout << "index " << check.first << " " << check.second * -multiplier << std::endl; vertex.count[check.first] += check.second * -multiplier; - check = characterizeEdge45(pt2, pt3); + check = characterizeEdge45(pt2, pt3); //std::cout << "index " << check.first << " " << check.second * multiplier << std::endl; vertex.count[check.first] += check.second * multiplier; output.push_back(vertex); @@ -508,8 +509,8 @@ namespace boost { namespace polygon{ } template - inline void polygon_45_set_data::insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, - const point_data& pt3, + inline void polygon_45_set_data::insert_vertex_half_edge_45_pair(const point_data& pt1, point_data& pt2, + const point_data& pt3, direction_1d wdir) { if(insert_vertex_half_edge_45_pair_into_vector(data_, pt1, pt2, pt3, wdir)) is_manhattan_ = false; } @@ -611,7 +612,7 @@ namespace boost { namespace polygon{ template void insert_rectangle_into_vector_45(cT& output, const rT& rect, bool is_hole) { - point_data::coordinate_type> + point_data::coordinate_type> llpt = ll(rect), lrpt = lr(rect), ulpt = ul(rect), urpt = ur(rect); direction_1d dir = COUNTERCLOCKWISE; if(is_hole) dir = CLOCKWISE; @@ -623,7 +624,7 @@ namespace boost { namespace polygon{ template template - inline void polygon_45_set_data::insert_dispatch(const geometry_type& geometry_object, + inline void polygon_45_set_data::insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept ) { dirty_ = true; unsorted_ = true; @@ -640,7 +641,7 @@ namespace boost { namespace polygon{ } Unit low = (std::numeric_limits::max)(); Unit high = (std::numeric_limits::min)(); - interval_data xivl(low, high); + interval_data xivl(low, high); interval_data yivl(low, high); for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++ itr) { @@ -714,7 +715,7 @@ namespace boost { namespace polygon{ inline polygon_45_set_data& polygon_45_set_data::operator-=(const polygon_45_set_data& b) { //b.sort(); //sort(); - applyAdaptiveBoolean_<2>(b); + applyAdaptiveBoolean_<2>(b); dirty_ = false; unsorted_ = false; return *this; @@ -723,7 +724,7 @@ namespace boost { namespace polygon{ inline polygon_45_set_data& polygon_45_set_data::operator^=(const polygon_45_set_data& b) { //b.sort(); //sort(); - applyAdaptiveBoolean_<3>(b); + applyAdaptiveBoolean_<3>(b); dirty_ = false; unsorted_ = false; return *this; @@ -739,7 +740,7 @@ namespace boost { namespace polygon{ } template - inline polygon_45_set_data& + inline polygon_45_set_data& polygon_45_set_data::resize(Unit resizing, RoundingOption rounding, CornerOption corner) { if(resizing == 0) return *this; std::list > pl; @@ -852,7 +853,7 @@ namespace boost { namespace polygon{ Unit y = 0; if(run1 == 0) { x = pt1.x(); - y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y(); + y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y(); } else if(run2 == 0) { x = pt2.x(); y = (Unit)(((x2 - x1) * rise1) / run1) + pt1.y(); @@ -863,7 +864,7 @@ namespace boost { namespace polygon{ // (rise1/run1 - rise2/run2)x = y2 - y1 + rise1/run1 x1 - rise2/run2 x2 // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)/(rise1/run1 - rise2/run2) // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)(rise1 run2 - rise2 run1)/(run1 run2) - x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) * + x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) * (run1 * run2) / (rise1 * run2 - rise2 * run1)); if(rise1 == 0) { y = pt1.y(); @@ -873,7 +874,7 @@ namespace boost { namespace polygon{ // y - y1 = (rise1/run1)(x - x1) // (run1/rise1)(y - y1) = x - x1 // x = (run1/rise1)(y - y1) + x1 = (run2/rise2)(y - y2) + x2 - y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) * + y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) * (rise1 * rise2) / (run1 * rise2 - run2 * rise1)); } } @@ -882,7 +883,7 @@ namespace boost { namespace polygon{ template inline - void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data& sizingSet, point_data first, + void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data& sizingSet, point_data first, point_data second, Unit resizing, CornerOption corner) { if(first.x() == second.x()) { sizingSet.insert(rectangle_data(first.x() - resizing, first.y(), first.x() + resizing, second.y())); @@ -932,7 +933,7 @@ namespace boost { namespace polygon{ template inline - void handleResizingEdge45(polygon_45_set_data& sizingSet, point_data first, + void handleResizingEdge45(polygon_45_set_data& sizingSet, point_data first, point_data second, Unit resizing, RoundingOption rounding) { if(first.x() == second.x()) { sizingSet.insert(rectangle_data(first.x() - resizing, first.y(), first.x() + resizing, second.y())); @@ -998,14 +999,14 @@ namespace boost { namespace polygon{ template inline - void handleResizingVertex45(polygon_45_set_data& sizingSet, const point_data& first, - const point_data& second, const point_data& third, Unit resizing, - RoundingOption rounding, CornerOption corner, + void handleResizingVertex45(polygon_45_set_data& sizingSet, const point_data& first, + const point_data& second, const point_data& third, Unit resizing, + RoundingOption rounding, CornerOption corner, int multiplier) { unsigned int edge1 = getEdge45Direction(first, second); unsigned int edge2 = getEdge45Direction(second, third); unsigned int diffAngle; - if(multiplier < 0) + if(multiplier < 0) diffAngle = (edge2 + 8 - edge1) % 8; else diffAngle = (edge1 + 8 - edge2) % 8; @@ -1015,7 +1016,7 @@ namespace boost { namespace polygon{ } Unit bloating = abs(resizing); if(rounding == SQRT1OVER2) { - if(edge1 % 2 && edge2 % 2) return; + if(edge1 % 2 && edge2 % 2) return; if(corner == ORTHOGONAL && edge1 % 2 == 0 && edge2 % 2 == 0) { rectangle_data insertion_rect; set_points(insertion_rect, second, second); @@ -1074,7 +1075,7 @@ namespace boost { namespace polygon{ sizingSet.insert(insertion_rect); return; } - } + } std::vector > pts; pts.push_back(edgePoint1); pts.push_back(second); @@ -1086,15 +1087,15 @@ namespace boost { namespace polygon{ template template - inline polygon_45_set_data& + inline polygon_45_set_data& polygon_45_set_data::insert_with_resize_dispatch(const geometry_type& poly, - coordinate_type resizing, + coordinate_type resizing, RoundingOption rounding, CornerOption corner, bool hole, polygon_45_concept ) { direction_1d wdir = winding(poly); int multiplier = wdir == LOW ? -1 : 1; - if(hole) resizing *= -1; + if(hole) resizing *= -1; typedef typename polygon_45_data::iterator_type piterator; piterator first, second, third, end, real_end; real_end = end_points(poly); @@ -1113,8 +1114,8 @@ namespace boost { namespace polygon{ handleResizingEdge45(sizingSet, *first, *second, resizing, rounding); } else { handleResizingEdge45_SQRT1OVER2(sizingSet, *first, *second, resizing, corner); - } - if(corner != UNFILLED) + } + if(corner != UNFILLED) handleResizingVertex45(sizingSet, *first, *second, *third, resizing, rounding, corner, multiplier); first = second; second = third; @@ -1144,9 +1145,9 @@ namespace boost { namespace polygon{ template inline polygon_45_set_data& polygon_45_set_data::insert_with_resize_dispatch(const geometry_type& poly, - coordinate_type resizing, + coordinate_type resizing, RoundingOption rounding, - CornerOption corner, + CornerOption corner, bool hole, polygon_45_with_holes_concept ) { insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, polygon_45_concept()); for(typename polygon_with_holes_traits::iterator_holes_type itr = @@ -1170,11 +1171,11 @@ namespace boost { namespace polygon{ } clear(); insert(polys.begin(), polys.end()); - dirty_ = true; + dirty_ = true; unsorted_ = true; return *this; } - + template inline polygon_45_set_data& polygon_45_set_data::scale_up(typename coordinate_traits::unsigned_area_type factor) { scale_up_vertex_45_compact_range(data_.begin(), data_.end(), factor); @@ -1192,7 +1193,7 @@ namespace boost { namespace polygon{ } clear(); insert(polys.begin(), polys.end()); - dirty_ = true; + dirty_ = true; unsorted_ = true; return *this; } @@ -1208,7 +1209,7 @@ namespace boost { namespace polygon{ } clear(); insert(polys.begin(), polys.end()); - dirty_ = true; + dirty_ = true; unsorted_ = true; return *this; } @@ -1244,7 +1245,7 @@ namespace boost { namespace polygon{ typename boolean_op_45::template Scan45::Count2, typename boolean_op_45::template boolean_op_45_output_functor > scan45; std::vector::Vertex45> eventOut; - typedef std::pair::Point, + typedef std::pair::Point, typename boolean_op_45::template Scan45CountT::Count2> > Scan45Vertex; std::vector eventIn; typedef std::vector::Vertex45Compact> value_type; @@ -1262,7 +1263,7 @@ namespace boost { namespace polygon{ //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - gtlsort(eventOut.begin(), eventOut.end()); + polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && @@ -1270,7 +1271,7 @@ namespace boost { namespace polygon{ result_data.back().count += eventOut[i]; ++ptCount; } else { - if(!result_data.empty()) { + if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } @@ -1290,24 +1291,24 @@ namespace boost { namespace polygon{ x = currentX; } //std::cout << "get next\n"; - if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() || + if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() || (iter2->pt.x() == iter1->pt.x() && iter2->pt.y() < iter1->pt.y()) )) { //std::cout << "case1 next\n"; eventIn.push_back(Scan45Vertex - (iter2->pt, + (iter2->pt, typename polygon_45_formation:: Scan45Count(typename polygon_45_formation::Count2(0, iter2->count[0]), typename polygon_45_formation::Count2(0, iter2->count[1]), typename polygon_45_formation::Count2(0, iter2->count[2]), typename polygon_45_formation::Count2(0, iter2->count[3])))); ++iter2; - } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() || + } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() || (iter1->pt.x() == iter2->pt.x() && iter1->pt.y() < iter2->pt.y()) )) { //std::cout << "case2 next\n"; eventIn.push_back(Scan45Vertex - (iter1->pt, + (iter1->pt, typename polygon_45_formation:: Scan45Count( typename polygon_45_formation::Count2(iter1->count[0], 0), @@ -1318,22 +1319,22 @@ namespace boost { namespace polygon{ } else { //std::cout << "case3 next\n"; eventIn.push_back(Scan45Vertex - (iter2->pt, + (iter2->pt, typename polygon_45_formation:: - Scan45Count(typename polygon_45_formation::Count2(iter1->count[0], + Scan45Count(typename polygon_45_formation::Count2(iter1->count[0], iter2->count[0]), - typename polygon_45_formation::Count2(iter1->count[1], + typename polygon_45_formation::Count2(iter1->count[1], iter2->count[1]), - typename polygon_45_formation::Count2(iter1->count[2], + typename polygon_45_formation::Count2(iter1->count[2], iter2->count[2]), - typename polygon_45_formation::Count2(iter1->count[3], + typename polygon_45_formation::Count2(iter1->count[3], iter2->count[3])))); ++iter1; ++iter2; } } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - gtlsort(eventOut.begin(), eventOut.end()); + polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { @@ -1342,7 +1343,7 @@ namespace boost { namespace polygon{ result_data.back().count += eventOut[i]; ++ptCount; } else { - if(!result_data.empty()) { + if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } @@ -1385,7 +1386,7 @@ namespace boost { namespace polygon{ //std::cout << "SCAN " << currentX << "\n"; //scan event scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - gtlsort(eventOut.begin(), eventOut.end()); + polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { if(!result_data.empty() && @@ -1393,7 +1394,7 @@ namespace boost { namespace polygon{ result_data.back().count += eventOut[i]; ++ptCount; } else { - if(!result_data.empty()) { + if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } @@ -1414,7 +1415,7 @@ namespace boost { namespace polygon{ } //std::cout << "get next\n"; eventIn.push_back(Scan45Vertex - (iter1->pt, + (iter1->pt, Scan45Count( typename boolean_op_45::Count1(iter1->count[0]), typename boolean_op_45::Count1(iter1->count[1]), typename boolean_op_45::Count1(iter1->count[2]), @@ -1422,7 +1423,7 @@ namespace boost { namespace polygon{ ++iter1; } scan45.scan(eventOut, eventIn.begin(), eventIn.end()); - gtlsort(eventOut.begin(), eventOut.end()); + polygon_sort(eventOut.begin(), eventOut.end()); std::size_t ptCount = 0; for(std::size_t i = 0; i < eventOut.size(); ++i) { @@ -1431,7 +1432,7 @@ namespace boost { namespace polygon{ result_data.back().count += eventOut[i]; ++ptCount; } else { - if(!result_data.empty()) { + if(!result_data.empty()) { if(result_data.back().count.is_45()) { result_is_manhattan_ = false; } @@ -1453,9 +1454,9 @@ namespace boost { namespace polygon{ return result_is_manhattan_; } - template + template void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) { - typedef typename iT::value_type Point; + typedef typename std::iterator_traits::value_type Point; typedef typename point_traits::coordinate_type Unit; typedef typename coordinate_traits::area_type area_type; Point pt1, pt2, pt3; @@ -1493,7 +1494,7 @@ namespace boost { namespace polygon{ const Point& pt = *beginr; pt3 = pt; ++beginr; - if(beginr == endr) { + if(beginr == endr) { next_to_last = true; //skip last point equal to first continue; @@ -1508,7 +1509,7 @@ namespace boost { namespace polygon{ if(dir == CLOCKWISE) { posE.push_back(rectangle_data (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); - + } else { negE.push_back(rectangle_data (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1)); @@ -1518,8 +1519,8 @@ namespace boost { namespace polygon{ pt2 = pt3; } } - - template + + template void get_error_rects(cT& posE, cT& negE, const pT& p) { get_error_rects_shell(posE, negE, p.begin(), p.end()); for(typename pT::iterator_holes_type iHb = p.begin_holes(); @@ -1554,16 +1555,16 @@ namespace boost { namespace polygon{ #endif if(op == 0) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), - r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); } else if (op == 1) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), - r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); } else if (op == 2) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), - r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); } else if (op == 3) { output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(), - r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); + r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); } #ifdef BOOST_POLYGON_MSVC #pragma warning (default: 4127) @@ -1590,7 +1591,7 @@ namespace boost { namespace polygon{ lvalue_data.reserve(data_.size()); for(std::size_t i = 0 ; i < data_.size(); ++i) { const Vertex45Compact& vi = data_[i]; - Vertex45Compact2 ci; + Vertex45Compact2 ci; ci.pt = point_data(x(vi.pt), y(vi.pt)); ci.count = typename polygon_45_formation::Vertex45Count ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]); @@ -1639,7 +1640,7 @@ namespace boost { namespace polygon{ result.error_data_.push_back(ci); } Data2 new_result_data; - gtlsort(result_data.begin(), result_data.end()); + polygon_sort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } @@ -1709,7 +1710,7 @@ namespace boost { namespace polygon{ lvalue_data.reserve(data_.size()); for(std::size_t i = 0 ; i < data_.size(); ++i) { const Vertex45Compact& vi = data_[i]; - Vertex45Compact2 ci; + Vertex45Compact2 ci; ci.pt.x(static_cast(x(vi.pt))); ci.pt.y(static_cast(y(vi.pt))); ci.count = typename polygon_45_formation::Vertex45Count @@ -1749,7 +1750,7 @@ namespace boost { namespace polygon{ result.error_data_.push_back(ci); } Data2 new_result_data; - gtlsort(result_data.begin(), result_data.end()); + polygon_sort(result_data.begin(), result_data.end()); applyUnary45OpOnVectors(new_result_data, result_data); //OR operation result_data.swap(new_result_data); } @@ -1787,11 +1788,11 @@ namespace boost { namespace polygon{ public: inline property_merge_45() : tsd_() {} inline property_merge_45(const property_merge_45& that) : tsd_(that.tsd_) {} - inline property_merge_45& operator=(const property_merge_45& that) { - tsd_ = that.tsd_; + inline property_merge_45& operator=(const property_merge_45& that) { + tsd_ = that.tsd_; return *this; } - + inline void insert(const polygon_45_set_data& ps, property_type property) { ps.clean(); polygon_45_property_merge::populateMergeSetData(tsd_, ps.begin(), ps.end(), property); @@ -1844,12 +1845,12 @@ namespace boost { namespace polygon{ inline connectivity_extraction_45() : tsd_(), nodeCount_(0) {} inline connectivity_extraction_45(const connectivity_extraction_45& that) : tsd_(that.tsd_), nodeCount_(that.nodeCount_) {} - inline connectivity_extraction_45& operator=(const connectivity_extraction_45& that) { - tsd_ = that.tsd_; + inline connectivity_extraction_45& operator=(const connectivity_extraction_45& that) { + tsd_ = that.tsd_; nodeCount_ = that.nodeCount_; {} return *this; } - + //insert a polygon set graph node, the value returned is the id of the graph node inline unsigned int insert(const polygon_45_set_data& ps) { ps.clean(); @@ -1862,7 +1863,7 @@ namespace boost { namespace polygon{ ps.insert(geoObj); return insert(ps); } - + //extract connectivity and store the edges in the graph //graph must be indexable by graph node id and the indexed value must be a std::set of //graph node id diff --git a/include/boost/polygon/polygon_45_set_traits.hpp b/include/boost/polygon/polygon_45_set_traits.hpp old mode 100755 new mode 100644 index cfc0f98..f52f57f --- a/include/boost/polygon/polygon_45_set_traits.hpp +++ b/include/boost/polygon/polygon_45_set_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -43,13 +43,13 @@ namespace boost { namespace polygon{ typedef typename is_45_polygonal_concept::type>::type type; }; template - struct is_polygon_45_set_type > { + struct is_polygon_45_set_type > { typedef typename gtl_or< typename is_45_polygonal_concept >::type>::type, typename is_45_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_polygon_45_set_type > { + struct is_polygon_45_set_type > { typedef typename gtl_or< typename is_45_polygonal_concept >::type>::type, typename is_45_polygonal_concept::value_type>::type>::type>::type type; @@ -60,13 +60,13 @@ namespace boost { namespace polygon{ typedef typename gtl_same_type::type>::type type; }; template - struct is_mutable_polygon_45_set_type > { + struct is_mutable_polygon_45_set_type > { typedef typename gtl_or< typename gtl_same_type >::type>::type, typename is_45_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_mutable_polygon_45_set_type > { + struct is_mutable_polygon_45_set_type > { typedef typename gtl_or< typename gtl_same_type >::type>::type, typename is_45_polygonal_concept::value_type>::type>::type>::type type; @@ -94,6 +94,7 @@ namespace boost { namespace polygon{ static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); polygon_45_set_data >::coordinate_type> ps; + ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end); ps.sort(); ps.clean(); @@ -105,7 +106,10 @@ namespace boost { namespace polygon{ template static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); + size_t num_ele = std::distance(input_begin, input_end); + polygon_set.reserve(num_ele); polygon_45_set_data >::coordinate_type> ps; + ps.reserve(num_ele); ps.insert(input_begin, input_end); ps.sort(); ps.clean(); @@ -116,7 +120,7 @@ namespace boost { namespace polygon{ template struct polygon_45_set_mutable_traits > { template - static inline void set(polygon_45_set_data& polygon_set, + static inline void set(polygon_45_set_data& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.set(input_begin, input_end); } @@ -140,7 +144,6 @@ namespace boost { namespace polygon{ static inline bool sorted(const polygon_45_set_data& polygon_set) { polygon_set.sort(); return true; } }; -} +} } #endif - diff --git a/include/boost/polygon/polygon_45_with_holes_data.hpp b/include/boost/polygon/polygon_45_with_holes_data.hpp old mode 100755 new mode 100644 index 717bbd3..0601bdc --- a/include/boost/polygon/polygon_45_with_holes_data.hpp +++ b/include/boost/polygon/polygon_45_with_holes_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -18,7 +18,7 @@ public: typedef T coordinate_type; typedef typename polygon_45_data::iterator_type iterator_type; typedef typename std::list >::const_iterator iterator_holes_type; - typedef polygon_45_data hole_type; + typedef polygon_45_data hole_type; typedef typename coordinate_traits::coordinate_distance area_type; typedef point_data point_type; @@ -55,9 +55,9 @@ public: } // copy constructor (since we have dynamic memory) - inline polygon_45_with_holes_data(const polygon_45_with_holes_data& that) : self_(that.self_), + inline polygon_45_with_holes_data(const polygon_45_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_45_with_holes_data& operator=(const polygon_45_with_holes_data& that) { self_ = that.self_; @@ -80,7 +80,7 @@ public: inline std::size_t size() const { return self_.size(); - } + } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { @@ -98,11 +98,10 @@ public: public: polygon_45_data self_; - std::list holes_; + std::list holes_; }; } } #endif - diff --git a/include/boost/polygon/polygon_90_data.hpp b/include/boost/polygon/polygon_90_data.hpp old mode 100755 new mode 100644 index 7e1d969..1f14ed7 --- a/include/boost/polygon/polygon_90_data.hpp +++ b/include/boost/polygon/polygon_90_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -40,7 +40,7 @@ public: // copy constructor (since we have dynamic memory) inline polygon_90_data(const polygon_90_data& that) : coords_(that.coords_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_90_data& operator=(const polygon_90_data& that) { coords_ = that.coords_; @@ -63,18 +63,17 @@ public: // get begin iterator, returns a pointer to a const Unit inline compact_iterator_type begin_compact() const { return coords_.begin(); } - + // get end iterator, returns a pointer to a const Unit inline compact_iterator_type end_compact() const { return coords_.end(); } inline std::size_t size() const { return coords_.size(); } - + private: - std::vector coords_; + std::vector coords_; }; } } #endif - diff --git a/include/boost/polygon/polygon_90_set_concept.hpp b/include/boost/polygon/polygon_90_set_concept.hpp old mode 100755 new mode 100644 index 09d5eee..980c3e7 --- a/include/boost/polygon/polygon_90_set_concept.hpp +++ b/include/boost/polygon/polygon_90_set_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -17,14 +17,14 @@ namespace boost { namespace polygon{ begin_90_set_data(const polygon_set_type& polygon_set) { return polygon_90_set_traits::begin(polygon_set); } - + template typename enable_if< typename is_polygon_90_set_type::type, typename polygon_90_set_traits::iterator_type>::type end_90_set_data(const polygon_set_type& polygon_set) { return polygon_90_set_traits::end(polygon_set); } - + template typename enable_if< typename is_polygon_90_set_type::type, orientation_2d>::type @@ -47,7 +47,7 @@ namespace boost { namespace polygon{ typename is_polygon_90_set_type::type>::type, polygon_set_type_1>::type & assign(polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { - polygon_90_set_mutable_traits::set(lvalue, begin_90_set_data(rvalue), end_90_set_data(rvalue), + polygon_90_set_mutable_traits::set(lvalue, begin_90_set_data(rvalue), end_90_set_data(rvalue), scanline_orientation(rvalue)); return lvalue; } @@ -59,12 +59,12 @@ namespace boost { namespace polygon{ //equivalence template - typename enable_if< typename gtl_and_3< + typename enable_if< typename gtl_and_3< typename is_polygon_90_set_type::type, typename is_polygon_90_set_type::type, typename are_not_both_rectangle_concept::type, typename geometry_concept::type>::type>::type, - bool>::type + bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_90_set_data::coordinate_type> ps1; @@ -99,7 +99,7 @@ namespace boost { namespace polygon{ //get: min_rectangles max_rectangles template - typename enable_if ::type, typename gtl_same_type::coordinate_type>::getMaxCover(output, rects, scanline_orientation(polygon_set)); } - + //clear template typename enable_if< typename is_mutable_polygon_90_set_type::type, @@ -120,7 +120,7 @@ namespace boost { namespace polygon{ polygon_90_set_data::coordinate_type> ps(scanline_orientation(polygon_set)); assign(polygon_set, ps); } - + //empty template typename enable_if< typename is_mutable_polygon_90_set_type::type, @@ -132,13 +132,13 @@ namespace boost { namespace polygon{ ps.clean(); return ps.empty(); } - + //extents template typename enable_if ::type, typename is_mutable_rectangle_concept::type>::type>::type, bool>::type - extents(rectangle_type& extents_rectangle, + extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { typedef typename polygon_90_set_traits::coordinate_type Unit; polygon_90_set_data ps; @@ -177,7 +177,7 @@ namespace boost { namespace polygon{ assign(polygon_set_1, ps); return polygon_set_1; } - + //self_intersect template typename enable_if< typename is_mutable_polygon_90_set_type::type, @@ -207,7 +207,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - bloat(polygon_set_type& polygon_set, + bloat(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { return bloat(polygon_set, bloating, bloating, bloating, bloating); } @@ -250,7 +250,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - bloat(polygon_set_type& polygon_set, + bloat(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits::coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits::coordinate_type>::unsigned_area_type south_bloating, @@ -267,7 +267,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - shrink(polygon_set_type& polygon_set, + shrink(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type shrinking) { return shrink(polygon_set, shrinking, shrinking, shrinking, shrinking); } @@ -310,7 +310,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - shrink(polygon_set_type& polygon_set, + shrink(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type west_shrinking, typename coordinate_traits::coordinate_type>::unsigned_area_type east_shrinking, typename coordinate_traits::coordinate_type>::unsigned_area_type south_shrinking, @@ -354,7 +354,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - grow_and(polygon_set_type& polygon_set, + grow_and(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type bloating) { return grow_and(polygon_set, bloating, bloating, bloating, bloating); } @@ -397,7 +397,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_if::type>::type, polygon_set_type>::type & - grow_and(polygon_set_type& polygon_set, + grow_and(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type west_bloating, typename coordinate_traits::coordinate_type>::unsigned_area_type east_bloating, typename coordinate_traits::coordinate_type>::unsigned_area_type south_bloating, @@ -422,7 +422,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - scale_up(polygon_set_type& polygon_set, + scale_up(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type> ::unsigned_area_type factor) { typedef typename polygon_90_set_traits::coordinate_type Unit; @@ -436,7 +436,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - scale_down(polygon_set_type& polygon_set, + scale_down(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type> ::unsigned_area_type factor) { typedef typename polygon_90_set_traits::coordinate_type Unit; @@ -450,7 +450,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - scale(polygon_set_type& polygon_set, + scale(polygon_set_type& polygon_set, const scaling_type& scaling) { typedef typename polygon_90_set_traits::coordinate_type Unit; polygon_90_set_data ps; @@ -460,24 +460,27 @@ namespace boost { namespace polygon{ return polygon_set; } + struct y_p_s_move : gtl_yes {}; + //move template - polygon_set_type& + typename enable_if< typename gtl_and::type>::type>::type, + polygon_set_type>::type & move(polygon_set_type& polygon_set, - orientation_2d orient, typename polygon_90_set_traits::coordinate_type displacement, - typename enable_if< typename is_mutable_polygon_90_set_type::type>::type * = 0) { + orientation_2d orient, typename polygon_90_set_traits::coordinate_type displacement) { if(orient == HORIZONTAL) return move(polygon_set, displacement, 0); - else + else return move(polygon_set, 0, displacement); } + struct y_p_s_move2 : gtl_yes {}; + template - polygon_set_type& - move(polygon_set_type& polygon_set, typename polygon_90_set_traits::coordinate_type x_displacement, - typename polygon_90_set_traits::coordinate_type y_displacement, - typename enable_if< typename is_mutable_polygon_90_set_type::type>::type * = 0 - ) { + typename enable_if< typename gtl_and::type>::type>::type, + polygon_set_type>::type & + move(polygon_set_type& polygon_set, typename polygon_90_set_traits::coordinate_type x_displacement, + typename polygon_90_set_traits::coordinate_type y_displacement) { typedef typename polygon_90_set_traits::coordinate_type Unit; polygon_90_set_data ps; assign(ps, polygon_set); @@ -507,7 +510,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_90_set_type::type, polygon_set_type>::type & - keep(polygon_set_type& polygon_set, + keep(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type min_area, typename coordinate_traits::coordinate_type>::unsigned_area_type max_area, typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp old mode 100755 new mode 100644 index 151cb9d..042c3ca --- a/include/boost/polygon/polygon_90_set_data.hpp +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -13,6 +13,7 @@ #include "transform.hpp" #include "interval_concept.hpp" #include "rectangle_concept.hpp" +#include "segment_concept.hpp" #include "detail/iterator_points_to_compact.hpp" #include "detail/iterator_compact_to_points.hpp" #include "polygon_traits.hpp" @@ -46,7 +47,7 @@ namespace boost { namespace polygon{ // constructor from an iterator pair over vertex data template - inline polygon_90_set_data(orientation_2d orient, iT input_begin, iT input_end) : + inline polygon_90_set_data(orientation_2d orient, iT input_begin, iT input_end) : orient_(HORIZONTAL), data_(), dirty_(false), unsorted_(false) { dirty_ = true; unsorted_ = true; @@ -54,14 +55,14 @@ namespace boost { namespace polygon{ } // copy constructor - inline polygon_90_set_data(const polygon_90_set_data& that) : + inline polygon_90_set_data(const polygon_90_set_data& that) : orient_(that.orient_), data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_) {} template inline polygon_90_set_data(const polygon_90_set_view& that); // copy with orientation change constructor - inline polygon_90_set_data(orientation_2d orient, const polygon_90_set_data& that) : + inline polygon_90_set_data(orientation_2d orient, const polygon_90_set_data& that) : orient_(orient), data_(), dirty_(false), unsorted_(false) { insert(that, false, that.orient_); } @@ -138,7 +139,7 @@ namespace boost { namespace polygon{ insert(begin_input, end_input, orient_); } - inline void insert(const std::pair >& vertex, bool is_hole = false, + inline void insert(const std::pair >& vertex, bool is_hole = false, orientation_2d orient = HORIZONTAL) { data_.push_back(vertex); if(orient != orient_) std::swap(data_.back().first, data_.back().second.first); @@ -190,7 +191,7 @@ namespace boost { namespace polygon{ } } - // equivalence operator + // equivalence operator inline bool operator==(const polygon_90_set_data& p) const { if(orient_ == p.orient()) { clean(); @@ -201,7 +202,7 @@ namespace boost { namespace polygon{ } } - // inequivalence operator + // inequivalence operator inline bool operator!=(const polygon_90_set_data& p) const { return !((*this) == p); } @@ -260,7 +261,7 @@ namespace boost { namespace polygon{ // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), - // that.begin(), that.end(), boolean_op::BinaryCount()); + // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator^=(const polygon_90_set_data& that) { @@ -269,7 +270,7 @@ namespace boost { namespace polygon{ // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), - // that.begin(), that.end(), boolean_op::BinaryCount()); + // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator&=(const polygon_90_set_data& that) { @@ -278,7 +279,7 @@ namespace boost { namespace polygon{ // value_type data; // std::swap(data, data_); // applyBooleanBinaryOp(data.begin(), data.end(), - // that.begin(), that.end(), boolean_op::BinaryCount()); + // that.begin(), that.end(), boolean_op::BinaryCount()); // return *this; // } // polygon_90_set_data& operator|=(const polygon_90_set_data& that) { @@ -296,7 +297,7 @@ namespace boost { namespace polygon{ void sort() const{ if(unsorted_) { - gtlsort(data_.begin(), data_.end()); + polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -304,6 +305,7 @@ namespace boost { namespace polygon{ template void set(input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { data_.clear(); + reserve(std::distance(input_begin, input_end)); data_.insert(data_.end(), input_begin, input_end); orient_ = orient; dirty_ = true; @@ -311,7 +313,7 @@ namespace boost { namespace polygon{ } void set(const value_type& value, orientation_2d orient) { - data_ = value; + data_ = value; orient_ = orient; dirty_ = true; unsorted_ = true; @@ -345,11 +347,11 @@ namespace boost { namespace polygon{ typename coordinate_traits::unsigned_area_type north_bloating) { std::vector > rects; clean(); - rects.reserve(data_.size() / 2); + rects.reserve(data_.size() / 2); get(rects); - rectangle_data convolutionRectangle(interval_data(-((coordinate_type)west_bloating), + rectangle_data convolutionRectangle(interval_data(-((coordinate_type)west_bloating), (coordinate_type)east_bloating), - interval_data(-((coordinate_type)south_bloating), + interval_data(-((coordinate_type)south_bloating), (coordinate_type)north_bloating)); for(typename std::vector >::iterator itr = rects.begin(); itr != rects.end(); ++itr) { @@ -392,7 +394,7 @@ namespace boost { namespace polygon{ if(nyg) pt.x(current_pt.x() + east_bloating); } - static void resize_poly_up(std::vector >& poly, + static void resize_poly_up(std::vector >& poly, coordinate_type west_bloating, coordinate_type east_bloating, coordinate_type south_bloating, @@ -415,7 +417,7 @@ namespace boost { namespace polygon{ modify_pt(poly[0], prev_pt, current_pt, next_pt, west_bloating, east_bloating, south_bloating, north_bloating); remove_colinear_pts(poly); } - static bool resize_poly_down(std::vector >& poly, + static bool resize_poly_down(std::vector >& poly, coordinate_type west_shrinking, coordinate_type east_shrinking, coordinate_type south_shrinking, @@ -427,7 +429,7 @@ namespace boost { namespace polygon{ point_data prev_pt = poly[0]; point_data current_pt = poly[1]; encompass(extents_rectangle, current_pt); - for(int i = 2; i < poly.size(); ++i) { + for(std::size_t i = 2; i < poly.size(); ++i) { point_data next_pt = poly[i]; encompass(extents_rectangle, next_pt); modify_pt(poly[i-1], prev_pt, current_pt, next_pt, west_shrinking, east_shrinking, south_shrinking, north_shrinking); @@ -451,7 +453,7 @@ namespace boost { namespace polygon{ bool found_colinear = true; while(found_colinear && poly.size() >= 4) { found_colinear = false; - typename std::vector >::iterator itr = poly.begin(); + typename std::vector >::iterator itr = poly.begin(); itr += poly.size() - 1; //get last element position typename std::vector >::iterator itr2 = poly.begin(); typename std::vector >::iterator itr3 = itr2; @@ -477,7 +479,7 @@ namespace boost { namespace polygon{ poly.erase(poly.end() - count, poly.end()); } return poly.size() >= 4; - } + } polygon_90_set_data& bloat(typename coordinate_traits::unsigned_area_type west_bloating, @@ -493,9 +495,10 @@ namespace boost { namespace polygon{ //psref.insert(view_as((*itr).self_)); //rectangle_data prerect; //psref.extents(prerect); - resize_poly_up((*itr).self_.coords_, west_bloating, east_bloating, south_bloating, north_bloating); + resize_poly_up((*itr).self_.coords_, (coordinate_type)west_bloating, (coordinate_type)east_bloating, + (coordinate_type)south_bloating, (coordinate_type)north_bloating); iterator_geometry_to_set > > - begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //polygon_90_set_data pstest; @@ -512,15 +515,16 @@ namespace boost { namespace polygon{ //psrefhole.insert(prerect); //psrefhole.insert(view_as(*itrh), true); //polygon_45_data testpoly(*itrh); - if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { + if(resize_poly_down((*itrh).coords_,(coordinate_type)west_bloating, (coordinate_type)east_bloating, + (coordinate_type)south_bloating, (coordinate_type)north_bloating)) { iterator_geometry_to_set > > - begin_input2(view_as(*itrh), LOW, orient_, true, true), + begin_input2(view_as(*itrh), LOW, orient_, true, true), end_input2(view_as(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > - // begin_input2(view_as(*itrh), LOW, orient_, true, true); + // begin_input2(view_as(*itrh), LOW, orient_, true, true); //pstesthole.insert(begin_input2, end_input, orient_); //psrefhole.bloat2(west_bloating, east_bloating, south_bloating, north_bloating); //if(!equivalence(psrefhole, pstesthole)) { @@ -556,13 +560,14 @@ namespace boost { namespace polygon{ //rectangle_data prerect; //psref.extents(prerect); //polygon_45_data testpoly((*itr).self_); - if(resize_poly_down((*itr).self_.coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking)) { + if(resize_poly_down((*itr).self_.coords_, -(coordinate_type)west_shrinking, -(coordinate_type)east_shrinking, + -(coordinate_type)south_shrinking, -(coordinate_type)north_shrinking)) { iterator_geometry_to_set > > - begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), + begin_input(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE), end_input(view_as((*itr).self_), HIGH, orient_, false, true, COUNTERCLOCKWISE); insert(begin_input, end_input, orient_); //iterator_geometry_to_set > > - // begin_input2(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); + // begin_input2(view_as((*itr).self_), LOW, orient_, false, true, COUNTERCLOCKWISE); //polygon_90_set_data pstest; //pstest.insert(begin_input2, end_input, orient_); //psref.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); @@ -577,15 +582,16 @@ namespace boost { namespace polygon{ //psrefhole.insert(prerect); //psrefhole.insert(view_as(*itrh), true); //polygon_45_data testpoly(*itrh); - resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); + resize_poly_up((*itrh).coords_, -(coordinate_type)west_shrinking, -(coordinate_type)east_shrinking, + -(coordinate_type)south_shrinking, -(coordinate_type)north_shrinking); iterator_geometry_to_set > > - begin_input2(view_as(*itrh), LOW, orient_, true, true), + begin_input2(view_as(*itrh), LOW, orient_, true, true), end_input2(view_as(*itrh), HIGH, orient_, true, true); insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > - // begin_input2(view_as(*itrh), LOW, orient_, true, true); + // begin_input2(view_as(*itrh), LOW, orient_, true, true); //pstesthole.insert(begin_input2, end_input, orient_); //psrefhole.shrink2(west_shrinking, east_shrinking, south_shrinking, north_shrinking); //if(!equivalence(psrefhole, pstesthole)) { @@ -618,13 +624,13 @@ namespace boost { namespace polygon{ insert(externalBoundary, true); //note that the set is in a dirty state now sort(); //does not apply implicit OR operation std::vector > rects; - rects.reserve(data_.size() / 2); + rects.reserve(data_.size() / 2); //begin does not apply implicit or operation, this is a dirty range form_rectangles(rects, data_.begin(), data_.end(), orient_, rectangle_concept()); clear(); - rectangle_data convolutionRectangle(interval_data(-((coordinate_type)east_shrinking), + rectangle_data convolutionRectangle(interval_data(-((coordinate_type)east_shrinking), (coordinate_type)west_shrinking), - interval_data(-((coordinate_type)north_shrinking), + interval_data(-((coordinate_type)north_shrinking), (coordinate_type)south_shrinking)); for(typename std::vector >::iterator itr = rects.begin(); itr != rects.end(); ++itr) { @@ -663,10 +669,10 @@ namespace boost { namespace polygon{ } polygon_90_set_data& - resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north); + resize(coordinate_type west, coordinate_type east, coordinate_type south, coordinate_type north); polygon_90_set_data& move(coordinate_type x_delta, coordinate_type y_delta) { - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { (*itr).first += x_delta; @@ -701,7 +707,7 @@ namespace boost { namespace polygon{ // scale set polygon_90_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor) { - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first *= (coordinate_type)factor; (*itr).second.first *= (coordinate_type)factor; @@ -710,7 +716,7 @@ namespace boost { namespace polygon{ } polygon_90_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor) { typedef typename coordinate_traits::coordinate_distance dt; - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy::round((dt)((*itr).first) / (dt)factor); (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) / (dt)factor); @@ -720,7 +726,7 @@ namespace boost { namespace polygon{ } template polygon_90_set_data& scale(const anisotropic_scale_factor& scaling) { - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { scaling.scale((*itr).first, (*itr).second.first); @@ -733,7 +739,7 @@ namespace boost { namespace polygon{ } template polygon_90_set_data& scale_with(const scaling_type& scaling) { - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { if(orient_ == orientation_2d(VERTICAL)) { scaling.scale((*itr).first, (*itr).second.first); @@ -746,7 +752,7 @@ namespace boost { namespace polygon{ } polygon_90_set_data& scale(double factor) { typedef typename coordinate_traits::coordinate_distance dt; - for(typename std::vector > >::iterator + for(typename std::vector > >::iterator itr = data_.begin(); itr != data_.end(); ++itr) { (*itr).first = scaling_policy::round((dt)((*itr).first) * (dt)factor); (*itr).second.first = scaling_policy::round((dt)((*itr).second.first) * (dt)factor); @@ -812,7 +818,7 @@ namespace boost { namespace polygon{ mutable value_type data_; mutable bool dirty_; mutable bool unsorted_; - + private: //functions template @@ -882,7 +888,7 @@ namespace boost { namespace polygon{ return bloat(0, e_total, 0, n_total); } } - + template class property_merge_90 { private: @@ -905,7 +911,7 @@ namespace boost { namespace polygon{ //with unique sets of merged properties to polygons sets in a map keyed by sets of properties // T = std::map, polygon_90_set_data > or // T = std::map, polygon_90_set_data > - template + template inline void merge(ResultType& result) { merge_scanline, typename ResultType::key_type> ms; ms.perform_merge(result, pmd_); @@ -924,12 +930,12 @@ namespace boost { namespace polygon{ inline connectivity_extraction_90() : tsd_(), nodeCount_(0) {} inline connectivity_extraction_90(const connectivity_extraction_90& that) : tsd_(that.tsd_), nodeCount_(that.nodeCount_) {} - inline connectivity_extraction_90& operator=(const connectivity_extraction_90& that) { - tsd_ = that.tsd_; + inline connectivity_extraction_90& operator=(const connectivity_extraction_90& that) { + tsd_ = that.tsd_; nodeCount_ = that.nodeCount_; {} return *this; } - + //insert a polygon set graph node, the value returned is the id of the graph node inline unsigned int insert(const polygon_90_set_data& ps) { ps.clean(); @@ -942,7 +948,7 @@ namespace boost { namespace polygon{ ps.insert(geoObj); return insert(ps); } - + //extract connectivity and store the edges in the graph //graph must be indexable by graph node id and the indexed value must be a std::set of //graph node id @@ -954,4 +960,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/polygon_90_set_traits.hpp b/include/boost/polygon/polygon_90_set_traits.hpp old mode 100755 new mode 100644 index 18e6329..debcf57 --- a/include/boost/polygon/polygon_90_set_traits.hpp +++ b/include/boost/polygon/polygon_90_set_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -24,6 +24,8 @@ namespace boost { namespace polygon{ template struct traits_by_concept { typedef rectangle_traits type; }; template + struct traits_by_concept { typedef segment_traits type; }; + template struct traits_by_concept { typedef polygon_traits type; }; template struct traits_by_concept { typedef polygon_traits type; }; @@ -63,7 +65,7 @@ namespace boost { namespace polygon{ typedef typename traits_type::coordinate_type type; }; template - struct get_coordinate_type { + struct get_coordinate_type { typedef typename get_coordinate_type_2::value_type, typename geometry_concept struct get_iterator_type_2 { - typedef const T* type; + typedef const T* type; static type begin(const T& t) { return &t; } static type end(const T& t) { const T* tp = &t; ++tp; return tp; } }; @@ -88,7 +90,7 @@ namespace boost { namespace polygon{ static type begin(const T& t) { return t.begin(); } static type end(const T& t) { return t.end(); } }; - + // //helpers for allowing polygon 45 and containers of polygon 45 to behave interchangably in polygon_45_set_traits // template // struct get_coordinate_type_45 {}; @@ -109,25 +111,25 @@ namespace boost { namespace polygon{ // struct get_iterator_type_45 {}; // template // struct get_iterator_type_45 { -// typedef typename T::const_iterator type; +// typedef typename T::const_iterator type; // static type begin(const T& t) { return t.begin(); } // static type end(const T& t) { return t.end(); } // }; // template -// struct get_iterator_type_45 { -// typedef const T* type; +// struct get_iterator_type_45 { +// typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; // template -// struct get_iterator_type_45 { -// typedef const T* type; +// struct get_iterator_type_45 { +// typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; // template -// struct get_iterator_type_45 { -// typedef const T* type; +// struct get_iterator_type_45 { +// typedef const T* type; // static type begin(const T& t) { return &t; } // static type end(const T& t) { const T* tp = &t; ++tp; return tp; } // }; @@ -170,13 +172,13 @@ namespace boost { namespace polygon{ typedef typename is_manhattan_polygonal_concept::type>::type type; }; template - struct is_polygon_90_set_type > { + struct is_polygon_90_set_type > { typedef typename gtl_or< typename is_manhattan_polygonal_concept >::type>::type, typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_polygon_90_set_type > { + struct is_polygon_90_set_type > { typedef typename gtl_or< typename is_manhattan_polygonal_concept >::type>::type, typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; @@ -187,15 +189,15 @@ namespace boost { namespace polygon{ typedef typename gtl_same_type::type>::type type; }; template - struct is_mutable_polygon_90_set_type > { + struct is_mutable_polygon_90_set_type > { typedef typename gtl_or< - typename gtl_same_type >::type>::type, + typename gtl_same_type >::type>::type, typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_mutable_polygon_90_set_type > { + struct is_mutable_polygon_90_set_type > { typedef typename gtl_or< - typename gtl_same_type >::type>::type, + typename gtl_same_type >::type>::type, typename is_manhattan_polygonal_concept::value_type>::type>::type>::type type; }; @@ -278,6 +280,7 @@ namespace boost { namespace polygon{ static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); polygon_90_set_data >::coordinate_type> ps(orient); + ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end, orient); ps.clean(); get_90_dispatch(polygon_set, ps, orient, concept_type()); @@ -289,7 +292,10 @@ namespace boost { namespace polygon{ template static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); + size_t num_ele = std::distance(input_begin, input_end); + polygon_set.reserve(num_ele); polygon_90_set_data >::coordinate_type> ps(orient); + ps.reserve(num_ele); ps.insert(input_begin, input_end, orient); ps.clean(); get_90_dispatch(polygon_set, ps, orient, concept_type()); @@ -300,10 +306,11 @@ namespace boost { namespace polygon{ struct polygon_90_set_mutable_traits > { template - static inline void set(polygon_90_set_data& polygon_set, - input_iterator_type input_begin, input_iterator_type input_end, + static inline void set(polygon_90_set_data& polygon_set, + input_iterator_type input_begin, input_iterator_type input_end, orientation_2d orient) { polygon_set.clear(); + polygon_set.reserve(std::distance(input_begin, input_end)); polygon_set.insert(input_begin, input_end, orient); } @@ -341,15 +348,15 @@ namespace boost { namespace polygon{ struct is_polygon_90_set_concept { typedef gtl_yes type; }; template <> struct is_polygon_90_set_concept { typedef gtl_yes type; }; - + template struct is_mutable_polygon_90_set_concept { typedef gtl_no type; }; template <> struct is_mutable_polygon_90_set_concept { typedef gtl_yes type; }; - + template struct geometry_concept > { typedef polygon_90_set_concept type; }; - + //template //typename enable_if::type, void>::type //print_is_polygon_90_set_concept(const T& t) { std::cout << "is polygon 90 set concept\n"; } @@ -359,4 +366,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/polygon_90_with_holes_data.hpp b/include/boost/polygon/polygon_90_with_holes_data.hpp old mode 100755 new mode 100644 index 2fb6cdb..be43b65 --- a/include/boost/polygon/polygon_90_with_holes_data.hpp +++ b/include/boost/polygon/polygon_90_with_holes_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -19,7 +19,7 @@ public: typedef typename polygon_90_data::iterator_type iterator_type; typedef typename polygon_90_data::compact_iterator_type compact_iterator_type; typedef typename std::list >::const_iterator iterator_holes_type; - typedef polygon_90_data hole_type; + typedef polygon_90_data hole_type; typedef typename coordinate_traits::area_type area_type; typedef point_data point_type; @@ -55,9 +55,9 @@ public: } // copy constructor (since we have dynamic memory) - inline polygon_90_with_holes_data(const polygon_90_with_holes_data& that) : self_(that.self_), + inline polygon_90_with_holes_data(const polygon_90_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_90_with_holes_data& operator=(const polygon_90_with_holes_data& that) { self_ = that.self_; @@ -90,7 +90,7 @@ public: inline std::size_t size() const { return self_.size(); - } + } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { @@ -108,9 +108,8 @@ public: private: polygon_90_data self_; - std::list holes_; + std::list holes_; }; } } #endif - diff --git a/include/boost/polygon/polygon_data.hpp b/include/boost/polygon/polygon_data.hpp old mode 100755 new mode 100644 index cd3b672..9784466 --- a/include/boost/polygon/polygon_data.hpp +++ b/include/boost/polygon/polygon_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -32,7 +32,7 @@ public: // copy constructor (since we have dynamic memory) inline polygon_data(const polygon_data& that) : coords_(that.coords_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_data& operator=(const polygon_data& that) { coords_ = that.coords_; @@ -61,10 +61,9 @@ public: inline std::size_t size() const { return coords_.size(); } public: - std::vector > coords_; + std::vector > coords_; }; } } #endif - diff --git a/include/boost/polygon/polygon_set_concept.hpp b/include/boost/polygon/polygon_set_concept.hpp old mode 100755 new mode 100644 index ecd2c70..e3d37b8 --- a/include/boost/polygon/polygon_set_concept.hpp +++ b/include/boost/polygon/polygon_set_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -27,14 +27,14 @@ namespace boost { namespace polygon{ begin_polygon_set_data(const polygon_set_type& polygon_set) { return polygon_set_traits::begin(polygon_set); } - + template typename enable_if< typename is_any_polygon_set_type::type, typename polygon_set_traits::iterator_type>::type end_polygon_set_data(const polygon_set_type& polygon_set) { return polygon_set_traits::end(polygon_set); } - + template typename enable_if< typename is_polygon_set_type::type, bool>::type @@ -83,11 +83,11 @@ namespace boost { namespace polygon{ //equivalence template - typename enable_if< typename gtl_and_3 < + typename enable_if< typename gtl_and_3 < typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, - bool>::type + bool>::type equivalence(const polygon_set_type_1& lvalue, const polygon_set_type_2& rvalue) { polygon_set_data::coordinate_type> ps1; @@ -117,14 +117,14 @@ namespace boost { namespace polygon{ ps.clean(); return ps.empty(); } - + //extents template - typename enable_if< typename gtl_and< + typename enable_if< typename gtl_and< typename is_mutable_polygon_set_type::type, typename is_mutable_rectangle_concept::type>::type>::type, bool>::type - extents(rectangle_type& extents_rectangle, + extents(rectangle_type& extents_rectangle, const polygon_set_type& polygon_set) { clean(polygon_set); polygon_set_data::coordinate_type> ps; @@ -161,11 +161,11 @@ namespace boost { namespace polygon{ assign(polys, polygon_set); std::size_t retval = 0; for(std::size_t i = 0; i < polys.size(); ++i) { - retval += detail::simplify_detail::simplify(polys[i].self_.coords_, + retval += detail::simplify_detail::simplify(polys[i].self_.coords_, polys[i].self_.coords_, threshold); - for(typename std::list >::iterator itrh = + for(typename std::list >::iterator itrh = polys[i].holes_.begin(); itrh != (polys[i].holes_.end()); ++itrh) { - retval += detail::simplify_detail::simplify((*itrh).coords_, + retval += detail::simplify_detail::simplify((*itrh).coords_, (*itrh).coords_, threshold); } } @@ -204,7 +204,7 @@ namespace boost { namespace polygon{ //interact template - typename enable_if< typename gtl_and_3 < + typename enable_if< typename gtl_and_3 < typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, @@ -222,7 +222,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_set_type::type, polygon_set_type>::type & - scale_up(polygon_set_type& polygon_set, + scale_up(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_set_traits::coordinate_type Unit; clean(polygon_set); @@ -236,7 +236,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_set_type::type, polygon_set_type>::type & - scale_down(polygon_set_type& polygon_set, + scale_down(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { typedef typename polygon_set_traits::coordinate_type Unit; clean(polygon_set); @@ -266,7 +266,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename is_mutable_polygon_set_type::type, polygon_set_type>::type & - keep(polygon_set_type& polygon_set, + keep(polygon_set_type& polygon_set, typename coordinate_traits::coordinate_type>::area_type min_area, typename coordinate_traits::coordinate_type>::area_type max_area, typename coordinate_traits::coordinate_type>::unsigned_area_type min_width, @@ -307,7 +307,7 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and_4 < yes_ps_ob, typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, - polygon_set_view >::type + polygon_set_view >::type operator|(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); @@ -317,23 +317,23 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_4 < yes_ps_op, - typename gtl_if::type>::type, - typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type, typename gtl_if::type>::type> - ::type, polygon_set_view >::type + ::type, polygon_set_view >::type operator+(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); } - + struct yes_ps_os : gtl_yes {}; template - typename enable_if< typename gtl_and_4 < yes_ps_os, + typename enable_if< typename gtl_and_4 < yes_ps_os, typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, - polygon_set_view >::type + polygon_set_view >::type operator*(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); @@ -346,7 +346,7 @@ namespace boost { namespace polygon{ typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, - polygon_set_view >::type + polygon_set_view >::type operator&(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); @@ -359,30 +359,30 @@ namespace boost { namespace polygon{ typename is_any_polygon_set_type::type, typename is_any_polygon_set_type::type, typename is_either_polygon_set_type::type>::type, - polygon_set_view >::type + polygon_set_view >::type operator^(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); } - + struct yes_ps_om : gtl_yes {}; template typename enable_if< typename gtl_and_4 < yes_ps_om, - typename gtl_if::type>::type, - typename gtl_if::type>::type, + typename gtl_if::type>::type, + typename gtl_if::type>::type, typename gtl_if::type>::type> - ::type, polygon_set_view >::type + ::type, polygon_set_view >::type operator-(const geometry_type_1& lvalue, const geometry_type_2& rvalue) { return polygon_set_view (lvalue, rvalue); } - + struct yes_ps_ope : gtl_yes {}; template - typename enable_if< typename gtl_and_4< yes_ps_ope, gtl_yes, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename enable_if< typename gtl_and_4< yes_ps_ope, gtl_yes, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator+=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -391,8 +391,8 @@ namespace boost { namespace polygon{ struct yes_ps_obe : gtl_yes {}; template - typename enable_if< typename gtl_and_3< yes_ps_obe, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename enable_if< typename gtl_and_3< yes_ps_obe, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator|=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -401,8 +401,8 @@ namespace boost { namespace polygon{ struct yes_ps_ose : gtl_yes {}; template - typename enable_if< typename gtl_and_3< yes_ps_ose, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename enable_if< typename gtl_and_3< yes_ps_ose, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator*=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -412,8 +412,8 @@ namespace boost { namespace polygon{ template typename enable_if< - typename gtl_and_3< yes_ps_oae, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename gtl_and_3< yes_ps_oae, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator&=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -422,8 +422,8 @@ namespace boost { namespace polygon{ struct yes_ps_oxe : gtl_yes {}; template - typename enable_if< typename gtl_and_3< yes_ps_oxe, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename enable_if< typename gtl_and_3< yes_ps_oxe, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator^=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -432,9 +432,9 @@ namespace boost { namespace polygon{ struct yes_ps_ome : gtl_yes {}; template - typename enable_if< - typename gtl_and_3< yes_ps_ome, typename is_mutable_polygon_set_type::type, - typename is_any_polygon_set_type::type>::type, + typename enable_if< + typename gtl_and_3< yes_ps_ome, typename is_mutable_polygon_set_type::type, + typename is_any_polygon_set_type::type>::type, geometry_type_1>::type & operator-=(geometry_type_1& lvalue, const geometry_type_2& rvalue) { return self_assignment_boolean_op(lvalue, rvalue); @@ -550,13 +550,13 @@ namespace boost { namespace polygon{ return polygon_set.end(); } - static inline orientation_2d orient(const view_of& polygon_set) { + static inline orientation_2d orient(const view_of& polygon_set) { return polygon_set.orient(); } - static inline bool clean(const view_of& polygon_set) { + static inline bool clean(const view_of& polygon_set) { return polygon_set.clean(); } - static inline bool sorted(const view_of& polygon_set) { + static inline bool sorted(const view_of& polygon_set) { return polygon_set.sorted(); } }; diff --git a/include/boost/polygon/polygon_set_data.hpp b/include/boost/polygon/polygon_set_data.hpp old mode 100755 new mode 100644 index bbddacf..41a1b59 --- a/include/boost/polygon/polygon_set_data.hpp +++ b/include/boost/polygon/polygon_set_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -11,7 +11,6 @@ #include "polygon_45_set_concept.hpp" #include "polygon_traits.hpp" #include "detail/polygon_arbitrary_formation.hpp" -#include namespace boost { namespace polygon { @@ -22,7 +21,7 @@ namespace boost { namespace polygon { template static inline T round_down(double val) { T rounded_val = (T)(val); - if(val < (double)rounded_val) + if(val < (double)rounded_val) --rounded_val; return rounded_val; } @@ -57,11 +56,11 @@ namespace boost { namespace polygon { } // copy constructor - inline polygon_set_data(const polygon_set_data& that) : + inline polygon_set_data(const polygon_set_data& that) : data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {} // copy constructor - template + template inline polygon_set_data(const polygon_set_view& that); // destructor @@ -150,10 +149,10 @@ namespace boost { namespace polygon { insert(polygon_object, is_hole, polygon_concept()); } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_concept()); - for(typename polygon_with_holes_traits::iterator_holes_type itr = + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon_with_holes_object); itr != end_holes(polygon_with_holes_object); ++itr) { insert(*itr, !is_hole, polygon_concept()); @@ -161,12 +160,12 @@ namespace boost { namespace polygon { } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_45_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_90_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } @@ -212,7 +211,7 @@ namespace boost { namespace polygon { first_point = previous_point = current_point; } else { if(previous_point != current_point) { - element_type elem(edge_type(previous_point, current_point), + element_type elem(edge_type(previous_point, current_point), ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); insert_clean(elem); } @@ -222,7 +221,7 @@ namespace boost { namespace polygon { current_point = first_point; if(!first_iteration) { if(previous_point != current_point) { - element_type elem(edge_type(previous_point, current_point), + element_type elem(edge_type(previous_point, current_point), ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); insert_clean(elem); } @@ -248,7 +247,7 @@ namespace boost { namespace polygon { data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); //std::cout << "DONE FORMING POLYGONS\n"; } @@ -270,14 +269,10 @@ namespace boost { namespace polygon { } } - // equivalence operator - inline bool operator==(const polygon_set_data& p) const { - clean(); - p.clean(); - return data_ == p.data_; - } - - // inequivalence operator + // equivalence operator + inline bool operator==(const polygon_set_data& p) const; + + // inequivalence operator inline bool operator!=(const polygon_set_data& p) const { return !((*this) == p); } @@ -321,7 +316,7 @@ namespace boost { namespace polygon { void sort() const{ if(unsorted_) { - gtlsort(data_.begin(), data_.end()); + polygon_sort(data_.begin(), data_.end()); unsorted_ = false; } } @@ -329,13 +324,14 @@ namespace boost { namespace polygon { template void set(input_iterator_type input_begin, input_iterator_type input_end) { clear(); + reserve(std::distance(input_begin,input_end)); insert(input_begin, input_end); dirty_ = true; unsorted_ = true; } void set(const value_type& value) { - data_ = value; + data_ = value; dirty_ = true; unsorted_ = true; } @@ -362,7 +358,7 @@ namespace boost { namespace polygon { resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); template - inline polygon_set_data& + inline polygon_set_data& transform(const transform_type& tr) { std::vector > polys; get(polys); @@ -376,7 +372,7 @@ namespace boost { namespace polygon { return *this; } - inline polygon_set_data& + inline polygon_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { ::boost::polygon::scale_up((*itr).first.first, factor); @@ -384,31 +380,41 @@ namespace boost { namespace polygon { } return *this; } - - inline polygon_set_data& + + inline polygon_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { + bool vb = (*itr).first.first.x() == (*itr).first.second.x(); ::boost::polygon::scale_down((*itr).first.first, factor); ::boost::polygon::scale_down((*itr).first.second, factor); - } - unsorted_ = true; - dirty_ = true; - return *this; - } - - template - inline polygon_set_data& scale(polygon_set_data& polygon_set, - const scaling_type& scaling) { - for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { - ::boost::polygon::scale((*itr).first.first, scaling); - ::boost::polygon::scale((*itr).first.second, scaling); + bool va = (*itr).first.first.x() == (*itr).first.second.x(); + if(!vb && va) { + (*itr).second *= -1; + } } unsorted_ = true; dirty_ = true; return *this; } - static inline void compute_offset_edge(point_data& pt1, point_data& pt2, + template + inline polygon_set_data& scale(polygon_set_data& polygon_set, + const scaling_type& scaling) { + for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { + bool vb = (*itr).first.first.x() == (*itr).first.second.x(); + ::boost::polygon::scale((*itr).first.first, scaling); + ::boost::polygon::scale((*itr).first.second, scaling); + bool va = (*itr).first.first.x() == (*itr).first.second.x(); + if(!vb && va) { + (*itr).second *= -1; + } + } + unsorted_ = true; + dirty_ = true; + return *this; + } + + static inline void compute_offset_edge(point_data& pt1, point_data& pt2, const point_data& prev_pt, const point_data& current_pt, long double distance, int multiplier) { @@ -439,17 +445,17 @@ namespace boost { namespace polygon { he2.second.y((long double)(next_pt.y())); compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); - typename scanline_base::compute_intersection_pack pack; + typedef scanline_base::compute_intersection_pack pack; point_data rpt; point_data bisectorpt((he1.second.x()+he2.first.x())/2, (he1.second.y()+he2.first.y())/2); point_data orig_pt((long double)pt.x(), (long double)pt.y()); if(euclidean_distance(bisectorpt, orig_pt) < distance/2) { - if(!pack.compute_lazy_intersection(rpt, he1, he2, true, false)) { + if(!pack::compute_lazy_intersection(rpt, he1, he2, true, false)) { rpt = he1.second; //colinear offset edges use shared point } } else { - if(!pack.compute_lazy_intersection(rpt, he1, std::pair, point_data >(orig_pt, bisectorpt), true, false)) { + if(!pack::compute_lazy_intersection(rpt, he1, std::pair, point_data >(orig_pt, bisectorpt), true, false)) { rpt = he1.second; //colinear offset edges use shared point } } @@ -565,8 +571,8 @@ namespace boost { namespace polygon { } template - inline polygon_set_data& - insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_with_holes_concept tag) { insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept()); for(typename polygon_with_holes_traits::iterator_holes_type itr = @@ -578,14 +584,14 @@ namespace boost { namespace polygon { } template - inline polygon_set_data& - insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_concept tag) { if (resizing==0) return *this; - + // one dimensional used to store CCW/CW flag //direction_1d wdir = winding(poly); // LOW==CLOCKWISE just faster to type @@ -630,25 +636,25 @@ namespace boost { namespace polygon { point_data normal2( third->y()-second->y(), second->x()-third->x()); double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y(); bool convex = direction>0; - + bool treat_as_concave = !convex; if(sizing_sign) treat_as_concave = convex; point_data v; assign(v, normal1); double s2 = (v.x()*v.x()+v.y()*v.y()); - double s = sqrt(s2)/resizing; + double s = std::sqrt(s2)/resizing; v = point_data(v.x()/s,v.y()/s); point_data curr_prev; if (prev_concave) //TODO missing round_down() curr_prev = point_data(first->x()+v.x(),first->y()+v.y()); - else + else curr_prev = prev_point; // around concave corners - insert rectangle // if previous corner is concave it's point info may be ignored - if ( treat_as_concave) { + if ( treat_as_concave) { std::vector > pts; pts.push_back(point_data(second->x()+v.x(),second->y()+v.y())); @@ -669,13 +675,13 @@ namespace boost { namespace polygon { direction_1d winding; winding = convex?COUNTERCLOCKWISE:CLOCKWISE; if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing - , num_circle_segments, corner_fill_arc)) + , num_circle_segments, corner_fill_arc)) { if (first_pts.size()) { for (int i=0; i tmp; //insert original shape @@ -721,7 +727,7 @@ namespace boost { namespace polygon { inline polygon_set_data& - interact(const polygon_set_data& that); + interact(const polygon_set_data& that); inline bool downcast(polygon_45_set_data& result) const { if(!is_45_) return false; @@ -790,7 +796,7 @@ namespace boost { namespace polygon { data.push_back(vertex_half_edge((*itr).first.first, (*itr).first.second, (*itr).second)); data.push_back(vertex_half_edge((*itr).first.second, (*itr).first.first, -1 * (*itr).second)); } - gtlsort(data.begin(), data.end()); + polygon_sort(data.begin(), data.end()); pf.scan(container, data.begin(), data.end()); } }; @@ -810,17 +816,17 @@ namespace boost { namespace polygon { // } template - inline int make_resizing_vertex_list(std::vector > >& return_points, + inline int make_resizing_vertex_list(std::vector > >& return_points, point_data& curr_prev, bool ignore_prev_point, point_data< T> start, point_data middle, point_data< T> end, double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) { // handle the case of adding an intersection point point_data dn1( middle.y()-start.y(), start.x()-middle.x()); - double size = sizing_distance/sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y()); + double size = sizing_distance/std::sqrt( dn1.x()*dn1.x()+dn1.y()*dn1.y()); dn1 = point_data( dn1.x()*size, dn1.y()* size); point_data dn2( end.y()-middle.y(), middle.x()-end.x()); - size = sizing_distance/sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y()); + size = sizing_distance/std::sqrt( dn2.x()*dn2.x()+dn2.y()*dn2.y()); dn2 = point_data( dn2.x()*size, dn2.y()* size); point_data start_offset((start.x()+dn1.x()),(start.y()+dn1.y())); point_data mid1_offset((middle.x()+dn1.x()),(middle.y()+dn1.y())); @@ -843,7 +849,7 @@ namespace boost { namespace polygon { int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); curr_prev = round_down(mid2_offset); return num; - + } std::pair,point_data > he1(start_offset,mid1_offset); @@ -881,21 +887,21 @@ namespace boost { namespace polygon { // returnPoints will start with the first point after start // returnPoints vector may be empty template - inline int make_arc(std::vector >& return_points, + inline int make_arc(std::vector >& return_points, point_data< double> start, point_data< double> end, point_data< double> center, double r, unsigned int num_circle_segments) { const double our_pi=3.1415926535897932384626433832795028841971; - // derive start and end angles + // derive start and end angles double ps = atan2(start.y()-center.y(), start.x()-center.x()); double pe = atan2(end.y()-center.y(), end.x()-center.x()); - if (ps < 0.0) + if (ps < 0.0) ps += 2.0 * our_pi; - if (pe <= 0.0) + if (pe <= 0.0) pe += 2.0 * our_pi; - if (ps >= 2.0 * our_pi) + if (ps >= 2.0 * our_pi) ps -= 2.0 * our_pi; - while (pe <= ps) + while (pe <= ps) pe += 2.0 * our_pi; double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; if ( start==end) // full circle? @@ -941,12 +947,12 @@ namespace boost { namespace polygon { inline connectivity_extraction() : ce_(), nodeCount_(0) {} inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_), nodeCount_(that.nodeCount_) {} - inline connectivity_extraction& operator=(const connectivity_extraction& that) { - ce_ = that.ce_; + inline connectivity_extraction& operator=(const connectivity_extraction& that) { + ce_ = that.ce_; nodeCount_ = that.nodeCount_; {} return *this; } - + //insert a polygon set graph node, the value returned is the id of the graph node inline unsigned int insert(const polygon_set_data& ps) { ps.clean(); @@ -959,7 +965,7 @@ namespace boost { namespace polygon { ps.insert(geoObj); return insert(ps); } - + //extract connectivity and store the edges in the graph //graph must be indexable by graph node id and the indexed value must be a std::set of //graph node id @@ -997,4 +1003,3 @@ namespace boost { namespace polygon { #include "polygon_set_concept.hpp" #include "detail/minkowski.hpp" #endif - diff --git a/include/boost/polygon/polygon_set_traits.hpp b/include/boost/polygon/polygon_set_traits.hpp old mode 100755 new mode 100644 index 93604c4..b68bbc1 --- a/include/boost/polygon/polygon_set_traits.hpp +++ b/include/boost/polygon/polygon_set_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -45,13 +45,13 @@ namespace boost { namespace polygon{ typedef typename is_polygonal_concept::type>::type type; }; template - struct is_polygon_set_type > { + struct is_polygon_set_type > { typedef typename gtl_or< typename is_polygonal_concept >::type>::type, typename is_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_polygon_set_type > { + struct is_polygon_set_type > { typedef typename gtl_or< typename is_polygonal_concept >::type>::type, typename is_polygonal_concept::value_type>::type>::type>::type type; @@ -62,13 +62,13 @@ namespace boost { namespace polygon{ typedef typename gtl_same_type::type>::type type; }; template - struct is_mutable_polygon_set_type > { + struct is_mutable_polygon_set_type > { typedef typename gtl_or< - typename gtl_same_type >::type>::type, + typename gtl_same_type >::type>::type, typename is_polygonal_concept::value_type>::type>::type>::type type; }; template - struct is_mutable_polygon_set_type > { + struct is_mutable_polygon_set_type > { typedef typename gtl_or< typename gtl_same_type >::type>::type, typename is_polygonal_concept::value_type>::type>::type>::type type; @@ -82,6 +82,7 @@ namespace boost { namespace polygon{ static inline void set(std::list& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); polygon_set_data >::coordinate_type> ps; + ps.reserve(std::distance(input_begin, input_end)); ps.insert(input_begin, input_end); ps.get(polygon_set); } @@ -91,7 +92,10 @@ namespace boost { namespace polygon{ template static inline void set(std::vector& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.clear(); + size_t num_ele = std::distance(input_begin, input_end); + polygon_set.reserve(num_ele); polygon_set_data >::coordinate_type> ps; + ps.reserve(num_ele); ps.insert(input_begin, input_end); ps.get(polygon_set); } @@ -100,7 +104,7 @@ namespace boost { namespace polygon{ template struct polygon_set_mutable_traits > { template - static inline void set(polygon_set_data& polygon_set, + static inline void set(polygon_set_data& polygon_set, input_iterator_type input_begin, input_iterator_type input_end) { polygon_set.set(input_begin, input_end); } @@ -124,7 +128,6 @@ namespace boost { namespace polygon{ static inline bool sorted(const polygon_set_data& polygon_set) { polygon_set.sort(); return true; } }; -} +} } #endif - diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp old mode 100755 new mode 100644 index 041321d..5595adf --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -18,17 +18,17 @@ namespace boost { namespace polygon{ static inline compact_iterator_type begin_compact(const T& t) { return t.begin_compact(); } - + // Get the end iterator static inline compact_iterator_type end_compact(const T& t) { return t.end_compact(); } - + // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return t.size(); } - + // Get the winding direction of the polygon static inline winding_direction winding(const T&) { return unknown_winding; @@ -45,17 +45,17 @@ namespace boost { namespace polygon{ static inline iterator_type begin_points(const T& t) { return t.begin(); } - + // Get the end iterator static inline iterator_type end_points(const T& t) { return t.end(); } - + // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return t.size(); } - + // Get the winding direction of the polygon static inline winding_direction winding(const T&) { return unknown_winding; @@ -73,18 +73,18 @@ namespace boost { namespace polygon{ return iterator_type(polygon_90_traits::begin_compact(t), polygon_90_traits::end_compact(t)); } - + // Get the end iterator static inline iterator_type end_points(const T& t) { return iterator_type(polygon_90_traits::end_compact(t), polygon_90_traits::end_compact(t)); } - + // Get the number of sides of the polygon static inline std::size_t size(const T& t) { return polygon_90_traits::size(t); } - + // Get the winding direction of the polygon static inline winding_direction winding(const T& t) { return polygon_90_traits::winding(t); @@ -97,7 +97,7 @@ namespace boost { namespace polygon{ struct polygon_traits {}; template - struct polygon_traits::type, polygon_concept>::type, typename gtl_same_type::type, polygon_45_concept>::type, @@ -106,7 +106,7 @@ namespace boost { namespace polygon{ >::type> : public polygon_traits_general {}; template - struct polygon_traits< T, + struct polygon_traits< T, typename gtl_or< typename gtl_same_type::type, polygon_90_concept>::type, typename gtl_same_type::type, polygon_90_with_holes_concept>::type @@ -161,7 +161,7 @@ namespace boost { namespace polygon{ return t.end_holes(); } - // Get the number of holes + // Get the number of holes static inline std::size_t size_holes(const T& t) { return t.size_holes(); } @@ -169,14 +169,14 @@ namespace boost { namespace polygon{ template struct polygon_90_mutable_traits { - + // Set the data of a polygon with the unique coordinates in an iterator, starting with an x template static inline T& set_compact(T& t, iT input_begin, iT input_end) { t.set_compact(input_begin, input_end); return t; } - + }; template @@ -199,7 +199,7 @@ namespace boost { namespace polygon{ t.set(input_begin, input_end); return t; } - + }; template @@ -251,7 +251,7 @@ namespace boost { namespace polygon{ struct polygon_45_with_holes_concept {}; struct polygon_90_concept {}; struct polygon_90_with_holes_concept {}; - + template struct is_polygon_90_type { @@ -272,7 +272,7 @@ namespace boost { namespace polygon{ typedef typename gtl_or::type, typename gtl_same_type::type>::type type; }; - + template struct is_polygon_90_with_holes_type { typedef typename geometry_concept::type GC; @@ -284,7 +284,7 @@ namespace boost { namespace polygon{ struct is_polygon_45_with_holes_type { typedef typename geometry_concept::type GC; typedef typename gtl_or_3::type, - typename is_polygon_45_type::type, + typename is_polygon_45_type::type, typename gtl_same_type::type>::type type; }; @@ -292,7 +292,7 @@ namespace boost { namespace polygon{ struct is_polygon_with_holes_type { typedef typename geometry_concept::type GC; typedef typename gtl_or_3::type, - typename is_polygon_type::type, + typename is_polygon_type::type, typename gtl_same_type::type>::type type; }; @@ -301,7 +301,7 @@ namespace boost { namespace polygon{ typedef typename geometry_concept::type GC; typedef typename gtl_same_type::type type; }; - + template struct is_mutable_polygon_45_type { typedef typename geometry_concept::type GC; @@ -313,7 +313,7 @@ namespace boost { namespace polygon{ typedef typename geometry_concept::type GC; typedef typename gtl_same_type::type type; }; - + template struct is_mutable_polygon_90_with_holes_type { typedef typename geometry_concept::type GC; @@ -341,10 +341,10 @@ namespace boost { namespace polygon{ template struct is_any_mutable_polygon_without_holes_type { typedef typename gtl_or_3< - typename is_mutable_polygon_90_type::type, - typename is_mutable_polygon_45_type::type, + typename is_mutable_polygon_90_type::type, + typename is_mutable_polygon_45_type::type, typename is_mutable_polygon_type::type>::type type; }; - + template struct is_any_mutable_polygon_type { typedef typename gtl_or::type, @@ -372,7 +372,7 @@ namespace boost { namespace polygon{ template struct distance_type_by_domain { typedef typename coordinate_traits::coordinate_distance type; }; template - struct distance_type_by_domain { + struct distance_type_by_domain { typedef typename coordinate_traits::coordinate_difference type; }; // \brief Sets the boundary of the polygon to the points in the iterator range @@ -399,9 +399,9 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_90_concept template - typename enable_if ::type, - typename is_mutable_polygon_90_with_holes_type::type>::type, T>::type & + typename enable_if ::type, + typename is_mutable_polygon_90_with_holes_type::type>::type, T>::type & set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { polygon_90_mutable_traits::set_compact(t, begin_compact_coordinates, end_compact_coordinates); return t; @@ -411,7 +411,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and < typename is_any_mutable_polygon_with_holes_type::type, - typename gtl_different_type::type>::type, + typename gtl_different_type::type>::type, manhattan_domain>::type>::type, T>::type & set_compact(T& t, iT begin_compact_coordinates, iT end_compact_coordinates) { @@ -434,29 +434,29 @@ namespace boost { namespace polygon{ typename polygon_90_traits::compact_iterator_type begin_compact(const T& polygon, typename enable_if< - typename gtl_and ::type, + typename gtl_and ::type, typename gtl_same_type::type>::type, manhattan_domain>::type>::type>::type * = 0 ) { return polygon_90_traits::begin_compact(polygon); } - + /// \relatesalso polygon_90_concept template typename polygon_90_traits::compact_iterator_type end_compact(const T& polygon, - typename enable_if< - typename gtl_and ::type, + typename enable_if< + typename gtl_and ::type, typename gtl_same_type::type>::type, manhattan_domain>::type>::type>::type * = 0 ) { return polygon_90_traits::end_compact(polygon); } - + /// \relatesalso polygon_concept template typename enable_if < typename gtl_if< - typename is_polygon_with_holes_type::type>::type, + typename is_polygon_with_holes_type::type>::type, typename polygon_traits::iterator_type>::type begin_points(const T& polygon) { return polygon_traits::begin_points(polygon); @@ -465,7 +465,7 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_concept template typename enable_if < typename gtl_if< - typename is_polygon_with_holes_type::type>::type, + typename is_polygon_with_holes_type::type>::type, typename polygon_traits::iterator_type>::type end_points(const T& polygon) { return polygon_traits::end_points(polygon); @@ -473,7 +473,7 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_concept template - typename enable_if ::type, + typename enable_if ::type, std::size_t>::type size(const T& polygon) { return polygon_traits::size(polygon); @@ -482,7 +482,7 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_with_holes_concept template typename enable_if < typename gtl_if< - typename is_polygon_with_holes_type::type>::type, + typename is_polygon_with_holes_type::type>::type, typename polygon_with_holes_traits::iterator_holes_type>::type begin_holes(const T& polygon) { return polygon_with_holes_traits::begin_holes(polygon); @@ -491,7 +491,7 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_with_holes_concept template typename enable_if < typename gtl_if< - typename is_polygon_with_holes_type::type>::type, + typename is_polygon_with_holes_type::type>::type, typename polygon_with_holes_traits::iterator_holes_type>::type end_holes(const T& polygon) { return polygon_with_holes_traits::end_holes(polygon); @@ -499,7 +499,7 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_with_holes_concept template - typename enable_if ::type, + typename enable_if ::type, std::size_t>::type size_holes(const T& polygon) { return polygon_with_holes_traits::size_holes(polygon); @@ -550,7 +550,7 @@ namespace boost { namespace polygon{ polygon_with_holes_traits::end_holes(rvalue)); return lvalue; } - + // \relatesalso polygon_90_concept template typename enable_if< @@ -561,7 +561,7 @@ namespace boost { namespace polygon{ polygon_90_traits::end_compact(rvalue)); return lvalue; } - + // \relatesalso polygon_90_with_holes_concept template typename enable_if< @@ -589,14 +589,14 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_90_concept template - typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type::type, + typename enable_if< typename gtl_and< typename is_mutable_polygon_90_type::type, typename is_point_concept::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { std::vector::coordinate_type> coords; coords.reserve(size(polygon)); bool pingpong = true; - for(typename polygon_90_traits::compact_iterator_type iter = begin_compact(polygon); + for(typename polygon_90_traits::compact_iterator_type iter = begin_compact(polygon); iter != end_compact(polygon); ++iter) { coords.push_back((*iter) + (pingpong ? x(point) : y(point))); pingpong = !pingpong; @@ -607,15 +607,15 @@ namespace boost { namespace polygon{ /// \relatesalso polygon_concept template - typename enable_if< typename gtl_and< typename gtl_or< - typename is_mutable_polygon_45_type::type, - typename is_mutable_polygon_type::type>::type, + typename enable_if< typename gtl_and< typename gtl_or< + typename is_mutable_polygon_45_type::type, + typename is_mutable_polygon_type::type>::type, typename is_point_concept::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); convolve(points.back(), point); @@ -623,11 +623,11 @@ namespace boost { namespace polygon{ polygon_mutable_traits::set_points(polygon, points.begin(), points.end()); return polygon; } - + /// \relatesalso polygon_with_holes_concept template typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, + typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, typename is_point_concept::type>::type>::type, polygon_type>::type & convolve(polygon_type& polygon, const point_type& point) { @@ -654,7 +654,7 @@ namespace boost { namespace polygon{ typedef typename polygon_traits::coordinate_type Unit; if(orient == HORIZONTAL) return convolve(polygon, point_data(displacement, Unit(0))); return convolve(polygon, point_data(Unit(0), displacement)); - } + } /// \relatesalso polygon_concept /// \brief Applies a transformation to the polygon. @@ -667,7 +667,7 @@ namespace boost { namespace polygon{ transform(polygon_type& polygon, const transform_type& tr) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); transform(points.back(), tr); @@ -701,7 +701,7 @@ namespace boost { namespace polygon{ scale_up(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_up(points.back(), factor); @@ -732,15 +732,15 @@ namespace boost { namespace polygon{ //scale non-45 down template typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, typename gtl_not::type>::type>::type>::type>::type, polygon_type>::type & scale_down(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_down(points.back(), factor); @@ -756,8 +756,6 @@ namespace boost { namespace polygon{ void snap_point_vector_to_45(std::vector >& pts) { typedef point_data Point; if(pts.size() < 3) { pts.clear(); return; } - Point firstPt = pts.front(); - Point prevPt = firstPt; typename std::vector >::iterator endLocation = std::unique(pts.begin(), pts.end()); if(endLocation != pts.end()){ pts.resize(endLocation - pts.begin()); @@ -838,7 +836,7 @@ namespace boost { namespace polygon{ snap_to_45(polygon_type& polygon) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); } @@ -869,15 +867,15 @@ namespace boost { namespace polygon{ //scale specifically 45 down template typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, typename gtl_same_type - < forty_five_domain, + < forty_five_domain, typename geometry_domain::type>::type>::type>::type, polygon_type>::type & scale_down(polygon_type& polygon, typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale_down(points.back(), factor); @@ -906,18 +904,18 @@ namespace boost { namespace polygon{ return polygon; } - //scale non-45 + //scale non-45 template typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, typename gtl_not::type>::type>::type>::type>::type, polygon_type>::type & scale(polygon_type& polygon, double factor) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale(points.back(), anisotropic_scale_factor(factor, factor)); @@ -926,19 +924,19 @@ namespace boost { namespace polygon{ return polygon; } - //scale specifically 45 + //scale specifically 45 template polygon_type& scale(polygon_type& polygon, double factor, typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, + typename gtl_and< typename is_any_mutable_polygon_without_holes_type::type, typename gtl_same_type - < forty_five_domain, + < forty_five_domain, typename geometry_domain::type>::type>::type>::type>::type * = 0 ) { std::vector::iterator_type>::value_type> points; points.reserve(size(polygon)); - for(typename polygon_traits::iterator_type iter = begin_points(polygon); + for(typename polygon_traits::iterator_type iter = begin_points(polygon); iter != end_points(polygon); ++iter) { points.push_back(*iter); scale(points.back(), anisotropic_scale_factor(factor, factor)); @@ -1012,7 +1010,7 @@ namespace boost { namespace polygon{ } template - typename enable_if< + typename enable_if< typename is_polygon_with_holes_type::type, typename area_type_by_domain< typename geometry_domain::type>::type, typename polygon_traits::coordinate_type>::type>::type @@ -1036,7 +1034,7 @@ namespace boost { namespace polygon{ template bool point_sequence_is_45(iT itr, iT itr_end) { - typedef typename iT::value_type Point; + typedef typename std::iterator_traits::value_type Point; typedef typename point_traits::coordinate_type Unit; if(itr == itr_end) return true; Point firstPt = *itr; @@ -1097,7 +1095,7 @@ namespace boost { namespace polygon{ typename distance_type_by_domain ::type>::type, typename polygon_traits::coordinate_type>::type perimeter(const T& polygon, - typename enable_if< + typename enable_if< typename is_polygon_with_holes_type::type>::type * = 0 ) { typedef typename distance_type_by_domain @@ -1115,7 +1113,7 @@ namespace boost { namespace polygon{ } template - typename enable_if ::type, + typename enable_if ::type, direction_1d>::type winding(const T& polygon) { winding_direction wd = polygon_traits::winding(polygon); @@ -1129,9 +1127,9 @@ namespace boost { namespace polygon{ } template - typename enable_if< - typename gtl_and< typename is_polygon_90_type::type, - typename gtl_same_type::type, point_concept>::type>::type, + typename enable_if< + typename gtl_and< typename is_polygon_90_type::type, + typename gtl_same_type::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { typedef T polygon_type; @@ -1148,23 +1146,23 @@ namespace boost { namespace polygon{ if(i == num-1) iter = begin_points(polygon); else ++iter; point_type current_pt = *iter; - if(x(current_pt) == + if(x(current_pt) == x(prev_pt)) { - unsigned int index = x(current_pt) > + unsigned int index = x(current_pt) > x(point); std::size_t increment = 0; - interval_data ivl(y(current_pt), + interval_data ivl(y(current_pt), y(prev_pt)); if(contains(ivl, y(point), true)) { - if(x(current_pt) == + if(x(current_pt) == x(point)) return consider_touch; ++increment; - if(y(current_pt) != + if(y(current_pt) != y(point) && - y(prev_pt) != + y(prev_pt) != y(point)) { ++increment; - } + } counts[index] += increment; } } @@ -1173,7 +1171,7 @@ namespace boost { namespace polygon{ //odd count implies boundary condition if(counts[0] % 2 || counts[1] % 2) return consider_touch; //an odd number of edges to the left implies interior pt - return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; + return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; } //TODO: refactor to expose as user APIs @@ -1200,7 +1198,7 @@ namespace boost { namespace polygon{ return lp(pt, pt2) && lp(pt1, pt); return lp(pt, pt1) && lp(pt2, pt); } - + template static inline bool equal_slope(area_type dx1, area_type dy1, area_type dx2, area_type dy2) { typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; @@ -1240,7 +1238,7 @@ namespace boost { namespace polygon{ dy2 *= -1; dx2 *= -1; } else if(dx2 == 0) { - //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal + //if the second slope is vertical the first is always less unless it is also vertical, in which case they are equal return dx1 != 0; } typedef typename coordinate_traits::unsigned_area_type unsigned_product_type; @@ -1285,8 +1283,8 @@ namespace boost { namespace polygon{ }; template - typename enable_if< - typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, + typename enable_if< + typename gtl_and< typename is_any_mutable_polygon_with_holes_type::type, typename gtl_same_type::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { @@ -1306,10 +1304,10 @@ namespace boost { namespace polygon{ } template - typename enable_if< - typename gtl_and_3< - typename is_polygon_type::type, - typename gtl_different_type::type>::type, manhattan_domain>::type, + typename enable_if< + typename gtl_and_3< + typename is_polygon_type::type, + typename gtl_different_type::type>::type, manhattan_domain>::type, typename gtl_same_type::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { @@ -1367,16 +1365,16 @@ namespace boost { namespace polygon{ } } he.first = he.second; - } + } return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon } /* template - typename enable_if< - typename gtl_and_3< - typename is_polygon_with_holes_type::type, - typename gtl_different_type::type>::type, manhattan_domain>::type, + typename enable_if< + typename gtl_and_3< + typename is_polygon_with_holes_type::type, + typename gtl_different_type::type>::type, manhattan_domain>::type, typename gtl_same_type::type, point_concept>::type>::type, bool>::type contains(const T& polygon, const input_point_type& point, bool consider_touch = true) { @@ -1420,7 +1418,7 @@ namespace boost { namespace polygon{ } } he.first = he.second; - } + } return above % 2 != 0; //if the point is above an odd number of edges is must be inside polygon } */ @@ -1429,19 +1427,19 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and< typename is_mutable_point_concept::type>::type, typename is_polygon_with_holes_type::type>::type, - bool>::type + bool>::type center(T1& center_point, const T2& polygon) { typedef typename polygon_traits::coordinate_type coordinate_type; rectangle_data bbox; extents(bbox, polygon); return center(center_point, bbox); } - + template typename enable_if< typename gtl_and< typename is_mutable_rectangle_concept::type>::type, typename is_polygon_with_holes_type::type>::type, - bool>::type + bool>::type extents(T1& bounding_box, const T2& polygon) { typedef typename polygon_traits::iterator_type iterator; bool first_iteration = true; @@ -1548,7 +1546,7 @@ namespace boost { namespace polygon{ // }; template struct get_void {}; template <> struct get_void { typedef void type; }; - + template struct polygon_with_holes_traits< T, typename get_void::type>::type > { typedef T hole_type; @@ -1565,7 +1563,7 @@ namespace boost { namespace polygon{ rectangle_data rect; view_of(const T& obj) : rect() { point_data pts[2]; - typename polygon_traits::iterator_type itr = + typename polygon_traits::iterator_type itr = begin_points(obj), itre = end_points(obj); if(itr == itre) return; assign(pts[0], *itr); @@ -1584,7 +1582,7 @@ namespace boost { namespace polygon{ struct geometry_concept > { typedef rectangle_concept type; }; - + template struct view_of { const T* t; @@ -1597,17 +1595,17 @@ namespace boost { namespace polygon{ inline iterator_type begin() const { return polygon_traits::begin_points(*t); } - + /// Get the end iterator inline iterator_type end() const { return polygon_traits::end_points(*t); } - + /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits::size(*t); } - + /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits::winding(*t); @@ -1618,7 +1616,7 @@ namespace boost { namespace polygon{ struct geometry_concept > { typedef polygon_45_concept type; }; - + template struct view_of { const T* t; @@ -1633,18 +1631,18 @@ namespace boost { namespace polygon{ return compact_iterator_type(polygon_traits::begin_points(*t), polygon_traits::end_points(*t)); } - + /// Get the end iterator inline compact_iterator_type end_compact() const { return compact_iterator_type(polygon_traits::end_points(*t), polygon_traits::end_points(*t)); } - + /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits::size(*t); } - + /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits::winding(*t); @@ -1689,26 +1687,26 @@ namespace boost { namespace polygon{ inline bool operator!=(const iterator_holes_type& that) const { return (internal_itr != that.internal_itr); } - inline value_type operator*() const { + inline value_type operator*() const { return view_as(*internal_itr); } }; - + /// Get the begin iterator inline iterator_type begin() const { return polygon_traits::begin_points(*t); } - + /// Get the end iterator inline iterator_type end() const { return polygon_traits::end_points(*t); } - + /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits::size(*t); } - + /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits::winding(*t); @@ -1718,24 +1716,24 @@ namespace boost { namespace polygon{ inline iterator_holes_type begin_holes() const { return polygon_with_holes_traits::begin_holes(*t); } - + /// Get the end iterator inline iterator_holes_type end_holes() const { return polygon_with_holes_traits::end_holes(*t); } - + /// Get the number of sides of the polygon inline std::size_t size_holes() const { return polygon_with_holes_traits::size_holes(*t); } - + }; template struct geometry_concept > { typedef polygon_45_with_holes_concept type; }; - + template struct view_of { const T* t; @@ -1770,28 +1768,28 @@ namespace boost { namespace polygon{ inline bool operator!=(const iterator_holes_type& that) const { return (internal_itr != that.internal_itr); } - inline value_type operator*() const { + inline value_type operator*() const { return view_as(*internal_itr); } }; - + /// Get the begin iterator inline compact_iterator_type begin_compact() const { return compact_iterator_type(polygon_traits::begin_points(*t), polygon_traits::end_points(*t)); } - + /// Get the end iterator inline compact_iterator_type end_compact() const { return compact_iterator_type(polygon_traits::end_points(*t), polygon_traits::end_points(*t)); } - + /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits::size(*t); } - + /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits::winding(*t); @@ -1801,17 +1799,17 @@ namespace boost { namespace polygon{ inline iterator_holes_type begin_holes() const { return polygon_with_holes_traits::begin_holes(*t); } - + /// Get the end iterator inline iterator_holes_type end_holes() const { return polygon_with_holes_traits::end_holes(*t); } - + /// Get the number of sides of the polygon inline std::size_t size_holes() const { return polygon_with_holes_traits::size_holes(*t); } - + }; template @@ -1831,17 +1829,17 @@ namespace boost { namespace polygon{ inline iterator_type begin() const { return polygon_traits::begin_points(*t); } - + /// Get the end iterator inline iterator_type end() const { return polygon_traits::end_points(*t); } - + /// Get the number of sides of the polygon inline std::size_t size() const { return polygon_traits::size(*t); } - + /// Get the winding direction of the polygon inline winding_direction winding() const { return polygon_traits::winding(*t); @@ -1856,4 +1854,3 @@ namespace boost { namespace polygon{ } #endif - diff --git a/include/boost/polygon/polygon_with_holes_data.hpp b/include/boost/polygon/polygon_with_holes_data.hpp old mode 100755 new mode 100644 index e5a975b..a1a0e1d --- a/include/boost/polygon/polygon_with_holes_data.hpp +++ b/include/boost/polygon/polygon_with_holes_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -18,7 +18,7 @@ public: typedef T coordinate_type; typedef typename polygon_data::iterator_type iterator_type; typedef typename std::list >::const_iterator iterator_holes_type; - typedef polygon_data hole_type; + typedef polygon_data hole_type; typedef typename coordinate_traits::coordinate_distance area_type; typedef point_data point_type; @@ -55,9 +55,9 @@ public: } // copy constructor (since we have dynamic memory) - inline polygon_with_holes_data(const polygon_with_holes_data& that) : self_(that.self_), + inline polygon_with_holes_data(const polygon_with_holes_data& that) : self_(that.self_), holes_(that.holes_) {} - + // assignment operator (since we have dynamic memory do a deep copy) inline polygon_with_holes_data& operator=(const polygon_with_holes_data& that) { self_ = that.self_; @@ -80,7 +80,7 @@ public: inline std::size_t size() const { return self_.size(); - } + } // get begin iterator, returns a pointer to a const polygon inline const iterator_holes_type begin_holes() const { @@ -98,11 +98,10 @@ public: public: polygon_data self_; - std::list holes_; + std::list holes_; }; - + } } #endif - diff --git a/include/boost/polygon/rectangle_concept.hpp b/include/boost/polygon/rectangle_concept.hpp old mode 100755 new mode 100644 index e302b99..13aee46 --- a/include/boost/polygon/rectangle_concept.hpp +++ b/include/boost/polygon/rectangle_concept.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -25,7 +25,7 @@ namespace boost { namespace polygon{ struct rectangle_concept {}; - + template struct is_rectangle_concept { typedef gtl_no type; }; template <> @@ -62,8 +62,8 @@ namespace boost { namespace polygon{ template struct rectangle_difference_type_by_concept { typedef void type; }; template - struct rectangle_difference_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; + struct rectangle_difference_type_by_concept { + typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; template struct rectangle_difference_type { @@ -74,8 +74,8 @@ namespace boost { namespace polygon{ template struct rectangle_distance_type_by_concept { typedef void type; }; template - struct rectangle_distance_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_distance type; }; + struct rectangle_distance_type_by_concept { + typedef typename coordinate_traits::type>::coordinate_distance type; }; template struct rectangle_distance_type { @@ -83,91 +83,92 @@ namespace boost { namespace polygon{ T, typename is_rectangle_concept::type>::type>::type type; }; + struct y_r_get_interval : gtl_yes {}; + template - typename rectangle_interval_type::type - get(const T& rectangle, orientation_2d orient, - typename enable_if< typename gtl_if::type>::type>::type>::type * = 0 - ) { - return rectangle_traits::get(rectangle, orient); + typename enable_if< typename gtl_and::type>::type>::type, + typename rectangle_interval_type::type>::type + get(const T& rectangle, orientation_2d orient) { + return rectangle_traits::get(rectangle, orient); } struct y_r_h : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, - typename rectangle_traits::interval_type>::type + typename enable_if< typename gtl_and::type>::type>::type, + typename rectangle_interval_type::type>::type horizontal(const T& rectangle) { - return rectangle_traits::get(rectangle, HORIZONTAL); + return rectangle_traits::get(rectangle, HORIZONTAL); } struct y_r_v : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, - typename rectangle_traits::interval_type>::type + typename enable_if< typename gtl_and::type>::type>::type, + typename rectangle_interval_type::type>::type vertical(const T& rectangle) { - return rectangle_traits::get(rectangle, VERTICAL); + return rectangle_traits::get(rectangle, VERTICAL); } struct y_r_set : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - void>::type + void>::type set(T& rectangle, const T2& interval) { - rectangle_mutable_traits::set(rectangle, orient, interval); + rectangle_mutable_traits::set(rectangle, orient, interval); } struct y_r_set2 : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - void>::type + void>::type set(T& rectangle, orientation_2d orient, const T2& interval) { - rectangle_mutable_traits::set(rectangle, orient, interval); + rectangle_mutable_traits::set(rectangle, orient, interval); } struct y_r_h2 : gtl_yes {}; template - typename enable_if< typename gtl_and_3::type>::type, + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - void>::type + void>::type horizontal(T& rectangle, const T2& interval) { - rectangle_mutable_traits::set(rectangle, HORIZONTAL, interval); + rectangle_mutable_traits::set(rectangle, HORIZONTAL, interval); } struct y_r_v2 : gtl_yes {}; template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, void>::type + typename enable_if< + typename gtl_and_3::type>::type, + typename is_interval_concept::type>::type>::type, void>::type vertical(T& rectangle, const T2& interval) { - rectangle_mutable_traits::set(rectangle, VERTICAL, interval); + rectangle_mutable_traits::set(rectangle, VERTICAL, interval); } struct y_r_construct : gtl_yes {}; template typename enable_if< typename gtl_and::type>::type>::type, - T>::type + T>::type construct(const T2& interval_horizontal, const T3& interval_vertical) { return rectangle_mutable_traits::construct(interval_horizontal, interval_vertical); } - + struct y_r_construct2 : gtl_yes {}; template typename enable_if< typename gtl_and::type>::type>::type, - T>::type + T>::type construct(coord_type xl, coord_type yl, coord_type xh, coord_type yh) { - return rectangle_mutable_traits::construct(interval_data(xl, xh), - interval_data(yl, yh)); + return rectangle_mutable_traits::construct(interval_data(xl, xh), + interval_data(yl, yh)); } - + struct y_r_cconstruct : gtl_yes {}; template @@ -179,11 +180,11 @@ namespace boost { namespace polygon{ copy_construct(const T2& rectangle) { return construct (get(rectangle, HORIZONTAL), get(rectangle, VERTICAL)); } - + struct y_r_assign : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3< y_r_assign, typename is_mutable_rectangle_concept::type>::type, typename is_rectangle_concept::type>::type>::type, @@ -193,36 +194,36 @@ namespace boost { namespace polygon{ set(lvalue, VERTICAL, get(rvalue, VERTICAL)); return lvalue; } - + struct y_r_equiv : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3< y_r_equiv, typename is_rectangle_concept::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type equivalence(const T& rect1, const T2& rect2) { return equivalence(get(rect1, HORIZONTAL), get(rect2, HORIZONTAL)) && equivalence(get(rect1, VERTICAL), get(rect2, VERTICAL)); } - + struct y_r_get : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_coordinate_type::type>::type get(const rectangle_type& rectangle, orientation_2d orient, direction_1d dir) { - return get(rectangle_traits::get(rectangle, orient), dir); + return get(rectangle_traits::get(rectangle, orient), dir); } - + struct y_r_set3 : gtl_yes {}; template - typename enable_if::type>::type>::type, void>::type - set(rectangle_type& rectangle, orientation_2d orient, direction_1d dir, - typename rectangle_traits::coordinate_type value) { - typename rectangle_traits::interval_type ivl = get(rectangle, orient); + typename enable_if::type>::type>::type, void>::type + set(rectangle_type& rectangle, orientation_2d orient, direction_1d dir, + typename rectangle_coordinate_type::type value) { + typename rectangle_interval_type::type ivl = get(rectangle, orient); set(ivl, dir, value); set(rectangle, orient, ivl); } @@ -230,7 +231,7 @@ namespace boost { namespace polygon{ struct y_r_xl : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_coordinate_type::type>::type xl(const rectangle_type& rectangle) { return get(rectangle, HORIZONTAL, LOW); @@ -239,15 +240,15 @@ namespace boost { namespace polygon{ struct y_r_xl2 : gtl_yes {}; template - typename enable_if::type>::type>::type, void>::type - xl(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + typename enable_if::type>::type>::type, void>::type + xl(rectangle_type& rectangle, typename rectangle_coordinate_type::type value) { return set(rectangle, HORIZONTAL, LOW, value); } struct y_r_xh : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_coordinate_type::type>::type xh(const rectangle_type& rectangle) { return get(rectangle, HORIZONTAL, HIGH); @@ -256,32 +257,32 @@ namespace boost { namespace polygon{ struct y_r_xh2 : gtl_yes {}; template - typename enable_if::type>::type>::type, void>::type - xh(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + typename enable_if::type>::type>::type, void>::type + xh(rectangle_type& rectangle, typename rectangle_coordinate_type::type value) { return set(rectangle, HORIZONTAL, HIGH, value); } struct y_r_yl : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_coordinate_type::type>::type yl(const rectangle_type& rectangle) { return get(rectangle, VERTICAL, LOW); } - + struct y_r_yl2 : gtl_yes {}; template - typename enable_if::type>::type>::type, void>::type - yl(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + typename enable_if::type>::type>::type, void>::type + yl(rectangle_type& rectangle, typename rectangle_coordinate_type::type value) { return set(rectangle, VERTICAL, LOW, value); } struct y_r_yh : gtl_yes {}; template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_coordinate_type::type>::type yh(const rectangle_type& rectangle) { return get(rectangle, VERTICAL, HIGH); @@ -290,45 +291,45 @@ namespace boost { namespace polygon{ struct y_r_yh2 : gtl_yes {}; template - typename enable_if::type>::type>::type, void>::type - yh(rectangle_type& rectangle, typename rectangle_traits::coordinate_type value) { + typename enable_if::type>::type>::type, void>::type + yh(rectangle_type& rectangle, typename rectangle_coordinate_type::type value) { return set(rectangle, VERTICAL, HIGH, value); } struct y_r_ll : gtl_yes {}; template - typename enable_if::type>::type>::type>::type, - point_data::coordinate_type> >::type + typename enable_if::type>::type>::type, + point_data::type> >::type ll(const rectangle_type& rectangle) { - return point_data::coordinate_type> (xl(rectangle), yl(rectangle)); + return point_data::type> (xl(rectangle), yl(rectangle)); } struct y_r_lr : gtl_yes {}; template - typename enable_if::type>::type>::type>::type, - point_data::coordinate_type> >::type + typename enable_if::type>::type>::type, + point_data::type> >::type lr(const rectangle_type& rectangle) { - return point_data::coordinate_type> (xh(rectangle), yl(rectangle)); + return point_data::type> (xh(rectangle), yl(rectangle)); } struct y_r_ul : gtl_yes {}; template - typename enable_if::type>::type>::type>::type, - point_data::coordinate_type> >::type + typename enable_if::type>::type>::type, + point_data::type> >::type ul(const rectangle_type& rectangle) { - return point_data::coordinate_type> (xl(rectangle), yh(rectangle)); + return point_data::type> (xl(rectangle), yh(rectangle)); } struct y_r_ur : gtl_yes {}; template - typename enable_if::type>::type>::type>::type, - point_data::coordinate_type> >::type + typename enable_if::type>::type>::type, + point_data::type> >::type ur(const rectangle_type& rectangle) { - return point_data::coordinate_type> (xh(rectangle), yh(rectangle)); + return point_data::type> (xh(rectangle), yh(rectangle)); } struct y_r_contains : gtl_yes {}; @@ -336,8 +337,8 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type - contains(const rectangle_type& rectangle, const rectangle_type_2 rectangle_contained, + bool>::type + contains(const rectangle_type& rectangle, const rectangle_type_2 rectangle_contained, bool consider_touch = true) { return contains(horizontal(rectangle), horizontal(rectangle_contained), consider_touch) && contains(vertical(rectangle), vertical(rectangle_contained), consider_touch); @@ -347,8 +348,8 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, - typename is_point_concept::type>::type>::type, bool>::type - contains(const rectangle_type& rectangle, const point_type point_contained, + typename is_point_concept::type>::type>::type, bool>::type + contains(const rectangle_type& rectangle, const point_type point_contained, bool consider_touch = true) { return contains(horizontal(rectangle), x(point_contained), consider_touch) && contains(vertical(rectangle), y(point_contained), consider_touch); @@ -359,30 +360,31 @@ namespace boost { namespace polygon{ // set all four coordinates based upon two points template typename enable_if< typename gtl_and_4< y_r_set_points, - typename is_mutable_rectangle_concept::type>::type, - typename is_point_concept::type>::type, - typename is_point_concept::type>::type>::type, + typename is_mutable_rectangle_concept::type>::type, + typename is_point_concept::type>::type, + typename is_point_concept::type>::type>::type, rectangle_type>::type & set_points(rectangle_type& rectangle, const point_type_1& p1, const point_type_2& p2) { - typedef typename rectangle_traits::coordinate_type Unit; + typedef typename rectangle_coordinate_type::type Unit; Unit x1(x(p1)); Unit x2(x(p2)); Unit y1(y(p1)); Unit y2(y(p2)); - horizontal(rectangle, construct::interval_type>(x1, x2)); - vertical(rectangle, construct::interval_type>(y1, y2)); + horizontal(rectangle, construct::type>(x1, x2)); + vertical(rectangle, construct::type>(y1, y2)); return rectangle; } - + + struct y_r_move : gtl_yes {}; + // move rectangle by delta in orient template - rectangle_type& - move(rectangle_type& rectangle, orientation_2d orient, - typename coordinate_traits::coordinate_type>::coordinate_difference delta, - typename enable_if::type>::type>::type * = 0 - ) { - typename rectangle_traits::interval_type ivl = get(rectangle, orient); + typename enable_if< typename gtl_and::type>::type>::type, + rectangle_type>::type & + move(rectangle_type& rectangle, orientation_2d orient, + typename coordinate_traits::type>::coordinate_difference delta) { + typename rectangle_interval_type::type ivl = get(rectangle, orient); move(ivl, delta); set(rectangle, orient, ivl); return rectangle; @@ -394,18 +396,18 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3< y_r_convolve, - typename is_mutable_rectangle_concept::type>::type, - typename is_rectangle_concept::type>::type>::type, + typename is_mutable_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type>::type, rectangle_type_1>::type & convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, convolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, convolve(ivl, vertical(convolution_rectangle))); return rectangle; } - + struct y_r_deconvolve : gtl_yes {}; // deconvolve this with b @@ -415,13 +417,13 @@ namespace boost { namespace polygon{ typename is_rectangle_concept::type>::type>::type, rectangle_type_1>::type & deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, deconvolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, deconvolve(ivl, vertical(convolution_rectangle))); return rectangle; } - + struct y_r_reconvolve : gtl_yes {}; // reflectedConvolve this with b @@ -431,13 +433,13 @@ namespace boost { namespace polygon{ typename is_rectangle_concept::type>::type>::type, rectangle_type_1>::type & reflected_convolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, reflected_convolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, reflected_convolve(ivl, vertical(convolution_rectangle))); return rectangle; } - + struct y_r_redeconvolve : gtl_yes {}; // reflectedDeconvolve this with b @@ -448,13 +450,13 @@ namespace boost { namespace polygon{ typename is_rectangle_concept::type>::type>::type, rectangle_type_1>::type & reflected_deconvolve(rectangle_type_1& rectangle, const rectangle_type_2& convolution_rectangle) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, reflected_deconvolve(ivl, horizontal(convolution_rectangle))); ivl = vertical(rectangle); vertical(rectangle, reflected_deconvolve(ivl, vertical(convolution_rectangle))); return rectangle; } - + struct y_r_convolve2 : gtl_yes {}; // convolve with point @@ -463,7 +465,7 @@ namespace boost { namespace polygon{ typename is_point_concept::type>::type>::type, rectangle_type>::type & convolve(rectangle_type& rectangle, const point_type& convolution_point) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, convolve(ivl, x(convolution_point))); ivl = vertical(rectangle); vertical(rectangle, convolve(ivl, y(convolution_point))); @@ -474,11 +476,11 @@ namespace boost { namespace polygon{ // deconvolve with point template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_point_concept::type>::type>::type, rectangle_type>::type & deconvolve(rectangle_type& rectangle, const point_type& convolution_point) { - typename rectangle_traits::interval_type ivl = horizontal(rectangle); + typename rectangle_interval_type::type ivl = horizontal(rectangle); horizontal(rectangle, deconvolve(ivl, x(convolution_point))); ivl = vertical(rectangle); vertical(rectangle, deconvolve(ivl, y(convolution_point))); @@ -489,7 +491,7 @@ namespace boost { namespace polygon{ // get the magnitude of the interval range depending on orient template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_difference_type::type>::type delta(const rectangle_type& rectangle, orientation_2d orient) { return delta(get(rectangle, orient)); @@ -500,9 +502,9 @@ namespace boost { namespace polygon{ // get the area of the rectangle template typename enable_if< typename gtl_and::type>::type>::type, - typename coordinate_traits::coordinate_type>::manhattan_area_type>::type + typename coordinate_traits::type>::manhattan_area_type>::type area(const rectangle_type& rectangle) { - typedef typename coordinate_traits::coordinate_type>::manhattan_area_type area_type; + typedef typename coordinate_traits::type>::manhattan_area_type area_type; return (area_type)delta(rectangle, HORIZONTAL) * (area_type)delta(rectangle, VERTICAL); } @@ -510,8 +512,8 @@ namespace boost { namespace polygon{ // returns the orientation of the longest side template - typename enable_if::type>::type>::type, - orientation_2d>::type + typename enable_if::type>::type>::type, + orientation_2d>::type guess_orientation(const rectangle_type& rectangle) { return delta(rectangle, HORIZONTAL) >= delta(rectangle, VERTICAL) ? HORIZONTAL : VERTICAL; @@ -521,18 +523,19 @@ namespace boost { namespace polygon{ // get the half perimeter of the rectangle template - typename enable_if< typename gtl_and::type>::type>::type>::type, + typename enable_if< typename gtl_and::type>::type>::type, typename rectangle_difference_type::type>::type half_perimeter(const rectangle_type& rectangle) { return delta(rectangle, HORIZONTAL) + delta(rectangle, VERTICAL); } - + + struct y_r_perimeter : gtl_yes {}; + // get the perimeter of the rectangle template - typename rectangle_difference_type::type - perimeter(const rectangle_type& rectangle, - typename enable_if< typename is_rectangle_concept::type>::type>::type * = 0 - ) { + typename enable_if< typename gtl_and::type>::type>::type, + typename rectangle_difference_type::type>::type + perimeter(const rectangle_type& rectangle) { return 2 * half_perimeter(rectangle); } @@ -543,10 +546,10 @@ namespace boost { namespace polygon{ // [in] considerTouch If true, return true even if b touches the boundary // [ret] . true if `t` intersects b template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type intersects(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { return intersects(horizontal(rectangle), horizontal(b), consider_touch) && intersects(vertical(rectangle), vertical(b), consider_touch); @@ -559,44 +562,44 @@ namespace boost { namespace polygon{ // [in] considerTouch If true, return true even if p is on the foundary // [ret] . true if `t` contains p template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type boundaries_intersect(const rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { return (intersects(rectangle, b, consider_touch) && !(contains(rectangle, b, !consider_touch)) && !(contains(b, rectangle, !consider_touch))); } - + struct y_r_b_abuts : gtl_yes {}; // check if b is touching 'this' on the end specified by dir template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, direction_2d dir) { - return + return abuts(get(rectangle, orientation_2d(dir)), get(b, orientation_2d(dir)), direction_1d(dir)) && intersects(get(rectangle, orientation_2d(dir).get_perpendicular()), get(b, orientation_2d(dir).get_perpendicular()), true); } - + struct y_r_b_abuts2 : gtl_yes {}; // check if they are touching in the given orientation template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b, orientation_2d orient) { - return + return abuts(get(rectangle, orient), get(b, orient)) && intersects(get(rectangle, orient.get_perpendicular()), get(b, orient.get_perpendicular()), true); @@ -608,7 +611,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type abuts(const rectangle_type_1& rectangle, const rectangle_type_2& b) { return abuts(rectangle, b, HORIZONTAL) || abuts(rectangle, b, VERTICAL); } @@ -617,13 +620,13 @@ namespace boost { namespace polygon{ // intersect rectangle with interval on orient template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_interval_concept::type>::type>::type, - bool>::type + bool>::type intersect(rectangle_type& rectangle, const interval_type& b, orientation_2d orient, bool consider_touch = true) { - typename rectangle_traits::interval_type ivl = get(rectangle, orient); + typename rectangle_interval_type::type ivl = get(rectangle, orient); if(intersect(ivl, b, consider_touch)) { set(rectangle, orient, ivl); return true; @@ -637,7 +640,7 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type intersect(rectangle_type_1& rectangle, const rectangle_type_2& b, bool consider_touch = true) { if(intersects(rectangle, b)) { intersect(rectangle, horizontal(b), HORIZONTAL, consider_touch); @@ -656,7 +659,7 @@ namespace boost { namespace polygon{ typename is_rectangle_concept::type>::type>::type, rectangle_type_1>::type & generalized_intersect(rectangle_type_1& rectangle, const rectangle_type_2& b) { - typename rectangle_traits::interval_type ivl = get(rectangle, HORIZONTAL); + typename rectangle_interval_type::type ivl = get(rectangle, HORIZONTAL); generalized_intersect(ivl, horizontal(b)); horizontal(rectangle, ivl); ivl = vertical(rectangle); @@ -669,11 +672,11 @@ namespace boost { namespace polygon{ // bloat the interval specified by orient by bloating template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & - bloat(rectangle_type& rectangle, orientation_2d orient, - typename rectangle_traits::coordinate_type bloating) { - typename rectangle_traits::interval_type ivl = get(rectangle, orient); + bloat(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_coordinate_type::type bloating) { + typename rectangle_interval_type::type ivl = get(rectangle, orient); bloat(ivl, bloating); set(rectangle, orient, ivl); return rectangle; @@ -683,10 +686,10 @@ namespace boost { namespace polygon{ // bloat the Rectangle by bloating template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & bloat(rectangle_type& rectangle, - typename rectangle_traits::coordinate_type bloating) { + typename rectangle_coordinate_type::type bloating) { bloat(rectangle, HORIZONTAL, bloating); return bloat(rectangle, VERTICAL, bloating); } @@ -695,11 +698,11 @@ namespace boost { namespace polygon{ // bloat the interval cooresponding to orient by bloating in dir direction template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & bloat(rectangle_type& rectangle, direction_2d dir, - typename rectangle_traits::coordinate_type bloating) { - typename rectangle_traits::interval_type ivl = get(rectangle, orientation_2d(dir)); + typename rectangle_coordinate_type::type bloating) { + typename rectangle_interval_type::type ivl = get(rectangle, orientation_2d(dir)); bloat(ivl, direction_1d(dir), bloating); set(rectangle, orientation_2d(dir), ivl); return rectangle; @@ -709,10 +712,10 @@ namespace boost { namespace polygon{ // shrink the interval specified by orient by bloating template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & - shrink(rectangle_type& rectangle, orientation_2d orient, - typename rectangle_traits::coordinate_type shrinking) { + shrink(rectangle_type& rectangle, orientation_2d orient, + typename rectangle_coordinate_type::type shrinking) { return bloat(rectangle, orient, -shrinking); } @@ -720,10 +723,10 @@ namespace boost { namespace polygon{ // shrink the Rectangle by bloating template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & - shrink(rectangle_type& rectangle, - typename rectangle_traits::coordinate_type shrinking) { + shrink(rectangle_type& rectangle, + typename rectangle_coordinate_type::type shrinking) { return bloat(rectangle, -shrinking); } @@ -731,10 +734,10 @@ namespace boost { namespace polygon{ // shrink the interval cooresponding to orient by bloating in dir direction template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & shrink(rectangle_type& rectangle, direction_2d dir, - typename rectangle_traits::coordinate_type shrinking) { + typename rectangle_coordinate_type::type shrinking) { return bloat(rectangle, dir, -shrinking); } @@ -742,13 +745,13 @@ namespace boost { namespace polygon{ // encompass interval on orient template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - encompass(rectangle_type& rectangle, const interval_type& b, - orientation_2d orient) { - typename rectangle_traits::interval_type ivl = get(rectangle, orient); + typename enable_if::type>::type, + typename is_interval_concept::type>::type>::type, + bool>::type + encompass(rectangle_type& rectangle, const interval_type& b, orientation_2d orient) { + typename rectangle_interval_type::type ivl = get(rectangle, orient); if(encompass(ivl, b)) { set(rectangle, orient, ivl); return true; @@ -760,12 +763,12 @@ namespace boost { namespace polygon{ // enlarge rectangle to encompass the Rectangle b template - bool - encompass(rectangle_type_1& rectangle, const rectangle_type_2& b, - typename enable_if< typename gtl_and_3::type>::type, - typename is_rectangle_concept::type>::type >::type>::type * = 0 - ) { + typename enable_if< typename gtl_and_3< + y_r_encompass2, + typename is_mutable_rectangle_concept::type>::type, + typename is_rectangle_concept::type>::type >::type, + bool>::type + encompass(rectangle_type_1& rectangle, const rectangle_type_2& b) { //note that operator | is intentional because both should be called regardless return encompass(rectangle, horizontal(b), HORIZONTAL) | encompass(rectangle, vertical(b), VERTICAL); @@ -775,16 +778,13 @@ namespace boost { namespace polygon{ // enlarge rectangle to encompass the point b template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_point_concept::type>::type>::type, - bool>::type - encompass(rectangle_type_1& rectangle, const point_type& b, - typename enable_if< - typename gtl_and< typename is_mutable_rectangle_concept::type>::type, - typename is_point_concept::type>::type>::type>::type * = 0 - ) { - typename rectangle_traits::interval_type hivl, vivl; + typename enable_if::type>::type, + typename is_point_concept::type>::type>::type, + bool>::type + encompass(rectangle_type_1& rectangle, const point_type& b) { + typename rectangle_interval_type::type hivl, vivl; hivl = horizontal(rectangle); vivl = vertical(rectangle); //note that operator | is intentional because both should be called regardless @@ -803,7 +803,7 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type center(point_type& center_point, const rectangle_type& rectangle) { center_point = construct(center(horizontal(rectangle)), center(vertical(rectangle))); @@ -816,9 +816,9 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type get_corner(point_type& corner_point, const rectangle_type& rectangle, direction_2d direction_facing, direction_1d direction_turning) { - typedef typename rectangle_traits::coordinate_type Unit; + typedef typename rectangle_coordinate_type::type Unit; Unit u1 = get(rectangle, direction_facing); Unit u2 = get(rectangle, direction_facing.turn(direction_turning)); if(orientation_2d(direction_facing).to_int()) std::swap(u1, u2); @@ -829,8 +829,8 @@ namespace boost { namespace polygon{ struct y_r_get_half : gtl_yes {}; template - typename enable_if::type>::type>::type, - rectangle_type>::type + typename enable_if::type>::type>::type, + rectangle_type>::type get_half(const rectangle_type& rectangle, direction_2d dir) { rectangle_type retval(rectangle); set(retval, orientation_2d(dir), get_half(get(rectangle, orientation_2d(dir)), direction_1d(dir))); @@ -842,10 +842,10 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type join_with(rectangle_type_1& rectangle, const rectangle_type_2& b) { - typedef typename rectangle_traits::interval_type Interval1; - typedef typename rectangle_traits::interval_type Interval2; + typedef typename rectangle_interval_type::type Interval1; + typedef typename rectangle_interval_type::type Interval2; Interval1 hi1 = get(rectangle, HORIZONTAL); Interval1 vi1 = get(rectangle, VERTICAL); Interval2 hi2 = get(b, HORIZONTAL), vi2 = get(b, VERTICAL); @@ -860,7 +860,7 @@ namespace boost { namespace polygon{ } return false; } - + struct y_r_eda2 : gtl_yes {}; template @@ -875,8 +875,8 @@ namespace boost { namespace polygon{ struct y_r_eda : gtl_yes {}; template - typename enable_if< - typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, typename rectangle_difference_type::type>::type @@ -887,12 +887,12 @@ namespace boost { namespace polygon{ struct y_r_sed : gtl_yes {}; template - typename enable_if< typename gtl_if< typename gtl_and_3::type>::type, - typename is_point_concept::type>::type>::type>::type, + typename is_point_concept::type>::type>::type, typename rectangle_difference_type::type>::type square_euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { - typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + typename coordinate_traits::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return (xdist * xdist) + (ydist * ydist); @@ -901,12 +901,12 @@ namespace boost { namespace polygon{ struct y_r_sed2 : gtl_yes {}; template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_rectangle_concept< typename geometry_concept::type>::type>::type, + typename enable_if< + typename gtl_and_3::type>::type, + typename is_rectangle_concept< typename geometry_concept::type>::type>::type, typename rectangle_difference_type::type>::type square_euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { - typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + typename coordinate_traits::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return (xdist * xdist) + (ydist * ydist); @@ -917,10 +917,9 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_point_concept::type>::type>::type, - typename rectangle_distance_type::type>::type + typename rectangle_distance_type::type>::type euclidean_distance(rectangle_type& lvalue, const point_type& rvalue) { - return sqrt((double) - (square_euclidean_distance(lvalue, rvalue))); + return std::sqrt((double)(square_euclidean_distance(lvalue, rvalue))); } struct y_r_edist2 : gtl_yes {}; @@ -928,21 +927,21 @@ namespace boost { namespace polygon{ template typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, - typename rectangle_distance_type::type>::type + typename rectangle_distance_type::type>::type euclidean_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { double val = (int)square_euclidean_distance(lvalue, rvalue); - return sqrt(val); + return std::sqrt(val); } struct y_r_mdist : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_point_concept::type>::type>::type, typename rectangle_difference_type::type>::type manhattan_distance(rectangle_type& lvalue, const point_type& rvalue) { - typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + typename coordinate_traits::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return xdist + ydist; @@ -951,12 +950,12 @@ namespace boost { namespace polygon{ struct y_r_mdist2 : gtl_yes {}; template - typename enable_if< + typename enable_if< typename gtl_and_3::type>::type, typename is_rectangle_concept::type>::type>::type, typename rectangle_difference_type::type>::type manhattan_distance(const rectangle_type& lvalue, const rectangle_type_2& rvalue) { - typename coordinate_traits::coordinate_type>::coordinate_difference xdist, ydist; + typename coordinate_traits::type>::coordinate_difference xdist, ydist; xdist = euclidean_distance(lvalue, rvalue, HORIZONTAL); ydist = euclidean_distance(lvalue, rvalue, VERTICAL); return xdist + ydist; @@ -965,22 +964,22 @@ namespace boost { namespace polygon{ struct y_r_scale_up : gtl_yes {}; template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & - scale_up(rectangle_type& rectangle, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + scale_up(rectangle_type& rectangle, + typename coordinate_traits::type>::unsigned_area_type factor) { horizontal(rectangle, scale_up(horizontal(rectangle), factor)); vertical(rectangle, scale_up(vertical(rectangle), factor)); return rectangle; } - + struct y_r_scale_down : gtl_yes {}; - + template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & - scale_down(rectangle_type& rectangle, - typename coordinate_traits::coordinate_type>::unsigned_area_type factor) { + scale_down(rectangle_type& rectangle, + typename coordinate_traits::type>::unsigned_area_type factor) { horizontal(rectangle, scale_down(horizontal(rectangle), factor)); vertical(rectangle, scale_down(vertical(rectangle), factor)); return rectangle; @@ -989,31 +988,31 @@ namespace boost { namespace polygon{ struct y_r_scale : gtl_yes {}; template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & scale(rectangle_type& rectangle, const scaling_type& scaling) { - point_data::coordinate_type> llp(xl(rectangle), yl(rectangle)); - point_data::coordinate_type> urp(xl(rectangle), yl(rectangle)); + point_data::type> llp(xl(rectangle), yl(rectangle)); + point_data::type> urp(xl(rectangle), yl(rectangle)); scale(llp, scaling); scale(urp, scaling); set_points(rectangle, llp, urp); return rectangle; } - + struct y_r_transform : gtl_yes {}; - + template - typename enable_if::type>::type>::type, + typename enable_if::type>::type>::type, rectangle_type>::type & transform(rectangle_type& rectangle, const transformation_type& transformation) { - point_data::coordinate_type> llp(xl(rectangle), yl(rectangle)); - point_data::coordinate_type> urp(xh(rectangle), yh(rectangle)); + point_data::type> llp(xl(rectangle), yl(rectangle)); + point_data::type> urp(xh(rectangle), yh(rectangle)); transform(llp, transformation); transform(urp, transformation); set_points(rectangle, llp, urp); return rectangle; } - + template class less_rectangle_concept { private: @@ -1023,12 +1022,12 @@ namespace boost { namespace polygon{ typename enable_if< typename gtl_and< typename is_rectangle_concept::type>::type, typename is_rectangle_concept::type>::type>::type, - bool>::type + bool>::type operator () (const rectangle_type_1& a, const rectangle_type_2& b) const { - typedef typename rectangle_traits::coordinate_type Unit; - Unit vl1 = get(get(a, orient_), LOW); - Unit vl2 = get(get(b, orient_), LOW); + typedef typename rectangle_coordinate_type::type Unit; + Unit vl1 = get(get(a, orient_), LOW); + Unit vl2 = get(get(b, orient_), LOW); if(vl1 > vl2) return false; if(vl1 == vl2) { orientation_2d perp = orient_.get_perpendicular(); @@ -1036,8 +1035,8 @@ namespace boost { namespace polygon{ Unit hl2 = get(get(b, perp), LOW); if(hl1 > hl2) return false; if(hl1 == hl2) { - Unit vh1 = get(get(a, orient_), HIGH); - Unit vh2 = get(get(b, orient_), HIGH); + Unit vh1 = get(get(a, orient_), HIGH); + Unit vh2 = get(get(b, orient_), HIGH); if(vh1 > vh2) return false; if(vh1 == vh2) { Unit hh1 = get(get(a, perp), HIGH); @@ -1048,7 +1047,7 @@ namespace boost { namespace polygon{ } return true; } - + }; template @@ -1063,7 +1062,7 @@ namespace boost { namespace polygon{ assign(*this, rvalue); return *this; } - + template template bool rectangle_data::operator==(const T2& rvalue) const { @@ -1077,4 +1076,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/rectangle_data.hpp b/include/boost/polygon/rectangle_data.hpp old mode 100755 new mode 100644 index 2bcbb46..5a1f99e --- a/include/boost/polygon/rectangle_data.hpp +++ b/include/boost/polygon/rectangle_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -52,13 +52,12 @@ public: return ranges_[orientation_2d(dir).to_int()].set(direction_1d(dir), value); } template - inline void set(orientation_2d orient, const interval_type_1& interval); + inline void set(orientation_2d orient, const interval_type_1& interval); private: - interval_data ranges_[2]; + interval_data ranges_[2]; }; } } #endif - diff --git a/include/boost/polygon/rectangle_traits.hpp b/include/boost/polygon/rectangle_traits.hpp old mode 100755 new mode 100644 index fe777a4..25d934b --- a/include/boost/polygon/rectangle_traits.hpp +++ b/include/boost/polygon/rectangle_traits.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -35,4 +35,3 @@ namespace boost { namespace polygon{ } } #endif - diff --git a/include/boost/polygon/segment_concept.hpp b/include/boost/polygon/segment_concept.hpp new file mode 100644 index 0000000..8d8aaa1 --- /dev/null +++ b/include/boost/polygon/segment_concept.hpp @@ -0,0 +1,754 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_SEGMENT_CONCEPT_HPP +#define BOOST_POLYGON_SEGMENT_CONCEPT_HPP + +#include "isotropy.hpp" +#include "segment_data.hpp" +#include "segment_traits.hpp" +#include "rectangle_concept.hpp" + +namespace boost { +namespace polygon { +struct segment_concept {}; + +template +struct is_segment_concept { + typedef gtl_no type; +}; + +template <> +struct is_segment_concept { + typedef gtl_yes type; +}; + +template +struct is_mutable_segment_concept { + typedef gtl_no type; +}; + +template <> +struct is_mutable_segment_concept { + typedef gtl_yes type; +}; + +template +struct segment_distance_type_by_concept { + typedef void type; +}; + +template +struct segment_distance_type_by_concept { + typedef typename coordinate_traits< + typename segment_traits::coordinate_type + >::coordinate_distance type; +}; + +template +struct segment_distance_type { + typedef typename segment_distance_type_by_concept< + Segment, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type type; +}; + +template +struct segment_point_type_by_concept { + typedef void type; +}; + +template +struct segment_point_type_by_concept { + typedef typename segment_traits::point_type type; +}; + +template +struct segment_point_type { + typedef typename segment_point_type_by_concept< + Segment, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type type; +}; + +template +struct segment_coordinate_type_by_concept { + typedef void type; +}; + +template +struct segment_coordinate_type_by_concept { + typedef typename segment_traits::coordinate_type type; +}; + +template +struct segment_coordinate_type { + typedef typename segment_coordinate_type_by_concept< + Segment, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type type; +}; + +struct y_s_get : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_get, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_point_type::type +>::type +get(const Segment& segment, direction_1d dir) { + return segment_traits::get(segment, dir); +} + +struct y_s_set : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_set, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type +set(Segment& segment, direction_1d dir, const Point& point) { + segment_mutable_traits::set(segment, dir, point); +} + +struct y_s_construct : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_4< + y_s_construct, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type +construct(const Point1& low, const Point2& high) { + return segment_mutable_traits::construct(low, high); +} + +struct y_s_copy_construct : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_copy_construct, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment1 +>::type +copy_construct(const Segment2& segment) { + return construct(get(segment, LOW), get(segment, HIGH)); +} + +struct y_s_assign : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_assign, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment1 +>::type & +assign(Segment1& segment1, const Segment2& segment2) { + return segment1 = copy_construct(segment2); +} + +struct y_s_equivalence : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_equivalence, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +equivalence(const Segment1& segment1, const Segment2& segment2) { + return get(segment1, LOW) == get(segment2, LOW) && + get(segment1, HIGH) == get(segment2, HIGH); +} + +struct y_s_low : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_low, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_point_type::type +>::type +low(const Segment& segment) { + return get(segment, LOW); +} + +struct y_s_high : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_high, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_point_type::type +>::type +high(const Segment& segment) { + return get(segment, HIGH); +} + +struct y_s_center : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_center, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_point_type::type +>::type +center(const Segment& segment) { + return construct::type>( + (x(high(segment)) + x(low(segment)))/2, + (y(high(segment)) + y(low(segment)))/2); +} + +struct y_s_low2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_low2, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type +low(Segment& segment, const Point& point) { + set(segment, LOW, point); +} + +struct y_s_high2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_high2, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type +high(Segment& segment, const Point& point) { + set(segment, HIGH, point); +} + +struct y_s_orientation1 : gtl_yes {}; + +// -1 for CW, 0 for collinear and 1 for CCW. +template +typename enable_if< + typename gtl_and_3< + y_s_orientation1, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + int +>::type +orientation(const Segment1& segment1, const Segment2& segment2) { + typedef typename coordinate_traits< + typename segment_traits::coordinate_type + >::manhattan_area_type int_x2; + typedef typename coordinate_traits< + typename segment_traits::coordinate_type + >::unsigned_area_type uint_x2; + int_x2 a1 = (int_x2)x(high(segment1)) - (int_x2)x(low(segment1)); + int_x2 b1 = (int_x2)y(high(segment1)) - (int_x2)y(low(segment1)); + int_x2 a2 = (int_x2)x(high(segment2)) - (int_x2)x(low(segment2)); + int_x2 b2 = (int_x2)y(high(segment2)) - (int_x2)y(low(segment2)); + + int sign1 = 0; + int sign2 = 0; + if (a1 && b2) + sign1 = ((a1 > 0) ^ (b2 > 0)) ? -1 : 1; + if (a2 && b1) + sign2 = ((a2 > 0) ^ (b1 > 0)) ? -1 : 1; + + if (sign1 != sign2) + return (sign1 < sign2) ? -1 : 1; + uint_x2 a3 = (uint_x2)(a1 < 0 ? -a1 : a1) * (uint_x2)(b2 < 0 ? -b2 : b2); + uint_x2 b3 = (uint_x2)(b1 < 0 ? -b1 : b1) * (uint_x2)(a2 < 0 ? -a2 : a2); + if (a3 == b3) + return 0; + return ((a3 < b3) ^ (sign1 == 1)) ? 1 : -1; +} + +struct y_s_orientation2 : gtl_yes {}; + +// -1 for right, 0 for collinear and 1 for left. +template +typename enable_if< + typename gtl_and_3< + y_s_orientation2, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + int +>::type +orientation(const Segment& segment, const Point& point) { + Segment segment2 = construct(high(segment), point); + return orientation(segment, segment2); +} + +struct y_s_contains : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_contains, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +contains(const Segment& segment, + const Point& point, + bool consider_touch = true ) { + if (orientation(segment, point)) + return false; + rectangle_data::type> rect; + set_points(rect, low(segment), high(segment)); + if (!contains(rect, point, true)) + return false; + if (!consider_touch && + (equivalence(low(segment), point) || + equivalence(high(segment), point))) + return false; + return true; +} + +struct y_s_contains2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_contains2, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +contains(const Segment1& segment1, + const Segment2& segment2, + bool consider_touch = true) { + return contains(segment1, get(segment2, LOW), consider_touch) && + contains(segment1, get(segment2, HIGH), consider_touch); +} + +struct y_s_length : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_length, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_distance_type::type +>::type +length(const Segment& segment) { + return euclidean_distance(low(segment), high(segment)); +} + +struct y_s_scale_up : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_scale_up, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +scale_up(Segment& segment, + typename coordinate_traits< + typename segment_coordinate_type::type + >::unsigned_area_type factor) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, scale_up(l, factor)); + high(segment, scale_up(h, factor)); + return segment; +} + +struct y_s_scale_down : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_scale_down, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +scale_down(Segment& segment, + typename coordinate_traits< + typename segment_coordinate_type::type + >::unsigned_area_type factor) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, scale_down(l, factor)); + high(segment, scale_down(h, factor)); + return segment; +} + +struct y_s_scale : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_scale, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +scale(Segment& segment, const Scale& sc) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, scale(l, sc)); + high(segment, scale(h, sc)); + return segment; +} + +struct y_s_transform : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_transform, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +transform(Segment& segment, const Transform& tr) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, transform(l, tr)); + high(segment, transform(h, tr)); + return segment; +} + +struct y_s_move : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_s_move, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +move(Segment& segment, orientation_2d orient, + typename segment_coordinate_type::type displacement) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, move(l, orient, displacement)); + high(segment, move(h, orient, displacement)); + return segment; +} + +struct y_s_convolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_convolve, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +convolve(Segment& segment, const Point& point) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, convolve(l, point)); + high(segment, convolve(h, point)); + return segment; +} + +struct y_s_deconvolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_deconvolve, + typename is_mutable_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + Segment +>::type & +deconvolve(Segment& segment, const Point& point) { + typename segment_point_type::type l = low(segment); + typename segment_point_type::type h = high(segment); + low(segment, deconvolve(l, point)); + high(segment, deconvolve(h, point)); + return segment; +} + +struct y_s_abuts1 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_abuts1, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +abuts(const Segment1& segment1, const Segment2& segment2, direction_1d dir) { + return dir.to_int() ? equivalence(low(segment2) , high(segment1)) : + equivalence(low(segment1) , high(segment2)); +} + +struct y_s_abuts2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_abuts2, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +abuts(const Segment1& segment1, const Segment2& segment2) { + return abuts(segment1, segment2, HIGH) || abuts(segment1, segment2, LOW); +} + +struct y_s_e_intersects : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_e_intersects, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type +intersects(const Segment1& segment1, const Segment2& segment2, + bool consider_touch = true) { + rectangle_data::type> rect1, rect2; + set_points(rect1, low(segment1), high(segment1)); + set_points(rect2, low(segment2), high(segment2)); + // Check if axis-parallel rectangles containing segments intersect. + if (!intersects(rect1, rect2, true)) + return false; + int or1_1 = orientation(segment1, low(segment2)); + int or1_2 = orientation(segment1, high(segment2)); + if (or1_1 * or1_2 > 0) + return false; + int or2_1 = orientation(segment2, low(segment1)); + int or2_2 = orientation(segment2, high(segment1)); + if (or2_1 * or2_2 > 0) + return false; + if (consider_touch || (or1_1 && or1_2) || (or2_1 && or2_2)) + return true; + if (or1_1 || or1_2) + return false; + return intersects(vertical(rect1), vertical(rect2), false) || + intersects(horizontal(rect1), horizontal(rect2), false); +} + +struct y_s_e_dist : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_e_dist, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_distance_type::type +>::type +euclidean_distance(const Segment& segment, const Point& point) { + typedef typename segment_distance_type::type Unit; + Unit x1 = x(low(segment)); + Unit y1 = y(low(segment)); + Unit x2 = x(high(segment)); + Unit y2 = y(high(segment)); + Unit X = x(point); + Unit Y = y(point); + Unit A = X - x1; + Unit B = Y - y1; + Unit C = x2 - x1; + Unit D = y2 - y1; + Unit param = (A * C + B * D); + Unit length_sq = C * C + D * D; + if (param > length_sq) { + return euclidean_distance(high(segment), point); + } else if (param < 0.0) { + return euclidean_distance(low(segment), point); + } + if (length_sq == 0.0) + return 0.0; + Unit denom = std::sqrt(length_sq); + Unit result = (A * D - C * B) / denom; + return (result < 0.0) ? -result : result; +} + +struct y_s_e_dist2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_s_e_dist2, + typename is_segment_concept< + typename geometry_concept::type + >::type, + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + typename segment_distance_type::type +>::type +euclidean_distance(const Segment1& segment1, const Segment2& segment2) { + if (intersects(segment1, segment2)) + return 0.0; + typename segment_distance_type::type + result1 = euclidean_distance(segment1, low(segment2)), + result2 = euclidean_distance(segment1, high(segment2)), + result3 = euclidean_distance(segment2, low(segment1)), + result4 = euclidean_distance(segment2, high(segment1)); + if (result2 < result1) + result1 = result2; + if (result4 < result3) + result3 = result4; + return (result1 < result3) ? result1 : result3; +} + +template +template +segment_data& segment_data::operator=(const Segment& rvalue) { + assign(*this, rvalue); + return *this; +} + +template +struct geometry_concept > { + typedef segment_concept type; +}; +} +} +#endif diff --git a/include/boost/polygon/segment_data.hpp b/include/boost/polygon/segment_data.hpp new file mode 100644 index 0000000..7d1fa05 --- /dev/null +++ b/include/boost/polygon/segment_data.hpp @@ -0,0 +1,108 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_SEGMENT_DATA_HPP +#define BOOST_POLYGON_SEGMENT_DATA_HPP + +#include "isotropy.hpp" + +namespace boost { +namespace polygon { +template +class segment_data { + public: + typedef T coordinate_type; + typedef point_data point_type; + + inline segment_data() +#ifndef BOOST_POLYGON_MSVC + :points_() +#endif + {} + + inline segment_data(const point_type& low, const point_type& high) +#ifndef BOOST_POLYGON_MSVC + :points_() +#endif + { + points_[LOW] = low; + points_[HIGH] = high; + } + + inline segment_data(const segment_data& that) +#ifndef BOOST_POLYGON_MSVC + :points_() +#endif + { + (*this) = that; + } + + inline segment_data& operator=(const segment_data& that) { + points_[0] = that.points_[0]; + points_[1] = that.points_[1]; + return *this; + } + + template + inline segment_data& operator=(const Segment& that); + + inline point_type get(direction_1d dir) const { + return points_[dir.to_int()]; + } + + inline void set(direction_1d dir, const point_type& point) { + points_[dir.to_int()] = point; + } + + inline point_type low() const { return points_[0]; } + + inline segment_data& low(const point_type& point) { + points_[0] = point; + return *this; + } + + inline point_type high() const {return points_[1]; } + + inline segment_data& high(const point_type& point) { + points_[1] = point; + return *this; + } + + inline bool operator==(const segment_data& that) const { + return low() == that.low() && high() == that.high(); + } + + inline bool operator!=(const segment_data& that) const { + return low() != that.low() || high() != that.high(); + } + + inline bool operator<(const segment_data& that) const { + if (points_[0] < that.points_[0]) + return true; + if (points_[0] > that.points_[0]) + return false; + return points_[1] < that.points_[1]; + } + + inline bool operator<=(const segment_data& that) const { + return !(that < *this); + } + + inline bool operator>(const segment_data& that) const { + return that < *this; + } + + inline bool operator>=(const segment_data& that) const { + return !((*this) < that); + } + + private: + point_type points_[2]; +}; +} +} +#endif diff --git a/include/boost/polygon/segment_traits.hpp b/include/boost/polygon/segment_traits.hpp new file mode 100644 index 0000000..956c0d2 --- /dev/null +++ b/include/boost/polygon/segment_traits.hpp @@ -0,0 +1,38 @@ +/* + Copyright 2008 Intel Corporation + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ +#ifndef BOOST_POLYGON_SEGMENT_TRAITS_HPP +#define BOOST_POLYGON_SEGMENT_TRAITS_HPP +namespace boost { +namespace polygon { + template + struct segment_traits { + typedef typename Segment::coordinate_type coordinate_type; + typedef typename Segment::point_type point_type; + + static inline point_type get(const Segment& segment, direction_1d dir) { + return segment.get(dir); + } + }; + + template + struct segment_mutable_traits { + typedef typename segment_traits::point_type point_type; + + static inline void set( + Segment& segment, direction_1d dir, const point_type& point) { + segment.set(dir, point); + } + + static inline Segment construct( + const point_type& low, const point_type& high) { + return Segment(low, high); + } + }; +} +} +#endif diff --git a/include/boost/polygon/segment_utils.hpp b/include/boost/polygon/segment_utils.hpp new file mode 100644 index 0000000..97d8885 --- /dev/null +++ b/include/boost/polygon/segment_utils.hpp @@ -0,0 +1,159 @@ +/* + Copyright 2012 Lucanus Simonson + + Use, modification and distribution are subject to the Boost Software License, + Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +*/ + +#ifndef BOOST_POLYGON_SEGMENT_UTILS_HPP +#define BOOST_POLYGON_SEGMENT_UTILS_HPP + +#include +#include +#include + +namespace boost { +namespace polygon { + +template +typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type + >::type, + void +>::type +intersect_segments( + std::vector >& result, + SegmentIterator first, SegmentIterator last) { + typedef typename segment_traits::coordinate_type Unit; + typedef typename scanline_base::Point Point; + typedef typename scanline_base::half_edge half_edge; + typedef int segment_id; + std::vector > half_edges; + std::vector > half_edges_out; + segment_id id_in = 0; + half_edges.reserve(std::distance(first, last)); + for (; first != last; ++first) { + Point l, h; + assign(l, low(*first)); + assign(h, high(*first)); + half_edges.push_back(std::make_pair(half_edge(l, h), id_in++)); + } + half_edges_out.reserve(half_edges.size()); + // Apparently no need to pre-sort data when calling validate_scan. + if (half_edges.size() != 0) { + line_intersection::validate_scan( + half_edges_out, half_edges.begin(), half_edges.end()); + } + + result.reserve(result.size() + half_edges_out.size()); + for (std::size_t i = 0; i < half_edges_out.size(); ++i) { + std::size_t id = (std::size_t)(half_edges_out[i].second); + Point l = half_edges_out[i].first.first; + Point h = half_edges_out[i].first.second; + result.push_back(std::make_pair(id, construct(l, h))); + } +} + +template +typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename SegmentContainer::value_type + >::type + >::type + >::type + >::type, + void +>::type +intersect_segments( + SegmentContainer& result, + SegmentIterator first, + SegmentIterator last) { + typedef typename SegmentContainer::value_type segment_type; + typedef typename segment_traits::coordinate_type Unit; + typedef typename scanline_base::Point Point; + typedef typename scanline_base::half_edge half_edge; + typedef int segment_id; + std::vector > half_edges; + std::vector > half_edges_out; + segment_id id_in = 0; + half_edges.reserve(std::distance(first, last)); + for (; first != last; ++first) { + Point l, h; + assign(l, low(*first)); + assign(h, high(*first)); + half_edges.push_back(std::make_pair(half_edge(l, h), id_in++)); + } + half_edges_out.reserve(half_edges.size()); + // Apparently no need to pre-sort data when calling validate_scan. + if (half_edges.size() != 0) { + line_intersection::validate_scan( + half_edges_out, half_edges.begin(), half_edges.end()); + } + + result.reserve(result.size() + half_edges_out.size()); + for (std::size_t i = 0; i < half_edges_out.size(); ++i) { + Point l = half_edges_out[i].first.first; + Point h = half_edges_out[i].first.second; + result.push_back(construct(l, h)); + } +} + +template +typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_rectangle_concept< + typename geometry_concept::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type + >::type, + bool +>::type +envelope_segments( + Rectangle& rect, + SegmentIterator first, + SegmentIterator last) { + for (SegmentIterator it = first; it != last; ++it) { + if (it == first) { + set_points(rect, low(*it), high(*it)); + } else { + encompass(rect, low(*it)); + encompass(rect, high(*it)); + } + } + return first != last; +} +} // polygon +} // boost + +#endif // BOOST_POLYGON_SEGMENT_UTILS_HPP diff --git a/include/boost/polygon/transform.hpp b/include/boost/polygon/transform.hpp old mode 100755 new mode 100644 index 16b566d..ed75ddd --- a/include/boost/polygon/transform.hpp +++ b/include/boost/polygon/transform.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -22,7 +22,7 @@ namespace boost { namespace polygon{ // positive proximal direction to. // The zero position bit (LSB) indicates whether the horizontal axis flips // when transformed. -// The 1st postion bit indicates whether the vertical axis flips when +// The 1st postion bit indicates whether the vertical axis flips when // transformed. // The 2nd position bit indicates whether the horizontal and vertical axis // swap positions when transformed. @@ -39,110 +39,110 @@ namespace boost { namespace polygon{ // meaning of the 2nd position bit to mean that the horizontal and vertical are // swapped in their new positions. // Enum Values: -// 000000 EAST NORTH UP -// 000001 WEST NORTH UP -// 000010 EAST SOUTH UP -// 000011 WEST SOUTH UP -// 000100 NORTH EAST UP -// 000101 SOUTH EAST UP -// 000110 NORTH WEST UP -// 000111 SOUTH WEST UP -// 001000 EAST NORTH DOWN -// 001001 WEST NORTH DOWN -// 001010 EAST SOUTH DOWN -// 001011 WEST SOUTH DOWN -// 001100 NORTH EAST DOWN -// 001101 SOUTH EAST DOWN -// 001110 NORTH WEST DOWN -// 001111 SOUTH WEST DOWN -// 010000 UP NORTH EAST -// 010001 DOWN NORTH EAST -// 010010 UP SOUTH EAST -// 010011 DOWN SOUTH EAST -// 010100 NORTH UP EAST -// 010101 SOUTH UP EAST -// 010110 NORTH DOWN EAST -// 010111 SOUTH DOWN EAST -// 011000 UP NORTH WEST -// 011001 DOWN NORTH WEST -// 011010 UP SOUTH WEST -// 011011 DOWN SOUTH WEST -// 011100 NORTH UP WEST -// 011101 SOUTH UP WEST -// 011110 NORTH DOWN WEST -// 011111 SOUTH DOWN WEST -// 100000 EAST UP NORTH -// 100001 WEST UP NORTH -// 100010 EAST DOWN NORTH -// 100011 WEST DOWN NORTH -// 100100 UP EAST NORTH -// 100101 DOWN EAST NORTH -// 100110 UP WEST NORTH -// 100111 DOWN WEST NORTH -// 101000 EAST UP SOUTH -// 101001 WEST UP SOUTH -// 101010 EAST DOWN SOUTH -// 101011 WEST DOWN SOUTH -// 101100 UP EAST SOUTH -// 101101 DOWN EAST SOUTH -// 101110 UP WEST SOUTH -// 101111 DOWN WEST SOUTH +// 000000 EAST NORTH UP +// 000001 WEST NORTH UP +// 000010 EAST SOUTH UP +// 000011 WEST SOUTH UP +// 000100 NORTH EAST UP +// 000101 SOUTH EAST UP +// 000110 NORTH WEST UP +// 000111 SOUTH WEST UP +// 001000 EAST NORTH DOWN +// 001001 WEST NORTH DOWN +// 001010 EAST SOUTH DOWN +// 001011 WEST SOUTH DOWN +// 001100 NORTH EAST DOWN +// 001101 SOUTH EAST DOWN +// 001110 NORTH WEST DOWN +// 001111 SOUTH WEST DOWN +// 010000 UP NORTH EAST +// 010001 DOWN NORTH EAST +// 010010 UP SOUTH EAST +// 010011 DOWN SOUTH EAST +// 010100 NORTH UP EAST +// 010101 SOUTH UP EAST +// 010110 NORTH DOWN EAST +// 010111 SOUTH DOWN EAST +// 011000 UP NORTH WEST +// 011001 DOWN NORTH WEST +// 011010 UP SOUTH WEST +// 011011 DOWN SOUTH WEST +// 011100 NORTH UP WEST +// 011101 SOUTH UP WEST +// 011110 NORTH DOWN WEST +// 011111 SOUTH DOWN WEST +// 100000 EAST UP NORTH +// 100001 WEST UP NORTH +// 100010 EAST DOWN NORTH +// 100011 WEST DOWN NORTH +// 100100 UP EAST NORTH +// 100101 DOWN EAST NORTH +// 100110 UP WEST NORTH +// 100111 DOWN WEST NORTH +// 101000 EAST UP SOUTH +// 101001 WEST UP SOUTH +// 101010 EAST DOWN SOUTH +// 101011 WEST DOWN SOUTH +// 101100 UP EAST SOUTH +// 101101 DOWN EAST SOUTH +// 101110 UP WEST SOUTH +// 101111 DOWN WEST SOUTH class axis_transformation { public: // Enum Names and values // NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, - // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, // WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, // ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, - // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, + // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, // NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, - // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, - // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, - // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, + // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, + // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, + // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, // END_2D_TRANSFORM = 7, - // END = 8, EAST_NORTH_DOWN = 8, - // WND = 9, WEST_NORTH_DOWN = 9, - // ESD = 10, EAST_SOUTH_DOWN = 10, - // WSD = 11, WEST_SOUTH_DOWN = 11, - // NED = 12, NORTH_EAST_DOWN = 12, - // SED = 13, SOUTH_EAST_DOWN = 13, - // NWD = 14, NORTH_WEST_DOWN = 14, - // SWD = 15, SOUTH_WEST_DOWN = 15, - // UNE = 16, UP_NORTH_EAST = 16, - // DNE = 17, DOWN_NORTH_EAST = 17, - // USE = 18, UP_SOUTH_EAST = 18, - // DSE = 19, DOWN_SOUTH_EAST = 19, - // NUE = 20, NORTH_UP_EAST = 20, - // SUE = 21, SOUTH_UP_EAST = 21, - // NDE = 22, NORTH_DOWN_EAST = 22, - // SDE = 23, SOUTH_DOWN_EAST = 23, - // UNW = 24, UP_NORTH_WEST = 24, - // DNW = 25, DOWN_NORTH_WEST = 25, - // USW = 26, UP_SOUTH_WEST = 26, - // DSW = 27, DOWN_SOUTH_WEST = 27, - // NUW = 28, NORTH_UP_WEST = 28, - // SUW = 29, SOUTH_UP_WEST = 29, - // NDW = 30, NORTH_DOWN_WEST = 30, - // SDW = 31, SOUTH_DOWN_WEST = 31, - // EUN = 32, EAST_UP_NORTH = 32, - // WUN = 33, WEST_UP_NORTH = 33, - // EDN = 34, EAST_DOWN_NORTH = 34, - // WDN = 35, WEST_DOWN_NORTH = 35, - // UEN = 36, UP_EAST_NORTH = 36, - // DEN = 37, DOWN_EAST_NORTH = 37, - // UWN = 38, UP_WEST_NORTH = 38, - // DWN = 39, DOWN_WEST_NORTH = 39, - // EUS = 40, EAST_UP_SOUTH = 40, - // WUS = 41, WEST_UP_SOUTH = 41, - // EDS = 42, EAST_DOWN_SOUTH = 42, - // WDS = 43, WEST_DOWN_SOUTH = 43, - // UES = 44, UP_EAST_SOUTH = 44, - // DES = 45, DOWN_EAST_SOUTH = 45, - // UWS = 46, UP_WEST_SOUTH = 46, - // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + // END = 8, EAST_NORTH_DOWN = 8, + // WND = 9, WEST_NORTH_DOWN = 9, + // ESD = 10, EAST_SOUTH_DOWN = 10, + // WSD = 11, WEST_SOUTH_DOWN = 11, + // NED = 12, NORTH_EAST_DOWN = 12, + // SED = 13, SOUTH_EAST_DOWN = 13, + // NWD = 14, NORTH_WEST_DOWN = 14, + // SWD = 15, SOUTH_WEST_DOWN = 15, + // UNE = 16, UP_NORTH_EAST = 16, + // DNE = 17, DOWN_NORTH_EAST = 17, + // USE = 18, UP_SOUTH_EAST = 18, + // DSE = 19, DOWN_SOUTH_EAST = 19, + // NUE = 20, NORTH_UP_EAST = 20, + // SUE = 21, SOUTH_UP_EAST = 21, + // NDE = 22, NORTH_DOWN_EAST = 22, + // SDE = 23, SOUTH_DOWN_EAST = 23, + // UNW = 24, UP_NORTH_WEST = 24, + // DNW = 25, DOWN_NORTH_WEST = 25, + // USW = 26, UP_SOUTH_WEST = 26, + // DSW = 27, DOWN_SOUTH_WEST = 27, + // NUW = 28, NORTH_UP_WEST = 28, + // SUW = 29, SOUTH_UP_WEST = 29, + // NDW = 30, NORTH_DOWN_WEST = 30, + // SDW = 31, SOUTH_DOWN_WEST = 31, + // EUN = 32, EAST_UP_NORTH = 32, + // WUN = 33, WEST_UP_NORTH = 33, + // EDN = 34, EAST_DOWN_NORTH = 34, + // WDN = 35, WEST_DOWN_NORTH = 35, + // UEN = 36, UP_EAST_NORTH = 36, + // DEN = 37, DOWN_EAST_NORTH = 37, + // UWN = 38, UP_WEST_NORTH = 38, + // DWN = 39, DOWN_WEST_NORTH = 39, + // EUS = 40, EAST_UP_SOUTH = 40, + // WUS = 41, WEST_UP_SOUTH = 41, + // EDS = 42, EAST_DOWN_SOUTH = 42, + // WDS = 43, WEST_DOWN_SOUTH = 43, + // UES = 44, UP_EAST_SOUTH = 44, + // DES = 45, DOWN_EAST_SOUTH = 45, + // UWS = 46, UP_WEST_SOUTH = 46, + // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 enum ATR { NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, - ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, + ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, @@ -151,47 +151,47 @@ public: NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_2D_TRANSFORM = 7, END = 8, EAST_NORTH_DOWN = 8, FLIP_Z = 8, - WND = 9, WEST_NORTH_DOWN = 9, - ESD = 10, EAST_SOUTH_DOWN = 10, - WSD = 11, WEST_SOUTH_DOWN = 11, - NED = 12, NORTH_EAST_DOWN = 12, - SED = 13, SOUTH_EAST_DOWN = 13, - NWD = 14, NORTH_WEST_DOWN = 14, - SWD = 15, SOUTH_WEST_DOWN = 15, - UNE = 16, UP_NORTH_EAST = 16, - DNE = 17, DOWN_NORTH_EAST = 17, - USE = 18, UP_SOUTH_EAST = 18, - DSE = 19, DOWN_SOUTH_EAST = 19, - NUE = 20, NORTH_UP_EAST = 20, - SUE = 21, SOUTH_UP_EAST = 21, - NDE = 22, NORTH_DOWN_EAST = 22, - SDE = 23, SOUTH_DOWN_EAST = 23, - UNW = 24, UP_NORTH_WEST = 24, - DNW = 25, DOWN_NORTH_WEST = 25, - USW = 26, UP_SOUTH_WEST = 26, - DSW = 27, DOWN_SOUTH_WEST = 27, - NUW = 28, NORTH_UP_WEST = 28, - SUW = 29, SOUTH_UP_WEST = 29, - NDW = 30, NORTH_DOWN_WEST = 30, - SDW = 31, SOUTH_DOWN_WEST = 31, - EUN = 32, EAST_UP_NORTH = 32, - WUN = 33, WEST_UP_NORTH = 33, - EDN = 34, EAST_DOWN_NORTH = 34, - WDN = 35, WEST_DOWN_NORTH = 35, - UEN = 36, UP_EAST_NORTH = 36, - DEN = 37, DOWN_EAST_NORTH = 37, - UWN = 38, UP_WEST_NORTH = 38, - DWN = 39, DOWN_WEST_NORTH = 39, - EUS = 40, EAST_UP_SOUTH = 40, - WUS = 41, WEST_UP_SOUTH = 41, - EDS = 42, EAST_DOWN_SOUTH = 42, - WDS = 43, WEST_DOWN_SOUTH = 43, - UES = 44, UP_EAST_SOUTH = 44, - DES = 45, DOWN_EAST_SOUTH = 45, - UWS = 46, UP_WEST_SOUTH = 46, - DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + WND = 9, WEST_NORTH_DOWN = 9, + ESD = 10, EAST_SOUTH_DOWN = 10, + WSD = 11, WEST_SOUTH_DOWN = 11, + NED = 12, NORTH_EAST_DOWN = 12, + SED = 13, SOUTH_EAST_DOWN = 13, + NWD = 14, NORTH_WEST_DOWN = 14, + SWD = 15, SOUTH_WEST_DOWN = 15, + UNE = 16, UP_NORTH_EAST = 16, + DNE = 17, DOWN_NORTH_EAST = 17, + USE = 18, UP_SOUTH_EAST = 18, + DSE = 19, DOWN_SOUTH_EAST = 19, + NUE = 20, NORTH_UP_EAST = 20, + SUE = 21, SOUTH_UP_EAST = 21, + NDE = 22, NORTH_DOWN_EAST = 22, + SDE = 23, SOUTH_DOWN_EAST = 23, + UNW = 24, UP_NORTH_WEST = 24, + DNW = 25, DOWN_NORTH_WEST = 25, + USW = 26, UP_SOUTH_WEST = 26, + DSW = 27, DOWN_SOUTH_WEST = 27, + NUW = 28, NORTH_UP_WEST = 28, + SUW = 29, SOUTH_UP_WEST = 29, + NDW = 30, NORTH_DOWN_WEST = 30, + SDW = 31, SOUTH_DOWN_WEST = 31, + EUN = 32, EAST_UP_NORTH = 32, + WUN = 33, WEST_UP_NORTH = 33, + EDN = 34, EAST_DOWN_NORTH = 34, + WDN = 35, WEST_DOWN_NORTH = 35, + UEN = 36, UP_EAST_NORTH = 36, + DEN = 37, DOWN_EAST_NORTH = 37, + UWN = 38, UP_WEST_NORTH = 38, + DWN = 39, DOWN_WEST_NORTH = 39, + EUS = 40, EAST_UP_SOUTH = 40, + WUS = 41, WEST_UP_SOUTH = 41, + EDS = 42, EAST_DOWN_SOUTH = 42, + WDS = 43, WEST_DOWN_SOUTH = 43, + UES = 44, UP_EAST_SOUTH = 44, + DES = 45, DOWN_EAST_SOUTH = 45, + UWS = 46, UP_WEST_SOUTH = 46, + DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 }; - + // Individual axis enum values indicate which axis an implicit individual // axis will be mapped to. // The value of the enum paired with an axis provides the information @@ -224,10 +224,10 @@ public: explicit axis_transformation(const orientation_2d& orient); explicit axis_transformation(const direction_2d& dir); - // assignment operator + // assignment operator axis_transformation& operator=(const axis_transformation& a); - // assignment operator + // assignment operator axis_transformation& operator=(const ATR& atr); // equivalence operator @@ -239,7 +239,7 @@ public: // ordering bool operator<(const axis_transformation& a) const; - // concatenation operator + // concatenation operator axis_transformation operator+(const axis_transformation& a) const; // concatenate this with that @@ -255,7 +255,7 @@ public: direction_2d& vertical_dir) const { bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; + bool bit0 = (atr_ & 1) != 0; vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1)); horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); } @@ -270,19 +270,19 @@ public: bool bit3 = (atr_ & 8) != 0; bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; + bool bit0 = (atr_ & 1) != 0; proximal_dir = direction_3d((direction_2d_enum)((((int)(!bit4 & !bit5)) << 2) + - ((int)(bit5) << 1) + + ((int)(bit5) << 1) + !bit3)); vertical_dir = direction_3d((direction_2d_enum)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ - ((int)(!bit5 & !bit2) << 1) + + ((int)(!bit5 & !bit2) << 1) + !bit1)); - horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) | + horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) | (bit4 & !bit2))) << 2) + - ((int)(bit2 & !bit5) << 1) + + ((int)(bit2 & !bit5) << 1) + !bit0)); } - + // combine_axis_arrays concatenates this_array and that_array overwriting // the result into this_array static void combine_axis_arrays (INDIVIDUAL_AXIS this_array[], @@ -293,7 +293,7 @@ public: void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]); // behavior is deterministic but undefined in the case where illegal - // combinations of directions are passed in. + // combinations of directions are passed in. axis_transformation& set_directions(const direction_2d& horizontal_dir, const direction_2d& vertical_dir); // behavior is deterministic but undefined in the case where illegal @@ -341,31 +341,31 @@ class anisotropic_scale_factor { public: inline anisotropic_scale_factor() #ifndef BOOST_POLYGON_MSVC - : scale_() + : scale_() #endif { scale_[0] = 1; scale_[1] = 1; scale_[2] = 1; - } + } inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale) #ifndef BOOST_POLYGON_MSVC - : scale_() -#endif + : scale_() +#endif { scale_[0] = xscale; scale_[1] = yscale; scale_[2] = 1; - } - inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale) + } + inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale) #ifndef BOOST_POLYGON_MSVC - : scale_() -#endif + : scale_() +#endif { scale_[0] = xscale; scale_[1] = yscale; scale_[2] = zscale; - } + } // get a component of the anisotropic_scale_factor by orientation scale_factor_type get(orientation_3d orient) const; @@ -400,7 +400,7 @@ public: void scale(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; // invert this scale factor to give the reverse scale factor - anisotropic_scale_factor& invert(); + anisotropic_scale_factor& invert(); private: scale_factor_type scale_[3]; @@ -428,16 +428,16 @@ public: transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt); transformation(const transformation& tr); - // equivalence operator + // equivalence operator bool operator==(const transformation& tr) const; - // inequivalence operator + // inequivalence operator bool operator!=(const transformation& tr) const; // ordering bool operator<(const transformation& tr) const; - // concatenation operator + // concatenation operator transformation operator+(const transformation& tr) const; // concatenate this with that @@ -465,7 +465,7 @@ public: // invert this transformation transformation& invert(); - + // get the inverse of this transformation transformation inverse() const; @@ -498,4 +498,3 @@ private: } #include "detail/transform_detail.hpp" #endif - diff --git a/include/boost/polygon/voronoi.hpp b/include/boost/polygon/voronoi.hpp new file mode 100644 index 0000000..fb7de49 --- /dev/null +++ b/include/boost/polygon/voronoi.hpp @@ -0,0 +1,155 @@ +// Boost.Polygon library voronoi.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_VORONOI +#define BOOST_POLYGON_VORONOI + +#include "isotropy.hpp" +#include "point_concept.hpp" +#include "segment_concept.hpp" + +#include "voronoi_builder.hpp" +#include "voronoi_diagram.hpp" + +// Public methods to compute Voronoi diagram. +// Coordinates of the points and of the endpoints of the segments should belong +// to the 32-bit signed integer range [-2^31, 2^31-1]. To use wider input +// coordinate range voronoi_builder configuration via coordinate type traits is +// is required. +// Complexity - O(N*logN), memory usage - O(N), N - number of input objects. +namespace boost { +namespace polygon { + +template +typename enable_if< + typename gtl_if< + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + std::size_t +>::type +insert(const Point& point, VB* vb) { + return vb->insert_point(x(point), y(point)); +} + +template +typename enable_if< + typename gtl_if< + typename is_point_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + void +>::type +insert(PointIterator first, const PointIterator last, VB* vb) { + for (PointIterator it = first; it != last; ++it) { + insert(*it, vb); + } +} + +template +typename enable_if< + typename gtl_if< + typename is_segment_concept< + typename geometry_concept::type + >::type + >::type, + std::size_t +>::type +insert(const Segment& segment, VB* vb) { + return vb->insert_segment( + x(low(segment)), y(low(segment)), + x(high(segment)), y(high(segment))); +} + +template +typename enable_if< + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + void +>::type +insert(SegmentIterator first, SegmentIterator last, VB* vb) { + for (SegmentIterator it = first; it != last; ++it) { + insert(*it, vb); + } +} + +template +typename enable_if< + typename gtl_if< + typename is_point_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + void +>::type +construct_voronoi(PointIterator first, PointIterator last, VD* vd) { + default_voronoi_builder builder; + insert(first, last, &builder); + builder.construct(vd); +} + +template +typename enable_if< + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + void +>::type +construct_voronoi(SegmentIterator first, SegmentIterator last, VD* vd) { + default_voronoi_builder builder; + insert(first, last, &builder); + builder.construct(vd); +} + +template +typename enable_if< + typename gtl_and< + typename gtl_if< + typename is_point_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type, + typename gtl_if< + typename is_segment_concept< + typename geometry_concept< + typename std::iterator_traits::value_type + >::type + >::type + >::type + >::type, + void +>::type +construct_voronoi(PointIterator p_first, PointIterator p_last, + SegmentIterator s_first, SegmentIterator s_last, VD* vd) { + default_voronoi_builder builder; + insert(p_first, p_last, &builder); + insert(s_first, s_last, &builder); + builder.construct(vd); +} +} // polygon +} // boost + +#endif // BOOST_POLYGON_VORONOI diff --git a/include/boost/polygon/voronoi_builder.hpp b/include/boost/polygon/voronoi_builder.hpp new file mode 100644 index 0000000..918b86a --- /dev/null +++ b/include/boost/polygon/voronoi_builder.hpp @@ -0,0 +1,517 @@ +// Boost.Polygon library voronoi_builder.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_VORONOI_BUILDER +#define BOOST_POLYGON_VORONOI_BUILDER + +#include +#include +#include +#include +#include + +#include "detail/voronoi_ctypes.hpp" +#include "detail/voronoi_predicates.hpp" +#include "detail/voronoi_structures.hpp" + +#include "voronoi_geometry_type.hpp" + +namespace boost { +namespace polygon { +// GENERAL INFO: +// The sweepline algorithm implementation to compute Voronoi diagram of +// points and non-intersecting segments (except endpoints). +// Complexity - O(N*logN), memory usage - O(N), where N is the total number +// of input geometries. Input geometries should have integer coordinate type. +// +// IMPLEMENTATION DETAILS: +// Each input point creates one site event. Each input segment creates three +// site events: two for its endpoints and one for the segment itself (this is +// made to simplify output construction). All the site events are constructed +// and sorted at the algorithm initialization step. Priority queue is used to +// dynamically hold circle events. At each step of the algorithm execution the +// leftmost event is retrieved by comparing the current site event and the +// topmost element from the circle event queue. STL map (red-black tree) +// container was chosen to hold state of the beach line. The keys of the map +// correspond to the neighboring sites that form a bisector and values map to +// the corresponding Voronoi edges in the output data structure. +template , + typename VP = detail::voronoi_predicates > +class voronoi_builder { + public: + typedef typename CTT::int_type int_type; + typedef typename CTT::fpt_type fpt_type; + + voronoi_builder() : index_(0) {} + + // Each point creates a single site event. + std::size_t insert_point(const int_type& x, const int_type& y) { + site_events_.push_back(site_event_type(x, y)); + site_events_.back().initial_index(index_); + site_events_.back().source_category(SOURCE_CATEGORY_SINGLE_POINT); + return index_++; + } + + // Each segment creates three site events that correspond to: + // 1) the start point of the segment; + // 2) the end point of the segment; + // 3) the segment itself defined by its start point. + std::size_t insert_segment( + const int_type& x1, const int_type& y1, + const int_type& x2, const int_type& y2) { + // Set up start point site. + point_type p1(x1, y1); + site_events_.push_back(site_event_type(p1)); + site_events_.back().initial_index(index_); + site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_START_POINT); + + // Set up end point site. + point_type p2(x2, y2); + site_events_.push_back(site_event_type(p2)); + site_events_.back().initial_index(index_); + site_events_.back().source_category(SOURCE_CATEGORY_SEGMENT_END_POINT); + + // Set up segment site. + if (point_comparison_(p1, p2)) { + site_events_.push_back(site_event_type(p1, p2)); + site_events_.back().source_category(SOURCE_CATEGORY_INITIAL_SEGMENT); + } else { + site_events_.push_back(site_event_type(p2, p1)); + site_events_.back().source_category(SOURCE_CATEGORY_REVERSE_SEGMENT); + } + site_events_.back().initial_index(index_); + return index_++; + } + + // Run sweepline algorithm and fill output data structure. + template + void construct(OUTPUT* output) { + // Init structures. + output->_reserve(site_events_.size()); + init_sites_queue(); + init_beach_line(output); + + // The algorithm stops when there are no events to process. + event_comparison_predicate event_comparison; + while (!circle_events_.empty() || + !(site_event_iterator_ == site_events_.end())) { + if (circle_events_.empty()) { + process_site_event(output); + } else if (site_event_iterator_ == site_events_.end()) { + process_circle_event(output); + } else { + if (event_comparison(*site_event_iterator_, + circle_events_.top().first)) { + process_site_event(output); + } else { + process_circle_event(output); + } + } + while (!circle_events_.empty() && + !circle_events_.top().first.is_active()) { + circle_events_.pop(); + } + } + beach_line_.clear(); + + // Finish construction. + output->_build(); + } + + void clear() { + index_ = 0; + site_events_.clear(); + } + + private: + typedef detail::point_2d point_type; + typedef detail::site_event site_event_type; + typedef typename std::vector::const_iterator + site_event_iterator_type; + typedef detail::circle_event circle_event_type; + typedef typename VP::template point_comparison_predicate + point_comparison_predicate; + typedef typename VP:: + template event_comparison_predicate + event_comparison_predicate; + typedef typename VP:: + template circle_formation_predicate + circle_formation_predicate_type; + typedef void edge_type; + typedef detail::beach_line_node_key key_type; + typedef detail::beach_line_node_data + value_type; + typedef typename VP::template node_comparison_predicate + node_comparer_type; + typedef std::map< key_type, value_type, node_comparer_type > beach_line_type; + typedef typename beach_line_type::iterator beach_line_iterator; + typedef std::pair event_type; + typedef struct { + bool operator()(const event_type& lhs, const event_type& rhs) const { + return predicate(rhs.first, lhs.first); + } + event_comparison_predicate predicate; + } event_comparison_type; + typedef detail::ordered_queue + circle_event_queue_type; + typedef std::pair end_point_type; + + void init_sites_queue() { + // Sort site events. + std::sort(site_events_.begin(), site_events_.end(), + event_comparison_predicate()); + + // Remove duplicates. + site_events_.erase(std::unique( + site_events_.begin(), site_events_.end()), site_events_.end()); + + // Index sites. + for (std::size_t cur = 0; cur < site_events_.size(); ++cur) { + site_events_[cur].sorted_index(cur); + } + + // Init site iterator. + site_event_iterator_ = site_events_.begin(); + } + + template + void init_beach_line(OUTPUT* output) { + if (site_events_.empty()) + return; + if (site_events_.size() == 1) { + // Handle single site event case. + output->_process_single_site(site_events_[0]); + ++site_event_iterator_; + } else { + int skip = 0; + + while (site_event_iterator_ != site_events_.end() && + VP::is_vertical(site_event_iterator_->point0(), + site_events_.begin()->point0()) && + VP::is_vertical(*site_event_iterator_)) { + ++site_event_iterator_; + ++skip; + } + + if (skip == 1) { + // Init beach line with the first two sites. + init_beach_line_default(output); + } else { + // Init beach line with collinear vertical sites. + init_beach_line_collinear_sites(output); + } + } + } + + // Init beach line with the two first sites. + // The first site is always a point. + template + void init_beach_line_default(OUTPUT* output) { + // Get the first and the second site event. + site_event_iterator_type it_first = site_events_.begin(); + site_event_iterator_type it_second = site_events_.begin(); + ++it_second; + insert_new_arc( + *it_first, *it_first, *it_second, beach_line_.end(), output); + // The second site was already processed. Move the iterator. + ++site_event_iterator_; + } + + // Init beach line with collinear sites. + template + void init_beach_line_collinear_sites(OUTPUT* output) { + site_event_iterator_type it_first = site_events_.begin(); + site_event_iterator_type it_second = site_events_.begin(); + ++it_second; + while (it_second != site_event_iterator_) { + // Create a new beach line node. + key_type new_node(*it_first, *it_second); + + // Update the output. + edge_type* edge = output->_insert_new_edge(*it_first, *it_second).first; + + // Insert a new bisector into the beach line. + beach_line_.insert(beach_line_.end(), + std::pair(new_node, value_type(edge))); + + // Update iterators. + ++it_first; + ++it_second; + } + } + + void deactivate_circle_event(value_type* value) { + if (value->circle_event()) { + value->circle_event()->deactivate(); + value->circle_event(NULL); + } + } + + template + void process_site_event(OUTPUT* output) { + // Get next site event to process. + site_event_type site_event = *site_event_iterator_; + + // Move site iterator. + site_event_iterator_type last = site_event_iterator_ + 1; + + // If a new site is an end point of some segment, + // remove temporary nodes from the beach line data structure. + if (!site_event.is_segment()) { + while (!end_points_.empty() && + end_points_.top().first == site_event.point0()) { + beach_line_iterator b_it = end_points_.top().second; + end_points_.pop(); + beach_line_.erase(b_it); + } + } else { + while (last != site_events_.end() && + last->is_segment() && last->point0() == site_event.point0()) + ++last; + } + + // Find the node in the binary search tree with left arc + // lying above the new site point. + key_type new_key(*site_event_iterator_); + beach_line_iterator right_it = beach_line_.lower_bound(new_key); + + for (; site_event_iterator_ != last; ++site_event_iterator_) { + site_event = *site_event_iterator_; + beach_line_iterator left_it = right_it; + + // Do further processing depending on the above node position. + // For any two neighboring nodes the second site of the first node + // is the same as the first site of the second node. + if (right_it == beach_line_.end()) { + // The above arc corresponds to the second arc of the last node. + // Move the iterator to the last node. + --left_it; + + // Get the second site of the last node + const site_event_type& site_arc = left_it->first.right_site(); + + // Insert new nodes into the beach line. Update the output. + right_it = insert_new_arc( + site_arc, site_arc, site_event, right_it, output); + + // Add a candidate circle to the circle event queue. + // There could be only one new circle event formed by + // a new bisector and the one on the left. + activate_circle_event(left_it->first.left_site(), + left_it->first.right_site(), + site_event, right_it); + } else if (right_it == beach_line_.begin()) { + // The above arc corresponds to the first site of the first node. + const site_event_type& site_arc = right_it->first.left_site(); + + // Insert new nodes into the beach line. Update the output. + left_it = insert_new_arc( + site_arc, site_arc, site_event, right_it, output); + + // If the site event is a segment, update its direction. + if (site_event.is_segment()) { + site_event.inverse(); + } + + // Add a candidate circle to the circle event queue. + // There could be only one new circle event formed by + // a new bisector and the one on the right. + activate_circle_event(site_event, right_it->first.left_site(), + right_it->first.right_site(), right_it); + right_it = left_it; + } else { + // The above arc corresponds neither to the first, + // nor to the last site in the beach line. + const site_event_type& site_arc2 = right_it->first.left_site(); + const site_event_type& site3 = right_it->first.right_site(); + + // Remove the candidate circle from the event queue. + deactivate_circle_event(&right_it->second); + --left_it; + const site_event_type& site_arc1 = left_it->first.right_site(); + const site_event_type& site1 = left_it->first.left_site(); + + // Insert new nodes into the beach line. Update the output. + beach_line_iterator new_node_it = + insert_new_arc(site_arc1, site_arc2, site_event, right_it, output); + + // Add candidate circles to the circle event queue. + // There could be up to two circle events formed by + // a new bisector and the one on the left or right. + activate_circle_event(site1, site_arc1, site_event, new_node_it); + + // If the site event is a segment, update its direction. + if (site_event.is_segment()) { + site_event.inverse(); + } + activate_circle_event(site_event, site_arc2, site3, right_it); + right_it = new_node_it; + } + } + } + + // In general case circle event is made of the three consecutive sites + // that form two bisectors in the beach line data structure. + // Let circle event sites be A, B, C, two bisectors that define + // circle event are (A, B), (B, C). During circle event processing + // we remove (A, B), (B, C) and insert (A, C). As beach line comparison + // works correctly only if one of the nodes is a new one we remove + // (B, C) bisector and change (A, B) bisector to the (A, C). That's + // why we use const_cast there and take all the responsibility that + // map data structure keeps correct ordering. + template + void process_circle_event(OUTPUT* output) { + // Get the topmost circle event. + const event_type& e = circle_events_.top(); + const circle_event_type& circle_event = e.first; + beach_line_iterator it_first = e.second; + beach_line_iterator it_last = it_first; + + // Get the C site. + site_event_type site3 = it_first->first.right_site(); + + // Get the half-edge corresponding to the second bisector - (B, C). + edge_type* bisector2 = it_first->second.edge(); + + // Get the half-edge corresponding to the first bisector - (A, B). + --it_first; + edge_type* bisector1 = it_first->second.edge(); + + // Get the A site. + site_event_type site1 = it_first->first.left_site(); + + if (!site1.is_segment() && site3.is_segment() && + site3.point1(true) == site1.point0()) { + site3.inverse(); + } + + // Change the (A, B) bisector node to the (A, C) bisector node. + const_cast(it_first->first).right_site(site3); + + // Insert the new bisector into the beach line. + it_first->second.edge(output->_insert_new_edge( + site1, site3, circle_event, bisector1, bisector2).first); + + // Remove the (B, C) bisector node from the beach line. + beach_line_.erase(it_last); + it_last = it_first; + + // Pop the topmost circle event from the event queue. + circle_events_.pop(); + + // Check new triplets formed by the neighboring arcs + // to the left for potential circle events. + if (it_first != beach_line_.begin()) { + deactivate_circle_event(&it_first->second); + --it_first; + const site_event_type& site_l1 = it_first->first.left_site(); + activate_circle_event(site_l1, site1, site3, it_last); + } + + // Check the new triplet formed by the neighboring arcs + // to the right for potential circle events. + ++it_last; + if (it_last != beach_line_.end()) { + deactivate_circle_event(&it_last->second); + const site_event_type& site_r1 = it_last->first.right_site(); + activate_circle_event(site1, site3, site_r1, it_last); + } + } + + // Insert new nodes into the beach line. Update the output. + template + beach_line_iterator insert_new_arc( + const site_event_type& site_arc1, const site_event_type &site_arc2, + const site_event_type& site_event, beach_line_iterator position, + OUTPUT* output) { + // Create two new bisectors with opposite directions. + key_type new_left_node(site_arc1, site_event); + key_type new_right_node(site_event, site_arc2); + + // Set correct orientation for the first site of the second node. + if (site_event.is_segment()) { + new_right_node.left_site().inverse(); + } + + // Update the output. + std::pair edges = + output->_insert_new_edge(site_arc2, site_event); + position = beach_line_.insert(position, + typename beach_line_type::value_type( + new_right_node, value_type(edges.second))); + + if (site_event.is_segment()) { + // Update the beach line with temporary bisector, that will + // disappear after processing site event corresponding to the + // second endpoint of the segment site. + key_type new_node(site_event, site_event); + new_node.right_site().inverse(); + position = beach_line_.insert(position, + typename beach_line_type::value_type(new_node, value_type(NULL))); + + // Update the data structure that holds temporary bisectors. + end_points_.push(std::make_pair(site_event.point1(), position)); + } + + position = beach_line_.insert(position, + typename beach_line_type::value_type( + new_left_node, value_type(edges.first))); + + return position; + } + + // Add a new circle event to the event queue. + // bisector_node corresponds to the (site2, site3) bisector. + void activate_circle_event(const site_event_type& site1, + const site_event_type& site2, + const site_event_type& site3, + beach_line_iterator bisector_node) { + circle_event_type c_event; + // Check if the three input sites create a circle event. + if (circle_formation_predicate_(site1, site2, site3, c_event)) { + // Add the new circle event to the circle events queue. + // Update bisector's circle event iterator to point to the + // new circle event in the circle event queue. + event_type& e = circle_events_.push( + std::pair( + c_event, bisector_node)); + bisector_node->second.circle_event(&e.first); + } + } + + private: + point_comparison_predicate point_comparison_; + struct end_point_comparison { + bool operator() (const end_point_type& end1, + const end_point_type& end2) const { + return point_comparison(end2.first, end1.first); + } + point_comparison_predicate point_comparison; + }; + + std::vector site_events_; + site_event_iterator_type site_event_iterator_; + std::priority_queue< end_point_type, std::vector, + end_point_comparison > end_points_; + circle_event_queue_type circle_events_; + beach_line_type beach_line_; + circle_formation_predicate_type circle_formation_predicate_; + std::size_t index_; + + // Disallow copy constructor and operator= + voronoi_builder(const voronoi_builder&); + void operator=(const voronoi_builder&); +}; + +typedef voronoi_builder default_voronoi_builder; +} // polygon +} // boost + +#endif // BOOST_POLYGON_VORONOI_BUILDER diff --git a/include/boost/polygon/voronoi_diagram.hpp b/include/boost/polygon/voronoi_diagram.hpp new file mode 100644 index 0000000..0a56173 --- /dev/null +++ b/include/boost/polygon/voronoi_diagram.hpp @@ -0,0 +1,620 @@ +// Boost.Polygon library voronoi_diagram.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_VORONOI_DIAGRAM +#define BOOST_POLYGON_VORONOI_DIAGRAM + +#include +#include + +#include "detail/voronoi_ctypes.hpp" +#include "detail/voronoi_structures.hpp" + +#include "voronoi_geometry_type.hpp" + +namespace boost { +namespace polygon { + +// Forward declarations. +template +class voronoi_edge; + +// Represents Voronoi cell. +// Data members: +// 1) index of the source within the initial input set +// 2) pointer to the incident edge +// 3) mutable color member +// Cell may contain point or segment site inside. +template +class voronoi_cell { + public: + typedef T coordinate_type; + typedef std::size_t color_type; + typedef voronoi_edge voronoi_edge_type; + typedef std::size_t source_index_type; + typedef SourceCategory source_category_type; + + voronoi_cell(source_index_type source_index, + source_category_type source_category) : + source_index_(source_index), + incident_edge_(NULL), + color_(source_category) {} + + // Returns true if the cell contains point site, false else. + bool contains_point() const { + source_category_type source_category = this->source_category(); + return belongs(source_category, GEOMETRY_CATEGORY_POINT); + } + + // Returns true if the cell contains segment site, false else. + bool contains_segment() const { + source_category_type source_category = this->source_category(); + return belongs(source_category, GEOMETRY_CATEGORY_SEGMENT); + } + + source_index_type source_index() const { + return source_index_; + } + + source_category_type source_category() const { + return static_cast(color_ & SOURCE_CATEGORY_BITMASK); + } + + // Degenerate cells don't have any incident edges. + bool is_degenerate() const { return incident_edge_ == NULL; } + + voronoi_edge_type* incident_edge() { return incident_edge_; } + const voronoi_edge_type* incident_edge() const { return incident_edge_; } + void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; } + + color_type color() const { return color_ >> BITS_SHIFT; } + void color(color_type color) const { + color_ &= BITS_MASK; + color_ |= color << BITS_SHIFT; + } + + private: + // 5 color bits are reserved. + enum Bits { + BITS_SHIFT = 0x5, + BITS_MASK = 0x1F + }; + + source_index_type source_index_; + voronoi_edge_type* incident_edge_; + mutable color_type color_; +}; + +// Represents Voronoi vertex. +// Data members: +// 1) vertex coordinates +// 2) pointer to the incident edge +// 3) mutable color member +template +class voronoi_vertex { + public: + typedef T coordinate_type; + typedef std::size_t color_type; + typedef voronoi_edge voronoi_edge_type; + + voronoi_vertex(const coordinate_type& x, const coordinate_type& y) : + x_(x), + y_(y), + incident_edge_(NULL), + color_(0) {} + + const coordinate_type& x() const { return x_; } + const coordinate_type& y() const { return y_; } + + bool is_degenerate() const { return incident_edge_ == NULL; } + + voronoi_edge_type* incident_edge() { return incident_edge_; } + const voronoi_edge_type* incident_edge() const { return incident_edge_; } + void incident_edge(voronoi_edge_type* e) { incident_edge_ = e; } + + color_type color() const { return color_ >> BITS_SHIFT; } + void color(color_type color) const { + color_ &= BITS_MASK; + color_ |= color << BITS_SHIFT; + } + + private: + // 5 color bits are reserved. + enum Bits { + BITS_SHIFT = 0x5, + BITS_MASK = 0x1F + }; + + coordinate_type x_; + coordinate_type y_; + voronoi_edge_type* incident_edge_; + mutable color_type color_; +}; + +// Half-edge data structure. Represents Voronoi edge. +// Data members: +// 1) pointer to the corresponding cell +// 2) pointer to the vertex that is the starting +// point of the half-edge +// 3) pointer to the twin edge +// 4) pointer to the CCW next edge +// 5) pointer to the CCW prev edge +// 6) mutable color member +template +class voronoi_edge { + public: + typedef T coordinate_type; + typedef voronoi_cell voronoi_cell_type; + typedef voronoi_vertex voronoi_vertex_type; + typedef voronoi_edge voronoi_edge_type; + typedef std::size_t color_type; + + voronoi_edge(bool is_linear, bool is_primary) : + cell_(NULL), + vertex_(NULL), + twin_(NULL), + next_(NULL), + prev_(NULL), + color_(0) { + if (is_linear) + color_ |= BIT_IS_LINEAR; + if (is_primary) + color_ |= BIT_IS_PRIMARY; + } + + voronoi_cell_type* cell() { return cell_; } + const voronoi_cell_type* cell() const { return cell_; } + void cell(voronoi_cell_type* c) { cell_ = c; } + + voronoi_vertex_type* vertex0() { return vertex_; } + const voronoi_vertex_type* vertex0() const { return vertex_; } + void vertex0(voronoi_vertex_type* v) { vertex_ = v; } + + voronoi_vertex_type* vertex1() { return twin_->vertex0(); } + const voronoi_vertex_type* vertex1() const { return twin_->vertex0(); } + + voronoi_edge_type* twin() { return twin_; } + const voronoi_edge_type* twin() const { return twin_; } + void twin(voronoi_edge_type* e) { twin_ = e; } + + voronoi_edge_type* next() { return next_; } + const voronoi_edge_type* next() const { return next_; } + void next(voronoi_edge_type* e) { next_ = e; } + + voronoi_edge_type* prev() { return prev_; } + const voronoi_edge_type* prev() const { return prev_; } + void prev(voronoi_edge_type* e) { prev_ = e; } + + // Returns a pointer to the rotation next edge + // over the starting point of the half-edge. + voronoi_edge_type* rot_next() { return prev_->twin(); } + const voronoi_edge_type* rot_next() const { return prev_->twin(); } + + // Returns a pointer to the rotation prev edge + // over the starting point of the half-edge. + voronoi_edge_type* rot_prev() { return twin_->next(); } + const voronoi_edge_type* rot_prev() const { return twin_->next(); } + + // Returns true if the edge is finite (segment, parabolic arc). + // Returns false if the edge is infinite (ray, line). + bool is_finite() const { return vertex0() && vertex1(); } + + // Returns true if the edge is infinite (ray, line). + // Returns false if the edge is finite (segment, parabolic arc). + bool is_infinite() const { return !vertex0() || !vertex1(); } + + // Returns true if the edge is linear (segment, ray, line). + // Returns false if the edge is curved (parabolic arc). + bool is_linear() const { + return (color_ & BIT_IS_LINEAR) ? true : false; + } + + // Returns true if the edge is curved (parabolic arc). + // Returns false if the edge is linear (segment, ray, line). + bool is_curved() const { + return (color_ & BIT_IS_LINEAR) ? false : true; + } + + // Returns false if edge goes through the endpoint of the segment. + // Returns true else. + bool is_primary() const { + return (color_ & BIT_IS_PRIMARY) ? true : false; + } + + // Returns true if edge goes through the endpoint of the segment. + // Returns false else. + bool is_secondary() const { + return (color_ & BIT_IS_PRIMARY) ? false : true; + } + + color_type color() const { return color_ >> BITS_SHIFT; } + void color(color_type color) const { + color_ &= BITS_MASK; + color_ |= color << BITS_SHIFT; + } + + private: + // 5 color bits are reserved. + enum Bits { + BIT_IS_LINEAR = 0x1, // linear is opposite to curved + BIT_IS_PRIMARY = 0x2, // primary is opposite to secondary + + BITS_SHIFT = 0x5, + BITS_MASK = 0x1F + }; + + voronoi_cell_type* cell_; + voronoi_vertex_type* vertex_; + voronoi_edge_type* twin_; + voronoi_edge_type* next_; + voronoi_edge_type* prev_; + mutable color_type color_; +}; + +template +struct voronoi_diagram_traits { + typedef T coordinate_type; + typedef voronoi_cell cell_type; + typedef voronoi_vertex vertex_type; + typedef voronoi_edge edge_type; + typedef class { + public: + enum { ULPS = 128 }; + bool operator()(const vertex_type& v1, const vertex_type& v2) const { + return (ulp_cmp(v1.x(), v2.x(), ULPS) == + detail::ulp_comparison::EQUAL) && + (ulp_cmp(v1.y(), v2.y(), ULPS) == + detail::ulp_comparison::EQUAL); + } + private: + typename detail::ulp_comparison ulp_cmp; + } vertex_equality_predicate_type; +}; + +// Voronoi output data structure. +// CCW ordering is used on the faces perimeter and around the vertices. +template > +class voronoi_diagram { + public: + typedef typename TRAITS::coordinate_type coordinate_type; + typedef typename TRAITS::cell_type cell_type; + typedef typename TRAITS::vertex_type vertex_type; + typedef typename TRAITS::edge_type edge_type; + + typedef std::vector cell_container_type; + typedef typename cell_container_type::const_iterator const_cell_iterator; + + typedef std::vector vertex_container_type; + typedef typename vertex_container_type::const_iterator const_vertex_iterator; + + typedef std::vector edge_container_type; + typedef typename edge_container_type::const_iterator const_edge_iterator; + + voronoi_diagram() {} + + void clear() { + cells_.clear(); + vertices_.clear(); + edges_.clear(); + } + + const cell_container_type& cells() const { + return cells_; + } + + const vertex_container_type& vertices() const { + return vertices_; + } + + const edge_container_type& edges() const { + return edges_; + } + + std::size_t num_cells() const { + return cells_.size(); + } + + std::size_t num_edges() const { + return edges_.size(); + } + + std::size_t num_vertices() const { + return vertices_.size(); + } + + void _reserve(int num_sites) { + cells_.reserve(num_sites); + vertices_.reserve(num_sites << 1); + edges_.reserve((num_sites << 2) + (num_sites << 1)); + } + + template + void _process_single_site(const detail::site_event& site) { + cells_.push_back(cell_type(site.initial_index(), site.source_category())); + } + + // Insert a new half-edge into the output data structure. + // Takes as input left and right sites that form a new bisector. + // Returns a pair of pointers to a new half-edges. + template + std::pair _insert_new_edge( + const detail::site_event& site1, + const detail::site_event& site2) { + // Get sites' indexes. + int site_index1 = site1.sorted_index(); + int site_index2 = site2.sorted_index(); + + bool is_linear = is_linear_edge(site1, site2); + bool is_primary = is_primary_edge(site1, site2); + + // Create a new half-edge that belongs to the first site. + edges_.push_back(edge_type(is_linear, is_primary)); + edge_type& edge1 = edges_.back(); + + // Create a new half-edge that belongs to the second site. + edges_.push_back(edge_type(is_linear, is_primary)); + edge_type& edge2 = edges_.back(); + + // Add the initial cell during the first edge insertion. + if (cells_.empty()) { + cells_.push_back(cell_type( + site1.initial_index(), site1.source_category())); + } + + // The second site represents a new site during site event + // processing. Add a new cell to the cell records. + cells_.push_back(cell_type( + site2.initial_index(), site2.source_category())); + + // Set up pointers to cells. + edge1.cell(&cells_[site_index1]); + edge2.cell(&cells_[site_index2]); + + // Set up twin pointers. + edge1.twin(&edge2); + edge2.twin(&edge1); + + // Return a pointer to the new half-edge. + return std::make_pair(&edge1, &edge2); + } + + // Insert a new half-edge into the output data structure with the + // start at the point where two previously added half-edges intersect. + // Takes as input two sites that create a new bisector, circle event + // that corresponds to the intersection point of the two old half-edges, + // pointers to those half-edges. Half-edges' direction goes out of the + // new Voronoi vertex point. Returns a pair of pointers to a new half-edges. + template + std::pair _insert_new_edge( + const detail::site_event& site1, + const detail::site_event& site3, + const detail::circle_event& circle, + void* data12, void* data23) { + edge_type* edge12 = static_cast(data12); + edge_type* edge23 = static_cast(data23); + + // Add a new Voronoi vertex. + vertices_.push_back(vertex_type(circle.x(), circle.y())); + vertex_type& new_vertex = vertices_.back(); + + // Update vertex pointers of the old edges. + edge12->vertex0(&new_vertex); + edge23->vertex0(&new_vertex); + + bool is_linear = is_linear_edge(site1, site3); + bool is_primary = is_primary_edge(site1, site3); + + // Add a new half-edge. + edges_.push_back(edge_type(is_linear, is_primary)); + edge_type& new_edge1 = edges_.back(); + new_edge1.cell(&cells_[site1.sorted_index()]); + + // Add a new half-edge. + edges_.push_back(edge_type(is_linear, is_primary)); + edge_type& new_edge2 = edges_.back(); + new_edge2.cell(&cells_[site3.sorted_index()]); + + // Update twin pointers. + new_edge1.twin(&new_edge2); + new_edge2.twin(&new_edge1); + + // Update vertex pointer. + new_edge2.vertex0(&new_vertex); + + // Update Voronoi prev/next pointers. + edge12->prev(&new_edge1); + new_edge1.next(edge12); + edge12->twin()->next(edge23); + edge23->prev(edge12->twin()); + edge23->twin()->next(&new_edge2); + new_edge2.prev(edge23->twin()); + + // Return a pointer to the new half-edge. + return std::make_pair(&new_edge1, &new_edge2); + } + + void _build() { + // Remove degenerate edges. + edge_iterator last_edge = edges_.begin(); + for (edge_iterator it = edges_.begin(); it != edges_.end(); it += 2) { + const vertex_type* v1 = it->vertex0(); + const vertex_type* v2 = it->vertex1(); + if (v1 && v2 && vertex_equality_predicate_(*v1, *v2)) { + remove_edge(&(*it)); + } else { + if (it != last_edge) { + edge_type* e1 = &(*last_edge = *it); + edge_type* e2 = &(*(last_edge + 1) = *(it + 1)); + e1->twin(e2); + e2->twin(e1); + if (e1->prev()) { + e1->prev()->next(e1); + e2->next()->prev(e2); + } + if (e2->prev()) { + e1->next()->prev(e1); + e2->prev()->next(e2); + } + } + last_edge += 2; + } + } + edges_.erase(last_edge, edges_.end()); + + // Set up incident edge pointers for cells and vertices. + for (edge_iterator it = edges_.begin(); it != edges_.end(); ++it) { + it->cell()->incident_edge(&(*it)); + if (it->vertex0()) { + it->vertex0()->incident_edge(&(*it)); + } + } + + // Remove degenerate vertices. + vertex_iterator last_vertex = vertices_.begin(); + for (vertex_iterator it = vertices_.begin(); it != vertices_.end(); ++it) { + if (it->incident_edge()) { + if (it != last_vertex) { + *last_vertex = *it; + vertex_type* v = &(*last_vertex); + edge_type* e = v->incident_edge(); + do { + e->vertex0(v); + e = e->rot_next(); + } while (e != v->incident_edge()); + } + ++last_vertex; + } + } + vertices_.erase(last_vertex, vertices_.end()); + + // Set up next/prev pointers for infinite edges. + if (vertices_.empty()) { + if (!edges_.empty()) { + // Update prev/next pointers for the line edges. + edge_iterator edge_it = edges_.begin(); + edge_type* edge1 = &(*edge_it); + edge1->next(edge1); + edge1->prev(edge1); + ++edge_it; + edge1 = &(*edge_it); + ++edge_it; + + while (edge_it != edges_.end()) { + edge_type* edge2 = &(*edge_it); + ++edge_it; + + edge1->next(edge2); + edge1->prev(edge2); + edge2->next(edge1); + edge2->prev(edge1); + + edge1 = &(*edge_it); + ++edge_it; + } + + edge1->next(edge1); + edge1->prev(edge1); + } + } else { + // Update prev/next pointers for the ray edges. + for (cell_iterator cell_it = cells_.begin(); + cell_it != cells_.end(); ++cell_it) { + if (cell_it->is_degenerate()) + continue; + // Move to the previous edge while + // it is possible in the CW direction. + edge_type* left_edge = cell_it->incident_edge(); + while (left_edge->prev() != NULL) { + left_edge = left_edge->prev(); + // Terminate if this is not a boundary cell. + if (left_edge == cell_it->incident_edge()) + break; + } + + if (left_edge->prev() != NULL) + continue; + + edge_type* right_edge = cell_it->incident_edge(); + while (right_edge->next() != NULL) + right_edge = right_edge->next(); + left_edge->prev(right_edge); + right_edge->next(left_edge); + } + } + } + + private: + typedef typename cell_container_type::iterator cell_iterator; + typedef typename vertex_container_type::iterator vertex_iterator; + typedef typename edge_container_type::iterator edge_iterator; + typedef typename TRAITS::vertex_equality_predicate_type + vertex_equality_predicate_type; + + template + bool is_primary_edge(const SEvent& site1, const SEvent& site2) const { + bool flag1 = site1.is_segment(); + bool flag2 = site2.is_segment(); + if (flag1 && !flag2) { + return (site1.point0() != site2.point0()) && + (site1.point1() != site2.point0()); + } + if (!flag1 && flag2) { + return (site2.point0() != site1.point0()) && + (site2.point1() != site1.point0()); + } + return true; + } + + template + bool is_linear_edge(const SEvent& site1, const SEvent& site2) const { + if (!is_primary_edge(site1, site2)) { + return true; + } + return !(site1.is_segment() ^ site2.is_segment()); + } + + // Remove degenerate edge. + void remove_edge(edge_type* edge) { + // Update the endpoints of the incident edges to the second vertex. + vertex_type* vertex = edge->vertex0(); + edge_type* updated_edge = edge->twin()->rot_next(); + while (updated_edge != edge->twin()) { + updated_edge->vertex0(vertex); + updated_edge = updated_edge->rot_next(); + } + + edge_type* edge1 = edge; + edge_type* edge2 = edge->twin(); + + edge_type* edge1_rot_prev = edge1->rot_prev(); + edge_type* edge1_rot_next = edge1->rot_next(); + + edge_type* edge2_rot_prev = edge2->rot_prev(); + edge_type* edge2_rot_next = edge2->rot_next(); + + // Update prev/next pointers for the incident edges. + edge1_rot_next->twin()->next(edge2_rot_prev); + edge2_rot_prev->prev(edge1_rot_next->twin()); + edge1_rot_prev->prev(edge2_rot_next->twin()); + edge2_rot_next->twin()->next(edge1_rot_prev); + } + + cell_container_type cells_; + vertex_container_type vertices_; + edge_container_type edges_; + vertex_equality_predicate_type vertex_equality_predicate_; + + // Disallow copy constructor and operator= + voronoi_diagram(const voronoi_diagram&); + void operator=(const voronoi_diagram&); +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_VORONOI_DIAGRAM diff --git a/include/boost/polygon/voronoi_geometry_type.hpp b/include/boost/polygon/voronoi_geometry_type.hpp new file mode 100644 index 0000000..0b66626 --- /dev/null +++ b/include/boost/polygon/voronoi_geometry_type.hpp @@ -0,0 +1,46 @@ +// Boost.Polygon library voronoi_geometry_type.hpp header file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_POLYGON_VORONOI_GEOMETRY_TYPE +#define BOOST_POLYGON_VORONOI_GEOMETRY_TYPE + +namespace boost { +namespace polygon { +// Represents topology type of the voronoi site. +enum GeometryCategory { + GEOMETRY_CATEGORY_POINT = 0x0, + GEOMETRY_CATEGORY_SEGMENT = 0x1 +}; + +// Represents category of the input source that forms Voronoi cell. +enum SourceCategory { + // Point subtypes. + SOURCE_CATEGORY_SINGLE_POINT = 0x0, + SOURCE_CATEGORY_SEGMENT_START_POINT = 0x1, + SOURCE_CATEGORY_SEGMENT_END_POINT = 0x2, + + // Segment subtypes. + SOURCE_CATEGORY_INITIAL_SEGMENT = 0x8, + SOURCE_CATEGORY_REVERSE_SEGMENT = 0x9, + + SOURCE_CATEGORY_GEOMETRY_SHIFT = 0x3, + SOURCE_CATEGORY_BITMASK = 0x1F +}; + +bool belongs( + SourceCategory source_category, + GeometryCategory geometry_category) { + return (static_cast(source_category) >> + SOURCE_CATEGORY_GEOMETRY_SHIFT) == + static_cast(geometry_category); +} +} // polygon +} // boost + +#endif // BOOST_POLYGON_VORONOI_GEOMETRY_TYPE diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1462d79..c970b59 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -13,10 +13,24 @@ project polygon-test requirements . msvc:on + /boost/test//boost_unit_test_framework ; test-suite polygon-unit : - [ run gtl_boost_unit_test.cpp ] + [ run polygon_segment_test.cpp ] + [ run gtl_boost_unit_test.cpp ] ; +test-suite voronoi-unit + : + [ run voronoi_builder_test.cpp ] + [ run voronoi_ctypes_test.cpp ] + [ run voronoi_diagram_test.cpp ] + [ run voronoi_geometry_type_test.cpp ] + [ run voronoi_predicates_test.cpp ] + [ run voronoi_robust_fpt_test.cpp ] + [ run voronoi_structures_test.cpp ] + ; + + diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index ee3e9a1..ea4d289 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -1,30 +1,38 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). */ #include +//#define BOOST_POLYGON_NO_DEPS #include + namespace gtl = boost::polygon; using namespace boost::polygon::operators; #include #include +void assert_s(bool c, std::string msg) { + if(!c) { + std::cout << msg << std::endl; + exit( 1); + } +} + namespace boost { namespace polygon{ - void addpoly(polygon_45_set_data& pset, - int* pts, int numpts) { - std::vector > mppts; - for(unsigned int i = 0; i < numpts*2; i += 2) { - point_data pt(pts[i], pts[i+1]); - mppts.push_back(pt); - } - polygon_45_data poly; - poly.set(mppts.begin(), mppts.end()); - pset += poly; + void addpoly(polygon_45_set_data& pset, + int* pts, unsigned int numpts) { + std::vector > mppts; + for(unsigned int i = 0; i < numpts*2; i += 2) { + point_data pt(pts[i], pts[i+1]); + mppts.push_back(pt); } - + polygon_45_data poly; + poly.set(mppts.begin(), mppts.end()); + pset += poly; + } template std::ostream& operator << (std::ostream& o, const interval_data& i) @@ -39,11 +47,11 @@ namespace boost { namespace polygon{ template std::ostream& operator<<(std::ostream& o, const polygon_45_data& poly) { o << "Polygon { "; - for(typename polygon_45_data::iterator_type itr = poly.begin(); + for(typename polygon_45_data::iterator_type itr = poly.begin(); itr != poly.end(); ++itr) { if(itr != poly.begin()) o << ", "; o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); - } + } o << " } "; return o; } @@ -82,7 +90,7 @@ namespace boost { namespace polygon{ std::istream& operator >> (std::istream& i, polygon_90_data& r) { std::size_t size; - i >> size; + i >> size; std::vector vec; vec.reserve(size); for(std::size_t ii = 0; ii < size; ++ii) { @@ -93,12 +101,12 @@ namespace boost { namespace polygon{ r.set_compact(vec.begin(), vec.end()); return i; } - + template std::ostream& operator << (std::ostream& o, const std::vector >& r) { o << r.size() << ' '; for(std::size_t ii = 0; ii < r.size(); ++ii) { - o << (r[ii]); + o << (r[ii]); } return o; } @@ -118,14 +126,14 @@ namespace boost { namespace polygon{ template std::ostream& operator<<(std::ostream& o, const polygon_data& poly) { o << "Polygon { "; - for(typename polygon_data::iterator_type itr = poly.begin(); + for(typename polygon_data::iterator_type itr = poly.begin(); itr != poly.end(); ++itr) { if(itr != poly.begin()) o << ", "; o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); - } + } o << " } "; return o; - } + } template std::ostream& operator << (std::ostream& o, const polygon_set_data& r) { @@ -139,7 +147,7 @@ namespace boost { namespace polygon{ template std::ostream& operator<<(std::ostream& o, const polygon_90_with_holes_data& poly) { o << "Polygon With Holes { "; - for(typename polygon_90_with_holes_data::iterator_type itr = poly.begin(); + for(typename polygon_90_with_holes_data::iterator_type itr = poly.begin(); itr != poly.end(); ++itr) { if(itr != poly.begin()) o << ", "; o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); @@ -154,7 +162,7 @@ namespace boost { namespace polygon{ template std::ostream& operator<<(std::ostream& o, const polygon_45_with_holes_data& poly) { o << "Polygon With Holes { "; - for(typename polygon_45_with_holes_data::iterator_type itr = poly.begin(); + for(typename polygon_45_with_holes_data::iterator_type itr = poly.begin(); itr != poly.end(); ++itr) { if(itr != poly.begin()) o << ", "; o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); @@ -169,7 +177,7 @@ namespace boost { namespace polygon{ template std::ostream& operator<<(std::ostream& o, const polygon_with_holes_data& poly) { o << "Polygon With Holes { "; - for(typename polygon_with_holes_data::iterator_type itr = poly.begin(); + for(typename polygon_with_holes_data::iterator_type itr = poly.begin(); itr != poly.end(); ++itr) { if(itr != poly.begin()) o << ", "; o << (*itr).get(HORIZONTAL) << " " << (*itr).get(VERTICAL); @@ -186,6 +194,11 @@ namespace boost { namespace polygon{ { return o << r.get(HORIZONTAL) << ' ' << r.get(VERTICAL); } + template + std::ostream& operator << (std::ostream& o, const segment_data& r) + { + return o << r.get(LOW) << ' ' << r.get(HIGH); + } template @@ -204,7 +217,7 @@ namespace boost { namespace polygon{ booleanOr.processInterval(container, interval_data(0, 10), 1); booleanOr.advanceScan(); booleanOr.processInterval(container, interval_data(0, 10), -1); - if(container.size() != 2) { + if(container.size() != 2) { std::cout << "Test one rectangle, wrong output size\n"; return false; } @@ -339,7 +352,7 @@ namespace boost { namespace polygon{ polygon_90_set_data ps90; polygon_45_set_data ps45; polygon_set_data ps; - + assign(p, rect); assign(p90, view_as(p)); if(!equivalence(p90, rect)) @@ -373,7 +386,7 @@ namespace boost { namespace polygon{ std::cout << "fail 11\n"; assign(p90wh, view_as(p45wh)); if(!equivalence(p90wh, rect)) - std::cout << "fail 12\n"; + std::cout << "fail 12\n"; assign(p90, view_as(pwh)); if(!equivalence(p90, rect)) std::cout << "fail 13\n"; @@ -579,7 +592,7 @@ namespace boost { namespace polygon{ //poly.set(points.begin(), points.end()); //ps.insert(poly); polygon_45_set_data preps(polys[0]); - + ps.insert(polys[0]); convolve(polys[0], point_data(0, 1) ); @@ -910,18 +923,18 @@ bool testPolygonAssign() { //assign(p_90, p_wh); //assign(p_90, p_45_wh); //assign(p_90, p_90_wh); - assign(p_wh, p); - assign(p_wh, p_45); - assign(p_wh, p_90); + assign(p_wh, p); + assign(p_wh, p_45); + assign(p_wh, p_90); assign(p_wh1, p_wh); assign(p_wh, p_45_wh); assign(p_wh, p_90_wh); - //assign(p_45_wh, p); - assign(p_45_wh, p_45); - assign(p_45_wh, p_90); + //assign(p_45_wh, p); + assign(p_45_wh, p_45); + assign(p_45_wh, p_90); //assign(p_45_wh, p_wh); assign(p_45_wh1, p_45_wh); - //assign(p_90_wh, p); + //assign(p_90_wh, p); //assign(p_90_wh, p_45); assign(p_90_wh, p_90); assign(p_90_wh1, p_90_wh); @@ -1026,7 +1039,7 @@ Polygon45 getRandomTriangle() { x(pts[1], x(pts[1]) + disp); if(dir) y(pts[1], y(pts[1]) + disp); - else + else y(pts[1], y(pts[1]) - disp); return Polygon45(pts, pts+3); } @@ -2138,23 +2151,23 @@ void max_cover_stress_test() { // inline iterator_type begin() const { // return polygon_traits::begin_points(*t); // } - + // /// Get the end iterator // inline iterator_type end() const { // return polygon_traits::end_points(*t); // } - + // /// Get the number of sides of the polygon // inline unsigned int size() const { // return polygon_traits::size(*t); // } - + // /// Get the winding direction of the polygon // inline winding_direction winding() const { // return polygon_traits::winding(*t); // } // }; - + // template // view_of view_as(const T2& obj) { return view_of(obj); } @@ -2177,18 +2190,18 @@ void max_cover_stress_test() { // return compact_iterator_type(polygon_traits::begin_points(*t), // polygon_traits::end_points(*t)); // } - + // /// Get the end iterator // inline compact_iterator_type end_compact() const { // return compact_iterator_type(polygon_traits::end_points(*t), // polygon_traits::end_points(*t)); // } - + // /// Get the number of sides of the polygon // inline unsigned int size() const { // return polygon_traits::size(*t); // } - + // /// Get the winding direction of the polygon // inline winding_direction winding() const { // return polygon_traits::winding(*t); @@ -2220,7 +2233,7 @@ bool test_colinear_duplicate_points() { bool test_extents() { PolygonSet psT(gtl::VERTICAL); - //int xy[] = { 126, 69, 54, 69, 54, 81, 126, 81 }; + //int xy[] = { 126, 69, 54, 69, 54, 81, 126, 81 }; //CPolygonQuery polygon(0, 4, xy); //Rectangle rectIn(54, 69, 126, 81); polygon_data polygon; @@ -2231,11 +2244,11 @@ bool test_extents() { pts.push_back(Point(126, 81)); set_points(polygon, pts.begin(), pts.end()); psT.insert(view_as(polygon)); - + Rectangle rect, rect2; psT.extents(rect2); gtl::extents(rect, psT); - + if (rect != rect2) { std::cout << "gtl::Rectangles differ: " << gtl::xl(rect) << " " << gtl::xh(rect) << " " << gtl::yl(rect) << " " << gtl::yh(rect) << std::endl; std::cout << " " << gtl::xl(rect2) << " " << gtl::xh(rect2) << " " << gtl::yl(rect2) << " " << gtl::yh(rect2) << std::endl; @@ -2246,23 +2259,23 @@ bool test_extents() { bool test_extents2() { Polygon45Set psT; - Point xy[] = { Point(130, 50), Point(50, 50), Point(50, 100), Point(119, 100), + Point xy[] = { Point(130, 50), Point(50, 50), Point(50, 100), Point(119, 100), Point(119, 59), Point(89, 89), Point(59, 59), Point(119, 59), Point(119, 100), Point(130, 100) }; Polygon45 polygon(xy, xy+10); - + psT.insert(polygon); psT += 2; - + Rectangle rect, rect2; psT.extents(rect2); - gtl::extents(rect, psT); + gtl::extents(rect, psT); std::cout << "Extents: " << gtl::xl(rect) << " " << gtl::xh(rect) << " " << gtl::yl(rect) << " " << gtl::yh(rect) << std::endl; std::cout << "Extents: " << gtl::xl(rect2) << " " << gtl::xh(rect2) << " " << gtl::yl(rect2) << " " << gtl::yh(rect2) << std::endl; std::vector pwhs; psT.get(pwhs); for(unsigned int i = 0; i < pwhs.size(); ++i) { std::cout << pwhs[i] << std::endl; - } + } return gtl::equivalence(rect, rect2); } @@ -2398,7 +2411,7 @@ int main() { point_data pt(1, 1); std::cout << contains(p, pt) << std::endl; std::cout << contains(p90, pt) << std::endl; - + interval_data ivl = construct >(0, 10); std::cout << get(ivl, LOW) << std::endl; set(ivl, HIGH, 20); @@ -2646,7 +2659,7 @@ int main() { } std::cout << area(rv) << std::endl; std::cout << area(rv) << std::endl; - + scale_up(rv, 10); std::cout << area(rv) << std::endl; scale_down(rv, 7); @@ -2720,7 +2733,7 @@ int main() { std::cout << pwh << std::endl; std::cout << area(pwh) << std::endl; if(area(pwh) != 9900) return 1; - + //test point scale up / down Point pt(10, 10); scale_up(pt, 25); @@ -2964,7 +2977,7 @@ int main() { ps451.transform(tr); std::cout << (ps451 == ps452) << std::endl; if(ps451 != ps452) return 1; - + //test polygon45set area std::cout << area(ps451) << std::endl; if(area(ps451) != 12.5) return 1; @@ -3219,7 +3232,7 @@ int main() { ps45.insert(ps90); ps45.insert(p90whv); ps45.insert(p90whv + p90whv); - + ps45.insert(polygon_90_with_holes_data()); polygon_with_holes_data pwh; snap_to_45(pwh); @@ -3451,7 +3464,7 @@ int main() { //if(!equivalence(ps, ps45)) { // std::cout << "test 45 vs general resize up failed\n"; // return 1; - //} + //} ps.shrink(9); ps45.resize(-9); if(!equivalence(ps, ps45)) { @@ -3474,16 +3487,16 @@ int main() { std::cout << rupolys[0] << std::endl; std::cout << rupolys45[0] << std::endl; pts.clear(); - pts.push_back(point_data(12, -1)); - pts.push_back(point_data(5, 6)); - pts.push_back(point_data(5, 2)); - pts.push_back(point_data(2, 2)); - pts.push_back(point_data(2, 5)); - pts.push_back(point_data(5, 2)); - pts.push_back(point_data(5, 6)); - pts.push_back(point_data(-1, 12)); - pts.push_back(point_data(-1, -1)); - pts.push_back(point_data(12, -1)); + pts.push_back(point_data(12, -1)); + pts.push_back(point_data(5, 6)); + pts.push_back(point_data(5, 2)); + pts.push_back(point_data(2, 2)); + pts.push_back(point_data(2, 5)); + pts.push_back(point_data(5, 2)); + pts.push_back(point_data(5, 6)); + pts.push_back(point_data(-1, 12)); + pts.push_back(point_data(-1, -1)); + pts.push_back(point_data(12, -1)); set_points(poly, pts.begin(), pts.end()); //waived //if(!equivalence(ps, poly)) { @@ -3494,64 +3507,64 @@ int main() { //if(!equivalence(ps, ps45)) { // std::cout << "test 45 vs general resize up with holes failed\n"; // return 1; - //} + //} ps.shrink(1); ps45.resize(-1); if(!equivalence(ps, ps45)) { std::cout << "test 45 vs general resize down with holes failed\n"; return 1; - } + } ps.shrink(10); ps45.resize(-10); if(!equivalence(ps, ps45)) { std::cout << "test 45 vs general resize down 2 with holes failed\n"; return 1; - } + } } { - Point pts[] = {construct(1565, 5735), - construct(915, 5735), - construct(915, 7085), - construct(1565, 7085) }; - Polygon poly; - set_points(poly, pts, pts+4); - bool ret=gtl::contains(poly,gtl::construct(920, 7080)); + Point pts[] = {construct(1565, 5735), + construct(915, 5735), + construct(915, 7085), + construct(1565, 7085) }; + Polygon poly; + set_points(poly, pts, pts+4); + bool ret=gtl::contains(poly,gtl::construct(920, 7080)); if(!ret) { std::cout << "contains failed!" << std::endl; return 1; } polygon_data poly_aa; set_points(poly_aa, pts, pts+4); - ret=gtl::contains(poly,gtl::construct(920, 7080)); + ret=gtl::contains(poly,gtl::construct(920, 7080)); if(!ret) { std::cout << "contains 90 failed!" << std::endl; return 1; } polygon_with_holes_data pwh; polygon_90_with_holes_data p90wh; - Point pts2[] = {construct(565, 15735), - construct(15, 15735), - construct(15, 17085), - construct(565, 17085) }; - set_points(pwh, pts2, pts2+4); - set_points(p90wh, pts2, pts2+4); + Point pts2[] = {construct(565, 15735), + construct(15, 15735), + construct(15, 17085), + construct(565, 17085) }; + set_points(pwh, pts2, pts2+4); + set_points(p90wh, pts2, pts2+4); pwh.set_holes(&poly_aa, (&poly_aa)+1); p90wh.set_holes(&poly, (&poly)+1); - ret=gtl::contains(pwh,gtl::construct(920, 7080)); + ret=gtl::contains(pwh,gtl::construct(920, 7080)); if(ret) { std::cout << "contains wh failed!" << std::endl; return 1; } - ret=gtl::contains(p90wh,gtl::construct(920, 7080)); + ret=gtl::contains(p90wh,gtl::construct(920, 7080)); if(ret) { std::cout << "contains 90wh failed!" << std::endl; return 1; } std::reverse(pts, pts+4); - set_points(poly, pts, pts+4); - ret=gtl::contains(poly,gtl::construct(920, 7080)); + set_points(poly, pts, pts+4); + ret=gtl::contains(poly,gtl::construct(920, 7080)); if(!ret) { std::cout << "reverse contains failed!" << std::endl; return 1; @@ -3618,8 +3631,8 @@ int main() { testbug.insert(orr); std::cout << area(testbug) << std::endl; polygon_set_data testbug2; - for(int i = 0; i < polys.size(); ++i) { - for(int j = 0; j < polys.size(); ++j) { + for(size_t i = 0; i < polys.size(); ++i) { + for(size_t j = 0; j < polys.size(); ++j) { testbug2.clear(); testbug2.insert(polys[i]); testbug2.insert(polys[j]); @@ -3634,7 +3647,75 @@ int main() { } } } + + { + polygon_set_data t_eq; + t_eq.insert(rectangle_data(0, 0, 5, 10)); + t_eq.insert(rectangle_data(0, 5, 5, 10)); + std::cout << t_eq < t_eq2; + t_eq2 += rectangle_data(0, 0, 5, 10); + std::cout << area(t_eq) < Point; + typedef segment_data Dls; + Point pt1(0, 0); + Point pt2(10, 10); + Point pt3(20, 20); + Point pt4(20, 0); + Dls dls1(pt1, pt2); + Dls dls2(pt1, pt3); + Dls dls3(pt1, pt4); + Dls dls4(pt2, pt1); + typedef std::vector > Dlss; + Dlss dlss, result; + dlss.push_back(dls1); + dlss.push_back(dls2); + dlss.push_back(dls3); + dlss.push_back(dls4); + rectangle_data rect; + envelope_segments(rect, dlss.begin(), dlss.end()); + assert_s(area(rect) == 400.0, "envelope"); + intersect_segments(result, dlss.begin(), dlss.end()); + dlss.swap(result); + for (Dlss::iterator itr = dlss.begin(); itr != dlss.end(); ++itr) { + std::cout << *itr << std::endl; + } + assert_s(dlss.size() == 5, "intersection"); + Dls dls5(Point(0,5), Point(5,0)); + dlss.push_back(dls5); + std::cout << std::endl; + result.clear(); + intersect_segments(result, dlss.begin(), dlss.end()); + dlss.swap(result); + for (Dlss::iterator itr = dlss.begin(); itr != dlss.end(); ++itr) { + std::cout << *itr << std::endl; + } + assert_s(dlss.size() == 11, "intersection2"); + } + + if (1) { + using namespace boost::polygon; + std::vector > > segs; + segment_data sarray[2]; + sarray[0] = segment_data(point_data(0,0), point_data(10,10)); + sarray[1] = segment_data(point_data(10,0), point_data(0,10)); + std::iterator_traits*>::value_type s = sarray[0]; + intersect_segments(segs, sarray, sarray+2); + std::cout << segs.size() << std::endl; + assert_s(segs.size() == 4, "intersection3"); + } + std::cout << "ALL TESTS COMPLETE\n"; return 0; } - diff --git a/test/polygon_segment_test.cpp b/test/polygon_segment_test.cpp new file mode 100644 index 0000000..665fe4a --- /dev/null +++ b/test/polygon_segment_test.cpp @@ -0,0 +1,431 @@ +// Boost.Polygon library polygon_segment_test.cpp file + +// Copyright Andrii Sydorchuk 2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#define BOOST_TEST_MODULE POLYGON_SEGMENT_TEST +#include +#include + +#include "boost/polygon/polygon.hpp" +using namespace boost::polygon; + +typedef boost::mpl::list test_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_data_test, T, test_types) { + typedef point_data point_type; + typedef segment_data segment_type; + point_type point1(1, 2); + point_type point2(3, 4); + segment_type segment1(point1, point2); + segment_type segment2 = segment1; + + BOOST_CHECK(segment1.low() == point1); + BOOST_CHECK(segment1.high() == point2); + BOOST_CHECK(segment1.get(LOW) == point1); + BOOST_CHECK(segment1.get(HIGH) == point2); + BOOST_CHECK(segment1 == segment2); + BOOST_CHECK(!(segment1 != segment2)); + BOOST_CHECK(!(segment1 < segment2)); + BOOST_CHECK(!(segment1 > segment1)); + BOOST_CHECK(segment1 <= segment2); + BOOST_CHECK(segment1 >= segment2); + + segment1.low(point2); + segment1.high(point1); + BOOST_CHECK(segment1.low() == point2); + BOOST_CHECK(segment1.high() == point1); + BOOST_CHECK(!(segment1 == segment2)); + BOOST_CHECK(segment1 != segment2); + + segment2.set(LOW, point2); + segment2.set(HIGH, point1); + BOOST_CHECK(segment1 == segment2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_traits_test, T, test_types) { + typedef point_data point_type; + typedef segment_data segment_type; + + point_type point1(1, 2); + point_type point2(3, 4); + segment_type segment = segment_mutable_traits::construct(point1, point2); + + BOOST_CHECK(segment_traits::get(segment, LOW) == point1); + BOOST_CHECK(segment_traits::get(segment, HIGH) == point2); + + segment_mutable_traits::set(segment, LOW, point2); + segment_mutable_traits::set(segment, HIGH, point1); + + BOOST_CHECK(segment_traits::get(segment, LOW) == point2); + BOOST_CHECK(segment_traits::get(segment, HIGH) == point1); +} + +template +struct Segment { + point_data p0; + point_data p1; +}; + +namespace boost { +namespace polygon { + template + struct geometry_concept< Segment > { + typedef segment_concept type; + }; + + template + struct segment_traits< Segment > { + typedef T coordinate_type; + typedef point_data point_type; + + static point_type get(const Segment& segment, direction_1d dir) { + return dir.to_int() ? segment.p1 : segment.p0; + } + }; + + template + struct segment_mutable_traits< Segment > { + typedef point_data point_type; + + static inline void set(Segment& segment, direction_1d dir, const point_type& point) { + if (dir.to_int()) { + segment.p1 = point; + } else { + segment.p0 = point; + } + } + + static inline Segment construct(const point_type& point1, const point_type& point2) { + Segment segment; + segment.p0 = point1; + segment.p1 = point2; + return segment; + } + }; +} +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test1, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(1, 2); + point_type point2(3, 4); + point_type point3(2, 3); + segment_type segment1 = construct(point1, point2); + BOOST_CHECK(segment1.p0 == point1); + BOOST_CHECK(segment1.p1 == point2); + BOOST_CHECK(get(segment1, LOW) == point1); + BOOST_CHECK(low(segment1) == point1); + BOOST_CHECK(get(segment1, HIGH) == point2); + BOOST_CHECK(high(segment1) == point2); + BOOST_CHECK(center(segment1) == point3); + + set(segment1, LOW, point2); + set(segment1, HIGH, point1); + BOOST_CHECK(segment1.p0 == point2); + BOOST_CHECK(segment1.p1 == point1); + BOOST_CHECK(get(segment1, LOW) == point2); + BOOST_CHECK(get(segment1, HIGH) == point1); + low(segment1, point1); + high(segment1, point2); + BOOST_CHECK(segment1.p0 == point1); + BOOST_CHECK(segment1.p1 == point2); + + segment_data segment2 = copy_construct< segment_data >(segment1); + BOOST_CHECK(segment1.p0 == segment2.low()); + BOOST_CHECK(segment1.p1 == segment2.high()); + BOOST_CHECK(equivalence(segment1, segment2)); + + segment_data segment3 = construct< segment_data >(point2, point1); + assign(segment1, segment3); + BOOST_CHECK(segment1.p0 == point2); + BOOST_CHECK(segment1.p1 == point1); + BOOST_CHECK(!equivalence(segment1, segment2)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test2, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(1, 2); + point_type point2(2, 4); + point_type point3(0, 0); + point_type point4(5, 10); + point_type point5(1, 3); + point_type point6(2, 3); + point_type point7(100, 201); + point_type point8(100, 200); + point_type point9(100, 199); + segment_type segment1 = construct(point1, point2); + segment_type segment2 = construct(point2, point1); + segment_type segment3 = construct(point1, point5); + + BOOST_CHECK(orientation(segment1, point1) == 0); + BOOST_CHECK(orientation(segment1, point2) == 0); + BOOST_CHECK(orientation(segment1, point3) == 0); + BOOST_CHECK(orientation(segment1, point4) == 0); + BOOST_CHECK(orientation(segment1, point5) == 1); + BOOST_CHECK(orientation(segment2, point5) == -1); + BOOST_CHECK(orientation(segment1, point6) == -1); + BOOST_CHECK(orientation(segment2, point6) == 1); + BOOST_CHECK(orientation(segment1, point7) == 1); + BOOST_CHECK(orientation(segment2, point7) == -1); + BOOST_CHECK(orientation(segment1, point8) == 0); + BOOST_CHECK(orientation(segment1, point9) == -1); + BOOST_CHECK(orientation(segment2, point9) == 1); + BOOST_CHECK(orientation(segment3, point6) == -1); + BOOST_CHECK(orientation(segment3, point3) == 1); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test3, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + segment_type segment1 = construct(point_type(0, 0), point_type(1, 2)); + segment_type segment2 = construct(point_type(0, 0), point_type(2, 4)); + segment_type segment3 = construct(point_type(0, 0), point_type(2, 3)); + segment_type segment4 = construct(point_type(0, 0), point_type(2, 5)); + segment_type segment5 = construct(point_type(0, 2), point_type(2, 0)); + + BOOST_CHECK(orientation(segment1, segment2) == 0); + BOOST_CHECK(orientation(segment1, segment3) == -1); + BOOST_CHECK(orientation(segment3, segment1) == 1); + BOOST_CHECK(orientation(segment1, segment4) == 1); + BOOST_CHECK(orientation(segment4, segment1) == -1); + BOOST_CHECK(orientation(segment1, segment5) == -1); + BOOST_CHECK(orientation(segment5, segment1) == 1); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test4, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(1, 2); + point_type point2(3, 6); + point_type point3(2, 4); + point_type point4(4, 8); + point_type point5(0, 0); + segment_type segment = construct(point1, point2); + + BOOST_CHECK(contains(segment, point1, true)); + BOOST_CHECK(contains(segment, point2, true)); + BOOST_CHECK(!contains(segment, point1, false)); + BOOST_CHECK(!contains(segment, point2, false)); + BOOST_CHECK(contains(segment, point3, false)); + BOOST_CHECK(!contains(segment, point4, true)); + BOOST_CHECK(!contains(segment, point5, true)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test5, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(0, 0); + point_type point2(10, 0); + point_type point3(5, 0); + point_type point4(-1, 0); + point_type point5(11, 0); + segment_type segment = construct(point1, point2); + + BOOST_CHECK(contains(segment, point1, true)); + BOOST_CHECK(contains(segment, point2, true)); + BOOST_CHECK(!contains(segment, point1, false)); + BOOST_CHECK(!contains(segment, point2, false)); + BOOST_CHECK(contains(segment, point3, false)); + BOOST_CHECK(!contains(segment, point4, true)); + BOOST_CHECK(!contains(segment, point5, true)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test6, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(0, 0); + point_type point2(1, 2); + point_type point3(2, 4); + point_type point4(3, 6); + point_type point5(4, 8); + point_type point6(5, 10); + segment_type segment1 = construct(point2, point5); + segment_type segment2 = construct(point3, point4); + segment_type segment3 = construct(point1, point3); + segment_type segment4 = construct(point4, point6); + + BOOST_CHECK(contains(segment1, segment2, false)); + BOOST_CHECK(!contains(segment2, segment1, true)); + BOOST_CHECK(!contains(segment1, segment3, true)); + BOOST_CHECK(!contains(segment1, segment4, true)); + BOOST_CHECK(contains(segment1, segment1, true)); + BOOST_CHECK(!contains(segment1, segment1, false)); +} + +template +struct Transformer { + void scale(T& x, T& y) const { + x *= 2; + y *= 2; + } + + void transform(T& x, T& y) const { + T tmp = x; + x = y; + y = tmp; + } +}; + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test7, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(1, 2); + point_type point2(4, 6); + segment_type segment1 = construct(point1, point2); + + scale_up(segment1, 3); + BOOST_CHECK(low(segment1) == point_type(3, 6)); + BOOST_CHECK(high(segment1) == point_type(12, 18)); + + scale_down(segment1, 3); + BOOST_CHECK(low(segment1) == point1); + BOOST_CHECK(high(segment1) == point2); + BOOST_CHECK(length(segment1) == 5); + + move(segment1, HORIZONTAL, 1); + move(segment1, VERTICAL, 2); + BOOST_CHECK(low(segment1) == point_type(2, 4)); + BOOST_CHECK(high(segment1) == point_type(5, 8)); + BOOST_CHECK(length(segment1) == 5); + + convolve(segment1, point_type(1, 2)); + BOOST_CHECK(low(segment1) == point_type(3, 6)); + BOOST_CHECK(high(segment1) == point_type(6, 10)); + + deconvolve(segment1, point_type(2, 4)); + BOOST_CHECK(low(segment1) == point1); + BOOST_CHECK(high(segment1) == point2); + + scale(segment1, Transformer()); + BOOST_CHECK(low(segment1) == point_type(2, 4)); + BOOST_CHECK(high(segment1) == point_type(8, 12)); + transform(segment1, Transformer()); + BOOST_CHECK(low(segment1) == point_type(4, 2)); + BOOST_CHECK(high(segment1) == point_type(12, 8)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test8, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + segment_type segment1 = construct(point_type(0, 0), point_type(1, 2)); + segment_type segment2 = construct(point_type(1, 2), point_type(2, 4)); + segment_type segment3 = construct(point_type(2, 4), point_type(0, 4)); + segment_type segment4 = construct(point_type(0, 4), point_type(0, 0)); + + BOOST_CHECK(abuts(segment1, segment2, HIGH)); + BOOST_CHECK(abuts(segment2, segment3, HIGH)); + BOOST_CHECK(abuts(segment3, segment4, HIGH)); + BOOST_CHECK(abuts(segment4, segment1, HIGH)); + + BOOST_CHECK(!abuts(segment1, segment2, LOW)); + BOOST_CHECK(!abuts(segment2, segment3, LOW)); + BOOST_CHECK(!abuts(segment3, segment4, LOW)); + BOOST_CHECK(!abuts(segment4, segment1, LOW)); + + BOOST_CHECK(abuts(segment2, segment1)); + BOOST_CHECK(abuts(segment3, segment2)); + BOOST_CHECK(abuts(segment4, segment3)); + BOOST_CHECK(abuts(segment1, segment4)); + + BOOST_CHECK(!abuts(segment1, segment3)); + BOOST_CHECK(!abuts(segment2, segment4)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test9, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + segment_type segment1 = construct(point_type(0, 0), point_type(2, 2)); + segment_type segment2 = construct(point_type(1, 1), point_type(3, 3)); + segment_type segment3 = construct(point_type(2, 2), point_type(-1, -1)); + segment_type segment4 = construct(point_type(1, 3), point_type(3, 1)); + segment_type segment5 = construct(point_type(2, 2), point_type(1, 3)); + + BOOST_CHECK(intersects(segment1, segment2, false)); + BOOST_CHECK(intersects(segment1, segment2, true)); + BOOST_CHECK(intersects(segment1, segment3, false)); + BOOST_CHECK(intersects(segment1, segment3, true)); + BOOST_CHECK(intersects(segment2, segment3, false)); + BOOST_CHECK(intersects(segment2, segment3, true)); + BOOST_CHECK(intersects(segment4, segment3, false)); + BOOST_CHECK(intersects(segment4, segment3, true)); + BOOST_CHECK(intersects(segment4, segment2, false)); + BOOST_CHECK(intersects(segment4, segment2, true)); + BOOST_CHECK(!intersects(segment3, segment5, false)); + BOOST_CHECK(intersects(segment3, segment5, true)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test10, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + segment_type segment1 = construct(point_type(0, 0), point_type(0, 2)); + segment_type segment2 = construct(point_type(0, 1), point_type(0, 3)); + segment_type segment3 = construct(point_type(0, 1), point_type(0, 2)); + segment_type segment4 = construct(point_type(0, 2), point_type(0, 3)); + segment_type segment5 = construct(point_type(0, 2), point_type(2, 2)); + segment_type segment6 = construct(point_type(0, 1), point_type(1, 1)); + + BOOST_CHECK(intersects(segment1, segment1, false)); + BOOST_CHECK(intersects(segment1, segment1, true)); + BOOST_CHECK(intersects(segment1, segment2, false)); + BOOST_CHECK(intersects(segment1, segment2, true)); + BOOST_CHECK(intersects(segment1, segment3, false)); + BOOST_CHECK(intersects(segment1, segment3, true)); + BOOST_CHECK(intersects(segment2, segment3, false)); + BOOST_CHECK(intersects(segment2, segment3, true)); + BOOST_CHECK(!intersects(segment1, segment4, false)); + BOOST_CHECK(intersects(segment1, segment4, true)); + BOOST_CHECK(!intersects(segment1, segment5, false)); + BOOST_CHECK(intersects(segment1, segment5, true)); + BOOST_CHECK(intersects(segment1, segment6, false)); + BOOST_CHECK(intersects(segment1, segment6, true)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test11, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + point_type point1(1, 2); + point_type point2(7, 10); + segment_type segment1 = construct(point1, point2); + + BOOST_CHECK(euclidean_distance(segment1, point1) == 0.0); + BOOST_CHECK(euclidean_distance(segment1, point2) == 0.0); + BOOST_CHECK(euclidean_distance(segment1, point_type(10, 14)) == 5.0); + BOOST_CHECK(euclidean_distance(segment1, point_type(-3, -1)) == 5.0); + BOOST_CHECK(euclidean_distance(segment1, point_type(0, 9)) == 5.0); + BOOST_CHECK(euclidean_distance(segment1, point_type(8, 3)) == 5.0); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test12, T, test_types) { + typedef point_data point_type; + typedef Segment segment_type; + + segment_type segment1 = construct(point_type(0, 0), point_type(3, 4)); + segment_type segment2 = construct(point_type(2, 0), point_type(0, 2)); + segment_type segment3 = construct(point_type(1, -7), point_type(10, 5)); + segment_type segment4 = construct(point_type(7, 7), point_type(10, 11)); + + BOOST_CHECK(euclidean_distance(segment1, segment2) == 0.0); + BOOST_CHECK(euclidean_distance(segment1, segment3) == 5.0); + BOOST_CHECK(euclidean_distance(segment1, segment4) == 5.0); +} diff --git a/test/voronoi_builder_test.cpp b/test/voronoi_builder_test.cpp new file mode 100644 index 0000000..07fa2ae --- /dev/null +++ b/test/voronoi_builder_test.cpp @@ -0,0 +1,636 @@ +// Boost.Polygon library voronoi_builder_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include +#include +#include + +#define BOOST_TEST_MODULE voronoi_builder_test +#include +#include +#include + +#include +#include +#include "voronoi_test_helper.hpp" +using boost::polygon::voronoi_builder; +using boost::polygon::voronoi_diagram; + +typedef boost::mpl::list test_types; +typedef voronoi_diagram vd_type; +typedef vd_type::coordinate_type coordinate_type; +typedef vd_type::edge_type voronoi_edge_type; +typedef vd_type::const_cell_iterator const_cell_iterator; +typedef vd_type::const_vertex_iterator const_vertex_iterator; + +#define CHECK_OUTPUT_SIZE(output, cells, vertices, edges) \ + BOOST_CHECK_EQUAL(output.num_cells(), (std::size_t)cells); \ + BOOST_CHECK_EQUAL(output.num_vertices(), (std::size_t)vertices); \ + BOOST_CHECK_EQUAL(output.num_edges(), (std::size_t)edges) + +#define VERIFY_OUTPUT(output) \ + BOOST_CHECK(voronoi_test_helper::verify_output(output, \ + voronoi_test_helper::CELL_CONVEXITY)); \ + BOOST_CHECK(voronoi_test_helper::verify_output(output, \ + voronoi_test_helper::INCIDENT_EDGES_CCW_ORDER)); \ + BOOST_CHECK(voronoi_test_helper::verify_output(output, \ + voronoi_test_helper::NO_HALF_EDGE_INTERSECTIONS)) + +#define VERIFY_NO_HALF_EDGE_INTERSECTIONS(output) \ + BOOST_CHECK(voronoi_test_helper::verify_output(output, \ + voronoi_test_helper::NO_HALF_EDGE_INTERSECTIONS)) + +// Sites: (0, 0). +BOOST_AUTO_TEST_CASE_TEMPLATE(single_site_test, T, test_types) { + std::vector< point_data > points; + points.push_back(point_data(0, 0)); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + + BOOST_CHECK(test_output.cells().size() == 1); + CHECK_OUTPUT_SIZE(test_output, 1, 0, 0); + + const_cell_iterator it = test_output.cells().begin(); + BOOST_CHECK(it->incident_edge() == NULL); +} + +// Sites: (0, 0), (0, 1). +BOOST_AUTO_TEST_CASE_TEMPLATE(collinear_sites_test1, T, test_types) { + std::vector< point_data > points; + points.push_back(point_data(0, 0)); + points.push_back(point_data(0, 1)); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + CHECK_OUTPUT_SIZE(test_output, 2, 0, 2); + + const_cell_iterator cell_it = test_output.cells().begin(); + cell_it++; + + const voronoi_edge_type* edge1_1 = cell_it->incident_edge(); + const voronoi_edge_type* edge1_2 = edge1_1->twin(); + + BOOST_CHECK(edge1_1->twin() == edge1_2); + BOOST_CHECK(edge1_2->twin() == edge1_1); + + BOOST_CHECK(edge1_1->next() == edge1_1); + BOOST_CHECK(edge1_1->prev() == edge1_1); + BOOST_CHECK(edge1_1->rot_next() == edge1_2); + BOOST_CHECK(edge1_1->rot_prev() == edge1_2); + + BOOST_CHECK(edge1_2->next() == edge1_2); + BOOST_CHECK(edge1_2->prev() == edge1_2); + BOOST_CHECK(edge1_2->rot_next() == edge1_1); + BOOST_CHECK(edge1_2->rot_prev() == edge1_1); +} + +// Sites: (0, 0), (1, 1), (2, 2). +BOOST_AUTO_TEST_CASE_TEMPLATE(collinear_sites_test2, T, test_types) { + std::vector< point_data > points; + points.push_back(point_data(0, 0)); + points.push_back(point_data(1, 1)); + points.push_back(point_data(2, 2)); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + CHECK_OUTPUT_SIZE(test_output, 3, 0, 4); + + const_cell_iterator cell_it = test_output.cells().begin(); + const voronoi_edge_type* edge1_1 = cell_it->incident_edge(); + const voronoi_edge_type* edge1_2 = edge1_1->twin(); + cell_it++; + cell_it++; + const voronoi_edge_type* edge2_2 = cell_it->incident_edge(); + const voronoi_edge_type* edge2_1 = edge2_2->twin(); + + BOOST_CHECK(edge1_1->twin() == edge1_2 && edge1_2->twin() == edge1_1); + BOOST_CHECK(edge2_1->twin() == edge2_2 && edge2_2->twin() == edge2_1); + + BOOST_CHECK(edge1_1->next() == edge1_1 && edge1_1->prev() == edge1_1); + BOOST_CHECK(edge1_2->next() == edge2_1 && edge1_2->prev() == edge2_1); + BOOST_CHECK(edge2_1->next() == edge1_2 && edge2_1->prev() == edge1_2); + BOOST_CHECK(edge2_2->next() == edge2_2 && edge2_2->prev() == edge2_2); + + BOOST_CHECK(edge1_1->rot_next() == edge1_2 && edge1_1->rot_prev() == edge2_1); + BOOST_CHECK(edge1_2->rot_next() == edge2_2 && edge1_2->rot_prev() == edge1_1); + BOOST_CHECK(edge2_1->rot_next() == edge1_1 && edge2_1->rot_prev() == edge2_2); + BOOST_CHECK(edge2_2->rot_next() == edge2_1 && edge2_2->rot_prev() == edge1_2); + + BOOST_CHECK(edge1_2->next() == edge2_1 && edge1_2->prev() == edge2_1); + BOOST_CHECK(edge2_1->next() == edge1_2 && edge2_1->prev() == edge1_2); +} + +// Sites: (0, 0), (0, 4), (2, 1). +BOOST_AUTO_TEST_CASE_TEMPLATE(triangle_test1, T, test_types) { + point_data point1(0, 0); + point_data point2(0, 4); + point_data point3(2, 1); + std::vector< point_data > points; + points.push_back(point1); + points.push_back(point2); + points.push_back(point3); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + CHECK_OUTPUT_SIZE(test_output, 3, 1, 6); + + const_vertex_iterator it = test_output.vertices().begin(); + BOOST_CHECK_EQUAL(it->x(), 0.25); + BOOST_CHECK_EQUAL(it->y(), 2.0); + + const voronoi_edge_type* edge1_1 = it->incident_edge(); + const voronoi_edge_type* edge1_2 = edge1_1->twin(); + BOOST_CHECK(edge1_1->cell()->source_index() == 1); + BOOST_CHECK(edge1_2->cell()->source_index() == 2); + + const voronoi_edge_type* edge2_1 = edge1_1->rot_prev(); + const voronoi_edge_type* edge2_2 = edge2_1->twin(); + BOOST_CHECK(edge2_1->cell()->source_index() == 2); + BOOST_CHECK(edge2_2->cell()->source_index() == 0); + + const voronoi_edge_type* edge3_1 = edge2_1->rot_prev(); + const voronoi_edge_type* edge3_2 = edge3_1->twin(); + BOOST_CHECK(edge3_1->cell()->source_index() == 0); + BOOST_CHECK(edge3_2->cell()->source_index() == 1); + + BOOST_CHECK(edge1_2->twin() == edge1_1); + BOOST_CHECK(edge2_2->twin() == edge2_1); + BOOST_CHECK(edge3_2->twin() == edge3_1); + + BOOST_CHECK(edge1_1->prev() == edge3_2 && edge1_1->next() == edge3_2); + BOOST_CHECK(edge2_1->prev() == edge1_2 && edge2_1->next() == edge1_2); + BOOST_CHECK(edge3_1->prev() == edge2_2 && edge3_1->next() == edge2_2); + + BOOST_CHECK(edge1_2->next() == edge2_1 && edge1_2->prev() == edge2_1); + BOOST_CHECK(edge2_2->next() == edge3_1 && edge2_2->prev() == edge3_1); + BOOST_CHECK(edge3_2->next() == edge1_1 && edge3_2->prev() == edge1_1); + + BOOST_CHECK(edge1_1->rot_next() == edge3_1); + BOOST_CHECK(edge3_1->rot_next() == edge2_1); + BOOST_CHECK(edge2_1->rot_next() == edge1_1); + + BOOST_CHECK(edge1_2->rot_next() == edge2_2); + BOOST_CHECK(edge2_2->rot_next() == edge3_2); + BOOST_CHECK(edge3_2->rot_next() == edge1_2); +} + +// Sites: (0, 1), (2, 0), (2, 4). +BOOST_AUTO_TEST_CASE_TEMPLATE(triangle_test2, T, test_types) { + point_data point1(0, 1); + point_data point2(2, 0); + point_data point3(2, 4); + std::vector< point_data > points; + points.push_back(point1); + points.push_back(point2); + points.push_back(point3); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + CHECK_OUTPUT_SIZE(test_output, 3, 1, 6); + + const_vertex_iterator it = test_output.vertices().begin(); + BOOST_CHECK_EQUAL(it->x(), 1.75); + BOOST_CHECK_EQUAL(it->y(), 2.0); + + const voronoi_edge_type* edge1_1 = it->incident_edge(); + const voronoi_edge_type* edge1_2 = edge1_1->twin(); + BOOST_CHECK(edge1_1->cell()->source_index() == 2); + BOOST_CHECK(edge1_2->cell()->source_index() == 1); + + const voronoi_edge_type* edge2_1 = edge1_1->rot_prev(); + const voronoi_edge_type* edge2_2 = edge2_1->twin(); + BOOST_CHECK(edge2_1->cell()->source_index() == 1); + BOOST_CHECK(edge2_2->cell()->source_index() == 0); + + const voronoi_edge_type* edge3_1 = edge2_1->rot_prev(); + const voronoi_edge_type* edge3_2 = edge3_1->twin(); + BOOST_CHECK(edge3_1->cell()->source_index() == 0); + BOOST_CHECK(edge3_2->cell()->source_index() == 2); + + BOOST_CHECK(edge1_2->twin() == edge1_1); + BOOST_CHECK(edge2_2->twin() == edge2_1); + BOOST_CHECK(edge3_2->twin() == edge3_1); + + BOOST_CHECK(edge1_1->prev() == edge3_2 && edge1_1->next() == edge3_2); + BOOST_CHECK(edge2_1->prev() == edge1_2 && edge2_1->next() == edge1_2); + BOOST_CHECK(edge3_1->prev() == edge2_2 && edge3_1->next() == edge2_2); + + BOOST_CHECK(edge1_2->next() == edge2_1 && edge1_2->prev() == edge2_1); + BOOST_CHECK(edge2_2->next() == edge3_1 && edge2_2->prev() == edge3_1); + BOOST_CHECK(edge3_2->next() == edge1_1 && edge3_2->prev() == edge1_1); + + BOOST_CHECK(edge1_1->rot_next() == edge3_1); + BOOST_CHECK(edge3_1->rot_next() == edge2_1); + BOOST_CHECK(edge2_1->rot_next() == edge1_1); + + BOOST_CHECK(edge1_2->rot_next() == edge2_2); + BOOST_CHECK(edge2_2->rot_next() == edge3_2); + BOOST_CHECK(edge3_2->rot_next() == edge1_2); +} + +// Sites: (0, 0), (0, 1), (1, 0), (1, 1). +BOOST_AUTO_TEST_CASE_TEMPLATE(square_test1, T, test_types) { + point_data point1(0, 0); + point_data point2(0, 1); + point_data point3(1, 0); + point_data point4(1, 1); + std::vector< point_data > points; + points.push_back(point1); + points.push_back(point2); + points.push_back(point3); + points.push_back(point4); + vd_type test_output; + construct_voronoi(points.begin(), points.end(), &test_output); + VERIFY_OUTPUT(test_output); + CHECK_OUTPUT_SIZE(test_output, 4, 1, 8); + + // Check voronoi vertex. + const_vertex_iterator it = test_output.vertices().begin(); + BOOST_CHECK_EQUAL(it->x(), 0.5); + BOOST_CHECK_EQUAL(it->y(), 0.5); + + // Check voronoi edges. + const voronoi_edge_type* edge1_1 = it->incident_edge(); + const voronoi_edge_type* edge1_2 = edge1_1->twin(); + BOOST_CHECK(edge1_1->cell()->source_index() == 3); + BOOST_CHECK(edge1_2->cell()->source_index() == 2); + + const voronoi_edge_type* edge2_1 = edge1_1->rot_prev(); + const voronoi_edge_type* edge2_2 = edge2_1->twin(); + BOOST_CHECK(edge2_1->cell()->source_index() == 2); + BOOST_CHECK(edge2_2->cell()->source_index() == 0); + + const voronoi_edge_type* edge3_1 = edge2_1->rot_prev(); + const voronoi_edge_type* edge3_2 = edge3_1->twin(); + BOOST_CHECK(edge3_1->cell()->source_index() == 0); + BOOST_CHECK(edge3_2->cell()->source_index() == 1); + + const voronoi_edge_type* edge4_1 = edge3_1->rot_prev(); + const voronoi_edge_type* edge4_2 = edge4_1->twin(); + BOOST_CHECK(edge4_1->cell()->source_index() == 1); + BOOST_CHECK(edge4_2->cell()->source_index() == 3); + + BOOST_CHECK(edge1_2->twin() == edge1_1); + BOOST_CHECK(edge2_2->twin() == edge2_1); + BOOST_CHECK(edge3_2->twin() == edge3_1); + BOOST_CHECK(edge4_2->twin() == edge4_1); + + BOOST_CHECK(edge1_1->prev() == edge4_2 && edge1_1->next() == edge4_2); + BOOST_CHECK(edge2_1->prev() == edge1_2 && edge2_1->next() == edge1_2); + BOOST_CHECK(edge3_1->prev() == edge2_2 && edge3_1->next() == edge2_2); + BOOST_CHECK(edge4_1->prev() == edge3_2 && edge4_1->next() == edge3_2); + + BOOST_CHECK(edge1_2->next() == edge2_1 && edge1_2->prev() == edge2_1); + BOOST_CHECK(edge2_2->next() == edge3_1 && edge2_2->prev() == edge3_1); + BOOST_CHECK(edge3_2->next() == edge4_1 && edge3_2->prev() == edge4_1); + BOOST_CHECK(edge4_2->next() == edge1_1 && edge4_2->prev() == edge1_1); + + BOOST_CHECK(edge1_1->rot_next() == edge4_1); + BOOST_CHECK(edge4_1->rot_next() == edge3_1); + BOOST_CHECK(edge3_1->rot_next() == edge2_1); + BOOST_CHECK(edge2_1->rot_next() == edge1_1); + + BOOST_CHECK(edge1_2->rot_next() == edge2_2); + BOOST_CHECK(edge2_2->rot_next() == edge3_2); + BOOST_CHECK(edge3_2->rot_next() == edge4_2); + BOOST_CHECK(edge4_2->rot_next() == edge1_2); +} + +#ifdef NDEBUG +BOOST_AUTO_TEST_CASE_TEMPLATE(grid_test, T, test_types) { + vd_type test_output_small, test_output_large; + std::vector< point_data > point_vec_small, point_vec_large; + int grid_size[] = {10, 33, 101}; + int max_value[] = {10, 33, 101}; + int array_length = sizeof(grid_size) / sizeof(int); + for (int k = 0; k < array_length; k++) { + test_output_small.clear(); + test_output_large.clear(); + point_vec_small.clear(); + point_vec_large.clear(); + int koef = (std::numeric_limits::max)() / max_value[k]; + for (int i = 0; i < grid_size[k]; i++) { + for (int j = 0; j < grid_size[k]; j++) { + point_vec_small.push_back(point_data(i, j)); + point_vec_large.push_back(point_data(koef * i, koef * j)); + } + } + construct_voronoi(point_vec_small.begin(), point_vec_small.end(), &test_output_small); + construct_voronoi(point_vec_large.begin(), point_vec_large.end(), &test_output_large); + VERIFY_OUTPUT(test_output_small); + VERIFY_OUTPUT(test_output_large); + unsigned int num_cells = grid_size[k] * grid_size[k]; + unsigned int num_vertices = num_cells - 2 * grid_size[k] + 1; + unsigned int num_edges = 4 * num_cells - 4 * grid_size[k]; + CHECK_OUTPUT_SIZE(test_output_small, num_cells, num_vertices, num_edges); + CHECK_OUTPUT_SIZE(test_output_large, num_cells, num_vertices, num_edges); + } +} +#endif + +#ifdef NDEBUG +BOOST_AUTO_TEST_CASE_TEMPLATE(random_test, T, test_types) { + boost::mt19937 gen(static_cast(time(NULL))); + vd_type test_output_small, test_output_large; + std::vector< point_data > point_vec_small, point_vec_large; + int num_points[] = {10, 100, 1000, 10000}; + int num_runs[] = {1000, 100, 10, 1}; + int mod_koef[] = {10, 100, 100, 1000}; + int max_value[] = {5, 50, 50, 5000}; + int array_length = sizeof(num_points) / sizeof(int); + for (int k = 0; k < array_length; k++) { + int koef = (std::numeric_limits::max)() / max_value[k]; + for (int i = 0; i < num_runs[k]; i++) { + test_output_small.clear(); + test_output_large.clear(); + point_vec_small.clear(); + point_vec_large.clear(); + for (int j = 0; j < num_points[k]; j++) { + T x = gen() % mod_koef[k] - mod_koef[k] / 2; + T y = gen() % mod_koef[k] - mod_koef[k] / 2; + point_vec_small.push_back(point_data(x, y)); + point_vec_large.push_back(point_data(koef * x, koef * y)); + } + construct_voronoi(point_vec_small.begin(), point_vec_small.end(), &test_output_small); + construct_voronoi(point_vec_large.begin(), point_vec_large.end(), &test_output_large); + VERIFY_OUTPUT(test_output_small); + VERIFY_OUTPUT(test_output_large); + BOOST_CHECK_EQUAL(test_output_small.num_cells(), test_output_large.num_cells()); + BOOST_CHECK_EQUAL(test_output_small.num_vertices(), test_output_large.num_vertices()); + BOOST_CHECK_EQUAL(test_output_small.num_edges(), test_output_large.num_edges()); + } + } +} +#endif + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_sites_test1, T, test_types) { + vd_type test_output; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(1, 1); + segments.push_back(segment_data(point1, point2)); + construct_voronoi(segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 3, 0, 4); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_sites_test2, T, test_types) { + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(4, 4); + point_data point3(3, 1); + point_data point4(1, 3); + segments.push_back(segment_data(point1, point2)); + points.push_back(point3); + points.push_back(point4); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 5, 4, 16); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_sites_test3, T, test_types) { + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + point_data point1(4, 0); + point_data point2(0, 4); + point_data point3(3, 3); + point_data point4(1, 1); + segments.push_back(segment_data(point1, point2)); + points.push_back(point3); + points.push_back(point4); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 5, 4, 16); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_sites_test4, T, test_types) { + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + point_data point1(4, 0); + point_data point2(0, 4); + point_data point3(3, 2); + point_data point4(2, 3); + segments.push_back(segment_data(point1, point2)); + points.push_back(point3); + points.push_back(point4); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 5, 3, 14); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_site_test5, T, test_types) { + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(0, 8); + point_data point3(-2, -2); + point_data point4(-2, 4); + point_data point5(-2, 10); + segments.push_back(segment_data(point1, point2)); + points.push_back(point3); + points.push_back(point4); + points.push_back(point5); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 6, 4, 18); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_site_test6, T, test_types) { + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + point_data point1(-1, 1); + point_data point2(1, 0); + point_data point3(1, 2); + segments.push_back(segment_data(point2, point3)); + points.push_back(point1); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 4, 2, 10); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_site_test7, T, test_types) { + vd_type test_output; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(4, 0); + point_data point3(0, 4); + point_data point4(4, 4); + segments.push_back(segment_data(point1, point2)); + segments.push_back(segment_data(point2, point3)); + segments.push_back(segment_data(point3, point4)); + construct_voronoi(segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 7, 6, 24); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_site_test8, T, test_types) { + vd_type test_output; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(4, 0); + point_data point3(4, 4); + point_data point4(0, 4); + segments.push_back(segment_data(point1, point2)); + segments.push_back(segment_data(point2, point3)); + segments.push_back(segment_data(point3, point4)); + segments.push_back(segment_data(point4, point1)); + construct_voronoi(segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 8, 5, 24); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_site_test9, T, test_types) { + vd_type test_output; + std::vector< segment_data > segments; + point_data point1(0, 0); + point_data point2(2, 0); + point_data point3(4, 0); + segments.push_back(segment_data(point1, point2)); + segments.push_back(segment_data(point2, point3)); + construct_voronoi(segments.begin(), segments.end(), &test_output); + CHECK_OUTPUT_SIZE(test_output, 5, 0, 8); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); +} + +#ifdef NDEBUG +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_grid_test, T, test_types) { + vd_type test_output_small, test_output_large; + std::vector< segment_data > segments_small, segments_large; + int grid_size[] = {10, 27, 53}; + int max_value[] = {100, 330, 1000}; + int array_length = sizeof(grid_size) / sizeof(int); + for (int k = 0; k < array_length; k++) { + test_output_small.clear(); + test_output_large.clear(); + segments_small.clear(); + segments_large.clear(); + int cur_sz = grid_size[k]; + int koef = (std::numeric_limits::max)() / max_value[k]; + for (int i = 0; i < cur_sz + 1; i++) + for (int j = 0; j < cur_sz; j++) { + point_data point1_1(10 * i, 10 * j); + point_data point1_2(koef * 10 * i, koef * 10 * j); + point_data point2_1(10 * i, 10 * j + 10); + point_data point2_2(koef * 10 * i, koef * (10 * j + 10)); + segments_small.push_back(segment_data(point1_1, point2_1)); + segments_large.push_back(segment_data(point1_2, point2_2)); + point_data point3_1(10 * j, 10 * i); + point_data point3_2(koef * 10 * j, koef * 10 * i); + point_data point4_1(10 * j + 10, 10 * i); + point_data point4_2(koef * (10 * j + 10), koef * 10 * i); + segments_small.push_back(segment_data(point3_1, point4_1)); + segments_large.push_back(segment_data(point3_2, point4_2)); + } + construct_voronoi(segments_small.begin(), segments_small.end(), &test_output_small); + construct_voronoi(segments_large.begin(), segments_large.end(), &test_output_large); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output_small); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output_large); + BOOST_CHECK_EQUAL(test_output_small.num_cells(), test_output_large.num_cells()); + BOOST_CHECK_EQUAL(test_output_small.num_vertices(), test_output_large.num_vertices()); + BOOST_CHECK_EQUAL(test_output_small.num_edges(), test_output_large.num_edges()); + } +} +#endif + +#ifdef NDEBUG +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_random_test1, T, test_types) { + boost::mt19937 gen(static_cast(time(NULL))); + vd_type test_output; + std::vector< point_data > points; + std::vector< segment_data > segments; + int num_runs = 1000; + int num_segments = 10; + points.push_back(point_data(-100, -100)); + points.push_back(point_data(-100, 100)); + points.push_back(point_data(100, -100)); + points.push_back(point_data(100, 100)); + for (int i = 0; i < num_runs; i++) { + test_output.clear(); + segments.clear(); + for (int j = 0; j < num_segments; j++) { + T x1 = 0, y1 = 0, x2 = 0, y2 = 0; + while (x1 == x2 && y1 == y2) { + x1 = (gen() % 100) - 50; + y1 = (gen() % 100) - 50; + x2 = (gen() % 100) - 50; + y2 = (gen() % 100) - 50; + } + point_data point1(x1, y1); + point_data point2(x2, y2); + segments.push_back(segment_data(point1, point2)); + } + voronoi_test_helper::clean_segment_set(segments); + construct_voronoi(points.begin(), points.end(), segments.begin(), segments.end(), &test_output); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output); + } +} +#endif + +#ifdef NDEBUG +BOOST_AUTO_TEST_CASE_TEMPLATE(segment_random_test2, T, test_types) { + boost::mt19937 gen(static_cast(time(NULL))); + vd_type test_output_small, test_output_large; + std::vector< segment_data > segments_small, segments_large; + int num_segments[] = {5, 25, 125, 625}; + int num_runs[] = {1000, 100, 10, 1}; + int mod_koef1[] = {10, 100, 200, 300}; + int mod_koef2[] = {10, 20, 50, 100}; + int max_value[] = {10, 60, 125, 200}; + int array_length = sizeof(num_segments) / sizeof(int); + for (int k = 0; k < array_length; k++) { + int koef = (std::numeric_limits::max)() / max_value[k]; + for (int i = 0; i < num_runs[k]; i++) { + test_output_small.clear(); + test_output_large.clear(); + segments_small.clear(); + segments_large.clear(); + for (int j = 0; j < num_segments[k]; j++) { + T x1 = (gen() % mod_koef1[k]) - mod_koef1[k] / 2; + T y1 = (gen() % mod_koef1[k]) - mod_koef1[k] / 2; + T dx = 0, dy = 0; + while (dx == 0 && dy == 0) { + dx = (gen() % mod_koef2[k]) - mod_koef2[k] / 2; + dy = (gen() % mod_koef2[k]) - mod_koef2[k] / 2; + } + T x2 = x1 + dx; + T y2 = y1 + dy; + point_data point1_small(x1, y1); + point_data point2_small(x2, y2); + segments_small.push_back(segment_data(point1_small, point2_small)); + } + voronoi_test_helper::clean_segment_set(segments_small); + for (typename std::vector< segment_data >::iterator it = segments_small.begin(); + it != segments_small.end(); ++it) { + T x1 = it->low().x() * koef; + T y1 = it->low().y() * koef; + T x2 = it->high().x() * koef; + T y2 = it->high().y() * koef; + point_data point1_large(x1, y1); + point_data point2_large(x2, y2); + segments_large.push_back(segment_data(point1_large, point2_large)); + } + construct_voronoi(segments_small.begin(), segments_small.end(), &test_output_small); + construct_voronoi(segments_large.begin(), segments_large.end(), &test_output_large); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output_small); + VERIFY_NO_HALF_EDGE_INTERSECTIONS(test_output_large); + BOOST_CHECK_EQUAL(test_output_small.num_cells(), test_output_large.num_cells()); + BOOST_CHECK_EQUAL(test_output_small.num_vertices(), test_output_large.num_vertices()); + BOOST_CHECK_EQUAL(test_output_small.num_edges(), test_output_large.num_edges()); + } + } +} +#endif diff --git a/test/voronoi_ctypes_test.cpp b/test/voronoi_ctypes_test.cpp new file mode 100644 index 0000000..064f121 --- /dev/null +++ b/test/voronoi_ctypes_test.cpp @@ -0,0 +1,295 @@ +// Boost.Polygon library voronoi_ctypes_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#define BOOST_TEST_MODULE voronoi_ctypes_test +#include +#include +#include + +#include +using namespace boost::polygon::detail; + +type_converter_fpt to_fpt; + +BOOST_AUTO_TEST_CASE(ulp_comparison_test1) { + ulp_comparison ulp_cmp; + uint64 a = 22; + uint64 b = 27; + fpt64 da, db; + std::memcpy(&da, &a, sizeof(uint64)); + std::memcpy(&db, &b, sizeof(uint64)); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 1), ulp_cmp.LESS); + BOOST_CHECK_EQUAL(ulp_cmp(db, da, 1), ulp_cmp.MORE); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 4), ulp_cmp.LESS); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 5), ulp_cmp.EQUAL); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 6), ulp_cmp.EQUAL); +} + +BOOST_AUTO_TEST_CASE(ulp_comparison_test2) { + ulp_comparison ulp_cmp; + uint64 a = 0ULL; + uint64 b = 0x8000000000000002ULL; + fpt64 da, db; + std::memcpy(&da, &a, sizeof(uint64)); + std::memcpy(&db, &b, sizeof(uint64)); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 1), ulp_cmp.MORE); + BOOST_CHECK_EQUAL(ulp_cmp(db, da, 1), ulp_cmp.LESS); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 2), ulp_cmp.EQUAL); + BOOST_CHECK_EQUAL(ulp_cmp(da, db, 3), ulp_cmp.EQUAL); +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test1) { + boost::mt19937_64 gen(static_cast(time(NULL))); + fpt64 b = 0.0; + efpt64 eeb(b); + for (int i = 0; i < 1000; ++i) { + fpt64 a = to_fpt(static_cast(gen())); + efpt64 eea(a); + efpt64 neg = -eea; + efpt64 sum = eea + eeb; + efpt64 dif = eea - eeb; + efpt64 mul = eea * eeb; + BOOST_CHECK_EQUAL(to_fpt(neg), -a); + BOOST_CHECK_EQUAL(to_fpt(sum), a + b); + BOOST_CHECK_EQUAL(to_fpt(dif), a - b); + BOOST_CHECK_EQUAL(to_fpt(mul), a * b); + } +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test2) { + boost::mt19937_64 gen(static_cast(time(NULL))); + fpt64 a = 0.0; + efpt64 eea(a); + for (int i = 0; i < 1000; ++i) { + fpt64 b = to_fpt(static_cast(gen())); + if (b == 0.0) + continue; + efpt64 eeb(b); + efpt64 neg = -eea; + efpt64 sum = eea + eeb; + efpt64 dif = eea - eeb; + efpt64 mul = eea * eeb; + efpt64 div = eea / eeb; + BOOST_CHECK_EQUAL(to_fpt(neg), -a); + BOOST_CHECK_EQUAL(to_fpt(sum), a + b); + BOOST_CHECK_EQUAL(to_fpt(dif), a - b); + BOOST_CHECK_EQUAL(to_fpt(mul), a * b); + BOOST_CHECK_EQUAL(to_fpt(div), a / b); + } +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test3) { + boost::mt19937_64 gen(static_cast(time(NULL))); + for (int i = 0; i < 1000; ++i) { + fpt64 a = to_fpt(static_cast(gen())); + fpt64 b = to_fpt(static_cast(gen())); + if (b == 0.0) + continue; + efpt64 eea(a); + efpt64 eeb(b); + efpt64 neg = -eea; + efpt64 sum = eea + eeb; + efpt64 dif = eea - eeb; + efpt64 mul = eea * eeb; + efpt64 div = eea / eeb; + BOOST_CHECK_EQUAL(to_fpt(neg), -a); + BOOST_CHECK_EQUAL(to_fpt(sum), a + b); + BOOST_CHECK_EQUAL(to_fpt(dif), a - b); + BOOST_CHECK_EQUAL(to_fpt(mul), a * b); + BOOST_CHECK_EQUAL(to_fpt(div), a / b); + } +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test4) { + for (int exp = 0; exp < 64; ++exp) + for (int i = 1; i < 100; ++i) { + fpt64 a = i; + fpt64 b = to_fpt(1LL << exp); + efpt64 eea(a); + efpt64 eeb(b); + efpt64 neg = -eea; + efpt64 sum = eea + eeb; + efpt64 dif = eea - eeb; + efpt64 mul = eea * eeb; + efpt64 div = eea / eeb; + BOOST_CHECK_EQUAL(to_fpt(neg), -a); + BOOST_CHECK_EQUAL(to_fpt(sum), a + b); + BOOST_CHECK_EQUAL(to_fpt(dif), a - b); + BOOST_CHECK_EQUAL(to_fpt(mul), a * b); + BOOST_CHECK_EQUAL(to_fpt(div), a / b); + } +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test5) { + for (int i = 0; i < 100; ++i) { + efpt64 a(to_fpt(i * i)); + efpt64 b = a.sqrt(); + BOOST_CHECK_EQUAL(to_fpt(b), to_fpt(i)); + } +} + +BOOST_AUTO_TEST_CASE(extended_exponent_fpt_test6) { + for (int i = -10; i <= 10; ++i) { + efpt64 a(to_fpt(i)); + BOOST_CHECK_EQUAL(is_pos(a), i > 0); + BOOST_CHECK_EQUAL(is_neg(a), i < 0); + BOOST_CHECK_EQUAL(is_zero(a), !i); + } +} + +BOOST_AUTO_TEST_CASE(extended_int_test1) { + typedef extended_int<1> eint32; + eint32 e1(0), e2(32), e3(-32); + BOOST_CHECK_EQUAL(e1.count(), 0); + BOOST_CHECK_EQUAL(e1.size(), 0U); + BOOST_CHECK_EQUAL(e2.count(), 1); + BOOST_CHECK_EQUAL(e2.chunks()[0], 32U); + BOOST_CHECK_EQUAL(e2.size(), 1U); + BOOST_CHECK_EQUAL(e3.count(), -1); + BOOST_CHECK_EQUAL(e3.chunks()[0], 32U); + BOOST_CHECK_EQUAL(e3.size(), 1U); +} + +BOOST_AUTO_TEST_CASE(extended_int_test2) { + typedef extended_int<2> eint64; + int64 val64 = 0x7fffffffffffffffLL; + eint64 e1(0), e2(32), e3(-32), e4(val64), e5(-val64); + BOOST_CHECK_EQUAL(e1.count(), 0); + BOOST_CHECK_EQUAL(e2.count(), 1); + BOOST_CHECK_EQUAL(e2.chunks()[0], 32U); + BOOST_CHECK_EQUAL(e3.count(), -1); + BOOST_CHECK_EQUAL(e3.chunks()[0], 32U); + BOOST_CHECK_EQUAL(e4.count(), 2); + BOOST_CHECK_EQUAL(e4.chunks()[0], 0xffffffff); + BOOST_CHECK_EQUAL(e4.chunks()[1], val64 >> 32); + BOOST_CHECK_EQUAL(e5.count(), -2); + BOOST_CHECK_EQUAL(e5.chunks()[0], 0xffffffff); + BOOST_CHECK_EQUAL(e5.chunks()[1], val64 >> 32); +} + +BOOST_AUTO_TEST_CASE(extended_int_test3) { + typedef extended_int<2> eint64; + std::vector chunks; + chunks.push_back(1); + chunks.push_back(2); + eint64 e1(chunks, true), e2(chunks, false); + BOOST_CHECK_EQUAL(e1.count(), 2); + BOOST_CHECK_EQUAL(e1.chunks()[0], 2U); + BOOST_CHECK_EQUAL(e1.chunks()[1], 1U); + BOOST_CHECK_EQUAL(e2.count(), -2); + BOOST_CHECK_EQUAL(e2.chunks()[0], 2U); + BOOST_CHECK_EQUAL(e2.chunks()[1], 1U); +} + +BOOST_AUTO_TEST_CASE(extended_int_test4) { + typedef extended_int<2> eint64; + std::vector chunks; + chunks.push_back(1); + chunks.push_back(2); + eint64 e1(chunks, true), e2(chunks, false); + BOOST_CHECK_EQUAL(e1 == e2, false); + BOOST_CHECK_EQUAL(e1 == -e2, true); + BOOST_CHECK_EQUAL(e1 != e2, true); + BOOST_CHECK_EQUAL(e1 != -e2, false); + BOOST_CHECK_EQUAL(e1 < e2, false); + BOOST_CHECK_EQUAL(e1 < -e2, false); + BOOST_CHECK_EQUAL(e1 <= e2, false); + BOOST_CHECK_EQUAL(e1 <= -e2, true); + BOOST_CHECK_EQUAL(e1 > e2, true); + BOOST_CHECK_EQUAL(e1 > -e2, false); + BOOST_CHECK_EQUAL(e1 >= e2, true); + BOOST_CHECK_EQUAL(e1 >= -e2, true); +} + +BOOST_AUTO_TEST_CASE(extended_int_test5) { + typedef extended_int<2> eint64; + boost::mt19937_64 gen(static_cast(time(NULL))); + for (int i = 0; i < 1000; ++i) { + int64 i1 = static_cast(gen()); + int64 i2 = static_cast(gen()); + eint64 e1(i1), e2(i2); + BOOST_CHECK_EQUAL(e1 == e2, i1 == i2); + BOOST_CHECK_EQUAL(e1 != e2, i1 != i2); + BOOST_CHECK_EQUAL(e1 > e2, i1 > i2); + BOOST_CHECK_EQUAL(e1 >= e2, i1 >= i2); + BOOST_CHECK_EQUAL(e1 < e2, i1 < i2); + BOOST_CHECK_EQUAL(e1 <= e2, i1 <= i2); + } +} + +BOOST_AUTO_TEST_CASE(extended_int_test6) { + typedef extended_int<1> eint32; + eint32 e1(32); + eint32 e2 = -e1; + BOOST_CHECK_EQUAL(e2.count(), -1); + BOOST_CHECK_EQUAL(e2.size(), 1U); + BOOST_CHECK_EQUAL(e2.chunks()[0], 32U); +} + +BOOST_AUTO_TEST_CASE(extended_int_test7) { + typedef extended_int<2> eint64; + boost::mt19937_64 gen(static_cast(time(NULL))); + for (int i = 0; i < 1000; ++i) { + int64 i1 = static_cast(gen()) >> 2; + int64 i2 = static_cast(gen()) >> 2; + eint64 e1(i1), e2(i2), e3(i1 + i2), e4(i1 - i2); + BOOST_CHECK(e1 + e2 == e3); + BOOST_CHECK(e1 - e2 == e4); + } +} + +BOOST_AUTO_TEST_CASE(extended_int_test8) { + typedef extended_int<2> eint64; + boost::mt19937 gen(static_cast(time(NULL))); + for (int i = 0; i < 1000; ++i) { + int64 i1 = static_cast(gen()); + int64 i2 = static_cast(gen()); + eint64 e1(i1), e2(i2), e3(i1 * i2); + BOOST_CHECK(e1 * e2 == e3); + } +} + +BOOST_AUTO_TEST_CASE(exnteded_int_test9) { + typedef extended_int<1> eint32; + for (int i = -10; i <= 10; ++i) { + for (int j = -10; j <= 10; ++j) { + eint32 e1(i), e2(j), e3(i+j), e4(i-j), e5(i*j); + BOOST_CHECK(e1 + e2 == e3); + BOOST_CHECK(e1 - e2 == e4); + BOOST_CHECK(e1 * e2 == e5); + } + } +} + +BOOST_AUTO_TEST_CASE(extended_int_test10) { + typedef extended_int<2> eint64; + boost::mt19937_64 gen(static_cast(time(NULL))); + for (int i = 0; i < 100; ++i) { + int64 i1 = static_cast(gen()) >> 20; + int64 i2 = i1 >> 32; + eint64 e1(i1), e2(i2); + BOOST_CHECK(to_fpt(e1) == static_cast(i1)); + BOOST_CHECK(to_fpt(e2) == static_cast(i2)); + } +} + +BOOST_AUTO_TEST_CASE(extened_int_test11) { + typedef extended_int<1> eint32; + typedef extended_int<64> eint2048; + eint2048 two(2), value(1); + for (int i = 0; i < 1024; ++i) + value = value * two; + BOOST_CHECK_EQUAL(value.count(), 33); + for (std::size_t i = 1; i < value.size(); ++i) + BOOST_CHECK_EQUAL(value.chunks()[i-1], 0U); + BOOST_CHECK_EQUAL(value.chunks()[32], 1U); +} diff --git a/test/voronoi_diagram_test.cpp b/test/voronoi_diagram_test.cpp new file mode 100644 index 0000000..4e77d4c --- /dev/null +++ b/test/voronoi_diagram_test.cpp @@ -0,0 +1,113 @@ +// Boost.Polygon library voronoi_diagram_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#define BOOST_TEST_MODULE voronoi_diagram_test +#include + +#include +#include +using namespace boost::polygon; + +typedef voronoi_cell voronoi_cell_type; +typedef voronoi_vertex voronoi_vertex_type; +typedef voronoi_edge voronoi_edge_type; +typedef voronoi_diagram voronoi_diagram_type; + +BOOST_AUTO_TEST_CASE(voronoi_cell_test) { + voronoi_cell_type cell(1, SOURCE_CATEGORY_INITIAL_SEGMENT); + cell.color(27); + BOOST_CHECK(!cell.contains_point()); + BOOST_CHECK(cell.contains_segment()); + BOOST_CHECK(cell.is_degenerate()); + BOOST_CHECK(cell.source_index() == 1); + BOOST_CHECK(cell.source_category() == SOURCE_CATEGORY_INITIAL_SEGMENT); + BOOST_CHECK(cell.incident_edge() == NULL); + BOOST_CHECK(cell.color() == 27); + + voronoi_edge_type edge(true, true); + cell.incident_edge(&edge); + BOOST_CHECK(!cell.is_degenerate()); + BOOST_CHECK(cell.incident_edge() == &edge); +} + +BOOST_AUTO_TEST_CASE(voronoi_vertex_test) { + voronoi_vertex_type vertex(1, 2); + vertex.color(27); + BOOST_CHECK(vertex.is_degenerate()); + BOOST_CHECK(vertex.x() == 1); + BOOST_CHECK(vertex.y() == 2); + BOOST_CHECK(vertex.incident_edge() == NULL); + BOOST_CHECK(vertex.color() == 27); + + voronoi_edge_type edge(true, true); + vertex.incident_edge(&edge); + BOOST_CHECK(!vertex.is_degenerate()); + BOOST_CHECK(vertex.incident_edge() == &edge); +} + +BOOST_AUTO_TEST_CASE(voronoi_edge_test) { + voronoi_edge_type edge1(false, false); + edge1.color(13); + BOOST_CHECK(!edge1.is_primary()); + BOOST_CHECK(edge1.is_secondary()); + BOOST_CHECK(!edge1.is_linear()); + BOOST_CHECK(edge1.is_curved()); + BOOST_CHECK(!edge1.is_finite()); + BOOST_CHECK(edge1.is_infinite()); + BOOST_CHECK(edge1.color() == 13); + + voronoi_edge_type edge2(true, true); + edge2.color(14); + BOOST_CHECK(edge2.is_primary()); + BOOST_CHECK(!edge2.is_secondary()); + BOOST_CHECK(edge2.is_linear()); + BOOST_CHECK(!edge2.is_curved()); + BOOST_CHECK(!edge2.is_finite()); + BOOST_CHECK(edge2.is_infinite()); + BOOST_CHECK(edge2.color() == 14); + + edge1.twin(&edge2); + edge2.twin(&edge1); + BOOST_CHECK(edge1.twin() == &edge2); + BOOST_CHECK(edge2.twin() == &edge1); + + edge1.next(&edge2); + edge1.prev(&edge2); + edge2.next(&edge1); + edge2.prev(&edge1); + BOOST_CHECK(edge1.next() == &edge2); + BOOST_CHECK(edge1.prev() == &edge2); + BOOST_CHECK(edge1.rot_next() == &edge1); + BOOST_CHECK(edge1.rot_prev() == &edge1); + + voronoi_cell_type cell(1, SOURCE_CATEGORY_INITIAL_SEGMENT); + edge1.cell(&cell); + BOOST_CHECK(edge1.cell() == &cell); + + voronoi_vertex_type vertex0(1, 2); + edge1.vertex0(&vertex0); + BOOST_CHECK(edge1.vertex0() == &vertex0); + BOOST_CHECK(edge2.vertex1() == &vertex0); + + voronoi_vertex_type vertex1(2, 1); + edge2.vertex0(&vertex1); + BOOST_CHECK(edge1.vertex1() == &vertex1); + BOOST_CHECK(edge2.vertex0() == &vertex1); + + BOOST_CHECK(edge1.is_finite()); + BOOST_CHECK(edge2.is_finite()); +} + +BOOST_AUTO_TEST_CASE(voronoi_diagram_test) { + voronoi_diagram_type vd; + BOOST_CHECK(vd.num_cells() == 0); + BOOST_CHECK(vd.num_vertices() == 0); + BOOST_CHECK(vd.num_edges() == 0); + vd.clear(); +} diff --git a/test/voronoi_geometry_type_test.cpp b/test/voronoi_geometry_type_test.cpp new file mode 100644 index 0000000..a46ecc7 --- /dev/null +++ b/test/voronoi_geometry_type_test.cpp @@ -0,0 +1,28 @@ +// Boost.Polygon library voronoi_geometry_type_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#define BOOST_TEST_MODULE voronoi_geometry_type_test + +#include +#include +using namespace boost::polygon; + +BOOST_AUTO_TEST_CASE(source_category_test1) { + BOOST_CHECK(belongs(SOURCE_CATEGORY_SINGLE_POINT, GEOMETRY_CATEGORY_POINT)); + BOOST_CHECK(belongs(SOURCE_CATEGORY_SEGMENT_START_POINT, GEOMETRY_CATEGORY_POINT)); + BOOST_CHECK(belongs(SOURCE_CATEGORY_SEGMENT_END_POINT, GEOMETRY_CATEGORY_POINT)); + BOOST_CHECK(!belongs(SOURCE_CATEGORY_INITIAL_SEGMENT, GEOMETRY_CATEGORY_POINT)); + BOOST_CHECK(!belongs(SOURCE_CATEGORY_REVERSE_SEGMENT, GEOMETRY_CATEGORY_POINT)); + + BOOST_CHECK(!belongs(SOURCE_CATEGORY_SINGLE_POINT, GEOMETRY_CATEGORY_SEGMENT)); + BOOST_CHECK(!belongs(SOURCE_CATEGORY_SEGMENT_START_POINT, GEOMETRY_CATEGORY_SEGMENT)); + BOOST_CHECK(!belongs(SOURCE_CATEGORY_SEGMENT_END_POINT, GEOMETRY_CATEGORY_SEGMENT)); + BOOST_CHECK(belongs(SOURCE_CATEGORY_INITIAL_SEGMENT, GEOMETRY_CATEGORY_SEGMENT)); + BOOST_CHECK(belongs(SOURCE_CATEGORY_REVERSE_SEGMENT, GEOMETRY_CATEGORY_SEGMENT)); +} diff --git a/test/voronoi_predicates_test.cpp b/test/voronoi_predicates_test.cpp new file mode 100644 index 0000000..cef75bd --- /dev/null +++ b/test/voronoi_predicates_test.cpp @@ -0,0 +1,463 @@ +// Boost.Polygon library voronoi_predicates_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#define BOOST_TEST_MODULE voronoi_predicates_test +#include + +#include +#include +#include +using namespace boost::polygon::detail; + +#include +using namespace boost::polygon; + +ulp_comparison ulp_cmp; + +typedef voronoi_predicates< voronoi_ctype_traits > VP; +typedef point_2d point_type; +typedef site_event site_type; +typedef circle_event circle_type; +VP::event_comparison_predicate event_comparison; + +typedef beach_line_node_key key_type; +typedef VP::distance_predicate distance_predicate_type; +typedef VP::node_comparison_predicate node_comparison_type; +typedef std::map beach_line_type; +typedef beach_line_type::iterator bieach_line_iterator; +distance_predicate_type distance_predicate; +node_comparison_type node_comparison; + +typedef VP::circle_existence_predicate CEP_type; +typedef VP::mp_circle_formation_functor MP_CFF_type; +typedef VP::lazy_circle_formation_functor lazy_CFF_type; +VP::circle_formation_predicate mp_predicate; +VP::circle_formation_predicate lazy_predicate; + +#define CHECK_ORIENTATION(P1, P2, P3, R1, R2) \ + BOOST_CHECK_EQUAL(VP::ot::eval(P1, P2, P3) == R1, true); \ + BOOST_CHECK_EQUAL(VP::ot::eval(P1, P3, P2) == R2, true); \ + BOOST_CHECK_EQUAL(VP::ot::eval(P2, P1, P3) == R2, true); \ + BOOST_CHECK_EQUAL(VP::ot::eval(P2, P3, P1) == R1, true); \ + BOOST_CHECK_EQUAL(VP::ot::eval(P3, P1, P2) == R1, true); \ + BOOST_CHECK_EQUAL(VP::ot::eval(P3, P2, P1) == R2, true) + +#define CHECK_EVENT_COMPARISON(A, B, R1, R2) \ + BOOST_CHECK_EQUAL(event_comparison(A, B), R1); \ + BOOST_CHECK_EQUAL(event_comparison(B, A), R2) + +#define CHECK_DISTANCE_PREDICATE(S1, S2, S3, RES) \ + BOOST_CHECK_EQUAL(distance_predicate(S1, S2, S3), RES) + +#define CHECK_NODE_COMPARISON(node, nodes, res, sz) \ + for (int i = 0; i < sz; ++i) { \ + BOOST_CHECK_EQUAL(node_comparison(node, nodes[i]), res[i]); \ + BOOST_CHECK_EQUAL(node_comparison(nodes[i], node), !res[i]); \ + } + +#define CHECK_CIRCLE(circle, c_x, c_y, l_x) \ + BOOST_CHECK_EQUAL(ulp_cmp(c1.x(), c_x, 10), ulp_comparison::EQUAL); \ + BOOST_CHECK_EQUAL(ulp_cmp(c1.y(), c_y, 10), ulp_comparison::EQUAL); \ + BOOST_CHECK_EQUAL(ulp_cmp(c1.lower_x(), l_x, 10), ulp_comparison::EQUAL) + +#define CHECK_CIRCLE_EXISTENCE(s1, s2, s3, RES) \ + { circle_type c1; \ + BOOST_CHECK_EQUAL(lazy_predicate(s1, s2, s3, c1), RES); } + +#define CHECK_CIRCLE_FORMATION_PREDICATE(s1, s2, s3, c_x, c_y, l_x) \ + { circle_type c1, c2; \ + BOOST_CHECK_EQUAL(mp_predicate(s1, s2, s3, c1), true); \ + BOOST_CHECK_EQUAL(lazy_predicate(s1, s2, s3, c2), true); \ + CHECK_CIRCLE(c1, c_x, c_y, l_x); \ + CHECK_CIRCLE(c2, c_x, c_y, l_x); } + +BOOST_AUTO_TEST_CASE(orientation_test) { + int min_int = (std::numeric_limits::min)(); + int max_int = (std::numeric_limits::max)(); + point_type point1(min_int, min_int); + point_type point2(0, 0); + point_type point3(max_int, max_int); + point_type point4(min_int, max_int); + point_type point5(max_int-1, max_int); + CHECK_ORIENTATION(point1, point2, point3, VP::ot::COLLINEAR, VP::ot::COLLINEAR); + CHECK_ORIENTATION(point1, point4, point3, VP::ot::RIGHT, VP::ot::LEFT); + CHECK_ORIENTATION(point1, point5, point3, VP::ot::RIGHT, VP::ot::LEFT); +} + +BOOST_AUTO_TEST_CASE(event_comparison_test1) { + site_type site(1, 2); + CHECK_EVENT_COMPARISON(site, site_type(0, 2), false, true); + CHECK_EVENT_COMPARISON(site, site_type(1, 3), true, false); + CHECK_EVENT_COMPARISON(site, site_type(1, 2), false, false); +} + +BOOST_AUTO_TEST_CASE(event_comparison_test2) { + site_type site(0, 0, 0, 2); + CHECK_EVENT_COMPARISON(site, site_type(0, 2), true, false); + CHECK_EVENT_COMPARISON(site, site_type(0, 0), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, -2, 0, -1), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, -2, 1, 1), true, false); + CHECK_EVENT_COMPARISON(site, site_type(0, 0, 1, 1), true, false); +} + +BOOST_AUTO_TEST_CASE(event_comparison_test3) { + site_type site(0, 0, 10, 10); + CHECK_EVENT_COMPARISON(site, site_type(0, 0), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, -1), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, 1), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, 1, 0, 10), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, -10, 0, -1), false, true); + CHECK_EVENT_COMPARISON(site, site_type(0, 0, 10, 9), true, false); + CHECK_EVENT_COMPARISON(site, site_type(0, 0, 9, 10), false, true); +} + +BOOST_AUTO_TEST_CASE(event_comparison_test4) { + circle_type circle(1, 2, 3); + CHECK_EVENT_COMPARISON(circle, circle_type(1, 2, 3), false, false); + CHECK_EVENT_COMPARISON(circle, circle_type(1, 3, 3), true, false); + CHECK_EVENT_COMPARISON(circle, circle_type(1, 2, 4), true, false); + CHECK_EVENT_COMPARISON(circle, circle_type(0, 2, 2), false, true); + CHECK_EVENT_COMPARISON(circle, circle_type(-1, 2, 3), false, false); +} + +BOOST_AUTO_TEST_CASE(event_comparison_test5) { + circle_type circle(1, 2, 3); + CHECK_EVENT_COMPARISON(circle, site_type(0, 100), false, true); + CHECK_EVENT_COMPARISON(circle, site_type(3, 0), false, true); + CHECK_EVENT_COMPARISON(circle, site_type(3, 2), false, false); + CHECK_EVENT_COMPARISON(circle, site_type(3, 3), true, false); + CHECK_EVENT_COMPARISON(circle, site_type(4, 2), true, false); +} + +BOOST_AUTO_TEST_CASE(distance_predicate_test1) { + site_type site1(-5, 0); + site_type site2(-8, 9); + site_type site3(-2, 1); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 6), true); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 6), true); +} + +BOOST_AUTO_TEST_CASE(distance_predicate_test2) { + site_type site1(-4, 0, -4, 20); + site_type site2(-2, 10); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 11), false); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 9), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 11), true); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 9), true); +} + +BOOST_AUTO_TEST_CASE(disntace_predicate_test3) { + site_type site1(-5, 5, 2, -2); + site1.inverse(); + site_type site2(-2, 4); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -1), false); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -1), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 4), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 5), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 5), false); +} + +BOOST_AUTO_TEST_CASE(distance_predicate_test4) { + site_type site1(-5, 5, 2, -2); + site_type site2(-2, -4); + site_type site3(-4, 1); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -2), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -2), true); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -8), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -8), true); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -9), true); + CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -9), true); + CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -9), false); +} + +BOOST_AUTO_TEST_CASE(disntace_predicate_test5) { + site_type site1(-5, 5, 2, -2); + site_type site2 = site1; + site2.inverse(); + site_type site3(-2, 4); + site_type site4(-2, -4); + site_type site5(-4, 1); + CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 7), true); + CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -18), false); + CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -18), false); + CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -1), true); + CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -1), true); +} + +BOOST_AUTO_TEST_CASE(distance_predicate_test6) { + site_type site1(-5, 0, 2, 7); + site_type site2 = site1; + site2.inverse(); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(2, 7), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(1, 5), false); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(-1, 5), true); +} + +BOOST_AUTO_TEST_CASE(distance_predicate_test7) { + site_type site1(-5, 5, 2, -2); + site1.inverse(); + site_type site2(-5, 5, 0, 6); + site_type site3(-2, 4, 0, 4); + site_type site4(0, 2); + site_type site5(0, 5); + site_type site6(0, 6); + site_type site7(0, 8); + CHECK_DISTANCE_PREDICATE(site1, site2, site4, false); + CHECK_DISTANCE_PREDICATE(site1, site2, site5, true); + CHECK_DISTANCE_PREDICATE(site1, site2, site6, true); + CHECK_DISTANCE_PREDICATE(site1, site2, site7, true); + CHECK_DISTANCE_PREDICATE(site1, site3, site4, false); + CHECK_DISTANCE_PREDICATE(site1, site3, site5, true); + CHECK_DISTANCE_PREDICATE(site1, site3, site6, true); + CHECK_DISTANCE_PREDICATE(site1, site3, site7, true); + site3.inverse(); + CHECK_DISTANCE_PREDICATE(site3, site1, site4, false); + CHECK_DISTANCE_PREDICATE(site3, site1, site5, false); + CHECK_DISTANCE_PREDICATE(site3, site1, site6, false); + CHECK_DISTANCE_PREDICATE(site3, site1, site7, true); +} + +BOOST_AUTO_TEST_CASE(distatnce_predicate_test8) { + site_type site1(-5, 3, -2, 2); + site1.inverse(); + site_type site2(-5, 5, -2, 2); + CHECK_DISTANCE_PREDICATE(site1, site2, site_type(-4, 2), false); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test1) { + beach_line_type beach_line; + site_type site1(0, 0); + site1.sorted_index(0); + site_type site2(0, 2); + site2.sorted_index(1); + site_type site3(1, 0); + site3.sorted_index(2); + beach_line[key_type(site1, site2)] = 2; + beach_line[key_type(site1, site3)] = 0; + beach_line[key_type(site3, site1)] = 1; + int cur_index = 0; + for (bieach_line_iterator it = beach_line.begin(); + it != beach_line.end(); ++it, ++cur_index) { + BOOST_CHECK_EQUAL(it->second, cur_index); + } +} + +BOOST_AUTO_TEST_CASE(node_comparison_test2) { + beach_line_type beach_line; + site_type site1(0, 1); + site1.sorted_index(0); + site_type site2(2, 0); + site2.sorted_index(1); + site_type site3(2, 4); + site3.sorted_index(2); + beach_line[key_type(site1, site2)] = 0; + beach_line[key_type(site2, site1)] = 1; + beach_line[key_type(site1, site3)] = 2; + beach_line[key_type(site3, site1)] = 3; + int cur_index = 0; + for (bieach_line_iterator it = beach_line.begin(); + it != beach_line.end(); ++it, ++cur_index) { + BOOST_CHECK_EQUAL(it->second, cur_index); + } +} + +BOOST_AUTO_TEST_CASE(node_comparison_test3) { + key_type node(site_type(1, 0).sorted_index(1), site_type(0, 2).sorted_index(0)); + key_type nodes[] = { + key_type(site_type(2, -10).sorted_index(2)), + key_type(site_type(2, -1).sorted_index(2)), + key_type(site_type(2, 0).sorted_index(2)), + key_type(site_type(2, 1).sorted_index(2)), + key_type(site_type(2, 2).sorted_index(2)), + key_type(site_type(2, 3).sorted_index(2)), + }; + bool res[] = {false, false, false, false, true, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 6); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test4) { + key_type node(site_type(0, 1).sorted_index(0), site_type(1, 0).sorted_index(1)); + key_type nodes[] = { + key_type(site_type(2, -3).sorted_index(2)), + key_type(site_type(2, -2).sorted_index(2)), + key_type(site_type(2, -1).sorted_index(2)), + key_type(site_type(2, 0).sorted_index(2)), + key_type(site_type(2, 1).sorted_index(2)), + key_type(site_type(2, 3).sorted_index(2)), + }; + bool res[] = {false, true, true, true, true, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 6); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test5) { + key_type node(site_type(0, 0).sorted_index(0), site_type(1, 2).sorted_index(1)); + key_type nodes[] = { + key_type(site_type(2, -10).sorted_index(2)), + key_type(site_type(2, 0).sorted_index(2)), + key_type(site_type(2, 1).sorted_index(2)), + key_type(site_type(2, 2).sorted_index(2)), + key_type(site_type(2, 5).sorted_index(2)), + key_type(site_type(2, 20).sorted_index(2)), + }; + bool res[] = {false, false, true, true, true, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 6); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test6) { + key_type node(site_type(1, 1).sorted_index(1), site_type(0, 0).sorted_index(0)); + key_type nodes[] = { + key_type(site_type(2, -3).sorted_index(2)), + key_type(site_type(2, -2).sorted_index(2)), + key_type(site_type(2, 0).sorted_index(2)), + key_type(site_type(2, 1).sorted_index(2)), + key_type(site_type(2, 2).sorted_index(2)), + key_type(site_type(2, 3).sorted_index(2)), + key_type(site_type(2, 5).sorted_index(2)), + }; + bool res[] = {false, false, false, false, false, false, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 7); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test7) { + key_type node(site_type(0, 0).sorted_index(0), site_type(0, 2).sorted_index(1)); + key_type nodes[] = { + key_type(site_type(1, 0).sorted_index(2)), + key_type(site_type(1, 1).sorted_index(2)), + key_type(site_type(1, 2).sorted_index(2)), + }; + bool res[] = {false, false, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 3); +} + +BOOST_AUTO_TEST_CASE(node_comparison_test8) { + key_type node(site_type(0, 0).sorted_index(0), site_type(1, 1).sorted_index(2)); + key_type nodes[] = { + key_type(site_type(1, 0).sorted_index(1)), + key_type(site_type(1, 1).sorted_index(2)), + key_type(site_type(1, 2).sorted_index(3)), + key_type(site_type(1, 1).sorted_index(2), site_type(0, 0).sorted_index(0)), + }; + bool res[] = {false, true, true, true}; + CHECK_NODE_COMPARISON(node, nodes, res, 4); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test1) { + site_type site1(0, 0); + site_type site2(-8, 0); + site_type site3(0, 6); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, -4.0, 3.0, 1.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test2) { + int min_int = (std::numeric_limits::min)(); + int max_int = (std::numeric_limits::max)(); + site_type site1(min_int, min_int); + site_type site2(min_int, max_int); + site_type site3(max_int-1, max_int-1); + site_type site4(max_int, max_int); + CHECK_CIRCLE_EXISTENCE(site1, site2, site4, true); + CHECK_CIRCLE_EXISTENCE(site1, site3, site4, false); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test3) { + site_type site1(-4, 0); + site_type site2(0, 4); + site_type site3(site1.point0(), site2.point0()); + CHECK_CIRCLE_EXISTENCE(site1, site3, site2, false); + site_type site4(-2, 0); + site_type site5(0, 2); + CHECK_CIRCLE_EXISTENCE(site3, site4, site5, false); + CHECK_CIRCLE_EXISTENCE(site4, site5, site3, false); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test4) { + site_type site1(-4, 0, -4, 20); + site_type site2(-2, 10); + site_type site3(4, 10); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 1.0, 6.0, 6.0); + CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 14.0, 6.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test5) { + site_type site1(1, 0, 7, 0); + site1.inverse(); + site_type site2(-2, 4, 10, 4); + site_type site3(6, 2); + site_type site4(1, 0); + CHECK_CIRCLE_FORMATION_PREDICATE(site3, site1, site2, 4.0, 2.0, 6.0); + CHECK_CIRCLE_FORMATION_PREDICATE(site4, site2, site1, 1.0, 2.0, 3.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test6) { + site_type site1(-1, 2, 8, -10); + site1.inverse(); + site_type site2(-1, 0, 8, 12); + site_type site3(1, 1); + CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 6.0, 1.0, 11.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test7) { + site_type site1(1, 0, 6, 0); + site1.inverse(); + site_type site2(-6, 4, 0, 12); + site_type site3(1, 0); + CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 5.0, 6.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test8) { + site_type site1(1, 0, 5, 0); + site1.inverse(); + site_type site2(0, 12, 8, 6); + site_type site3(1, 0); + CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 5.0, 6.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test9) { + site_type site1(0, 0, 4, 0); + site_type site2(0, 0, 0, 4); + site_type site3(0, 4, 4, 4); + site1.inverse(); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 2.0, 2.0, 4.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test10) { + site_type site1(1, 0, 41, 30); + site_type site2(-39, 30, 1, 60); + site_type site3(1, 60, 41, 30); + site1.inverse(); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 1.0, 30.0, 25.0); +} diff --git a/test/voronoi_robust_fpt_test.cpp b/test/voronoi_robust_fpt_test.cpp new file mode 100644 index 0000000..5b98f88 --- /dev/null +++ b/test/voronoi_robust_fpt_test.cpp @@ -0,0 +1,355 @@ +// Boost.Polygon library voronoi_robust_fpt_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include +#include + +#define BOOST_TEST_MODULE voronoi_robust_fpt_test +#include +#include +#include + +#include +#include +using boost::polygon::detail::int32; +using boost::polygon::detail::uint32; +using boost::polygon::detail::int64; +using boost::polygon::detail::fpt64; +using boost::polygon::detail::efpt64; +using boost::polygon::detail::extended_int; +using boost::polygon::detail::extended_exponent_fpt; +using boost::polygon::detail::robust_fpt; +using boost::polygon::detail::robust_dif; +using boost::polygon::detail::robust_sqrt_expr; +using boost::polygon::detail::type_converter_fpt; +using boost::polygon::detail::type_converter_efpt; +using boost::polygon::detail::ulp_comparison; + +typedef robust_fpt rfpt_type; +typedef type_converter_fpt to_fpt_type; +typedef type_converter_efpt to_efpt_type; +type_converter_fpt to_fpt; + +BOOST_AUTO_TEST_CASE(robust_fpt_constructors_test1) { + rfpt_type a = rfpt_type(); + BOOST_CHECK_EQUAL(a.fpv(), 0.0); + BOOST_CHECK_EQUAL(a.re(), 0.0); + BOOST_CHECK_EQUAL(a.ulp(), 0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_constructors_test2) { + rfpt_type a(10.0, 1.0); + BOOST_CHECK_EQUAL(a.fpv(), 10.0); + BOOST_CHECK_EQUAL(a.re(), 1.0); + BOOST_CHECK_EQUAL(a.ulp(), 1.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_constructors_test3) { + rfpt_type a(10.0); + BOOST_CHECK_EQUAL(a.fpv(), 10.0); + BOOST_CHECK_EQUAL(a.re(), 0.0); + BOOST_CHECK_EQUAL(a.ulp(), 0.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_constructors_test4) { + rfpt_type a(10.0, 3.0); + BOOST_CHECK_EQUAL(a.fpv(), 10.0); + BOOST_CHECK_EQUAL(a.re(), 3.0); + BOOST_CHECK_EQUAL(a.ulp(), 3.0); + + rfpt_type b(10.0, 2.75); + BOOST_CHECK_EQUAL(b.fpv(), 10.0); + BOOST_CHECK_EQUAL(b.re(), 2.75); + BOOST_CHECK_EQUAL(b.ulp(), 2.75); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_sum_test1) { + rfpt_type a(2.0, 5.0); + rfpt_type b(3.0, 4.0); + rfpt_type c = a + b; + BOOST_CHECK_EQUAL(c.fpv(), 5.0); + BOOST_CHECK_EQUAL(c.re(), 6.0); + BOOST_CHECK_EQUAL(c.ulp(), 6.0); + + c += b; + BOOST_CHECK_EQUAL(c.fpv(), 8.0); + BOOST_CHECK_EQUAL(c.re(), 7.0); + BOOST_CHECK_EQUAL(c.ulp(), 7.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_sum_test2) { + rfpt_type a(3.0, 2.0); + rfpt_type b(-2.0, 3.0); + rfpt_type c = a + b; + BOOST_CHECK_EQUAL(c.fpv(), 1.0); + BOOST_CHECK_EQUAL(c.re(), 13.0); + BOOST_CHECK_EQUAL(c.ulp(), 13.0); + + c += b; + BOOST_CHECK_EQUAL(c.fpv(), -1.0); + BOOST_CHECK_EQUAL(c.re(), 20.0); + BOOST_CHECK_EQUAL(c.ulp(), 20.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_dif_test1) { + rfpt_type a(2.0, 5.0); + rfpt_type b(-3.0, 4.0); + rfpt_type c = a - b; + BOOST_CHECK_EQUAL(c.fpv(), 5.0); + BOOST_CHECK_EQUAL(c.re(), 6.0); + BOOST_CHECK_EQUAL(c.ulp(), 6.0); + + c -= b; + BOOST_CHECK_EQUAL(c.fpv(), 8.0); + BOOST_CHECK_EQUAL(c.re(), 7.0); + BOOST_CHECK_EQUAL(c.ulp(), 7.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_dif_test2) { + rfpt_type a(3.0, 2.0); + rfpt_type b(2.0, 3.0); + rfpt_type c = a - b; + BOOST_CHECK_EQUAL(c.fpv(), 1.0); + BOOST_CHECK_EQUAL(c.re(), 13.0); + BOOST_CHECK_EQUAL(c.ulp(), 13.0); + + c -= b; + BOOST_CHECK_EQUAL(c.fpv(), -1.0); + BOOST_CHECK_EQUAL(c.re(), 20.0); + BOOST_CHECK_EQUAL(c.ulp(), 20.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_mult_test3) { + rfpt_type a(2.0, 3.0); + rfpt_type b(4.0, 1.0); + rfpt_type c = a * b; + BOOST_CHECK_EQUAL(c.fpv(), 8.0); + BOOST_CHECK_EQUAL(c.re(), 5.0); + BOOST_CHECK_EQUAL(c.ulp(), 5.0); + + c *= b; + BOOST_CHECK_EQUAL(c.fpv(), 32.0); + BOOST_CHECK_EQUAL(c.re(), 7.0); + BOOST_CHECK_EQUAL(c.ulp(), 7.0); +} + +BOOST_AUTO_TEST_CASE(robust_fpt_div_test1) { + rfpt_type a(2.0, 3.0); + rfpt_type b(4.0, 1.0); + rfpt_type c = a / b; + BOOST_CHECK_EQUAL(c.fpv(), 0.5); + BOOST_CHECK_EQUAL(c.re(), 5.0); + BOOST_CHECK_EQUAL(c.ulp(), 5.0); + + c /= b; + BOOST_CHECK_EQUAL(c.fpv(), 0.125); + BOOST_CHECK_EQUAL(c.re(), 7.0); + BOOST_CHECK_EQUAL(c.ulp(), 7.0); +} + +BOOST_AUTO_TEST_CASE(robust_dif_constructors_test) { + robust_dif rd1; + BOOST_CHECK_EQUAL(rd1.pos(), 0); + BOOST_CHECK_EQUAL(rd1.neg(), 0); + BOOST_CHECK_EQUAL(rd1.dif(), 0); + + robust_dif rd2(1); + BOOST_CHECK_EQUAL(rd2.pos(), 1); + BOOST_CHECK_EQUAL(rd2.neg(), 0); + BOOST_CHECK_EQUAL(rd2.dif(), 1); + + robust_dif rd3(-1); + BOOST_CHECK_EQUAL(rd3.pos(), 0); + BOOST_CHECK_EQUAL(rd3.neg(), 1); + BOOST_CHECK_EQUAL(rd3.dif(), -1); + + robust_dif rd4(1, 2); + BOOST_CHECK_EQUAL(rd4.pos(), 1); + BOOST_CHECK_EQUAL(rd4.neg(), 2); + BOOST_CHECK_EQUAL(rd4.dif(), -1); +} + +BOOST_AUTO_TEST_CASE(robust_dif_operators_test1) { + robust_dif a(5, 2), b(1, 10); + int dif_a = a.dif(); + int dif_b = b.dif(); + robust_dif sum = a + b; + robust_dif dif = a - b; + robust_dif mult = a * b; + robust_dif umin = -a; + BOOST_CHECK_EQUAL(sum.dif(), dif_a + dif_b); + BOOST_CHECK_EQUAL(dif.dif(), dif_a - dif_b); + BOOST_CHECK_EQUAL(mult.dif(), dif_a * dif_b); + BOOST_CHECK_EQUAL(umin.dif(), -dif_a); +} + +BOOST_AUTO_TEST_CASE(robust_dif_operators_test2) { + robust_dif a(5, 2); + for (int b = -3; b <= 3; b += 6) { + int dif_a = a.dif(); + int dif_b = b; + robust_dif sum = a + b; + robust_dif dif = a - b; + robust_dif mult = a * b; + robust_dif div = a / b; + BOOST_CHECK_EQUAL(sum.dif(), dif_a + dif_b); + BOOST_CHECK_EQUAL(dif.dif(), dif_a - dif_b); + BOOST_CHECK_EQUAL(mult.dif(), dif_a * dif_b); + BOOST_CHECK_EQUAL(div.dif(), dif_a / dif_b); + } +} + +BOOST_AUTO_TEST_CASE(robust_dif_operators_test3) { + robust_dif b(5, 2); + for (int a = -3; a <= 3; a += 6) { + int dif_a = a; + int dif_b = b.dif(); + robust_dif sum = a + b; + robust_dif dif = a - b; + robust_dif mult = a * b; + BOOST_CHECK_EQUAL(sum.dif(), dif_a + dif_b); + BOOST_CHECK_EQUAL(dif.dif(), dif_a - dif_b); + BOOST_CHECK_EQUAL(mult.dif(), dif_a * dif_b); + } +} + +BOOST_AUTO_TEST_CASE(robust_dif_operators_test4) { + std::vector< robust_dif > a4(4, robust_dif(5, 2)); + std::vector< robust_dif > b4(4, robust_dif(1, 2)); + std::vector< robust_dif > c4 = a4; + c4[0] += b4[0]; + c4[1] -= b4[1]; + c4[2] *= b4[2]; + BOOST_CHECK_EQUAL(c4[0].dif(), a4[0].dif() + b4[0].dif()); + BOOST_CHECK_EQUAL(c4[1].dif(), a4[1].dif() - b4[1].dif()); + BOOST_CHECK_EQUAL(c4[2].dif(), a4[2].dif() * b4[2].dif()); + a4[0] += b4[0].dif(); + a4[1] -= b4[1].dif(); + a4[2] *= b4[2].dif(); + a4[3] /= b4[3].dif(); + BOOST_CHECK_EQUAL(c4[0].dif(), a4[0].dif()); + BOOST_CHECK_EQUAL(c4[1].dif(), a4[1].dif()); + BOOST_CHECK_EQUAL(c4[2].dif(), a4[2].dif()); + BOOST_CHECK_EQUAL(c4[3].dif() / b4[3].dif(), a4[3].dif()); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test1) { + robust_sqrt_expr sqrt_expr; + int32 A[1] = {10}; + int32 B[1] = {100}; + BOOST_CHECK_EQUAL(sqrt_expr.eval1(A, B), 100.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test2) { + robust_sqrt_expr sqrt_expr; + int32 A[2] = {10, 30}; + int32 B[2] = {400, 100}; + BOOST_CHECK_EQUAL(sqrt_expr.eval2(A, B), 500.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test3) { + robust_sqrt_expr sqrt_expr; + int32 A[2] = {10, -30}; + int32 B[2] = {400, 100}; + BOOST_CHECK_EQUAL(sqrt_expr.eval2(A, B), -100.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test4) { + robust_sqrt_expr sqrt_expr; + int32 A[3] = {10, 30, 20}; + int32 B[3] = {4, 1, 9}; + BOOST_CHECK_EQUAL(sqrt_expr.eval3(A, B), 110.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test5) { + robust_sqrt_expr sqrt_expr; + int32 A[3] = {10, 30, -20}; + int32 B[3] = {4, 1, 9}; + BOOST_CHECK_EQUAL(sqrt_expr.eval3(A, B), -10.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test6) { + robust_sqrt_expr sqrt_expr; + int32 A[4] = {10, 30, 20, 5}; + int32 B[4] = {4, 1, 9, 16}; + BOOST_CHECK_EQUAL(sqrt_expr.eval4(A, B), 130.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test7) { + robust_sqrt_expr sqrt_expr; + int32 A[4] = {10, 30, -20, -5}; + int32 B[4] = {4, 1, 9, 16}; + BOOST_CHECK_EQUAL(sqrt_expr.eval4(A, B), -30.0); +} + +BOOST_AUTO_TEST_CASE(robust_sqrt_expr_test8) { + typedef extended_int<16> eint512; + robust_sqrt_expr sqrt_expr; + int32 A[4] = {1000, 3000, -2000, -500}; + int32 B[4] = {400, 100, 900, 1600}; + eint512 AA[4], BB[4]; + for (std::size_t i = 0; i < 4; ++i) { + AA[i] = A[i]; + BB[i] = B[i]; + } + BOOST_CHECK_EQUAL(to_fpt(sqrt_expr.eval4(AA, BB)), -30000.0); +} + +template +class sqrt_expr_tester { + public: + static const std::size_t MX_SQRTS = 4; + + bool run() { + static boost::mt19937 gen(static_cast(time(NULL))); + bool ret_val = true; + for (std::size_t i = 0; i < MX_SQRTS; ++i) { + a[i] = gen() & 1048575; + int64 temp = gen() & 1048575; + b[i] = temp * temp; + } + uint32 mask = (1 << MX_SQRTS); + for (std::size_t i = 0; i < mask; i++) { + fpt64 expected_val = 0.0; + for (std::size_t j = 0; j < MX_SQRTS; j++) { + if (i & (1 << j)) { + A[j] = a[j]; + B[j] = b[j]; + expected_val += static_cast(a[j]) * + std::sqrt(static_cast(b[j])); + } else { + A[j] = -a[j]; + B[j] = b[j]; + expected_val -= static_cast(a[j]) * + std::sqrt(static_cast(b[j])); + } + } + fpt64 received_val = to_fpt(sqrt_expr_.eval4(A, B)); + ret_val &= ulp_cmp(expected_val, received_val, 25) == + ulp_comparison::EQUAL; + } + return ret_val; + } + + private: + robust_sqrt_expr<_int, _fpt, to_efpt_type> sqrt_expr_; + ulp_comparison ulp_cmp; + _int A[MX_SQRTS]; + _int B[MX_SQRTS]; + int64 a[MX_SQRTS]; + int64 b[MX_SQRTS]; +}; + +BOOST_AUTO_TEST_CASE(mpz_sqrt_evaluator_test) { + typedef extended_int<16> eint512; + sqrt_expr_tester tester; + for (int i = 0; i < 2000; ++i) + BOOST_CHECK(tester.run()); +} diff --git a/test/voronoi_structures_test.cpp b/test/voronoi_structures_test.cpp new file mode 100644 index 0000000..5fe35db --- /dev/null +++ b/test/voronoi_structures_test.cpp @@ -0,0 +1,131 @@ +// Boost.Polygon library voronoi_structures_test.cpp file + +// Copyright Andrii Sydorchuk 2010-2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#include +#include + +#define BOOST_TEST_MODULE voronoi_structures_test +#include +#include +using namespace boost::polygon::detail; + +#include +using namespace boost::polygon; + +typedef point_2d point_type; +typedef site_event site_type; +typedef circle_event circle_type; +typedef ordered_queue > ordered_queue_type; +typedef beach_line_node_key node_key_type; +typedef beach_line_node_data node_data_type; + +BOOST_AUTO_TEST_CASE(point_2d_test1) { + point_type p(1, 2); + BOOST_CHECK_EQUAL(p.x(), 1); + BOOST_CHECK_EQUAL(p.y(), 2); + p.x(3); + BOOST_CHECK_EQUAL(p.x(), 3); + p.y(4); + BOOST_CHECK_EQUAL(p.y(), 4); +} + +BOOST_AUTO_TEST_CASE(site_event_test1) { + site_type s(1, 2); + s.sorted_index(1); + s.initial_index(2); + s.source_category(SOURCE_CATEGORY_SEGMENT_START_POINT); + BOOST_CHECK(s.x0() == 1 && s.x1() == 1); + BOOST_CHECK(s.y0() == 2 && s.y1() == 2); + BOOST_CHECK(s.is_point()); + BOOST_CHECK(!s.is_segment()); + BOOST_CHECK(!s.is_inverse()); + BOOST_CHECK(s.sorted_index() == 1); + BOOST_CHECK(s.initial_index() == 2); + BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT); +} + +BOOST_AUTO_TEST_CASE(site_event_test2) { + site_type s(1, 2, 3, 4); + s.sorted_index(1); + s.initial_index(2); + s.source_category(SOURCE_CATEGORY_INITIAL_SEGMENT); + BOOST_CHECK(s.x0(true) == 1 && s.x0() == 1); + BOOST_CHECK(s.y0(true) == 2 && s.y0() == 2); + BOOST_CHECK(s.x1(true) == 3 && s.x1() == 3); + BOOST_CHECK(s.y1(true) == 4 && s.y1() == 4); + BOOST_CHECK(!s.is_point()); + BOOST_CHECK(s.is_segment()); + BOOST_CHECK(!s.is_inverse()); + BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_INITIAL_SEGMENT); + + s.inverse(); + BOOST_CHECK(s.x1(true) == 1 && s.x0() == 1); + BOOST_CHECK(s.y1(true) == 2 && s.y0() == 2); + BOOST_CHECK(s.x0(true) == 3 && s.x1() == 3); + BOOST_CHECK(s.y0(true) == 4 && s.y1() == 4); + BOOST_CHECK(s.is_inverse()); + BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_INITIAL_SEGMENT); +} + +BOOST_AUTO_TEST_CASE(circle_event_test) { + circle_type c(0, 1, 2); + BOOST_CHECK_EQUAL(c.x(), 0); + BOOST_CHECK_EQUAL(c.y(), 1); + BOOST_CHECK_EQUAL(c.lower_x(), 2); + BOOST_CHECK_EQUAL(c.lower_y(), 1); + BOOST_CHECK(c.is_active()); + c.x(3); + c.y(4); + c.lower_x(5); + BOOST_CHECK_EQUAL(c.x(), 3); + BOOST_CHECK_EQUAL(c.y(), 4); + BOOST_CHECK_EQUAL(c.lower_x(), 5); + BOOST_CHECK_EQUAL(c.lower_y(), 4); + c.deactivate(); + BOOST_CHECK(!c.is_active()); +} + +BOOST_AUTO_TEST_CASE(ordered_queue_test) { + ordered_queue_type q; + BOOST_CHECK(q.empty()); + std::vector vi; + for (int i = 0; i < 20; ++i) + vi.push_back(&q.push(i)); + for (int i = 0; i < 20; ++i) + *vi[i] <<= 1; + BOOST_CHECK(!q.empty()); + for (int i = 0; i < 20; ++i, q.pop()) + BOOST_CHECK_EQUAL(q.top(), i << 1); + BOOST_CHECK(q.empty()); +} + +BOOST_AUTO_TEST_CASE(beach_line_node_key_test) { + node_key_type key(1); + BOOST_CHECK_EQUAL(key.left_site(), 1); + BOOST_CHECK_EQUAL(key.right_site(), 1); + key.left_site(2); + BOOST_CHECK_EQUAL(key.left_site(), 2); + BOOST_CHECK_EQUAL(key.right_site(), 1); + key.right_site(3); + BOOST_CHECK_EQUAL(key.left_site(), 2); + BOOST_CHECK_EQUAL(key.right_site(), 3); +} + +BOOST_AUTO_TEST_CASE(beach_line_node_data_test) { + node_data_type node_data(NULL); + BOOST_CHECK(node_data.edge() == NULL); + BOOST_CHECK(node_data.circle_event() == NULL); + int data = 4; + node_data.circle_event(&data); + BOOST_CHECK(node_data.edge() == NULL); + BOOST_CHECK(node_data.circle_event() == &data); + node_data.edge(&data); + BOOST_CHECK(node_data.edge() == &data); + BOOST_CHECK(node_data.circle_event() == &data); +} diff --git a/test/voronoi_test_helper.hpp b/test/voronoi_test_helper.hpp new file mode 100644 index 0000000..170aa0b --- /dev/null +++ b/test/voronoi_test_helper.hpp @@ -0,0 +1,260 @@ +// Boost.Polygon library voronoi_test_helper.hpp file + +// Copyright Andrii Sydorchuk 2010-2011. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef VORONOI_TEST_HELPER +#define VORONOI_TEST_HELPER + +#include +#include +#include +#include +#include +#include +#include + +#include +using namespace boost::polygon; + +namespace voronoi_test_helper { + +enum kOrientation { + RIGHT = -1, + COLLINEAR = 0, + LEFT = 1 +}; + +template +kOrientation get_orientation( + const VERTEX& v1, const VERTEX& v2, const VERTEX& v3) { + typename VERTEX::coordinate_type lhs = (v2.x() - v1.x()) * (v3.y() - v2.y()); + typename VERTEX::coordinate_type rhs = (v2.y() - v1.y()) * (v3.x() - v2.x()); + if (lhs == rhs) { + return COLLINEAR; + } + return (lhs < rhs) ? RIGHT : LEFT; +} + +template +bool verify_cell_convexity(const OUTPUT& output) { + typename OUTPUT::const_cell_iterator cell_it; + for (cell_it = output.cells().begin(); + cell_it != output.cells().end(); cell_it++) { + const typename OUTPUT::edge_type* edge = cell_it->incident_edge(); + if (edge) + do { + if (edge->next()->prev() != edge) { + return false; + } + if (edge->cell() != &(*cell_it)) { + return false; + } + if (edge->vertex1() != edge->next()->vertex0()) { + return false; + } + if (edge->vertex0() != NULL && + edge->vertex1() != NULL && + edge->next()->vertex1() != NULL) { + if (get_orientation(*edge->vertex0(), + *edge->vertex1(), + *edge->next()->vertex1()) != LEFT) { + return false; + } + } + edge = edge->next(); + } while (edge != cell_it->incident_edge()); + } + return true; +} + +template +bool verify_incident_edges_ccw_order(const OUTPUT& output) { + typedef typename OUTPUT::edge_type voronoi_edge_type; + typename OUTPUT::const_vertex_iterator vertex_it; + for (vertex_it = output.vertices().begin(); + vertex_it != output.vertices().end(); vertex_it++) { + if (vertex_it->is_degenerate()) + continue; + const voronoi_edge_type* edge = vertex_it->incident_edge(); + do { + const voronoi_edge_type* next_edge = edge->rot_next(); + if (edge->vertex0() != next_edge->vertex0()) { + return false; + } + if (edge->vertex1() != NULL && next_edge->vertex1() != NULL && + get_orientation(*edge->vertex1(), + *edge->vertex0(), + *next_edge->vertex1()) == LEFT) { + return false; + } + edge = edge->rot_next(); + } while (edge != vertex_it->incident_edge()); + } + return true; +} + +template +struct cmp { + bool operator()(const VERTEX& v1, const VERTEX& v2) const { + if (v1.x() != v2.x()) + return v1.x() < v2.x(); + return v1.y() < v2.y(); + } +}; + +template +bool verfiy_no_line_edge_intersections(const Output &output) { + // Create map from edges with first point less than the second one. + // Key is the first point of the edge, value is a vector of second points + // with the same first point. + typedef typename Output::vertex_type vertex_type; + cmp comparator; + std::map< vertex_type, std::vector, cmp > edge_map; + typename Output::const_edge_iterator edge_it; + for (edge_it = output.edges().begin(); + edge_it != output.edges().end(); edge_it++) { + if (edge_it->is_finite()) { + if (comparator(*edge_it->vertex0(), *edge_it->vertex1())) { + edge_map[*edge_it->vertex0()].push_back(*edge_it->vertex1()); + } + } + } + return !intersection_check(edge_map); +} + +template +bool intersection_check( + const std::map< Point2D, std::vector, cmp > &edge_map) { + // Iterate over map of edges and check if there are any intersections. + // All the edges are stored by the low x value. That's why we iterate + // left to right checking for intersections between all pairs of edges + // that overlap in the x dimension. + // Complexity. Approximately N*sqrt(N). Worst case N^2. + typedef Point2D point_type; + typedef typename point_type::coordinate_type coordinate_type; + typedef typename std::map, cmp >::const_iterator + edge_map_iterator; + typedef typename std::vector::size_type size_type; + edge_map_iterator edge_map_it1, edge_map_it2, edge_map_it_bound; + for (edge_map_it1 = edge_map.begin(); + edge_map_it1 != edge_map.end(); edge_map_it1++) { + const point_type &point1 = edge_map_it1->first; + for (size_type i = 0; i < edge_map_it1->second.size(); i++) { + const point_type &point2 = edge_map_it1->second[i]; + coordinate_type min_y1 = (std::min)(point1.y(), point2.y()); + coordinate_type max_y1 = (std::max)(point1.y(), point2.y()); + + // Find the first edge with greater or equal first point. + edge_map_it_bound = edge_map.lower_bound(point2); + + edge_map_it2 = edge_map_it1; + edge_map_it2++; + for (; edge_map_it2 != edge_map_it_bound; edge_map_it2++) { + const point_type &point3 = edge_map_it2->first; + for (size_type j = 0; j < edge_map_it2->second.size(); j++) { + const point_type &point4 = edge_map_it2->second[j]; + coordinate_type min_y2 = (std::min)(point3.y(), point4.y()); + coordinate_type max_y2 = (std::max)(point3.y(), point4.y()); + + // In most cases it is enought to make + // simple intersection check in the y dimension. + if (!(max_y1 > min_y2 && max_y2 > min_y1)) + continue; + + // Intersection check. + if (get_orientation(point1, point2, point3) * + get_orientation(point1, point2, point4) == RIGHT && + get_orientation(point3, point4, point1) * + get_orientation(point3, point4, point2) == RIGHT) + return true; + } + } + } + } + return false; +} + +enum kVerification { + CELL_CONVEXITY = 1, + INCIDENT_EDGES_CCW_ORDER = 2, + NO_HALF_EDGE_INTERSECTIONS = 4, + FAST_VERIFICATION = 3, + COMPLETE_VERIFICATION = 7 +}; + +template +bool verify_output(const Output &output, kVerification mask) { + bool result = true; + if (mask & CELL_CONVEXITY) + result &= verify_cell_convexity(output); + if (mask & INCIDENT_EDGES_CCW_ORDER) + result &= verify_incident_edges_ccw_order(output); + if (mask & NO_HALF_EDGE_INTERSECTIONS) + result &= verfiy_no_line_edge_intersections(output); + return result; +} + +template +void save_points( + PointIterator first, PointIterator last, const char* file_name) { + std::ofstream ofs(file_name); + ofs << std::distance(first, last) << std::endl; + for (PointIterator it = first; it != last; ++it) { + ofs << it->x() << " " << it->y() << std::endl; + } + ofs.close(); +} + +template +void save_segments( + SegmentIterator first, SegmentIterator last, const char* file_name) { + std::ofstream ofs(file_name); + ofs << std::distance(first, last) << std::endl; + for (SegmentIterator it = first; it != last; ++it) { + ofs << it->low().x() << " " << it->low().y() << " "; + ofs << it->high().x() << " " << it->high().y() << std::endl; + } + ofs.close(); +} + +template +void clean_segment_set(std::vector< segment_data >& data) { + typedef T Unit; + typedef typename scanline_base::Point Point; + typedef typename scanline_base::half_edge half_edge; + typedef int segment_id; + std::vector > half_edges; + std::vector > half_edges_out; + segment_id id = 0; + half_edges.reserve(data.size()); + for (typename std::vector< segment_data >::iterator it = data.begin(); + it != data.end(); ++it) { + Point l = it->low(); + Point h = it->high(); + half_edges.push_back(std::make_pair(half_edge(l, h), id++)); + } + half_edges_out.reserve(half_edges.size()); + // Apparently no need to pre-sort data when calling validate_scan. + line_intersection::validate_scan( + half_edges_out, half_edges.begin(), half_edges.end()); + std::vector< segment_data > result; + result.reserve(half_edges_out.size()); + for (std::size_t i = 0; i < half_edges_out.size(); ++i) { + id = half_edges_out[i].second; + Point l = half_edges_out[i].first.first; + Point h = half_edges_out[i].first.second; + segment_data orig_seg = data[id]; + if (orig_seg.high() < orig_seg.low()) + std::swap(l, h); + result.push_back(segment_data(l, h)); + } + std::swap(result, data); +} +} // voronoi_test_helper + +#endif From fc5782529c6de4120d72c98e7754b7757c801bee Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Tue, 18 Sep 2012 21:13:41 +0000 Subject: [PATCH 21/32] Polygon: merging recent trunk fixes: removing all static data from the Voronoi headers; fixing lazy sss predicate logic. [SVN r80589] --- .../boost/polygon/detail/voronoi_ctypes.hpp | 42 ++++++++----------- .../polygon/detail/voronoi_predicates.hpp | 30 +++++++------ .../polygon/detail/voronoi_robust_fpt.hpp | 31 ++++---------- 3 files changed, 44 insertions(+), 59 deletions(-) diff --git a/include/boost/polygon/detail/voronoi_ctypes.hpp b/include/boost/polygon/detail/voronoi_ctypes.hpp index 63e42a9..45b97c8 100644 --- a/include/boost/polygon/detail/voronoi_ctypes.hpp +++ b/include/boost/polygon/detail/voronoi_ctypes.hpp @@ -74,11 +74,11 @@ template <> class extened_exponent_fpt_traits { public: typedef int exp_type; - static const int kMaxSignificantExpDif; + enum { + MAX_SIGNIFICANT_EXP_DIF = 54 + }; }; -const int extened_exponent_fpt_traits::kMaxSignificantExpDif = 54; - // Floating point type wrapper. Allows to extend exponent boundaries to the // integer type range. This class does not handle division by zero, subnormal // numbers or NaNs. @@ -115,11 +115,11 @@ class extended_exponent_fpt { extended_exponent_fpt operator+(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || - that.exp_ > this->exp_ + _traits::kMaxSignificantExpDif) { + that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return that; } if (that.val_ == 0.0 || - this->exp_ > that.exp_ + _traits::kMaxSignificantExpDif) { + this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { @@ -135,11 +135,11 @@ class extended_exponent_fpt { extended_exponent_fpt operator-(const extended_exponent_fpt& that) const { if (this->val_ == 0.0 || - that.exp_ > this->exp_ + _traits::kMaxSignificantExpDif) { + that.exp_ > this->exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return extended_exponent_fpt(-that.val_, that.exp_); } if (that.val_ == 0.0 || - this->exp_ > that.exp_ + _traits::kMaxSignificantExpDif) { + this->exp_ > that.exp_ + _traits::MAX_SIGNIFICANT_EXP_DIF) { return *this; } if (this->exp_ >= that.exp_) { @@ -226,9 +226,6 @@ bool is_zero(const extended_exponent_fpt<_fpt>& that) { template class extended_int { public: - static const uint64 kUInt64LowMask; - static const uint64 kUInt64HighMask; - extended_int() {} extended_int(int32 that) { @@ -245,12 +242,12 @@ class extended_int { extended_int(int64 that) { if (that > 0) { - this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; - this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { @@ -287,12 +284,12 @@ class extended_int { extended_int& operator=(int64 that) { if (that > 0) { - this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? 2 : 1; } else if (that < 0) { that = -that; - this->chunks_[0] = static_cast(that & kUInt64LowMask); + this->chunks_[0] = static_cast(that); this->chunks_[1] = that >> 32; this->count_ = this->chunks_[1] ? -2 : -1; } else { @@ -497,16 +494,16 @@ class extended_int { uint64 temp = 0; for (std::size_t i = 0; i < sz2; ++i) { temp += static_cast(c1[i]) + static_cast(c2[i]); - this->chunks_[i] = static_cast(temp & kUInt64LowMask); + this->chunks_[i] = static_cast(temp); temp >>= 32; } for (std::size_t i = sz2; i < sz1; ++i) { temp += static_cast(c1[i]); - this->chunks_[i] = static_cast(temp & kUInt64LowMask); + this->chunks_[i] = static_cast(temp); temp >>= 32; } if (temp && (this->count_ != N)) { - this->chunks_[this->count_] = static_cast(temp & kUInt64LowMask); + this->chunks_[this->count_] = static_cast(temp); ++this->count_; } } @@ -565,14 +562,14 @@ class extended_int { if (second >= sz2) continue; tmp = static_cast(c1[first]) * static_cast(c2[second]); - cur += tmp & kUInt64LowMask; + cur += static_cast(tmp); nxt += tmp >> 32; } - this->chunks_[shift] = static_cast(cur & kUInt64LowMask); + this->chunks_[shift] = static_cast(cur); cur = nxt + (cur >> 32); } if (cur && (this->count_ != N)) { - this->chunks_[this->count_] = static_cast(cur & kUInt64LowMask); + this->chunks_[this->count_] = static_cast(cur); ++this->count_; } } @@ -581,11 +578,6 @@ class extended_int { int32 count_; }; -template -const uint64 extended_int::kUInt64LowMask = 0x00000000ffffffffULL; -template -const uint64 extended_int::kUInt64HighMask = 0xffffffff00000000ULL; - template bool is_pos(const extended_int& that) { return that.count() > 0; diff --git a/include/boost/polygon/detail/voronoi_predicates.hpp b/include/boost/polygon/detail/voronoi_predicates.hpp index a1a3fad..fbaa96b 100644 --- a/include/boost/polygon/detail/voronoi_predicates.hpp +++ b/include/boost/polygon/detail/voronoi_predicates.hpp @@ -1390,41 +1390,47 @@ class voronoi_predicates { static_cast(site1.x0(true)), static_cast(site1.y1(true)) - static_cast(site1.y0(true))), to_fpt(1.0)); - robust_dif_type denom, c_x, c_y, r; // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2. + robust_dif_type denom; denom += cross_12 * len3; denom += cross_23 * len1; denom += cross_31 * len2; // denom * r = (b2 * c_x - a2 * c_y - c2 * denom) / len2. + robust_dif_type r; r -= cross_12 * c3; r -= cross_23 * c1; r -= cross_31 * c2; + robust_dif_type c_x; c_x += a1 * c2 * len3; c_x -= a2 * c1 * len3; c_x += a2 * c3 * len1; c_x -= a3 * c2 * len1; c_x += a3 * c1 * len2; c_x -= a1 * c3 * len2; + + robust_dif_type c_y; c_y += b1 * c2 * len3; c_y -= b2 * c1 * len3; c_y += b2 * c3 * len1; c_y -= b3 * c2 * len1; c_y += b3 * c1 * len2; c_y -= b1 * c3 * len2; - robust_dif_type lower_x(c_x + r); - bool recompute_c_x = c_x.dif().ulp() > ULPS; - bool recompute_c_y = c_y.dif().ulp() > ULPS; - bool recompute_lower_x = lower_x.dif().ulp() > ULPS; - bool recompute_denom = denom.dif().ulp() > ULPS; - c_event = circle_type( - c_x.dif().fpv() / denom.dif().fpv(), - c_y.dif().fpv() / denom.dif().fpv(), - lower_x.dif().fpv() / denom.dif().fpv()); - if (recompute_c_x || recompute_c_y || - recompute_lower_x || recompute_denom) { + + robust_dif_type lower_x = c_x + r; + + robust_fpt_type denom_dif = denom.dif(); + robust_fpt_type c_x_dif = c_x.dif() / denom_dif; + robust_fpt_type c_y_dif = c_y.dif() / denom_dif; + robust_fpt_type lower_x_dif = lower_x.dif() / denom_dif; + + bool recompute_c_x = c_x_dif.ulp() > ULPS; + bool recompute_c_y = c_y_dif.ulp() > ULPS; + bool recompute_lower_x = lower_x_dif.ulp() > ULPS; + c_event = circle_type(c_x_dif.fpv(), c_y_dif.fpv(), lower_x_dif.fpv()); + if (recompute_c_x || recompute_c_y || recompute_lower_x) { exact_circle_formation_functor_.sss( site1, site2, site3, c_event, recompute_c_x, recompute_c_y, recompute_lower_x); diff --git a/include/boost/polygon/detail/voronoi_robust_fpt.hpp b/include/boost/polygon/detail/voronoi_robust_fpt.hpp index 0d2e62b..01d337f 100644 --- a/include/boost/polygon/detail/voronoi_robust_fpt.hpp +++ b/include/boost/polygon/detail/voronoi_robust_fpt.hpp @@ -82,7 +82,9 @@ class robust_fpt { typedef _fpt relative_error_type; // Rounding error is at most 1 EPS. - static const relative_error_type ROUNDING_ERROR; + enum { + ROUNDING_ERROR = 1 + }; robust_fpt() : fpv_(0.0), re_(0.0) {} explicit robust_fpt(floating_point_type fpv) : @@ -215,10 +217,6 @@ class robust_fpt { relative_error_type re_; }; -template -const typename robust_fpt::relative_error_type - robust_fpt::ROUNDING_ERROR = 1; - template robust_fpt get_sqrt(const robust_fpt& that) { return that.sqrt(); @@ -435,10 +433,12 @@ robust_dif operator/(const robust_dif& lhs, const T& val) { template class robust_sqrt_expr { public: - static const unsigned int EVAL1_MAX_RELATIVE_ERROR; - static const unsigned int EVAL2_MAX_RELATIVE_ERROR; - static const unsigned int EVAL3_MAX_RELATIVE_ERROR; - static const unsigned int EVAL4_MAX_RELATIVE_ERROR; + enum MAX_RELATIVE_ERROR { + MAX_RELATIVE_ERROR_EVAL1 = 4, + MAX_RELATIVE_ERROR_EVAL2 = 7, + MAX_RELATIVE_ERROR_EVAL3 = 16, + MAX_RELATIVE_ERROR_EVAL4 = 25 + }; // Evaluates expression (re = 4 EPS): // A[0] * sqrt(B[0]). @@ -499,19 +499,6 @@ class robust_sqrt_expr { _int tB[5]; _converter convert; }; - -template -const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: - EVAL1_MAX_RELATIVE_ERROR = 4; -template -const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: - EVAL2_MAX_RELATIVE_ERROR = 7; -template -const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: - EVAL3_MAX_RELATIVE_ERROR = 16; -template -const unsigned int robust_sqrt_expr<_int, _fpt, _converter>:: - EVAL4_MAX_RELATIVE_ERROR = 25; } // detail } // polygon } // boost From 44a0c5f36ac8ffbcbf2394f452fed69b32c9296c Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Sun, 16 Dec 2012 23:16:06 +0000 Subject: [PATCH 22/32] Polygon: Merging trunk and release branches. Added tests and refactored data/traits/concept classes for point/interval/segment. Removed point_3d point/interval/segment. Simplified transform (3D->2D). Fixed bugs: #6366, #7678. [SVN r82040] --- doc/gtl_interval_concept.htm | 58 +- doc/gtl_point_concept.htm | 206 ++- doc/gtl_segment_concept.htm | 9 +- .../boost/polygon/detail/boolean_op_45.hpp | 110 +- .../polygon/detail/polygon_45_formation.hpp | 178 +- .../detail/polygon_arbitrary_formation.hpp | 258 +-- .../boost/polygon/detail/scan_arbitrary.hpp | 170 +- .../boost/polygon/detail/transform_detail.hpp | 548 ------ include/boost/polygon/interval_concept.hpp | 1551 ++++++++++------- include/boost/polygon/interval_data.hpp | 157 +- include/boost/polygon/interval_traits.hpp | 69 +- include/boost/polygon/point_3d_concept.hpp | 270 --- include/boost/polygon/point_3d_data.hpp | 49 - include/boost/polygon/point_3d_traits.hpp | 34 - include/boost/polygon/point_concept.hpp | 705 +++++--- include/boost/polygon/point_data.hpp | 222 +-- include/boost/polygon/point_traits.hpp | 66 +- include/boost/polygon/polygon.hpp | 6 - include/boost/polygon/polygon_90_set_data.hpp | 1 - .../boost/polygon/polygon_90_set_traits.hpp | 2 - include/boost/polygon/polygon_traits.hpp | 58 +- include/boost/polygon/segment_concept.hpp | 212 +-- include/boost/polygon/segment_data.hpp | 99 +- include/boost/polygon/segment_traits.hpp | 70 +- include/boost/polygon/transform.hpp | 676 ++++--- .../boost/polygon/voronoi_geometry_type.hpp | 2 +- test/Jamfile.v2 | 2 + test/gtl_boost_unit_test.cpp | 105 +- test/polygon_interval_test.cpp | 258 +++ test/polygon_point_test.cpp | 192 ++ test/polygon_segment_test.cpp | 98 +- 31 files changed, 3198 insertions(+), 3243 deletions(-) delete mode 100644 include/boost/polygon/detail/transform_detail.hpp delete mode 100644 include/boost/polygon/point_3d_concept.hpp delete mode 100644 include/boost/polygon/point_3d_data.hpp delete mode 100644 include/boost/polygon/point_3d_traits.hpp create mode 100644 test/polygon_interval_test.cpp create mode 100644 test/polygon_point_test.cpp diff --git a/doc/gtl_interval_concept.htm b/doc/gtl_interval_concept.htm index 0caac08..e690d84 100644 --- a/doc/gtl_interval_concept.htm +++ b/doc/gtl_interval_concept.htm @@ -7,6 +7,8 @@ + + - + - - + + - - + + - + - + - + - + @@ -510,10 +506,26 @@ convenient to use with the library traits.

      + + + + + + + + - + + + + + + + + +
      @@ -464,44 +466,38 @@ convenient to use with the library traits.

      Assignment operator.
      template <typename T2>  -
      interval_data& operator=(const T2& that) const
      template <typename IntervalType>  +
      interval_data& operator=(
      const IntervalType& that) const
      Assign from an object that is a model of interval.
      template <typename T2> -
      bool - operator==(const T2& that) const
      Compare equality to an object that is a model of interval.bool + operator==(const interval_data& that) constEquality operator overload.
      template <typename T2> -
      bool - operator!=(const T2& that) const
      Compare inequality to an object that is a model of interval.bool + operator!=(const interval_data& that) constInequality operator overload.
      template <typename T2> -
      bool - operator<(const T2& that) const
      bool + operator<(const interval_data& that) const Compares low coordinates then high coordinates to break ties.
      template <typename T2> -
      bool - operator<=(const T2& that) const
      bool + operator<=(const interval_data& that) const Compares low coordinates then high coordinates to break ties.
      template <typename T2> -
      bool - operator>(const T2& that) const
      bool + operator>(const interval_data& that) const Compares low coordinates then high coordinates to break ties.
      template <typename T2> -
      bool - operator>=(const T2& that) const
      bool + operator>=(const interval_data& that) const Compares low coordinates then high coordinates to break ties.
      Get the coordinate in the given direction.
      T low() constRetrieves the low value.
      T high() constRetrieves the high endpoint.
      void set(direction_1d dir, T value) Sets the coordinate in the given direction to the value.
      interval_data& low(T value)Sets the low value.
      interval_data& high(T value)Sets the high value.
      diff --git a/doc/gtl_point_concept.htm b/doc/gtl_point_concept.htm index 924df95..37b8a26 100644 --- a/doc/gtl_point_concept.htm +++ b/doc/gtl_point_concept.htm @@ -1,12 +1,15 @@ - -Boost Polygon Library: Point Concept + + + +
      @@ -85,26 +88,27 @@ The point concept tag is point_concept

      To register a user defined type as a model of point concept, specialize the -geometry concept meta-function for that type.  In the example below CPoint is registered as a model of +geometry concept meta-function for that type.  In the example below CPoint is registered as a model of point  concept.

      template <>
      struct geometry_concept<CPoint> { typedef point_concept type; };

      -The semantic of a point is that it has an x and y +The semantic of a point is that it has an x and y coordinate.  A std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> could all be made models of point by simply providing indirect access to their elements through traits, however, these objects cannot be made a model of both point and interval in the same compilation unit, for obvious reason that duplicate specialization of the geometry_concept struct is illegal, but also because it would make overloading generic function by concept ambiguous if a -type modeled more than one concept.

      -Below is shown the default point traits.  +type modeled more than one concept.

      +Below is shown the default point traits.  Specialization of these traits is required for types that don't conform to the -default behavior.

      +default behavior.

      +

      template <typename T>
      struct point_traits {
           typedef typename T::coordinate_type coordinate_type;

      -     static inline coordinate_type get(const T& point, +     static coordinate_type get(const T& point, orientation_2d orient) {
                return point.get(orient);
      @@ -113,107 +117,110 @@ orientation_2d orient) {

      template <typename T>
      struct point_mutable_traits {
      -     static inline void set(T& point, orientation_2d orient, +     static void set(T& point, orientation_2d orient, typename point_traits<T>::coordinate_type value) {
                point.set(orient, value);
           }
      -     static inline T construct(typename point_traits<T>::coordinate_type +     static T construct(typename point_traits<T>::coordinate_type x_value, typename point_traits<T>::coordinate_type y_value) {
                return T(x_value, y_value);
           }
      -};

      +};

      +

      Example code custom_point.cpp demonstrates how to map a user defined point class to the library point_concept

      Functions

      - - + + value.
      + +  - - + + - + - + - + - + - + - + - + - - - - transformed values. - - + - + - + - + - + - + @@ -293,28 +293,25 @@ convenient to use with the library traits.

      library provided point data type and functions

      Members

      template <typename T>
      - coordinate_type get(const T& point, orientation_2d)
      Expects a model of point.  Returns + template <typename PointType>
      + coordinate_type get(const PointType& point,
                          +orientation_2d)
      Expects a model of point. Returns the x or y coordinate of the point, depending on the orientation_2d - value.
      template <typename T, typename - coordinate_type>
      - void set(T& point, orientation_2d, coordinate_type)
      Expects a model of point.   - Sets the x or y coordinate of the point to the coordinate, depending on - the orientation_2d  value. template <typename PointType>
      + void set(PointType& point, orientation_2d,
      +         coordinate_type)
      Expects a model of point. Sets the x or y coordinate of the point to the coordinate, depending on + the orientation_2d  value.
      template <typename T>
      - T construct(coordinate_type x, coordinate_type y)
      template <typename PointType>
      PointType construct(coordinate_type x,
      +                    +coordinate_type y)
      Construct an object that is a model of point given x and y coordinate values.
      template <typename T1, typename - T2>
      - T1& assign(T1& left, const T2& right)
      template <typename PointType1, typename PointType2>
      + PointType1& assign(PointType1& left,
      +                   +const PointType2& right)
      Copies data from right object that models point into left object that models point.
      template <typename T, typename - T2>
      - bool equivalence(const T& point1, const T2& point2)
      template <typename PointType1, typename PointType2>
      + bool equivalence(const
      PointType1& point1,
      +                 const
      PointType2& point2)
      Given two objects that model point, compares and returns true if their x and y values are respectively equal to each other.
      template <typename point_type>
      - coordinate_type x(const point_type& point)
      template <typename PointType>
      + coordinate_type x(const
      PointType& point)
      Returns the x coordinate of an object that models point.
      template <typename point_type>
      - coordinate_type y(const point_type& point)
      template <typename PointType>
      + coordinate_type y(const
      PointType& point)
      Returns the y coordinate of an object that models point.
      template <typename point_type>
      - void x(point_type& point, coordinate_type )
      template <typename PointType>
      + void x(p
      PointType& point, coordinate_type )
      Sets the x coordinate of the object that models point to the coordinate value. 
      template <typename point_type>
      - void y(point_type& point, coordinate_type )
      template <typename PointType>
      + void y(
      PointType& point, coordinate_type )
      Sets the y coordinate of the object that models point to the coordinate value. 
      template <typename point_type>
      - point_type& scale_up(point_type& point,
                              +
      template <typename PointType>
      + point_type& scale_up(
      PointType& point,
                           unsigned_area_type factor)
      Multiplies x and y coordinate of an object that models point by unsigned factor.
      template <typename point_type>
      - point_type& scale_down(point_type& point,
      -                          +
      template <typename PointType>
      + point_type& scale_down(
      PointType& point,
                             unsigned_area_type factor)
      Divides x and y coordinate of an object that models point by unsigned factor.
      template <typename point_type, + template <typename PointType, typename scaling_type>
      - point_type& scale(point_type& point,
      + point_type& scale(
      PointType& point,
                        const scaling_type& factor)
      Calls the scale member function of scaling type on the x and y value of an object that models point and sets the point to the scaled values.
      template <typename point_type, + template <typename PointType, typename transform_type>
      - point_type& transform(point_type& point,
      + point_type& transform(
      PointType& point,
                            const transform_type& transform)
      Calls the transform member function of transform type on the x and y @@ -221,59 +228,52 @@ unsigned_area_type factor)
      template <typename point_type>
      - point_type& move(point_type& point, orientation_2d
      +
      template <typename PointType>
      + point_type& move(
      PointType& point, orientation_2d,
                       coordinate_difference displacement)
      Adds displacement value to the coordinate of an object that models point indicated by the orientation_2d.
      template <typename T1, typename - T2>
      - T1& convolve(T1& a, const T2& b)
      template <typename PointType1, typename PointType2>
      +
      PointType1& convolve(PointType1& a,
      +                     const
      PointType2& b)
      Adds x coordinate of b to x coordinate of a and adds y coordinate of b to y coordinate of a.
      template <typename T1, typename - T2>
      - T1& deconvolve(T1& a, const T2& b)
      template <typename PointType1, typename PointType2>
      +
      PointType1,& deconvolve(PointType1& a,
      +                        +const
      PointType2>& b)
      Subtracts x coordinate of b from x coordinate of a and subtracts y coordinate of b from y coordinate of a.
      template <typename T1, typename - T2>
      - coordinate_distance euclidean_distance(const T1&,
      -                                       -const T2&)
      template <typename PointType1, typename PointType2>
      distance_type euclidean_distance(
      +    const
      PointType1&, const PointType2&)
      Returns the distance from an object that models point to a second object that models point.
      template <typename T>
      - coordinate_difference euclidean_distance(const T&,
      -           orientation_2d, - coordinate_type)
      template <typename PointType1, typename PointType2>
      + coordinate_difference euclidean_distance(
      +    const
      PointType1&, const PointType2&, orientation_2d)
      Returns the distance from an object that models point to a coordinate in the given orientation_2d.
      template <typename T1, typename - T2>
      - coordinate_difference manhattan_distance(const T1&,
      -                                       -const T2&)
      template <typename PointType1, typename PointType2>
      + coordinate_difference manhattan_distance(
      +   
      const PointType1&, const PointType2&)
      Returns the distance in x plus the distance in y from an object that models point to a second object that models point.
      template <typename T1, typename - T2>
      - coordinate_difference distance_squared(const T1&,
      -                                       -const T2&)
      template <typename PointType1, typename PointType2>
      + coordinate_difference distance_squared(
      +   
      const PointType1&, const PointType2&)
      Returns the square of the distance in x plus the square of the distance in y from an object that models point to a second object that models point.
      - - - - + - + - + - + - - + - + - - + + - - + + - + - + - + - + diff --git a/doc/gtl_segment_concept.htm b/doc/gtl_segment_concept.htm index 60349a9..f183d59 100644 --- a/doc/gtl_segment_concept.htm +++ b/doc/gtl_segment_concept.htm @@ -1,6 +1,5 @@ - -Boost Polygon Library: Segment Concept @@ -18,6 +17,8 @@ + + @@ -411,8 +412,8 @@ type is implemented to be convenient to use with the library traits.

      Memb

      diff --git a/include/boost/polygon/detail/boolean_op_45.hpp b/include/boost/polygon/detail/boolean_op_45.hpp index fd64eff..061727b 100644 --- a/include/boost/polygon/detail/boolean_op_45.hpp +++ b/include/boost/polygon/detail/boolean_op_45.hpp @@ -395,9 +395,9 @@ namespace boost { namespace polygon{ int edgeType = applyLogic(count1, count2); if(edgeType) { int multiplier = end == LOW ? -1 : 1; - //std::cout << "cross logic: " << edgeType << std::endl; + //std::cout << "cross logic: " << edgeType << "\n"; output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); - //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << "\n"; } } }; @@ -428,9 +428,9 @@ namespace boost { namespace polygon{ int edgeType = applyLogic(count1, count2); if(edgeType) { int multiplier = end == LOW ? -1 : 1; - //std::cout << "cross logic: " << edgeType << std::endl; + //std::cout << "cross logic: " << edgeType << "\n"; output.insert(output.end(), Vertex45(pt, rise, edgeType * multiplier)); - //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << std::endl; + //std::cout << "write out: " << crossPoint << " " << Point(eraseItrs[i]->x, eraseItrs[i]->y) << "\n"; } } }; @@ -510,18 +510,18 @@ namespace boost { namespace polygon{ //std::cout << "1\n"; while(inputBegin != inputEnd) { //std::cout << "2\n"; - //std::cout << "x_ = " << x_ << std::endl; - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "x_ = " << x_ << "\n"; + //std::cout << "scan line size: " << scanData_.size() << "\n"; //for(iterator iter = scanData_.begin(); // iter != scanData_.end(); ++iter) { // std::cout << "scan element\n"; - // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + // std::cout << *iter << " " << iter->evalAtX(x_) << "\n"; // } - // std::cout << "cross queue size: " << crossQueue_.size() << std::endl; - // std::cout << "cross vector size: " << crossVector_.size() << std::endl; + // std::cout << "cross queue size: " << crossQueue_.size() << "\n"; + // std::cout << "cross vector size: " << crossVector_.size() << "\n"; //for(CrossQueue::iterator cqitr = crossQueue_.begin(); cqitr != crossQueue_.end(); ++cqitr) { // std::cout << *cqitr << " "; - //} std::cout << std::endl; + //} std::cout << "\n"; Unit nextX = (*inputBegin).first.x(); if(!crossVector_.empty() && crossVector_[0].first.x() < nextX) nextX = crossVector_[0].first.x(); if(nextX != x_) { @@ -567,18 +567,18 @@ namespace boost { namespace polygon{ //std::cout << "loop\n"; //pop point off the cross queue Point crossPoint = *(crossQueue_.begin()); - //std::cout << crossPoint << std::endl; + //std::cout << crossPoint << "\n"; //for(iterator iter = scanData_.begin(); // iter != scanData_.end(); ++iter) { // std::cout << "scan element\n"; - // std::cout << *iter << " " << iter->evalAtX(x_) << std::endl; + // std::cout << *iter << " " << iter->evalAtX(x_) << "\n"; //} crossQueue_.erase(crossQueue_.begin()); Scan45Vertex vertex(crossPoint, Scan45Count()); iterator lowIter = lookUp_(vertex.first.y()); - //std::cout << "searching at: " << vertex.first.y() << std::endl; + //std::cout << "searching at: " << vertex.first.y() << "\n"; //if(lowIter == scanData_.end()) std::cout << "could not find\n"; - //else std::cout << "found: " << *lowIter << std::endl; + //else std::cout << "found: " << *lowIter << "\n"; if(lowIter == scanData_.end() || lowIter->evalAtX(x_) != vertex.first.y()) { // std::cout << "skipping\n"; @@ -593,7 +593,7 @@ namespace boost { namespace polygon{ --searchDownItr; countBelow = searchDownItr->count; } - //std::cout << "Below Count: " << countBelow << std::endl; + //std::cout << "Below Count: " << countBelow << "\n"; Scan45Count count(countBelow); std::size_t numEdges = 0; iterator eraseItrs[3]; @@ -601,7 +601,7 @@ namespace boost { namespace polygon{ lowIter->evalAtX(x_) == vertex.first.y()) { for(int index = lowIter->rise +1; index >= 0; --index) count[index] = lowIter->count; - //std::cout << count << std::endl; + //std::cout << count << "\n"; eraseItrs[numEdges] = lowIter; ++numEdges; ++lowIter; @@ -630,8 +630,8 @@ namespace boost { namespace polygon{ vertex.second[0] = count[0] - count[1]; //add the point, deriviative pair into the cross vector //std::cout << "LOOK HERE!\n"; - //std::cout << count << std::endl; - //std::cout << vertex << std::endl; + //std::cout << count << "\n"; + //std::cout << vertex << "\n"; crossVector_.push_back(vertex); } //erase crossing elements @@ -686,10 +686,10 @@ namespace boost { namespace polygon{ iterator prevIter = scanData_.end(); while(inputBegin != inputEnd && (*inputBegin).first.x() == x_) { - //std::cout << (*inputBegin) << std::endl; + //std::cout << (*inputBegin) << "\n"; //std::cout << "loop\n"; Scan45Vertex vertex = *inputBegin; - //std::cout << vertex.first << std::endl; + //std::cout << vertex.first << "\n"; //if vertical count propigating up fake a null event at the next element if(verticalCount != CountType() && (prevIter != scanData_.end() && prevIter->evalAtX(x_) < vertex.first.y())) { @@ -707,13 +707,13 @@ namespace boost { namespace polygon{ ++inputBegin; } } - //std::cout << vertex.second << std::endl; + //std::cout << vertex.second << "\n"; //integrate vertex CountType currentCount = verticalCount;// + vertex.second[0]; for(unsigned int i = 0; i < 3; ++i) { vertex.second[i] = currentCount += vertex.second[i]; } - //std::cout << vertex.second << std::endl; + //std::cout << vertex.second << "\n"; //vertex represents the change in state at this point //get counts at current vertex @@ -725,8 +725,8 @@ namespace boost { namespace polygon{ countBelow = lowIter->count; ++lowIter; } - //std::cout << "Count Below: " << countBelow[0] << " " << countBelow[1] << std::endl; - //std::cout << "vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + //std::cout << "Count Below: " << countBelow[0] << " " << countBelow[1] << "\n"; + //std::cout << "vertical count: " << verticalCount[0] << " " << verticalCount[1] << "\n"; Scan45Count countAt(countBelow - verticalCount); //check if the vertical edge should be written out if(verticalCount != CountType()) { @@ -756,20 +756,20 @@ namespace boost { namespace polygon{ } verticalCount += vertex.second[3]; prevPoint = vertex.first; - //std::cout << "new vertical count: " << verticalCount[0] << " " << verticalCount[1] << std::endl; + //std::cout << "new vertical count: " << verticalCount[0] << " " << verticalCount[1] << "\n"; prevIter = lowIter; //count represents the current state at this point - //std::cout << vertex.second << std::endl; - //std::cout << countAt << std::endl; + //std::cout << vertex.second << "\n"; + //std::cout << countAt << "\n"; //std::cout << "ADD\n"; vertex.second += countAt; - //std::cout << vertex.second << std::endl; + //std::cout << vertex.second << "\n"; //add elements to the scanline for(int i = 0; i < 3; ++i) { if(vertex.second[i] != countBelow) { //std::cout << "insert: " << vertex.first.x() << " " << vertex.first.y() << " " << i-1 << - // " " << vertex.second[i][0] << " " << vertex.second[i][1] << std::endl; + // " " << vertex.second[i][0] << " " << vertex.second[i][1] << "\n"; iterator insertIter = scanData_.insert(scanData_.end(), Scan45ElementT(vertex.first.x(), vertex.first.y(), @@ -864,7 +864,7 @@ namespace boost { namespace polygon{ } } } - //std::cout << std::endl; + //std::cout << "\n"; } inline iterator lookUp_(Unit y){ @@ -878,7 +878,7 @@ namespace boost { namespace polygon{ // lessScan45Element >& data) { // typename std::set, lessScan45Element >::const_iterator iter; // for(iter = data.begin(); iter != data.end(); ++iter) { - // std::cout << iter->x << " " << iter->y << " " << iter->rise << std::endl; + // std::cout << iter->x << " " << iter->y << " " << iter->rise << "\n"; // } //} @@ -957,13 +957,13 @@ namespace boost { namespace polygon{ reference.push_back(Vertex45(Point(10, 10), 2, 1)); reference.push_back(Vertex45(Point(10, 10), 0, 1)); if(result != reference) { - stdcout << "result size == " << result.size() << std::endl; + stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { - //std::cout << "result == " << result[i]<< std::endl; + //std::cout << "result == " << result[i]<< "\n"; } - stdcout << "reference size == " << reference.size() << std::endl; + stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { - //std::cout << "reference == " << reference[i]<< std::endl; + //std::cout << "reference == " << reference[i]<< "\n"; } return false; } @@ -1007,13 +1007,13 @@ namespace boost { namespace polygon{ reference.push_back(Vertex45(Point(10, 20), 2, 1)); reference.push_back(Vertex45(Point(10, 20), 1, 1)); if(result != reference) { - stdcout << "result size == " << result.size() << std::endl; + stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { - //std::cout << "result == " << result[i]<< std::endl; + //std::cout << "result == " << result[i]<< "\n"; } - stdcout << "reference size == " << reference.size() << std::endl; + stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { - //std::cout << "reference == " << reference[i]<< std::endl; + //std::cout << "reference == " << reference[i]<< "\n"; } return false; } @@ -1057,13 +1057,13 @@ namespace boost { namespace polygon{ reference.push_back(Vertex45(Point(20, 10), 1, -1)); reference.push_back(Vertex45(Point(20, 10), 0, 1)); if(result != reference) { - stdcout << "result size == " << result.size() << std::endl; + stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { - //stdcout << "result == " << result[i]<< std::endl; + //stdcout << "result == " << result[i]<< "\n"; } - stdcout << "reference size == " << reference.size() << std::endl; + stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { - //stdcout << "reference == " << reference[i]<< std::endl; + //stdcout << "reference == " << reference[i]<< "\n"; } return false; } @@ -1114,13 +1114,13 @@ namespace boost { namespace polygon{ reference.push_back(Vertex45(Point(10, 10), 2, 1)); reference.push_back(Vertex45(Point(10, 10), 0, 1)); if(result != reference) { - stdcout << "result size == " << result.size() << std::endl; + stdcout << "result size == " << result.size() << "\n"; for(std::size_t i = 0; i < result.size(); ++i) { - //stdcout << "result == " << result[i]<< std::endl; + //stdcout << "result == " << result[i]<< "\n"; } - stdcout << "reference size == " << reference.size() << std::endl; + stdcout << "reference size == " << reference.size() << "\n"; for(std::size_t i = 0; i < reference.size(); ++i) { - //stdcout << "reference == " << reference[i]<< std::endl; + //stdcout << "reference == " << reference[i]<< "\n"; } return false; } @@ -1176,8 +1176,8 @@ namespace boost { namespace polygon{ // result == 12 8 1 -1 // result == 12 8 -1 1 if(result.size() != 24) { - //stdcout << "result size == " << result.size() << std::endl; - //stdcout << "reference size == " << 24 << std::endl; + //stdcout << "result size == " << result.size() << "\n"; + //stdcout << "reference size == " << 24 << "\n"; return false; } stdcout << "done testing Scan45Star1\n"; @@ -1232,8 +1232,8 @@ namespace boost { namespace polygon{ // result == 16 8 1 -1 // result == 16 8 0 1 if(result.size() != 24) { - //std::cout << "result size == " << result.size() << std::endl; - //std::cout << "reference size == " << 24 << std::endl; + //std::cout << "result size == " << result.size() << "\n"; + //std::cout << "reference size == " << 24 << "\n"; return false; } stdcout << "done testing Scan45Star2\n"; @@ -1297,8 +1297,8 @@ namespace boost { namespace polygon{ // result == 12 14 2 1 // result == 12 14 0 1 if(result.size() != 28) { - //std::cout << "result size == " << result.size() << std::endl; - //std::cout << "reference size == " << 28 << std::endl; + //std::cout << "result size == " << result.size() << "\n"; + //std::cout << "reference size == " << 28 << "\n"; return false; } @@ -1364,8 +1364,8 @@ namespace boost { namespace polygon{ // result == 16 12 2 1 // result == 16 12 0 1 if(result.size() != 28) { - //stdcout << "result size == " << result.size() << std::endl; - //stdcout << "reference size == " << 28 << std::endl; + //stdcout << "result size == " << result.size() << "\n"; + //stdcout << "reference size == " << 28 << "\n"; return false; } diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp index 8ad30f1..2e16570 100644 --- a/include/boost/polygon/detail/polygon_45_formation.hpp +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -311,7 +311,7 @@ namespace boost { namespace polygon{ at1->copyHoles(*(at1->otherTailp_)); //std::cout << "test2\n"; //Polygon45WithHolesImpl poly(polyData); - //std::cout << poly << std::endl; + //std::cout << poly << "\n"; //std::cout << "test3\n"; typedef typename cT::value_type pType; output.push_back(pType()); @@ -319,14 +319,14 @@ namespace boost { namespace polygon{ typename PolyLineByConcept::type polyData(at1); assign(output.back(), polyData); //std::cout << "test4\n"; - //std::cout << "delete " << at1->otherTailp_ << std::endl; + //std::cout << "delete " << at1->otherTailp_ << "\n"; //at1->print(); //at1->otherTailp_->print(); delete at1->otherTailp_; //at1->print(); //at1->otherTailp_->print(); //std::cout << "test5\n"; - //std::cout << "delete " << at1 << std::endl; + //std::cout << "delete " << at1 << "\n"; delete at1; //std::cout << "test6\n"; return 0; @@ -345,7 +345,7 @@ namespace boost { namespace polygon{ inline void destroyContents() { if(otherTailp_) { - //std::cout << "delete p " << tailp_ << std::endl; + //std::cout << "delete p " << tailp_ << "\n"; if(tailp_) delete tailp_; tailp_ = 0; otherTailp_->otherTailp_ = 0; @@ -353,7 +353,7 @@ namespace boost { namespace polygon{ otherTailp_ = 0; } for(typename std::list::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { - //std::cout << "delete p " << (*itr) << std::endl; + //std::cout << "delete p " << (*itr) << "\n"; if(*itr) { if((*itr)->otherTailp_) { delete (*itr)->otherTailp_; @@ -367,7 +367,7 @@ namespace boost { namespace polygon{ } // inline void print() { -// std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; +// std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << "\n"; // } static inline std::pair createActiveTail45sAsPair(Point point, bool solid, @@ -575,9 +575,9 @@ namespace boost { namespace polygon{ while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.x(); - //std::cout << "SCAN FORMATION " << x_ << std::endl; - //std::cout << "x_ = " << x_ << std::endl; - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "SCAN FORMATION " << x_ << "\n"; + //std::cout << "x_ = " << x_ << "\n"; + //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } } @@ -587,7 +587,7 @@ namespace boost { namespace polygon{ template inline std::pair processPoint_(cT& output, cT2& elements, Point point, Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { - //std::cout << point << std::endl; + //std::cout << point << "\n"; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; @@ -600,14 +600,14 @@ namespace boost { namespace polygon{ ActiveTail45* returnValue = 0; int returnCount = 0; for(int i = 0; i < 3; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { - //std::cout << "case1: " << i << " " << j << std::endl; + //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; @@ -623,14 +623,14 @@ namespace boost { namespace polygon{ //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; for(int i = 0; i < 3; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(incoming[j]) { if(incoming[j] == -1) { - //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, fractureHoles_ != 0); @@ -642,10 +642,10 @@ namespace boost { namespace polygon{ returnCount = 1; } else { Vertex45 vertex(point, i -1, incoming[i]); - //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << "new element " << j-1 << " " << -1 << "\n"; elements.push_back(std::pair(Vertex45(point, j -1, -1), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << "new element " << i-1 << " " << 1 << "\n"; elements.push_back(std::pair(Vertex45(point, i -1, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; @@ -662,14 +662,14 @@ namespace boost { namespace polygon{ //find pass through with solid on top //std::cout << "checking case 3\n"; for(int i = 0; i < 4; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = 3; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { - //std::cout << "case3: " << i << " " << j << std::endl; + //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); @@ -699,14 +699,14 @@ namespace boost { namespace polygon{ for(int j = 0; j < 4; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { - //std::cout << "case4: " << i << " " << j << std::endl; + //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom tails[i]->pushPoint(point); if(j == 3) { returnValue = tails[i]; returnCount = 1; } else { - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tails[i])); } tails[i] = 0; @@ -728,7 +728,7 @@ namespace boost { namespace polygon{ if(counts[i] != 0) { for(int j = i+1; j < 4; ++j) { if(counts[j] != 0) { - //std::cout << "case5: " << i << " " << j << std::endl; + //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole returnValue = ActiveTail45::joinChains(point, tails[i], tails[j], false, output); tails[i] = 0; @@ -746,7 +746,7 @@ namespace boost { namespace polygon{ if(incoming[i] != 0) { for(int j = i+1; j < 4; ++j) { if(incoming[j] != 0) { - //std::cout << "case6: " << i << " " << j << std::endl; + //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space ActiveTail45* holep = 0; if(counts[3] == 0) holep = tails[3]; @@ -756,10 +756,10 @@ namespace boost { namespace polygon{ returnValue = tailPair.first; returnCount = -1; } else { - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; elements.push_back(std::pair(Vertex45(point, i -1, incoming[i]), tailPair.second)); incoming[i] = 0; incoming[j] = 0; @@ -798,7 +798,7 @@ namespace boost { namespace polygon{ //std::cout << "loop2\n"; elementIters.push_back(iter); int index = iter->first.rise + 1; - //std::cout << index << " " << iter->first.count << std::endl; + //std::cout << index << " " << iter->first.count << "\n"; counts[index] = iter->first.count; tails[index] = iter->second; ++iter; @@ -834,7 +834,7 @@ namespace boost { namespace polygon{ verticalCount = result.first; verticalTail = result.second; //if(verticalTail) std::cout << "have vertical tail\n"; - //std::cout << "verticalCount: " << verticalCount << std::endl; + //std::cout << "verticalCount: " << verticalCount << "\n"; if(verticalTail && !verticalCount) { //we got a hole out of the point we just processed //iter is still at the next y element above the current y value in the tree @@ -906,9 +906,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -930,9 +930,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 20), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -955,9 +955,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1020,9 +1020,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), -1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1053,9 +1053,9 @@ namespace boost { namespace polygon{ polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1125,9 +1125,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1197,9 +1197,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1241,9 +1241,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1289,9 +1289,9 @@ namespace boost { namespace polygon{ while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.x(); - //std::cout << "SCAN FORMATION " << x_ << std::endl; - //std::cout << "x_ = " << x_ << std::endl; - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "SCAN FORMATION " << x_ << "\n"; + //std::cout << "x_ = " << x_ << "\n"; + //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } } @@ -1316,7 +1316,7 @@ namespace boost { namespace polygon{ std::pair& verticalPair, iterator previter, Point point, Vertex45Count& counts, ActiveTail45** tails, Vertex45Count& incoming) { - //std::cout << point << std::endl; + //std::cout << point << "\n"; //std::cout << counts[0] << " "; //std::cout << counts[1] << " "; //std::cout << counts[2] << " "; @@ -1332,14 +1332,14 @@ namespace boost { namespace polygon{ verticalPairOut.second = 0; int returnCount = 0; for(int i = 0; i < 3; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { - //std::cout << "case1: " << i << " " << j << std::endl; + //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output ActiveTail45::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; @@ -1355,14 +1355,14 @@ namespace boost { namespace polygon{ //find any pairs of incoming edges that need to create pair for leading solid //std::cout << "checking case2\n"; for(int i = 0; i < 3; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < 4; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(incoming[j]) { if(incoming[j] == -1) { - //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); @@ -1374,10 +1374,10 @@ namespace boost { namespace polygon{ returnCount = 1; } else { Vertex45 vertex(point, i -1, incoming[i]); - //std::cout << "new element " << j-1 << " " << -1 << std::endl; + //std::cout << "new element " << j-1 << " " << -1 << "\n"; elements.push_back(std::pair(Vertex45(point, j -1, -1), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << 1 << std::endl; + //std::cout << "new element " << i-1 << " " << 1 << "\n"; elements.push_back(std::pair(Vertex45(point, i -1, 1), tailPair.second)); incoming[i] = 0; incoming[j] = 0; @@ -1394,14 +1394,14 @@ namespace boost { namespace polygon{ //find pass through with solid on top //std::cout << "checking case 3\n"; for(int i = 0; i < 4; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = 3; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { - //std::cout << "case3: " << i << " " << j << std::endl; + //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top if(i != 3) @@ -1437,10 +1437,10 @@ namespace boost { namespace polygon{ for(int j = 0; j < 4; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { - //std::cout << "case4: " << i << " " << j << std::endl; + //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom if(i == 3) { - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; if(j == 3) { returnValue = tails[i]; returnCount = 1; @@ -1483,7 +1483,7 @@ namespace boost { namespace polygon{ if(counts[i] != 0) { for(int j = i+1; j < 4; ++j) { if(counts[j] != 0) { - //std::cout << "case5: " << i << " " << j << std::endl; + //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole tails[i]->pushPoint(point); verticalPairOut.first = tails[i]; @@ -1511,7 +1511,7 @@ namespace boost { namespace polygon{ if(incoming[i] != 0) { for(int j = i+1; j < 4; ++j) { if(incoming[j] != 0) { - //std::cout << "case6: " << i << " " << j << std::endl; + //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); @@ -1523,12 +1523,12 @@ namespace boost { namespace polygon{ } else { std::pair tailPair = ActiveTail45::createActiveTail45sAsPair(point, true, 0, false); - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; elements.push_back(std::pair(Vertex45(point, j -1, incoming[j]), tailPair.second)); verticalPairOut.second = tailPair.first; verticalPairOut.first = verticalPair.first; } - //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; + //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; elements.push_back(std::pair(Vertex45(point, i -1, incoming[i]), verticalPair.second)); incoming[i] = 0; incoming[j] = 0; @@ -1578,7 +1578,7 @@ namespace boost { namespace polygon{ //std::cout << "loop2\n"; elementIters.push_back(iter); int index = iter->first.rise + 1; - //std::cout << index << " " << iter->first.count << std::endl; + //std::cout << index << " " << iter->first.count << "\n"; counts[index] = iter->first.count; tails[index] = iter->second; ++iter; @@ -1670,9 +1670,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1694,9 +1694,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(10, 20), 1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1718,9 +1718,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, 10), 0, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1744,9 +1744,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, 20), 2, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1770,9 +1770,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(20, -10), 2, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1803,9 +1803,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(3, 2), 0, -1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1837,9 +1837,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1901,9 +1901,9 @@ namespace boost { namespace polygon{ data.push_back(Vertex45(Point(12, 8), -1, 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -1935,9 +1935,9 @@ namespace boost { namespace polygon{ polygon_sort(result.begin(), result.end()); pf.scan(polys, result.begin(), result.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -2007,9 +2007,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -2079,9 +2079,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; @@ -2123,9 +2123,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon tiling\n"; return true; diff --git a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp index 8c45617..e1acdbb 100644 --- a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp +++ b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -442,8 +442,8 @@ namespace boost { namespace polygon{ y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; - //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; - //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); if(round_closest) { @@ -460,10 +460,10 @@ namespace boost { namespace polygon{ if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) - // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); - //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!projected && !contains(rect1, result, true)) return false; if(!projected && !contains(rect2, result, true)) return false; @@ -554,9 +554,9 @@ namespace boost { namespace polygon{ y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; - //std::cout << x << " " << y << std::endl; - //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; - //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //std::cout << x << " " << y << "\n"; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); if(round_closest) { @@ -573,10 +573,10 @@ namespace boost { namespace polygon{ if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) - // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); - //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; @@ -644,8 +644,8 @@ namespace boost { namespace polygon{ high_precision y_den = (dx1 * dy2 - dx2 * dy1); high_precision x = x_num / x_den; high_precision y = y_num / y_den; - //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; - //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; + //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << "\n"; + //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << "\n"; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); //Unit exp_y = compute_x_intercept(y11, y21, x11, x21, dx1, dx2, dy1, dy2); Unit x_unit = convert_high_precision_type(x); @@ -658,10 +658,10 @@ namespace boost { namespace polygon{ if(is_horizontal(he2)) y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) - // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; + // std::cout << exp_x << " " << exp_y << " " << x << " " << y << "\n"; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); //Unit y2 = evalAtXforY(exp_x, he2.first, he2.second); - //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << std::endl; + //std::cout << exp_x << " " << exp_y << " " << y1 << " " << y2 << "\n"; Point result(x_unit, y_unit); if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; @@ -1121,21 +1121,21 @@ namespace boost { namespace polygon{ typename PolyLineArbitraryByConcept::type>::type polyData(at1); //poly_line_arbitrary_polygon_data polyData(at1); //std::cout << "test2\n"; - //std::cout << poly << std::endl; + //std::cout << poly << "\n"; //std::cout << "test3\n"; typedef typename cT::value_type result_type; typedef typename geometry_concept::type result_concept; output.push_back(result_type()); assign(output.back(), polyData); //std::cout << "test4\n"; - //std::cout << "delete " << at1->otherTailp_ << std::endl; + //std::cout << "delete " << at1->otherTailp_ << "\n"; //at1->print(); //at1->otherTailp_->print(); delete at1->otherTailp_; //at1->print(); //at1->otherTailp_->print(); //std::cout << "test5\n"; - //std::cout << "delete " << at1 << std::endl; + //std::cout << "delete " << at1 << "\n"; delete at1; //std::cout << "test6\n"; return 0; @@ -1154,7 +1154,7 @@ namespace boost { namespace polygon{ inline void destroyContents() { if(otherTailp_) { - //std::cout << "delete p " << tailp_ << std::endl; + //std::cout << "delete p " << tailp_ << "\n"; if(tailp_) delete tailp_; tailp_ = 0; otherTailp_->otherTailp_ = 0; @@ -1162,7 +1162,7 @@ namespace boost { namespace polygon{ otherTailp_ = 0; } for(typename std::list::iterator itr = holesList_.begin(); itr != holesList_.end(); ++itr) { - //std::cout << "delete p " << (*itr) << std::endl; + //std::cout << "delete p " << (*itr) << "\n"; if(*itr) { if((*itr)->otherTailp_) { delete (*itr)->otherTailp_; @@ -1176,7 +1176,7 @@ namespace boost { namespace polygon{ } inline void print() { - //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << std::endl; + //std::cout << this << " " << tailp_ << " " << otherTailp_ << " " << holesList_.size() << " " << head_ << "\n"; } static inline std::pair createActiveTailsAsPair(Point point, bool solid, @@ -1356,12 +1356,12 @@ namespace boost { namespace polygon{ while(inputBegin != inputEnd) { //std::cout << "2\n"; x_ = (*inputBegin).pt.get(HORIZONTAL); - //std::cout << "SCAN FORMATION " << x_ << std::endl; - //std::cout << "x_ = " << x_ << std::endl; - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "SCAN FORMATION " << x_ << "\n"; + //std::cout << "x_ = " << x_ << "\n"; + //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "scan line size: " << scanData_.size() << "\n"; } protected: @@ -1369,7 +1369,7 @@ namespace boost { namespace polygon{ template inline std::pair, active_tail_arbitrary*> processPoint_(cT& output, cT2& elements, Point point, incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { - //std::cout << "\nAT POINT: " << point << std::endl; + //std::cout << "\nAT POINT: " << point << "\n"; //join any closing solid corners std::vector counts; std::vector incoming; @@ -1401,25 +1401,25 @@ namespace boost { namespace polygon{ have_vertical_tail_from_below = true; } //assert size = size_less_1 + 1 - //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << "\n"; // for(std::size_t i = 0; i < counts.size(); ++i) { // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; // std::cout << counts_from_scanline[i].first.second << " "; - // } std::cout << std::endl; + // } std::cout << "\n"; // print(incoming_count); { for(int i = 0; i < c_size_less_1; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < c_size; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { - //std::cout << "case1: " << i << " " << j << std::endl; + //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; @@ -1437,15 +1437,15 @@ namespace boost { namespace polygon{ //std::cout << "checking case2\n"; { for(int i = 0; i < i_size_less_1; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < i_size; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(incoming[j]) { - //std::cout << incoming[j] << std::endl; + //std::cout << incoming[j] << "\n"; if(incoming[j] == -1) { - //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, fractureHoles_ != 0); @@ -1457,14 +1457,14 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = 1; } else { - //std::cout << "new element " << j-1 << " " << -1 << std::endl; - //std::cout << point << " " << incoming_count[j].first << std::endl; + //std::cout << "new element " << j-1 << " " << -1 << "\n"; + //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << 1 << std::endl; - //std::cout << point << " " << incoming_count[i].first << std::endl; + //std::cout << "new element " << i-1 << " " << 1 << "\n"; + //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); @@ -1484,14 +1484,14 @@ namespace boost { namespace polygon{ { //std::cout << "checking case 3\n"; for(int i = 0; i < c_size; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = i_size_less_1; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { - //std::cout << "case3: " << i << " " << j << std::endl; + //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); @@ -1521,13 +1521,13 @@ namespace boost { namespace polygon{ //find pass through with solid on bottom { for(int i = c_size_less_1; i >= 0; --i) { - //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + //std::cout << "i = " << i << " with count " << counts[i] << "\n"; if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < i_size; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { - //std::cout << "case4: " << i << " " << j << std::endl; + //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom tails[i]->pushPoint(point); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { @@ -1535,8 +1535,8 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = 1; } else { - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; - //std::cout << point << " " << incoming_count[j].first << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; + //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tails[i])); @@ -1561,11 +1561,11 @@ namespace boost { namespace polygon{ if(counts[i] != 0) { for(int j = i+1; j < c_size; ++j) { if(counts[j] != 0) { - //std::cout << "case5: " << i << " " << j << std::endl; + //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole returnValue = active_tail_arbitrary::joinChains(point, tails[i], tails[j], false, output); if(returnValue) returnCount.first = point; - //std::cout << returnValue << std::endl; + //std::cout << returnValue << "\n"; tails[i] = 0; tails[j] = 0; counts[i] = 0; @@ -1583,7 +1583,7 @@ namespace boost { namespace polygon{ if(incoming[i] != 0) { for(int j = i+1; j < i_size; ++j) { if(incoming[j] != 0) { - //std::cout << "case6: " << i << " " << j << std::endl; + //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space active_tail_arbitrary* holep = 0; //if(c_size && counts[c_size_less_1] == 0 && @@ -1596,20 +1596,20 @@ namespace boost { namespace polygon{ std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, false, holep, fractureHoles_ != 0); if(j == i_size_less_1 && incoming_count[j].first.get(HORIZONTAL) == point.get(HORIZONTAL)) { - //std::cout << "vertical element " << point << std::endl; + //std::cout << "vertical element " << point << "\n"; returnValue = tailPair.first; returnCount.first = point; //returnCount = incoming_count[j]; returnCount.second = -1; } else { - //std::cout << "new element " << j-1 << " " << incoming[j] << std::endl; - //std::cout << point << " " << incoming_count[j].first << std::endl; + //std::cout << "new element " << j-1 << " " << incoming[j] << "\n"; + //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, incoming[j]), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << incoming[i] << std::endl; - //std::cout << point << " " << incoming_count[i].first << std::endl; + //std::cout << "new element " << i-1 << " " << incoming[i] << "\n"; + //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, incoming[i]), tailPair.second)); @@ -1639,13 +1639,13 @@ namespace boost { namespace polygon{ //std::cout << count[i].first.get(HORIZONTAL) << ","; //std::cout << count[i].first.get(VERTICAL) << ":"; //std::cout << count[i].second << " "; - } //std::cout << std::endl; + } //std::cout << "\n"; } static inline void print(const scanline_data& data) { for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; - } //std::cout << std::endl; + } //std::cout << "\n"; } template @@ -1664,16 +1664,16 @@ namespace boost { namespace polygon{ while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.get(VERTICAL); - //std::cout << "current Y " << currentY << std::endl; - //std::cout << "scanline size " << scanData_.size() << std::endl; + //std::cout << "current Y " << currentY << "\n"; + //std::cout << "scanline size " << scanData_.size() << "\n"; //print(scanData_); iterator iter = lookUp_(currentY); - //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //std::cout << "found element in scanline " << (iter != scanData_.end()) << "\n"; //int counts[4] = {0, 0, 0, 0}; incoming_count counts_from_scanline; //std::cout << "finding elements in tree\n"; //if(iter != scanData_.end()) - // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << "\n"; while(iter != scanData_.end() && ((iter->first.pt.x() == x_ && iter->first.pt.y() == currentY) || (iter->first.other_pt.x() == x_ && iter->first.other_pt.y() == currentY))) { @@ -1688,7 +1688,7 @@ namespace boost { namespace polygon{ ++iter; } Point currentPoint(x_, currentY); - //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << "\n"; sort_incoming_count(counts_from_scanline, currentPoint); vertex_arbitrary_count incoming; @@ -1702,9 +1702,9 @@ namespace boost { namespace polygon{ currentIter->pt.get(HORIZONTAL) == x_); //print(incoming); sort_vertex_arbitrary_count(incoming, currentPoint); - //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << "\n"; //print(incoming); - //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //compact_vertex_arbitrary_count(currentPoint, incoming); vertex_arbitrary_count tmp; tmp.reserve(incoming.size()); @@ -1714,13 +1714,13 @@ namespace boost { namespace polygon{ } } incoming.swap(tmp); - //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //now counts_from_scanline has the data from the left and //incoming has the data from the right at this point //cancel out any end points if(verticalTail) { //std::cout << "adding vertical tail to counts from scanline\n"; - //std::cout << -verticalCount.second << std::endl; + //std::cout << -verticalCount.second << "\n"; counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> (std::pair, int>(std::pair(verticalCount.first, currentPoint), @@ -1737,7 +1737,7 @@ namespace boost { namespace polygon{ verticalTail = result.second; //if(verticalTail) { // std::cout << "have vertical tail\n"; - // std::cout << verticalCount.second << std::endl; + // std::cout << verticalCount.second << "\n"; //} if(verticalTail && !(verticalCount.second)) { //we got a hole out of the point we just processed @@ -1794,7 +1794,7 @@ namespace boost { namespace polygon{ inline iterator lookUp_(Unit y){ //if just before then we need to look from 1 not -1 - //std::cout << "just before " << justBefore_ << std::endl; + //std::cout << "just before " << justBefore_ << "\n"; return scanData_.lower_bound(vertex_half_edge(Point(x_, y), Point(x_, y+1), 0)); } @@ -1816,9 +1816,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1840,9 +1840,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1864,9 +1864,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1910,14 +1910,14 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } pf2.scan(polys2, data.begin(), data.end()); - stdcout << "result size: " << polys2.size() << std::endl; + stdcout << "result size: " << polys2.size() << "\n"; for(std::size_t i = 0; i < polys2.size(); ++i) { - stdcout << polys2[i] << std::endl; + stdcout << polys2[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1957,9 +1957,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -1997,9 +1997,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -2037,9 +2037,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -2065,9 +2065,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(0, 2), Point(-1, 4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing polygon formation\n"; return true; @@ -2281,12 +2281,12 @@ namespace boost { namespace polygon{ while(inputBegin != inputEnd) { //std::cout << "2\n"; polygon_arbitrary_formation::x_ = (*inputBegin).pt.get(HORIZONTAL); - //std::cout << "SCAN FORMATION " << x_ << std::endl; - //std::cout << "x_ = " << x_ << std::endl; - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "SCAN FORMATION " << x_ << "\n"; + //std::cout << "x_ = " << x_ << "\n"; + //std::cout << "scan line size: " << scanData_.size() << "\n"; inputBegin = processEvent_(output, inputBegin, inputEnd); } - //std::cout << "scan line size: " << scanData_.size() << std::endl; + //std::cout << "scan line size: " << scanData_.size() << "\n"; } private: @@ -2311,7 +2311,7 @@ namespace boost { namespace polygon{ std::pair& verticalPair, iterator previter, Point point, incoming_count& counts_from_scanline, vertex_arbitrary_count& incoming_count) { - //std::cout << "\nAT POINT: " << point << std::endl; + //std::cout << "\nAT POINT: " << point << "\n"; //join any closing solid corners std::vector counts; std::vector incoming; @@ -2346,25 +2346,25 @@ namespace boost { namespace polygon{ have_vertical_tail_from_below = true; } //assert size = size_less_1 + 1 - //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << std::endl; + //std::cout << tails.size() << " " << incoming.size() << " " << counts_from_scanline.size() << " " << incoming_count.size() << "\n"; // for(std::size_t i = 0; i < counts.size(); ++i) { // std::cout << counts_from_scanline[i].first.first.first.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.first.get(VERTICAL) << " "; // std::cout << counts_from_scanline[i].first.first.second.get(HORIZONTAL) << ","; // std::cout << counts_from_scanline[i].first.first.second.get(VERTICAL) << ":"; // std::cout << counts_from_scanline[i].first.second << " "; - // } std::cout << std::endl; + // } std::cout << "\n"; // print(incoming_count); { for(int i = 0; i < c_size_less_1; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] == -1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < c_size; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(counts[j]) { if(counts[j] == 1) { - //std::cout << "case1: " << i << " " << j << std::endl; + //std::cout << "case1: " << i << " " << j << "\n"; //if a figure is closed it will be written out by this function to output active_tail_arbitrary::joinChains(point, tails[i], tails[j], true, output); counts[i] = 0; @@ -2382,15 +2382,15 @@ namespace boost { namespace polygon{ //std::cout << "checking case2\n"; { for(int i = 0; i < i_size_less_1; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(incoming[i] == 1) { //std::cout << "fixed i\n"; for(int j = i + 1; j < i_size; ++j) { - //std::cout << j << std::endl; + //std::cout << j << "\n"; if(incoming[j]) { - //std::cout << incoming[j] << std::endl; + //std::cout << incoming[j] << "\n"; if(incoming[j] == -1) { - //std::cout << "case2: " << i << " " << j << std::endl; + //std::cout << "case2: " << i << " " << j << "\n"; //std::cout << "creating active tail pair\n"; std::pair tailPair = active_tail_arbitrary::createActiveTailsAsPair(point, true, 0, polygon_arbitrary_formation::fractureHoles_ != 0); @@ -2402,14 +2402,14 @@ namespace boost { namespace polygon{ returnCount.first = point; returnCount.second = 1; } else { - //std::cout << "new element " << j-1 << " " << -1 << std::endl; - //std::cout << point << " " << incoming_count[j].first << std::endl; + //std::cout << "new element " << j-1 << " " << -1 << "\n"; + //std::cout << point << " " << incoming_count[j].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[j].first, -1), tailPair.first)); } - //std::cout << "new element " << i-1 << " " << 1 << std::endl; - //std::cout << point << " " << incoming_count[i].first << std::endl; + //std::cout << "new element " << i-1 << " " << 1 << "\n"; + //std::cout << point << " " << incoming_count[i].first << "\n"; elements.push_back(std::pair(vertex_half_edge(point, incoming_count[i].first, 1), tailPair.second)); @@ -2429,14 +2429,14 @@ namespace boost { namespace polygon{ { //std::cout << "checking case 3\n"; for(int i = 0; i < c_size; ++i) { - //std::cout << i << std::endl; + //std::cout << i << "\n"; if(counts[i] != 0) { if(counts[i] == 1) { //std::cout << "fixed i\n"; for(int j = i_size_less_1; j >= 0; --j) { if(incoming[j] != 0) { if(incoming[j] == 1) { - //std::cout << "case3: " << i << " " << j << std::endl; + //std::cout << "case3: " << i << " " << j << "\n"; //tails[i]->print(); //pass through solid on top tails[i]->pushPoint(point); @@ -2470,13 +2470,13 @@ namespace boost { namespace polygon{ //find pass through with solid on bottom { for(int i = c_size_less_1; i >= 0; --i) { - //std::cout << "i = " << i << " with count " << counts[i] << std::endl; + //std::cout << "i = " << i << " with count " << counts[i] << "\n"; if(counts[i] != 0) { if(counts[i] == -1) { for(int j = 0; j < i_size; ++j) { if(incoming[j] != 0) { if(incoming[j] == -1) { - //std::cout << "case4: " << i << " " << j << std::endl; + //std::cout << "case4: " << i << " " << j << "\n"; //pass through solid on bottom //if count from scanline is vertical @@ -2536,7 +2536,7 @@ namespace boost { namespace polygon{ if(counts[i] != 0) { for(int j = i+1; j < c_size; ++j) { if(counts[j] != 0) { - //std::cout << "case5: " << i << " " << j << std::endl; + //std::cout << "case5: " << i << " " << j << "\n"; //we are ending a hole and may potentially close a figure and have to handle the hole tails[i]->pushPoint(point); verticalPairOut.first = tails[i]; @@ -2569,7 +2569,7 @@ namespace boost { namespace polygon{ if(incoming[i] != 0) { for(int j = i+1; j < i_size; ++j) { if(incoming[j] != 0) { - //std::cout << "case6: " << i << " " << j << std::endl; + //std::cout << "case6: " << i << " " << j << "\n"; //we are beginning a empty space if(verticalPair.first == 0) { getVerticalPair_(verticalPair, previter); @@ -2619,13 +2619,13 @@ namespace boost { namespace polygon{ //std::cout << count[i].first.get(HORIZONTAL) << ","; //std::cout << count[i].first.get(VERTICAL) << ":"; //std::cout << count[i].second << " "; - } //std::cout << std::endl; + } //std::cout << "\n"; } static inline void print(const scanline_data& data) { for(typename scanline_data::const_iterator itr = data.begin(); itr != data.end(); ++itr){ //std::cout << itr->first.pt << ", " << itr->first.other_pt << "; "; - } //std::cout << std::endl; + } //std::cout << "\n"; } template @@ -2645,16 +2645,16 @@ namespace boost { namespace polygon{ while(currentIter != inputEnd && currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation::x_) { //std::cout << "loop\n"; Unit currentY = (*currentIter).pt.get(VERTICAL); - //std::cout << "current Y " << currentY << std::endl; - //std::cout << "scanline size " << scanData_.size() << std::endl; + //std::cout << "current Y " << currentY << "\n"; + //std::cout << "scanline size " << scanData_.size() << "\n"; //print(scanData_); iterator iter = this->lookUp_(currentY); - //std::cout << "found element in scanline " << (iter != scanData_.end()) << std::endl; + //std::cout << "found element in scanline " << (iter != scanData_.end()) << "\n"; //int counts[4] = {0, 0, 0, 0}; incoming_count counts_from_scanline; //std::cout << "finding elements in tree\n"; //if(iter != scanData_.end()) - // std::cout << "first iter y is " << iter->first.evalAtX(x_) << std::endl; + // std::cout << "first iter y is " << iter->first.evalAtX(x_) << "\n"; iterator previter = iter; if(previter != polygon_arbitrary_formation::scanData_.end() && previter->first.evalAtX(polygon_arbitrary_formation::x_) >= currentY && @@ -2674,7 +2674,7 @@ namespace boost { namespace polygon{ ++iter; } Point currentPoint(polygon_arbitrary_formation::x_, currentY); - //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << std::endl; + //std::cout << "counts_from_scanline size " << counts_from_scanline.size() << "\n"; this->sort_incoming_count(counts_from_scanline, currentPoint); vertex_arbitrary_count incoming; @@ -2688,9 +2688,9 @@ namespace boost { namespace polygon{ currentIter->pt.get(HORIZONTAL) == polygon_arbitrary_formation::x_); //print(incoming); this->sort_vertex_arbitrary_count(incoming, currentPoint); - //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << std::endl; + //std::cout << currentPoint.get(HORIZONTAL) << "," << currentPoint.get(VERTICAL) << "\n"; //print(incoming); - //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //compact_vertex_arbitrary_count(currentPoint, incoming); vertex_arbitrary_count tmp; tmp.reserve(incoming.size()); @@ -2700,13 +2700,13 @@ namespace boost { namespace polygon{ } } incoming.swap(tmp); - //std::cout << "incoming counts from input size " << incoming.size() << std::endl; + //std::cout << "incoming counts from input size " << incoming.size() << "\n"; //now counts_from_scanline has the data from the left and //incoming has the data from the right at this point //cancel out any end points if(verticalTail) { //std::cout << "adding vertical tail to counts from scanline\n"; - //std::cout << -verticalCount.second << std::endl; + //std::cout << -verticalCount.second << "\n"; counts_from_scanline.push_back(std::pair, int>, active_tail_arbitrary*> (std::pair, int>(std::pair(verticalCount.first, currentPoint), @@ -2771,9 +2771,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 10), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; @@ -2794,9 +2794,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(10, 20), Point(0, 10), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; @@ -2817,9 +2817,9 @@ namespace boost { namespace polygon{ data.push_back(vertex_half_edge(Point(2, 4), Point(2, -4), 1)); polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; @@ -2862,14 +2862,14 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } //pf2.scan(polys2, data.begin(), data.end()); - //stdcout << "result size: " << polys2.size() << std::endl; + //stdcout << "result size: " << polys2.size() << "\n"; //for(std::size_t i = 0; i < polys2.size(); ++i) { - // stdcout << polys2[i] << std::endl; + // stdcout << polys2[i] << "\n"; //} stdcout << "done testing trapezoid formation\n"; return true; @@ -2909,9 +2909,9 @@ namespace boost { namespace polygon{ polygon_sort(data.begin(), data.end()); pf.scan(polys, data.begin(), data.end()); - stdcout << "result size: " << polys.size() << std::endl; + stdcout << "result size: " << polys.size() << "\n"; for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } stdcout << "done testing trapezoid formation\n"; return true; diff --git a/include/boost/polygon/detail/scan_arbitrary.hpp b/include/boost/polygon/detail/scan_arbitrary.hpp index 0c82fcf..735ed25 100644 --- a/include/boost/polygon/detail/scan_arbitrary.hpp +++ b/include/boost/polygon/detail/scan_arbitrary.hpp @@ -269,11 +269,11 @@ namespace boost { namespace polygon{ // for(typename std::set::iterator itr = intersection_points[offenders.first].begin(); // itr != intersection_points[offenders.first].end(); ++itr) { // std::cout << (*itr).x() << " " << (*itr).y() << " "; -// } std::cout << std::endl; +// } std::cout << "\n"; // for(typename std::set::iterator itr = intersection_points[offenders.second].begin(); // itr != intersection_points[offenders.second].end(); ++itr) { // std::cout << (*itr).x() << " " << (*itr).y() << " "; -// } std::cout << std::endl; +// } std::cout << "\n"; // exit(1); // } } @@ -307,7 +307,7 @@ namespace boost { namespace polygon{ if(scanline_base::intersects(he1, he2)) { offenders.first = id1; offenders.second = id2; - //std::cout << he1.first.x() << " " << he1.first.y() << " " << he1.second.x() << " " << he1.second.y() << " " << he2.first.x() << " " << he2.first.y() << " " << he2.second.x() << " " << he2.second.y() << std::endl; + //std::cout << he1.first.x() << " " << he1.first.y() << " " << he1.second.x() << " " << he1.second.y() << " " << he2.first.x() << " " << he2.first.y() << " " << he2.second.x() << " " << he2.second.y() << "\n"; return false; } } @@ -693,7 +693,7 @@ namespace boost { namespace polygon{ } edges.clear(); validate_scan(edges, input.begin(), input.end()); - stdcout << edges.size() << std::endl; + stdcout << edges.size() << "\n"; if(!verify_scan(result, edges.begin(), edges.end())) { stdcout << "s fail5 3 " << result.first << " " << result.second << "\n"; return false; @@ -876,7 +876,7 @@ namespace boost { namespace polygon{ for(std::size_t i = 0; i < vec.size(); ++ i) { // print(vec[i]); } - //std::cout << std::endl; + //std::cout << "\n"; } template @@ -1012,7 +1012,7 @@ namespace boost { namespace polygon{ void write_out(result_type& result, result_functor rf, const half_edge& he, const property_map& pm_left, const property_map& pm_right) { //std::cout << "write out "; - //std::cout << he.first << ", " << he.second << std::endl; + //std::cout << he.first << ", " << he.second << "\n"; property_set ps_left, ps_right; set_unique_property(ps_left, pm_left); set_unique_property(ps_right, pm_right); @@ -1230,7 +1230,7 @@ namespace boost { namespace polygon{ // for(std::size_t i = 0; i < mp.size(); ++i) { // std::cout << mp[i].first << ":" << mp[i].second << " "; // } std::cout << ") "; - // } std::cout << std::endl; + // } std::cout << "\n"; //} static inline void merge_property_maps(property_map& mp, const property_map& mp2) { @@ -1338,7 +1338,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); @@ -1350,7 +1350,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); @@ -1366,7 +1366,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(0, 10)), std::make_pair(0, 1))); @@ -1382,7 +1382,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); @@ -1398,7 +1398,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); @@ -1414,7 +1414,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(0, 0), Point(10, 0)), std::make_pair(0, 1))); @@ -1438,7 +1438,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; input.clear(); result.clear(); input.push_back(std::make_pair(half_edge(Point(-1, -1), Point(10, 0)), std::make_pair(0, 1))); //a @@ -1458,7 +1458,7 @@ namespace boost { namespace polygon{ stdcout << "scanned\n"; for(std::size_t i = 0; i < result.size(); ++i) { stdcout << result[i].first.first << ", " << result[i].first.second << "; "; - } stdcout << std::endl; + } stdcout << "\n"; return true; } @@ -1568,7 +1568,7 @@ namespace boost { namespace polygon{ } if(!line_intersection::verify_scan(offenders, lines.begin(), lines.end())) { //stdcout << "Intersection failed!\n"; - //stdcout << offenders.first << " " << offenders.second << std::endl; + //stdcout << offenders.first << " " << offenders.second << "\n"; return false; } std::vector pts; @@ -1790,7 +1790,7 @@ namespace boost { namespace polygon{ yh(rect, 11); si.insert(rect, 333); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; Point pts[4] = {Point(0, 0), Point(10,-3), Point(13, 8), Point(0, 0) }; polygon_data poly; @@ -1798,25 +1798,25 @@ namespace boost { namespace polygon{ poly.set(pts, pts+3); si2.insert(poly, 444); si2.sort_property_merge_data(); - print(stdcout, si2.pmd) << std::endl; + print(stdcout, si2.pmd) << "\n"; property_merge si3; poly.set(pts, pts+4); si3.insert(poly, 444); si3.sort_property_merge_data(); - stdcout << (si2.pmd == si3.pmd) << std::endl; + stdcout << (si2.pmd == si3.pmd) << "\n"; std::reverse(pts, pts+4); property_merge si4; poly.set(pts, pts+4); si4.insert(poly, 444); si4.sort_property_merge_data(); - print(stdcout, si4.pmd) << std::endl; - stdcout << (si2.pmd == si4.pmd) << std::endl; + print(stdcout, si4.pmd) << "\n"; + stdcout << (si2.pmd == si4.pmd) << "\n"; std::reverse(pts, pts+3); property_merge si5; poly.set(pts, pts+4); si5.insert(poly, 444); si5.sort_property_merge_data(); - stdcout << (si2.pmd == si5.pmd) << std::endl; + stdcout << (si2.pmd == si5.pmd) << "\n"; return true; } @@ -1833,7 +1833,7 @@ namespace boost { namespace polygon{ si.insert(rect, 333); std::map, polygon_set_data > result; si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; polygon_set_data psd = (*(result.begin())).second; std::vector > polys; psd.get(polys); @@ -1841,7 +1841,7 @@ namespace boost { namespace polygon{ stdcout << "fail merge 1\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; si.clear(); std::vector pts; pts.push_back(Point(0, 0)); @@ -1858,9 +1858,9 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { @@ -1884,9 +1884,9 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { @@ -1910,16 +1910,16 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 4\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; stdcout << "Polygon { -4 0, -2 -3, 3 -4 } \n"; stdcout << "Polygon { -1 1, 1 -2, -4 -3 } \n"; si.clear(); @@ -1937,9 +1937,9 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { @@ -1963,17 +1963,17 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() != 1) { stdcout << "fail merge 6\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 0 2, 3 -1, 4 1 } \n"; stdcout << "Polygon { -4 3, 3 3, 4 2 } \n"; @@ -1992,17 +1992,17 @@ namespace boost { namespace polygon{ si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 7\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 1 -2, -1 4, 3 -2 } \n"; stdcout << "Polygon { 0 -3, 3 1, -3 -4 } \n"; @@ -2021,17 +2021,17 @@ stdcout << "Polygon { 0 -3, 3 1, -3 -4 } \n"; si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 8\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; } stdcout << "Polygon { 2 2, 3 0, -3 4 } \n"; stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; @@ -2050,17 +2050,17 @@ stdcout << "Polygon { -2 -2, 0 0, -1 -1 } \n"; si.insert(poly, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { stdcout << "fail merge 9\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; } si.clear(); pts.clear(); @@ -2158,10 +2158,10 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 result.clear(); si.merge(result); si.verify1(); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; std::vector outpts; for(typename polygon_set_data::iterator_type itr = psd.begin(); itr != psd.end(); ++itr) { @@ -2172,8 +2172,8 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 for(std::size_t i = 0; i < outpts.size(); i+=2) { if(outpts[i] != outpts[i+1]) { stdcout << "Polygon set not a closed figure\n"; - stdcout << i << std::endl; - stdcout << outpts[i] << " " << outpts[i+1] << std::endl; + stdcout << i << "\n"; + stdcout << outpts[i] << " " << outpts[i+1] << "\n"; return 0; } } @@ -2183,10 +2183,10 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << "fail merge 10\n"; return false; } - stdcout << (polys[0]) << std::endl; + stdcout << (polys[0]) << "\n"; } for(unsigned int i = 0; i < 10; ++i) { - stdcout << "random case # " << i << std::endl; + stdcout << "random case # " << i << "\n"; si.clear(); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); @@ -2194,7 +2194,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data poly1; poly1.set(pts.begin(), pts.end()); - stdcout << poly1 << std::endl; + stdcout << poly1 << "\n"; si.insert(poly1, 444); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); @@ -2202,14 +2202,14 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data poly2; poly2.set(pts.begin(), pts.end()); - stdcout << poly2 << std::endl; + stdcout << poly2 << "\n"; si.insert(poly2, 444); result.clear(); si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; if(!result.empty()) { psd = (*(result.begin())).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; polys.clear(); psd.get(polys); if(polys.size() == 0) { @@ -2228,13 +2228,13 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 std::vector > polys2; psd.get(polys2); if(!polys1.empty() || !polys2.empty()) { - stdcout << "fail random merge " << i << std::endl; + stdcout << "fail random merge " << i << "\n"; return false; } } } if(!polys.empty()) - stdcout << polys.size() << ": " << (polys[0]) << std::endl; + stdcout << polys.size() << ": " << (polys[0]) << "\n"; } return true; } @@ -2249,13 +2249,13 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 std::vector > polys90; si.insert(rect1, 111); si90.insert(rect1, 111); - stdcout << rect1 << std::endl; + stdcout << rect1 << "\n"; si.insert(rect2, 222); si90.insert(rect2, 222); - stdcout << rect2 << std::endl; + stdcout << rect2 << "\n"; si.insert(rect3, 333); si90.insert(rect3, 333); - stdcout << rect3 << std::endl; + stdcout << rect3 << "\n"; si.merge(result); si90.merge(result90); if(result.size() != result90.size()) { @@ -2277,20 +2277,20 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 psd90.get(polys90); if(polys.size() != polys90.size()) { stdcout << "merge failed with polygon count mismatch\n"; - stdcout << psd << std::endl; + stdcout << psd << "\n"; for(std::size_t j = 0; j < polys.size(); ++j) { - stdcout << polys[j] << std::endl; + stdcout << polys[j] << "\n"; } stdcout << "reference\n"; for(std::size_t j = 0; j < polys90.size(); ++j) { - stdcout << polys90[j] << std::endl; + stdcout << polys90[j] << "\n"; } return 0; } bool failed = false; for(std::size_t j = 0; j < polys.size(); ++j) { - stdcout << polys[j] << std::endl; - stdcout << polys90[j] << std::endl; + stdcout << polys[j] << "\n"; + stdcout << polys90[j] << "\n"; #ifdef BOOST_POLYGON_ICC #pragma warning (disable:1572) #endif @@ -2324,7 +2324,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 property_merge_90 si90; std::map, polygon_90_set_data > result90; std::vector > polys90; - stdcout << "random case # " << i << std::endl; + stdcout << "random case # " << i << "\n"; set_points(rect1, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); set_points(rect2, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); set_points(rect3, (Point(rand()%9-4, rand()%9-4)), (Point(rand()%9-4, rand()%9-4))); @@ -2356,7 +2356,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 si.insert(rect, 555); std::map, polygon_set_data > result; si.merge(result); - print(stdcout, si.pmd) << std::endl; + print(stdcout, si.pmd) << "\n"; for(typename std::map, polygon_set_data >::iterator itr = result.begin(); itr != result.end(); ++itr) { stdcout << "( "; @@ -2365,18 +2365,18 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data psd = (*itr).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; std::vector > polys; psd.get(polys); for(std::size_t i = 0; i < polys.size(); ++i) { - stdcout << polys[i] << std::endl; + stdcout << polys[i] << "\n"; } } std::vector pts; std::vector > polys; for(unsigned int i = 0; i < 10; ++i) { property_merge si2; - stdcout << "random case # " << i << std::endl; + stdcout << "random case # " << i << "\n"; si.clear(); pts.clear(); pts.push_back(Point(rand()%9-4, rand()%9-4)); @@ -2384,7 +2384,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data poly1; poly1.set(pts.begin(), pts.end()); - stdcout << poly1 << std::endl; + stdcout << poly1 << "\n"; si.insert(poly1, 444); si2.insert(poly1, 333); pts.clear(); @@ -2393,7 +2393,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data poly2; poly2.set(pts.begin(), pts.end()); - stdcout << poly2 << std::endl; + stdcout << poly2 << "\n"; si.insert(poly2, 444); si2.insert(poly2, 444); pts.clear(); @@ -2402,7 +2402,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 pts.push_back(Point(rand()%9-4, rand()%9-4)); polygon_data poly3; poly3.set(pts.begin(), pts.end()); - stdcout << poly3 << std::endl; + stdcout << poly3 << "\n"; si.insert(poly3, 444); si2.insert(poly3, 555); result.clear(); @@ -2418,15 +2418,15 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data psd = (*itr).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; std::vector > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { - stdcout << polys2[ii] << std::endl; + stdcout << polys2[ii] << "\n"; } } stdcout << "intersected pmd\n"; - print(stdcout, si2.pmd) << std::endl; + print(stdcout, si2.pmd) << "\n"; stdcout << "intersected result\n"; for(typename std::map, polygon_set_data >::iterator itr = result2.begin(); itr != result2.end(); ++itr) { @@ -2436,11 +2436,11 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data psd = (*itr).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; std::vector > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { - stdcout << polys2[ii] << std::endl; + stdcout << polys2[ii] << "\n"; } } si.clear(); @@ -2463,11 +2463,11 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << (*set_itr) << " "; } stdcout << ") \n"; polygon_set_data psd = (*itr).second; - stdcout << psd << std::endl; + stdcout << psd << "\n"; std::vector > polys2; psd.get(polys2); for(std::size_t ii = 0; ii < polys2.size(); ++ii) { - stdcout << polys2[ii] << std::endl; + stdcout << polys2[ii] << "\n"; } } std::vector > polys2; @@ -2475,7 +2475,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 (*(result.begin())).second.get(polys); (*(result2.begin())).second.get(polys2); if(!(polys == polys2)) { - stdcout << "failed intersection check # " << i << std::endl; + stdcout << "failed intersection check # " << i << "\n"; return false; } } @@ -2660,7 +2660,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_OR); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { - stdcout << pv[i] << std::endl; + stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); @@ -2668,7 +2668,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_AND); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { - stdcout << pv[i] << std::endl; + stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); @@ -2676,7 +2676,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_XOR); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { - stdcout << pv[i] << std::endl; + stdcout << pv[i] << "\n"; } pv.clear(); abo.clear(); @@ -2684,7 +2684,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 abo.execute(psd3, psd.begin(), psd.end(), psd2.begin(), psd2.end(), arbitrary_boolean_op::BOOLEAN_NOT); psd3.get(pv); for(std::size_t i = 0; i < pv.size(); ++i) { - stdcout << pv[i] << std::endl; + stdcout << pv[i] << "\n"; } return true; } diff --git a/include/boost/polygon/detail/transform_detail.hpp b/include/boost/polygon/detail/transform_detail.hpp deleted file mode 100644 index daba231..0000000 --- a/include/boost/polygon/detail/transform_detail.hpp +++ /dev/null @@ -1,548 +0,0 @@ -/* - Copyright 2008 Intel Corporation - - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ -#ifndef BOOST_POLYGON_TRANSFORM_DETAIL_HPP -#define BOOST_POLYGON_TRANSFORM_DETAIL_HPP - -namespace boost { namespace polygon{ - // inline std::ostream& operator<< (std::ostream& o, const axis_transformation& r) { - // o << r.atr_; - // return o; - // } - - // inline std::istream& operator>> (std::istream& i, axis_transformation& r) { - // int tmp; - // i >> tmp; - // r = axis_transformation((axis_transformation::ATR)tmp); - // return i; - // } - - // template - // inline std::ostream& operator<< (std::ostream& o, const anisotropic_scale_factor& sc) { - // o << sc.scale_[0] << BOOST_POLYGON_SEP << sc.scale_[1] << GTL_SEP << sc.scale_[2]; - // return o; - // } - - // template - // inline std::istream& operator>> (std::istream& i, anisotropic_scale_factor& sc) { - // i >> sc.scale_[0] >> sc.scale_[1] >> sc.scale_[2]; - // return i; - // } - - // template - // inline std::ostream& operator<< (std::ostream& o, const transformation& tr) { - // o << tr.atr_ << BOOST_POLYGON_SEP << tr.p_; - // return o; - // } - - // template - // inline std::istream& operator>> (std::istream& i, transformation& tr) { - // i >> tr.atr_ >> tr.p_; - // return i; - // } - - - inline axis_transformation::axis_transformation(const orientation_3d& orient) : atr_(NULL_TRANSFORM) { - const ATR tmp[3] = { - UP_EAST_NORTH, //sort by x, then z, then y - EAST_UP_NORTH, //sort by y, then z, then x - EAST_NORTH_UP //sort by z, then y, then x - }; - atr_ = tmp[orient.to_int()]; - } - - inline axis_transformation::axis_transformation(const orientation_2d& orient) : atr_(NULL_TRANSFORM) { - const ATR tmp[3] = { - NORTH_EAST_UP, //sort by z, then x, then y - EAST_NORTH_UP //sort by z, then y, then x - }; - atr_ = tmp[orient.to_int()]; - } - - inline axis_transformation::axis_transformation(const direction_3d& dir) : atr_(NULL_TRANSFORM) { - const ATR tmp[6] = { - DOWN_EAST_NORTH, //sort by -x, then z, then y - UP_EAST_NORTH, //sort by x, then z, then y - EAST_DOWN_NORTH, //sort by -y, then z, then x - EAST_UP_NORTH, //sort by y, then z, then x - EAST_NORTH_DOWN, //sort by -z, then y, then x - EAST_NORTH_UP //sort by z, then y, then x - }; - atr_ = tmp[dir.to_int()]; - } - - inline axis_transformation::axis_transformation(const direction_2d& dir) : atr_(NULL_TRANSFORM) { - const ATR tmp[4] = { - SOUTH_EAST_UP, //sort by z, then x, then y - NORTH_EAST_UP, //sort by z, then x, then y - EAST_SOUTH_UP, //sort by z, then y, then x - EAST_NORTH_UP //sort by z, then y, then x - }; - atr_ = tmp[dir.to_int()]; - } - - inline axis_transformation& axis_transformation::operator=(const axis_transformation& a) { - atr_ = a.atr_; - return *this; - } - - inline axis_transformation& axis_transformation::operator=(const ATR& atr) { - atr_ = atr; - return *this; - } - - inline bool axis_transformation::operator==(const axis_transformation& a) const { - return atr_ == a.atr_; - } - - inline bool axis_transformation::operator!=(const axis_transformation& a) const { - return !(*this == a); - } - - inline bool axis_transformation::operator<(const axis_transformation& a) const { - return atr_ < a.atr_; - } - - inline axis_transformation& axis_transformation::operator+=(const axis_transformation& a){ - bool abit5 = (a.atr_ & 32) != 0; - bool abit4 = (a.atr_ & 16) != 0; - bool abit3 = (a.atr_ & 8) != 0; - bool abit2 = (a.atr_ & 4) != 0; - bool abit1 = (a.atr_ & 2) != 0; - bool abit0 = (a.atr_ & 1) != 0; - bool bit5 = (atr_ & 32) != 0; - bool bit4 = (atr_ & 16) != 0; - bool bit3 = (atr_ & 8) != 0; - bool bit2 = (atr_ & 4) != 0; - bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; - int indexes[2][3] = { - { - ((int)((bit5 & bit2) | (bit4 & !bit2)) << 1) + - (int)(bit2 & !bit5), - ((int)((bit4 & bit2) | (bit5 & !bit2)) << 1) + - (int)(!bit5 & !bit2), - ((int)(!bit4 & !bit5) << 1) + - (int)(bit5) - }, - { - ((int)((abit5 & abit2) | (abit4 & !abit2)) << 1) + - (int)(abit2 & !abit5), - ((int)((abit4 & abit2) | (abit5 & !abit2)) << 1) + - (int)(!abit5 & !abit2), - ((int)(!abit4 & !abit5) << 1) + - (int)(abit5) - } - }; - int zero_bits[2][3] = { - {bit0, bit1, bit3}, - {abit0, abit1, abit3} - }; - int nbit3 = zero_bits[0][2] ^ zero_bits[1][indexes[0][2]]; - int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; - int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; - indexes[0][0] = indexes[1][indexes[0][0]]; - indexes[0][1] = indexes[1][indexes[0][1]]; - indexes[0][2] = indexes[1][indexes[0][2]]; - int nbit5 = (indexes[0][2] == 1); - int nbit4 = (indexes[0][2] == 0); - int nbit2 = (!(nbit5 | nbit4) & (bool)(indexes[0][0] & 1)) | //swap xy - (nbit5 & ((indexes[0][0] & 2) >> 1)) | //z->y x->z - (nbit4 & ((indexes[0][1] & 2) >> 1)); //z->x y->z - atr_ = (ATR)((nbit5 << 5) + - (nbit4 << 4) + - (nbit3 << 3) + - (nbit2 << 2) + - (nbit1 << 1) + nbit0); - return *this; - } - - inline axis_transformation axis_transformation::operator+(const axis_transformation& a) const { - axis_transformation retval(*this); - return retval+=a; - } - - // populate_axis_array writes the three INDIVIDUAL_AXIS values that the - // ATR enum value of 'this' represent into axis_array - inline void axis_transformation::populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { - bool bit5 = (atr_ & 32) != 0; - bool bit4 = (atr_ & 16) != 0; - bool bit3 = (atr_ & 8) != 0; - bool bit2 = (atr_ & 4) != 0; - bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; - axis_array[2] = - (INDIVIDUAL_AXIS)((((int)(!bit4 & !bit5)) << 2) + - ((int)(bit5) << 1) + - bit3); - axis_array[1] = - (INDIVIDUAL_AXIS)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ - ((int)(!bit5 & !bit2) << 1) + - bit1); - axis_array[0] = - (INDIVIDUAL_AXIS)((((int)((bit5 & bit2) | (bit4 & !bit2))) << 2) + - ((int)(bit2 & !bit5) << 1) + - bit0); - } - - // combine_axis_arrays concatenates this_array and that_array overwriting - // the result into this_array - inline void - axis_transformation::combine_axis_arrays (INDIVIDUAL_AXIS this_array[], - const INDIVIDUAL_AXIS that_array[]){ - int indexes[3] = {this_array[0] >> 1, - this_array[1] >> 1, - this_array[2] >> 1}; - int zero_bits[2][3] = { - {this_array[0] & 1, this_array[1] & 1, this_array[2] & 1}, - {that_array[0] & 1, that_array[1] & 1, that_array[2] & 1} - }; - this_array[0] = that_array[indexes[0]]; - this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] & (int)((int)PZ+(int)PY)); - this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | - ((int)zero_bits[0][0] ^ - (int)zero_bits[1][indexes[0]])); - this_array[1] = that_array[indexes[1]]; - this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] & (int)((int)PZ+(int)PY)); - this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | - ((int)zero_bits[0][1] ^ - (int)zero_bits[1][indexes[1]])); - this_array[2] = that_array[indexes[2]]; - this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] & (int)((int)PZ+(int)PY)); - this_array[2] = (INDIVIDUAL_AXIS)((int)this_array[2] | - ((int)zero_bits[0][2] ^ - (int)zero_bits[1][indexes[2]])); - } - - // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values - // to the ATR enum value and sets 'this' to that value - inline void axis_transformation::write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { - int bit5 = ((int)this_array[2] & 2) != 0; - int bit4 = !((((int)this_array[2] & 4) != 0) | (((int)this_array[2] & 2) != 0)); - int bit3 = ((int)this_array[2] & 1) != 0; - //bit 2 is the tricky bit - int bit2 = ((!(bit5 | bit4)) & (((int)this_array[0] & 2) != 0)) | //swap xy - (bit5 & (((int)this_array[0] & 4) >> 2)) | //z->y x->z - (bit4 & (((int)this_array[1] & 4) >> 2)); //z->x y->z - int bit1 = ((int)this_array[1] & 1); - int bit0 = ((int)this_array[0] & 1); - atr_ = ATR((bit5 << 5) + - (bit4 << 4) + - (bit3 << 3) + - (bit2 << 2) + - (bit1 << 1) + bit0); - } - - // behavior is deterministic but undefined in the case where illegal - // combinations of directions are passed in. - inline axis_transformation& - axis_transformation::set_directions(const direction_2d& horizontalDir, - const direction_2d& verticalDir){ - int bit2 = (static_cast(horizontalDir).to_int()) != 0; - int bit1 = !(verticalDir.to_int() & 1); - int bit0 = !(horizontalDir.to_int() & 1); - atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); - return *this; - } - - // behavior is deterministic but undefined in the case where illegal - // combinations of directions are passed in. - inline axis_transformation& axis_transformation::set_directions( - const direction_3d& horizontalDir, - const direction_3d& verticalDir, - const direction_3d& proximalDir){ - unsigned int this_array[3] = {horizontalDir.to_int(), - verticalDir.to_int(), - proximalDir.to_int()}; - unsigned int bit5 = (this_array[2] & 2) != 0; - unsigned int bit4 = !(((this_array[2] & 4) != 0) | ((this_array[2] & 2) != 0)); - unsigned int bit3 = !((this_array[2] & 1) != 0); - //bit 2 is the tricky bit - unsigned int bit2 = (!(bit5 | bit4) & ((this_array[0] & 2) != 0 )) | //swap xy - (bit5 & ((this_array[0] & 4) >> 2)) | //z->y x->z - (bit4 & ((this_array[1] & 4) >> 2)); //z->x y->z - unsigned int bit1 = !(this_array[1] & 1); - unsigned int bit0 = !(this_array[0] & 1); - atr_ = ATR((bit5 << 5) | (bit4 << 4) | (bit3 << 3) | (bit2 << 2) | (bit1 << 1) | bit0); - return *this; - } - - template - inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y) const { - int bit2 = (atr_ & 4) != 0; - int bit1 = (atr_ & 2) != 0; - int bit0 = (atr_ & 1) != 0; - x *= -((bit0 << 1) - 1); - y *= -((bit1 << 1) - 1); - predicated_swap(bit2 != 0,x,y); - } - - template - inline void axis_transformation::transform(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { - int bit5 = (atr_ & 32) != 0; - int bit4 = (atr_ & 16) != 0; - int bit3 = (atr_ & 8) != 0; - int bit2 = (atr_ & 4) != 0; - int bit1 = (atr_ & 2) != 0; - int bit0 = (atr_ & 1) != 0; - x *= -((bit0 << 1) - 1); - y *= -((bit1 << 1) - 1); - z *= -((bit3 << 1) - 1); - predicated_swap(bit2 != 0, x, y); - predicated_swap(bit5 != 0, y, z); - predicated_swap(bit4 != 0, x, z); - } - - inline axis_transformation& axis_transformation::invert_2d() { - int bit2 = ((atr_ & 4) != 0); - int bit1 = ((atr_ & 2) != 0); - int bit0 = ((atr_ & 1) != 0); - //swap bit 0 and bit 1 if bit2 is 1 - predicated_swap(bit2 != 0, bit0, bit1); - bit1 = bit1 << 1; - atr_ = (ATR)(atr_ & (32+16+8+4)); //mask away bit0 and bit1 - atr_ = (ATR)(atr_ | bit0 | bit1); - return *this; - } - - inline axis_transformation axis_transformation::inverse_2d() const { - axis_transformation retval(*this); - return retval.invert_2d(); - } - - inline axis_transformation& axis_transformation::invert() { - int bit5 = ((atr_ & 32) != 0); - int bit4 = ((atr_ & 16) != 0); - int bit3 = ((atr_ & 8) != 0); - int bit2 = ((atr_ & 4) != 0); - int bit1 = ((atr_ & 2) != 0); - int bit0 = ((atr_ & 1) != 0); - predicated_swap(bit2 != 0, bit4, bit5); - predicated_swap(bit4 != 0, bit0, bit3); - predicated_swap(bit5 != 0, bit1, bit3); - predicated_swap(bit2 != 0, bit0, bit1); - atr_ = (ATR)((bit5 << 5) + - (bit4 << 4) + - (bit3 << 3) + - (bit2 << 2) + - (bit1 << 1) + bit0); - return *this; - } - - inline axis_transformation axis_transformation::inverse() const { - axis_transformation retval(*this); - return retval.invert(); - } - - template - inline scale_factor_type anisotropic_scale_factor::get(orientation_3d orient) const { - return scale_[orient.to_int()]; - } - - template - inline void anisotropic_scale_factor::set(orientation_3d orient, scale_factor_type value) { - scale_[orient.to_int()] = value; - } - - template - inline scale_factor_type anisotropic_scale_factor::x() const { return scale_[HORIZONTAL]; } - template - inline scale_factor_type anisotropic_scale_factor::y() const { return scale_[VERTICAL]; } - template - inline scale_factor_type anisotropic_scale_factor::z() const { return scale_[PROXIMAL]; } - template - inline void anisotropic_scale_factor::x(scale_factor_type value) { scale_[HORIZONTAL] = value; } - template - inline void anisotropic_scale_factor::y(scale_factor_type value) { scale_[VERTICAL] = value; } - template - inline void anisotropic_scale_factor::z(scale_factor_type value) { scale_[PROXIMAL] = value; } - - //concatenation operator (convolve scale factors) - template - inline anisotropic_scale_factor anisotropic_scale_factor::operator+(const anisotropic_scale_factor& s) const { - anisotropic_scale_factor retval(*this); - return retval+=s; - } - - //concatenate this with that - template - inline const anisotropic_scale_factor& anisotropic_scale_factor::operator+=(const anisotropic_scale_factor& s){ - scale_[0] *= s.scale_[0]; - scale_[1] *= s.scale_[1]; - scale_[2] *= s.scale_[2]; - return *this; - } - - //transform - template - inline anisotropic_scale_factor& anisotropic_scale_factor::transform(axis_transformation atr){ - direction_3d dirs[3]; - atr.get_directions(dirs[0],dirs[1],dirs[2]); - scale_factor_type tmp[3] = {scale_[0], scale_[1], scale_[2]}; - for(int i = 0; i < 3; ++i){ - scale_[orientation_3d(dirs[i]).to_int()] = tmp[i]; - } - return *this; - } - - template - template - inline void anisotropic_scale_factor::scale(coordinate_type_2& x, coordinate_type_2& y) const { - x = scaling_policy::round((scale_factor_type)x * get(HORIZONTAL)); - y = scaling_policy::round((scale_factor_type)y * get(HORIZONTAL)); - } - - template - template - inline void anisotropic_scale_factor::scale(coordinate_type_2& x, coordinate_type_2& y, coordinate_type_2& z) const { - scale(x, y); - z = scaling_policy::round((scale_factor_type)z * get(HORIZONTAL)); - } - - template - inline anisotropic_scale_factor& anisotropic_scale_factor::invert() { - x(1/x()); - y(1/y()); - z(1/z()); - return *this; - } - - - template - inline transformation::transformation() : atr_(), p_(0, 0, 0) {;} - - template - inline transformation::transformation(axis_transformation atr) : atr_(atr), p_(0, 0, 0){;} - - template - inline transformation::transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0, 0){;} - - template - template - inline transformation::transformation(const point_type& p) : atr_(), p_(0, 0, 0) { - set_translation(p); - } - - template - template - inline transformation::transformation(axis_transformation atr, const point_type& p) : - atr_(atr), p_(0, 0, 0) { - set_translation(p); - } - - template - template - inline transformation::transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt) : atr_(), p_(0, 0, 0) { - transformation tmp(referencePt); - transformation rotRef(atr); - transformation tmpInverse = tmp.inverse(); - point_type decon(referencePt); - deconvolve(decon, destinationPt); - transformation displacement(decon); - tmp += rotRef; - tmp += tmpInverse; - tmp += displacement; - (*this) = tmp; - } - - template - inline transformation::transformation(const transformation& tr) : - atr_(tr.atr_), p_(tr.p_) {;} - - template - inline bool transformation::operator==(const transformation& tr) const { - return atr_ == tr.atr_ && p_ == tr.p_; - } - - template - inline bool transformation::operator!=(const transformation& tr) const { - return !(*this == tr); - } - - template - inline bool transformation::operator<(const transformation& tr) const { - return atr_ < tr.atr_ || (atr_ == tr.atr_ && p_ < tr.p_); - } - - template - inline transformation transformation::operator+(const transformation& tr) const { - transformation retval(*this); - return retval+=tr; - } - - template - inline const transformation& transformation::operator+=(const transformation& tr){ - //apply the inverse transformation of this to the translation point of that - //and convolve it with this translation point - coordinate_type x, y, z; - transformation inv = inverse(); - inv.transform(x, y, z); - p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); - p_.set(VERTICAL, p_.get(VERTICAL) + y); - p_.set(PROXIMAL, p_.get(PROXIMAL) + z); - //concatenate axis transforms - atr_ += tr.atr_; - return *this; - } - - template - inline void transformation::set_axis_transformation(const axis_transformation& atr) { - atr_ = atr; - } - - template - template - inline void transformation::get_translation(point_type& p) const { - assign(p, p_); - } - - template - template - inline void transformation::set_translation(const point_type& p) { - assign(p_, p); - } - - template - inline void transformation::transform(coordinate_type& x, coordinate_type& y) const { - //subtract each component of new origin point - y -= p_.get(VERTICAL); - x -= p_.get(HORIZONTAL); - atr_.transform(x, y); - } - - template - inline void transformation::transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const { - //subtract each component of new origin point - z -= p_.get(PROXIMAL); - y -= p_.get(VERTICAL); - x -= p_.get(HORIZONTAL); - atr_.transform(x,y,z); - } - - // sets the axis_transform portion to its inverse - // transforms the tranlastion portion by that inverse axis_transform - // multiplies the translation portion by -1 to reverse it - template - inline transformation& transformation::invert() { - coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL), z = p_.get(PROXIMAL); - atr_.transform(x, y, z); - x *= -1; - y *= -1; - z *= -1; - p_ = point_3d_data(x, y, z); - atr_.invert(); - return *this; - } - - template - inline transformation transformation::inverse() const { - transformation retval(*this); - return retval.invert(); - } -} -} -#endif diff --git a/include/boost/polygon/interval_concept.hpp b/include/boost/polygon/interval_concept.hpp index f5516ad..4ea992c 100644 --- a/include/boost/polygon/interval_concept.hpp +++ b/include/boost/polygon/interval_concept.hpp @@ -1,632 +1,935 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library interval_concept.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_INTERVAL_CONCEPT_HPP #define BOOST_POLYGON_INTERVAL_CONCEPT_HPP + #include "isotropy.hpp" -#include "interval_data.hpp" #include "interval_traits.hpp" -namespace boost { namespace polygon{ - struct interval_concept {}; - - template - struct is_interval_concept { typedef gtl_no type; }; - template <> - struct is_interval_concept { typedef gtl_yes type; }; - - template - struct is_mutable_interval_concept { typedef gtl_no type; }; - template <> - struct is_mutable_interval_concept { typedef gtl_yes type; }; - - template - struct interval_coordinate_type_by_concept { typedef void type; }; - template - struct interval_coordinate_type_by_concept { typedef typename interval_traits::coordinate_type type; }; - - template - struct interval_coordinate_type { - typedef typename interval_coordinate_type_by_concept< - T, typename is_interval_concept::type>::type>::type type; - }; - - template - struct interval_difference_type_by_concept { typedef void type; }; - template - struct interval_difference_type_by_concept { - typedef typename coordinate_traits::coordinate_type>::coordinate_difference type; }; - - template - struct interval_difference_type { - typedef typename interval_difference_type_by_concept< - T, typename is_interval_concept::type>::type>::type type; - }; - - struct y_i_get : gtl_yes {}; - - template - typename enable_if< typename gtl_and< - y_i_get, - typename is_interval_concept::type>::type>::type, - typename interval_coordinate_type::type>::type - get(const T& interval, direction_1d dir) { - return interval_traits::get(interval, dir); - } - - struct y_i_set : gtl_yes {}; - - template - typename enable_if< typename gtl_and< - y_i_set, - typename is_mutable_interval_concept::type>::type>::type, - void>::type - set(T& interval, direction_1d dir, coordinate_type value) { - //this may need to be refined - interval_mutable_traits::set(interval, dir, value); - if(high(interval) < low(interval)) - interval_mutable_traits::set(interval, dir.backward(), value); - } - - struct y_i_construct : gtl_yes {}; - - template - typename enable_if< typename gtl_and< - y_i_construct, - typename is_mutable_interval_concept::type>::type>::type, - T>::type - construct(T2 low_value, T3 high_value) { - if(low_value > high_value) std::swap(low_value, high_value); - return interval_mutable_traits::construct(low_value, high_value); - } - - struct y_i_copy_construct : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_i_copy_construct, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - T>::type - copy_construct(const T2& interval) { - return construct(get(interval, LOW ), get(interval, HIGH)); - } - - struct y_i_assign : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_i_assign, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - T1>::type & - assign(T1& lvalue, const T2& rvalue) { - lvalue = copy_construct(rvalue); - return lvalue; - } - - struct y_i_equivalence : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_i_equivalence, - typename is_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - equivalence(const T& interval1, const T2& interval2) { - return get(interval1, LOW) == get(interval2, LOW) && - get(interval1, HIGH) == get(interval2, HIGH); - } - - struct y_i_contains : gtl_yes {}; - - template - typename enable_if< typename gtl_and< y_i_contains, typename is_interval_concept::type>::type >::type, bool>::type - contains(const interval_type& interval, - typename interval_coordinate_type::type value, - bool consider_touch = true ) { - if(consider_touch) { - return value <= high(interval) && value >= low(interval); - } else { - return value < high(interval) && value > low(interval); - } - } - - struct y_i_contains2 : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_i_contains2, - typename is_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - contains(const interval_type& interval, - const interval_type_2& value, - bool consider_touch = true) { - return contains(interval, get(value, LOW), consider_touch) && - contains(interval, get(value, HIGH), consider_touch); - } - - struct y_i_low : gtl_yes {}; - - // get the low coordinate - template - typename enable_if< typename gtl_and< - y_i_low, - typename is_interval_concept::type>::type>::type, - typename interval_coordinate_type::type>::type - low(const interval_type& interval) { return get(interval, LOW); } - - struct y_i_high : gtl_yes {}; - - // get the high coordinate - template - typename enable_if< typename gtl_and< - y_i_high, - typename is_interval_concept::type>::type>::type, - typename interval_coordinate_type::type>::type - high(const interval_type& interval) { return get(interval, HIGH); } - - struct y_i_center : gtl_yes {}; - - // get the center coordinate - template - typename enable_if< typename gtl_and< - y_i_center, - typename is_interval_concept::type>::type>::type, - typename interval_coordinate_type::type>::type - center(const interval_type& interval) { return (high(interval) + low(interval))/2; } - - - struct y_i_low2 : gtl_yes {}; - - // set the low coordinate to v - template - typename enable_if::type>::type>::type, - void>::type - low(interval_type& interval, - typename interval_coordinate_type::type v) { set(interval, LOW, v); } - - struct y_i_high2 : gtl_yes {}; - - // set the high coordinate to v - template - typename enable_if::type>::type>::type, - void>::type - high(interval_type& interval, - typename interval_coordinate_type::type v) { set(interval, HIGH, v); } - - struct y_i_delta : gtl_yes {}; - - // get the magnitude of the interval - template - typename enable_if< typename gtl_and< - y_i_delta, - typename is_interval_concept::type>::type>::type, - typename interval_difference_type::type >::type - delta(const interval_type& interval) { - typedef typename coordinate_traits::type>::coordinate_difference diffT; - return (diffT)high(interval) - (diffT)low(interval); } - - struct y_i_flip : gtl_yes {}; - - // flip this about coordinate - template - typename enable_if::type>::type>::type, interval_type>::type & - flip(interval_type& interval, - typename interval_coordinate_type::type axis = 0) { - typename interval_coordinate_type::type newLow, newHigh; - newLow = 2 * axis - high(interval); - newHigh = 2 * axis - low(interval); - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_scale_up : gtl_yes {}; - - // scale interval by factor - template - typename enable_if::type>::type>::type, interval_type>::type & - scale_up(interval_type& interval, - typename coordinate_traits::type>::unsigned_area_type factor) { - typedef typename interval_coordinate_type::type Unit; - Unit newHigh = high(interval) * (Unit)factor; - low(interval, low(interval) * (Unit)factor); - high(interval, (newHigh)); - return interval; - } - - struct y_i_scale_down : gtl_yes {}; - - template - typename enable_if::type>::type>::type, interval_type>::type & - scale_down(interval_type& interval, - typename coordinate_traits::type>::unsigned_area_type factor) { - typedef typename interval_coordinate_type::type Unit; - typedef typename coordinate_traits::coordinate_distance dt; - Unit newHigh = scaling_policy::round((dt)(high(interval)) / (dt)factor); - low(interval, scaling_policy::round((dt)(low(interval)) / (dt)factor)); - high(interval, (newHigh)); - return interval; - } - - struct y_i_scale : gtl_yes {}; - - template - typename enable_if::type>::type>::type, interval_type>::type & - scale(interval_type& interval, double factor) { - typedef typename interval_coordinate_type::type Unit; - Unit newHigh = scaling_policy::round((double)(high(interval)) * factor); - low(interval, scaling_policy::round((double)low(interval)* factor)); - high(interval, (newHigh)); - return interval; - } - - struct y_i_move : gtl_yes {}; - - // move interval by delta - template - typename enable_if< typename gtl_and< - y_i_move, - typename is_mutable_interval_concept::type>::type>::type, - interval_type>::type & - move(interval_type& interval, typename interval_difference_type::type displacement) { - typedef typename interval_coordinate_type::type ctype; - typedef typename coordinate_traits::coordinate_difference Unit; - Unit len = delta(interval); - low(interval, static_cast(static_cast(low(interval)) + displacement)); - high(interval, static_cast(static_cast(low(interval)) + len)); - return interval; - } - - struct y_i_convolve : gtl_yes {}; - - // convolve this with b - template - typename enable_if::type>::type>::type, interval_type>::type & - convolve(interval_type& interval, - typename interval_coordinate_type::type b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) + b; - Unit newHigh = high(interval) + b; - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_deconvolve : gtl_yes {}; - - // deconvolve this with b - template - typename enable_if::type>::type>::type, interval_type>::type & - deconvolve(interval_type& interval, - typename interval_coordinate_type::type b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) - b; - Unit newHigh = high(interval) - b; - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_convolve2 : gtl_yes {}; - - // convolve this with b - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - interval_type>::type & - convolve(interval_type& interval, - const interval_type_2& b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) + low(b); - Unit newHigh = high(interval) + high(b); - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_deconvolve2 : gtl_yes {}; - - // deconvolve this with b - template - typename enable_if< - typename gtl_and_3< y_i_deconvolve2, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - interval_type>::type & - deconvolve(interval_type& interval, - const interval_type_2& b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) - low(b); - Unit newHigh = high(interval) - high(b); - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_reconvolve : gtl_yes {}; - - // reflected convolve this with b - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - interval_type>::type & - reflected_convolve(interval_type& interval, - const interval_type_2& b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) - high(b); - Unit newHigh = high(interval) - low(b); - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_redeconvolve : gtl_yes {}; - - // reflected deconvolve this with b - template - typename enable_if< - typename gtl_and_3< y_i_redeconvolve, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - interval_type>::type & - reflected_deconvolve(interval_type& interval, - const interval_type_2& b) { - typedef typename interval_coordinate_type::type Unit; - Unit newLow = low(interval) + high(b); - Unit newHigh = high(interval) + low(b); - low(interval, newLow); - high(interval, newHigh); - return interval; - } - - struct y_i_e_dist1 : gtl_yes {}; - - // distance from a coordinate to an interval - template - typename enable_if< typename gtl_and::type>::type>::type, - typename interval_difference_type::type>::type - euclidean_distance(const interval_type& interval, - typename interval_coordinate_type::type position) { - typedef typename coordinate_traits::type>::coordinate_difference Unit; - Unit dist[3] = {0, (Unit)low(interval) - (Unit)position, (Unit)position - (Unit)high(interval)}; - return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; - } - - struct y_i_e_dist2 : gtl_yes {}; - - // distance between two intervals - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - typename interval_difference_type::type>::type - euclidean_distance(const interval_type& interval, - const interval_type_2& b) { - typedef typename coordinate_traits::type>::coordinate_difference Unit; - Unit dist[3] = {0, (Unit)low(interval) - (Unit)high(b), (Unit)low(b) - (Unit)high(interval)}; - return dist[ (dist[1] > 0) + ((dist[2] > 0) << 1) ]; - } - - struct y_i_e_intersects : gtl_yes {}; - - // check if Interval b intersects `this` Interval - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - intersects(const interval_type& interval, const interval_type_2& b, - bool consider_touch = true) { - return consider_touch ? - (low(interval) <= high(b)) & (high(interval) >= low(b)) : - (low(interval) < high(b)) & (high(interval) > low(b)); - } - - struct y_i_e_bintersect : gtl_yes {}; - - // check if Interval b partially overlaps `this` Interval - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - boundaries_intersect(const interval_type& interval, const interval_type_2& b, - bool consider_touch = true) { - return (contains(interval, low(b), consider_touch) || - contains(interval, high(b), consider_touch)) && - (contains(b, low(interval), consider_touch) || - contains(b, high(interval), consider_touch)); - } - - struct y_i_abuts1 : gtl_yes {}; - - // check if they are end to end - template - typename enable_if< typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - abuts(const interval_type& interval, const interval_type_2& b, direction_1d dir) { - return dir.to_int() ? low(b) == high(interval) : low(interval) == high(b); - } - - struct y_i_abuts2 : gtl_yes {}; - - // check if they are end to end - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - abuts(const interval_type& interval, const interval_type_2& b) { - return abuts(interval, b, HIGH) || abuts(interval, b, LOW); - } - - struct y_i_intersect : gtl_yes {}; - - // set 'this' interval to the intersection of 'this' and b - template - typename enable_if< typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - intersect(interval_type& interval, const interval_type_2& b, bool consider_touch = true) { - typedef typename interval_coordinate_type::type Unit; - Unit lowVal = (std::max)(low(interval), low(b)); - Unit highVal = (std::min)(high(interval), high(b)); - bool valid = consider_touch ? - lowVal <= highVal : - lowVal < highVal; - if(valid) { - low(interval, lowVal); - high(interval, highVal); - } - return valid; - } - - struct y_i_g_intersect : gtl_yes {}; - - // set 'this' interval to the generalized intersection of 'this' and b - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - interval_type>::type & - generalized_intersect(interval_type& interval, const interval_type_2& b) { - typedef typename interval_coordinate_type::type Unit; - Unit coords[4] = {low(interval), high(interval), low(b), high(b)}; - //consider implementing faster sorting of small fixed length range - polygon_sort(coords, coords+4); - low(interval, coords[1]); - high(interval, coords[2]); - return interval; - } - - struct y_i_bloat : gtl_yes {}; - - // bloat the Interval - template - typename enable_if< typename gtl_and::type>::type>::type, - interval_type>::type & - bloat(interval_type& interval, typename interval_coordinate_type::type bloating) { - low(interval, low(interval)-bloating); - high(interval, high(interval)+bloating); - return interval; - } - - struct y_i_bloat2 : gtl_yes {}; - - // bloat the specified side of `this` Interval - template - typename enable_if< typename gtl_and::type>::type>::type, - interval_type>::type & - bloat(interval_type& interval, direction_1d dir, typename interval_coordinate_type::type bloating) { - set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); - return interval; - } - - struct y_i_shrink : gtl_yes {}; - - // shrink the Interval - template - typename enable_if< typename gtl_and::type>::type>::type, - interval_type>::type & - shrink(interval_type& interval, typename interval_coordinate_type::type shrinking) { - return bloat(interval, -shrinking); - } - - struct y_i_shrink2 : gtl_yes {}; - - // shrink the specified side of `this` Interval - template - typename enable_if< typename gtl_and::type>::type>::type, - interval_type>::type & - shrink(interval_type& interval, direction_1d dir, typename interval_coordinate_type::type shrinking) { - return bloat(interval, dir, -shrinking); - } - - struct y_i_encompass : gtl_yes {}; - - // Enlarge `this` Interval to encompass the specified Interval - template - typename enable_if< typename gtl_and_3< - y_i_encompass, - typename is_mutable_interval_concept::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - encompass(interval_type& interval, const interval_type_2& b) { - bool retval = !contains(interval, b, true); - low(interval, (std::min)(low(interval), low(b))); - high(interval, (std::max)(high(interval), high(b))); - return retval; - } - - struct y_i_encompass2 : gtl_yes {}; - - // Enlarge `this` Interval to encompass the specified Interval - template - typename enable_if< typename gtl_and::type>::type>::type, - bool>::type - encompass(interval_type& interval, typename interval_coordinate_type::type b) { - bool retval = !contains(interval, b, true); - low(interval, (std::min)(low(interval), b)); - high(interval, (std::max)(high(interval), b)); - return retval; - } - - struct y_i_get_half : gtl_yes {}; - - // gets the half of the interval as an interval - template - typename enable_if::type>::type>::type, interval_type>::type - get_half(const interval_type& interval, direction_1d d1d) { - typedef typename interval_coordinate_type::type Unit; - Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; - return construct((d1d == LOW) ? get(interval, LOW) : c, - (d1d == LOW) ? c : get(interval, HIGH)); - } - - struct y_i_join_with : gtl_yes {}; - - // returns true if the 2 intervals exactly touch at one value, like in l1 <= h1 == l2 <= h2 - // sets the argument to the joined interval - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_interval_concept::type>::type>::type, - bool>::type - join_with(interval_type& interval, const interval_type_2& b) { - if(abuts(interval, b)) { - encompass(interval, b); - return true; - } - return false; - } - - template - template - interval_data& interval_data::operator=(const T2& rvalue) { - assign(*this, rvalue); - return *this; - } - - template - struct geometry_concept > { - typedef interval_concept type; - }; +namespace boost { +namespace polygon { + +struct interval_concept {}; + +template +struct is_interval_concept { + typedef gtl_no type; +}; + +template <> +struct is_interval_concept { + typedef gtl_yes type; +}; + +template +struct is_mutable_interval_concept { + typedef gtl_no type; +}; + +template <> +struct is_mutable_interval_concept { + typedef gtl_yes type; +}; + +template +struct interval_coordinate_type_by_concept { + typedef void type; +}; + +template +struct interval_coordinate_type_by_concept { + typedef typename interval_traits::coordinate_type type; +}; + +template +struct interval_coordinate_type { + typedef typename interval_coordinate_type_by_concept< + GeometryType, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type type; +}; + +template +struct interval_difference_type_by_concept { + typedef void type; +}; + +template +struct interval_difference_type_by_concept { + typedef typename coordinate_traits< + typename interval_traits::coordinate_type + >::coordinate_difference type; +}; + +template +struct interval_difference_type { + typedef typename interval_difference_type_by_concept< + GeometryType, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type type; +}; + +struct y_i_get : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_get, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_coordinate_type::type +>::type get(const IntervalType& interval, direction_1d dir) { + return interval_traits::get(interval, dir); } + +struct y_i_set : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_set, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type set(IntervalType& interval, direction_1d dir, + typename interval_mutable_traits::coordinate_type value) { + interval_mutable_traits::set(interval, dir, value); } -#endif + +struct y_i_construct : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_construct, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type construct( + typename interval_mutable_traits::coordinate_type low, + typename interval_mutable_traits::coordinate_type high) { + if (low > high) { + (std::swap)(low, high); + } + return interval_mutable_traits::construct(low, high); +} + +struct y_i_copy_construct : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_copy_construct, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type copy_construct(const IntervalType2& interval) { + return construct(get(interval, LOW), get(interval, HIGH)); +} + +struct y_i_assign : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_assign, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& assign(IntervalType1& lvalue, const IntervalType2& rvalue) { + set(lvalue, LOW, get(rvalue, LOW)); + set(lvalue, HIGH, get(rvalue, HIGH)); + return lvalue; +} + +struct y_i_low : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_low, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_coordinate_type::type +>::type low(const IntervalType& interval) { + return get(interval, LOW); +} + +struct y_i_high : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_high, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_coordinate_type::type +>::type high(const IntervalType& interval) { + return get(interval, HIGH); +} + +struct y_i_low2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_low2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type low(IntervalType& interval, + typename interval_mutable_traits::coordinate_type value) { + set(interval, LOW, value); +} + +struct y_i_high2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_high2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type high(IntervalType& interval, + typename interval_mutable_traits::coordinate_type value) { + set(interval, HIGH, value); +} + +struct y_i_equivalence : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_equivalence, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type equivalence( + const IntervalType1& interval1, + const IntervalType2& interval2) { + return (get(interval1, LOW) == get(interval2, LOW)) && + (get(interval1, HIGH) == get(interval2, HIGH)); +} + +struct y_i_contains : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_contains, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type contains( + const IntervalType& interval, + typename interval_coordinate_type::type value, + bool consider_touch = true ) { + if (consider_touch) { + return value <= high(interval) && value >= low(interval); + } else { + return value < high(interval) && value > low(interval); + } +} + +struct y_i_contains2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_contains2, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type contains( + const IntervalType1& interval1, + const IntervalType2& interval2, + bool consider_touch = true) { + return contains(interval1, get(interval2, LOW), consider_touch) && + contains(interval1, get(interval2, HIGH), consider_touch); +} + +struct y_i_center : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_center, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_coordinate_type::type +>::type center(const IntervalType& interval) { + return (high(interval) + low(interval)) / 2; +} + +struct y_i_delta : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_delta, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_difference_type::type +>::type delta(const IntervalType& interval) { + typedef typename interval_difference_type::type diff_type; + return static_cast(high(interval)) - + static_cast(low(interval)); +} + +struct y_i_flip : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_flip, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, +IntervalType>::type& flip( + IntervalType& interval, + typename interval_coordinate_type::type axis = 0) { + typename interval_coordinate_type::type newLow, newHigh; + newLow = 2 * axis - high(interval); + newHigh = 2 * axis - low(interval); + low(interval, newLow); + high(interval, newHigh); + return interval; +} + +struct y_i_scale_up : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_scale_up, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& scale_up( + IntervalType& interval, + typename interval_coordinate_type::type factor) { + typename interval_coordinate_type::type newHigh = + high(interval) * factor; + low(interval, low(interval) * factor); + high(interval, (newHigh)); + return interval; +} + +struct y_i_scale_down : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_scale_down, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& scale_down( + IntervalType& interval, + typename interval_coordinate_type::type factor) { + typedef typename interval_coordinate_type::type Unit; + typename interval_coordinate_type::type newHigh = + high(interval) / factor; + low(interval, low(interval) / factor); + high(interval, (newHigh)); + return interval; +} + +// TODO(asydorchuk): Deprecated. +struct y_i_scale : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_scale, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& scale(IntervalType& interval, double factor) { + typedef typename interval_coordinate_type::type Unit; + Unit newHigh = scaling_policy::round( + static_cast(high(interval)) * factor); + low(interval, scaling_policy::round( + static_cast(low(interval)) * factor)); + high(interval, (newHigh)); + return interval; +} + +struct y_i_move : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_move, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& move( + IntervalType& interval, + typename interval_difference_type::type displacement) { + typedef typename interval_coordinate_type::type ctype; + typedef typename coordinate_traits::coordinate_difference Unit; + low(interval, static_cast( + static_cast(low(interval)) + displacement)); + high(interval, static_cast( + static_cast(high(interval)) + displacement)); + return interval; +} + +struct y_i_convolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_convolve, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& convolve( + IntervalType& interval, + typename interval_coordinate_type::type value) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(interval) + value; + Unit newHigh = high(interval) + value; + low(interval, newLow); + high(interval, newHigh); + return interval; +} + +struct y_i_deconvolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_deconvolve, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& deconvolve( + IntervalType& interval, + typename interval_coordinate_type::type value) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(interval) - value; + Unit newHigh = high(interval) - value; + low(interval, newLow); + high(interval, newHigh); + return interval; +} + +struct y_i_convolve2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_convolve2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& convolve(IntervalType1& lvalue, const IntervalType2& rvalue) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(lvalue) + low(rvalue); + Unit newHigh = high(lvalue) + high(rvalue); + low(lvalue, newLow); + high(lvalue, newHigh); + return lvalue; +} + +struct y_i_deconvolve2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_deconvolve2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& deconvolve(IntervalType1& lvalue, const IntervalType2& rvalue) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(lvalue) - low(rvalue); + Unit newHigh = high(lvalue) - high(rvalue); + low(lvalue, newLow); + high(lvalue, newHigh); + return lvalue; +} + +struct y_i_reconvolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_reconvolve, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& reflected_convolve( + IntervalType1& lvalue, + const IntervalType2& rvalue) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(lvalue) - high(rvalue); + Unit newHigh = high(lvalue) - low(rvalue); + low(lvalue, newLow); + high(lvalue, newHigh); + return lvalue; +} + +struct y_i_redeconvolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_redeconvolve, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& reflected_deconvolve( + IntervalType1& lvalue, + const IntervalType2& rvalue) { + typedef typename interval_coordinate_type::type Unit; + Unit newLow = low(lvalue) + high(rvalue); + Unit newHigh = high(lvalue) + low(rvalue); + low(lvalue, newLow); + high(lvalue, newHigh); + return lvalue; +} + +struct y_i_e_dist1 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and::type + >::type + >::type, + typename interval_difference_type::type +>::type euclidean_distance( + const IntervalType& interval, + typename interval_coordinate_type::type position) { + typedef typename interval_difference_type::type Unit; + Unit dist[3] = { + 0, + (Unit)low(interval) - (Unit)position, + (Unit)position - (Unit)high(interval) + }; + return dist[(dist[1] > 0) + ((dist[2] > 0) << 1)]; +} + +struct y_i_e_dist2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_e_dist2, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + typename interval_difference_type::type +>::type euclidean_distance( + const IntervalType1& interval1, + const IntervalType2& interval2) { + typedef typename interval_difference_type::type Unit; + Unit dist[3] = { + 0, + (Unit)low(interval1) - (Unit)high(interval2), + (Unit)low(interval2) - (Unit)high(interval1) + }; + return dist[(dist[1] > 0) + ((dist[2] > 0) << 1)]; +} + +struct y_i_e_intersects : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_e_intersects, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type intersects( + const IntervalType1& interval1, + const IntervalType2& interval2, + bool consider_touch = true) { + return consider_touch ? + (low(interval1) <= high(interval2)) && + (high(interval1) >= low(interval2)) : + (low(interval1) < high(interval2)) && + (high(interval1) > low(interval2)); +} + +struct y_i_e_bintersect : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_e_bintersect, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type boundaries_intersect( + const IntervalType1& interval1, + const IntervalType2& interval2, + bool consider_touch = true) { + return (contains(interval1, low(interval2), consider_touch) || + contains(interval1, high(interval2), consider_touch)) && + (contains(interval2, low(interval1), consider_touch) || + contains(interval2, high(interval1), consider_touch)); +} + +struct y_i_intersect : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_intersect, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type intersect( + IntervalType1& lvalue, + const IntervalType2& rvalue, + bool consider_touch = true) { + typedef typename interval_coordinate_type::type Unit; + Unit lowVal = (std::max)(low(lvalue), low(rvalue)); + Unit highVal = (std::min)(high(lvalue), high(rvalue)); + bool valid = consider_touch ? lowVal <= highVal : lowVal < highVal; + if (valid) { + low(lvalue, lowVal); + high(lvalue, highVal); + } + return valid; +} + +struct y_i_g_intersect : gtl_yes {}; + +// TODO(asydorchuk): Deprecated. +template +typename enable_if< + typename gtl_and_3< + y_i_g_intersect, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType1 +>::type& generalized_intersect( + IntervalType1& lvalue, + const IntervalType2& rvalue) { + typedef typename interval_coordinate_type::type Unit; + Unit coords[4] = {low(lvalue), high(lvalue), low(rvalue), high(rvalue)}; + // TODO(asydorchuk): consider implementing faster sorting of small + // fixed length range. + polygon_sort(coords, coords+4); + low(lvalue, coords[1]); + high(lvalue, coords[2]); + return lvalue; +} + +struct y_i_abuts1 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_abuts1, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type abuts( + const IntervalType1& interval1, + const IntervalType2& interval2, + direction_1d dir) { + return dir.to_int() ? low(interval2) == high(interval1) : + low(interval1) == high(interval2); +} + +struct y_i_abuts2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_abuts2, + typename is_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type abuts( + const IntervalType1& interval1, + const IntervalType2& interval2) { + return abuts(interval1, interval2, HIGH) || + abuts(interval1, interval2, LOW); +} + +struct y_i_bloat : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_bloat, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& bloat( + IntervalType& interval, + typename interval_coordinate_type::type bloating) { + low(interval, low(interval) - bloating); + high(interval, high(interval) + bloating); + return interval; +} + +struct y_i_bloat2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_bloat2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& bloat( + IntervalType& interval, + direction_1d dir, + typename interval_coordinate_type::type bloating) { + set(interval, dir, get(interval, dir) + dir.get_sign() * bloating); + return interval; +} + +struct y_i_shrink : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_shrink, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& shrink( + IntervalType& interval, + typename interval_coordinate_type::type shrinking) { + return bloat(interval, -shrinking); +} + +struct y_i_shrink2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_shrink2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type& shrink( + IntervalType& interval, + direction_1d dir, + typename interval_coordinate_type::type shrinking) { + return bloat(interval, dir, -shrinking); +} + +struct y_i_encompass : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_encompass, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type encompass(IntervalType1& interval1, const IntervalType2& interval2) { + bool retval = !contains(interval1, interval2, true); + low(interval1, (std::min)(low(interval1), low(interval2))); + high(interval1, (std::max)(high(interval1), high(interval2))); + return retval; +} + +struct y_i_encompass2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_encompass2, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + bool +>::type encompass( + IntervalType& interval, + typename interval_coordinate_type::type value) { + bool retval = !contains(interval, value, true); + low(interval, (std::min)(low(interval), value)); + high(interval, (std::max)(high(interval), value)); + return retval; +} + +struct y_i_get_half : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_i_get_half, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type + >::type, + IntervalType +>::type get_half(const IntervalType& interval, direction_1d dir) { + typedef typename interval_coordinate_type::type Unit; + Unit c = (get(interval, LOW) + get(interval, HIGH)) / 2; + return construct( + (dir == LOW) ? get(interval, LOW) : c, + (dir == LOW) ? c : get(interval, HIGH)); +} + +struct y_i_join_with : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_i_join_with, + typename is_mutable_interval_concept< + typename geometry_concept::type + >::type, + typename is_interval_concept< + typename geometry_concept::type + >::type>::type, + bool +>::type join_with(IntervalType1& interval1, const IntervalType2& interval2) { + if (abuts(interval1, interval2)) { + encompass(interval1, interval2); + return true; + } + return false; +} +} // polygon +} // boost + +#endif // BOOST_POLYGON_INTERVAL_CONCEPT_HPP diff --git a/include/boost/polygon/interval_data.hpp b/include/boost/polygon/interval_data.hpp index dbb772e..b538b3e 100644 --- a/include/boost/polygon/interval_data.hpp +++ b/include/boost/polygon/interval_data.hpp @@ -1,67 +1,120 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library interval_data.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_INTERVAL_DATA_HPP #define BOOST_POLYGON_INTERVAL_DATA_HPP + #include "isotropy.hpp" -namespace boost { namespace polygon{ - template - class interval_data { - public: - typedef T coordinate_type; - inline interval_data() +#include "interval_concept.hpp" + +namespace boost { +namespace polygon { + +template +class interval_data { + public: + typedef T coordinate_type; + + interval_data() #ifndef BOOST_POLYGON_MSVC - :coords_() + : coords_() #endif - {} - inline interval_data(coordinate_type low, coordinate_type high) + {} + + interval_data(coordinate_type low, coordinate_type high) #ifndef BOOST_POLYGON_MSVC - :coords_() + : coords_() #endif - { - coords_[LOW] = low; coords_[HIGH] = high; - } - inline interval_data(const interval_data& that) + { + coords_[LOW] = low; + coords_[HIGH] = high; + } + + interval_data(const interval_data& that) #ifndef BOOST_POLYGON_MSVC - :coords_() + : coords_() #endif - { - (*this) = that; - } - inline interval_data& operator=(const interval_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; - } - template - inline interval_data& operator=(const T2& rvalue); - inline coordinate_type get(direction_1d dir) const { - return coords_[dir.to_int()]; - } - inline coordinate_type low() const { return coords_[0]; } - inline coordinate_type high() const { return coords_[1]; } - inline bool operator==(const interval_data& that) const { - return low() == that.low() && high() == that.high(); } - inline bool operator!=(const interval_data& that) const { - return low() != that.low() || high() != that.high(); } - inline bool operator<(const interval_data& that) const { - if(coords_[0] < that.coords_[0]) return true; - if(coords_[0] > that.coords_[0]) return false; - if(coords_[1] < that.coords_[1]) return true; - return false; - } - inline bool operator<=(const interval_data& that) const { return !(that < *this); } - inline bool operator>(const interval_data& that) const { return that < *this; } - inline bool operator>=(const interval_data& that) const { return !((*this) < that); } - inline void set(direction_1d dir, coordinate_type value) { + { + coords_[0] = that.coords_[0]; + coords_[1] = that.coords_[1]; + } + + interval_data& operator=(const interval_data& that) { + coords_[0] = that.coords_[0]; + coords_[1] = that.coords_[1]; + return *this; + } + + coordinate_type get(direction_1d dir) const { + return coords_[dir.to_int()]; + } + + void set(direction_1d dir, coordinate_type value) { coords_[dir.to_int()] = value; } -private: + + coordinate_type low() const { + return coords_[0]; + } + + interval_data& low(coordinate_type value) { + coords_[LOW] = value; + return *this; + } + + coordinate_type high() const { + return coords_[1]; + } + + interval_data& high(coordinate_type value) { + coords_[HIGH] = value; + return *this; + } + + bool operator==(const interval_data& that) const { + return low() == that.low() && high() == that.high(); + } + + bool operator!=(const interval_data& that) const { + return low() != that.low() || high() != that.high(); + } + + bool operator<(const interval_data& that) const { + if (coords_[0] != that.coords_[0]) { + return coords_[0] < that.coords_[0]; + } + return coords_[1] < that.coords_[1]; + } + + bool operator<=(const interval_data& that) const { + return !(that < *this); + } + + bool operator>(const interval_data& that) const { + return that < *this; + } + + bool operator>=(const interval_data& that) const { + return !((*this) < that); + } + + private: coordinate_type coords_[2]; }; -} -} -#endif +template +struct geometry_concept< interval_data > { + typedef interval_concept type; +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_INTERVAL_DATA_HPP diff --git a/include/boost/polygon/interval_traits.hpp b/include/boost/polygon/interval_traits.hpp index 97f918f..9c9062f 100644 --- a/include/boost/polygon/interval_traits.hpp +++ b/include/boost/polygon/interval_traits.hpp @@ -1,32 +1,47 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library interval_traits.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_INTERVAL_TRAITS_HPP #define BOOST_POLYGON_INTERVAL_TRAITS_HPP -namespace boost { namespace polygon{ - template - struct interval_traits { - typedef typename T::coordinate_type coordinate_type; - static inline coordinate_type get(const T& interval, direction_1d dir) { - return interval.get(dir); - } - }; +#include "isotropy.hpp" - template - struct interval_mutable_traits { - static inline void set(T& interval, direction_1d dir, typename interval_traits::coordinate_type value) { - interval.set(dir, value); - } - static inline T construct(typename interval_traits::coordinate_type low_value, - typename interval_traits::coordinate_type high_value) { - return T(low_value, high_value); - } - }; -} -} -#endif +namespace boost { +namespace polygon { + +template +struct interval_traits { + typedef Interval interval_type; + typedef typename interval_type::coordinate_type coordinate_type; + + static coordinate_type get(const interval_type& interval, direction_1d dir) { + return interval.get(dir); + } +}; + +template +struct interval_mutable_traits { + typedef Interval interval_type; + typedef typename interval_type::coordinate_type coordinate_type; + + static void set( + interval_type& interval, direction_1d dir, coordinate_type value) { + interval.set(dir, value); + } + + static interval_type construct(coordinate_type low, coordinate_type high) { + return interval_type(low, high); + } +}; +} // polygon +} // boost + +#endif // BOOST_POLICY_INTERVAL_TRAITS_HPP diff --git a/include/boost/polygon/point_3d_concept.hpp b/include/boost/polygon/point_3d_concept.hpp deleted file mode 100644 index 6183237..0000000 --- a/include/boost/polygon/point_3d_concept.hpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - Copyright 2008 Intel Corporation - - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ -#ifndef GLT_POINT_3D_CONCEPT_HPP -#define GLT_POINT_3D_CONCEPT_HPP -#include "point_concept.hpp" -#include "point_3d_data.hpp" -#include "point_3d_traits.hpp" -namespace boost { namespace polygon{ - struct point_3d_concept {}; - - template - struct is_point_3d_concept { typedef gtl_no type; }; - template <> - struct is_point_3d_concept { typedef gtl_yes type; }; - //template <> - //struct is_point_concept { typedef void type; }; - - template - struct is_mutable_point_3d_concept { typedef gtl_no type; }; - template <> - struct is_mutable_point_3d_concept { typedef gtl_yes type; }; - - template - struct point_3d_coordinate_type_by_concept { typedef void type; }; - template - struct point_3d_coordinate_type_by_concept { typedef typename point_3d_traits::coordinate_type type; }; - - template - struct point_3d_coordinate_type { - typedef typename point_3d_coordinate_type_by_concept::type>::type>::type type; - }; - - template - struct point_3d_difference_type_by_concept { typedef void type; }; - template - struct point_3d_difference_type_by_concept { - typedef typename coordinate_traits::type>::coordinate_difference type; }; - - template - struct point_3d_difference_type { - typedef typename point_3d_difference_type_by_concept< - T, typename is_point_3d_concept::type>::type>::type type; - }; - - template - struct point_3d_distance_type_by_concept { typedef void type; }; - template - struct point_3d_distance_type_by_concept { - typedef typename coordinate_traits::type>::coordinate_distance type; }; - - template - struct point_3d_distance_type { - typedef typename point_3d_distance_type_by_concept< - T, typename is_point_3d_concept::type>::type>::type type; - }; - - struct y_p3d_get : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_3d_coordinate_type::type >::type - get(const T& point, orientation_3d orient) { return point_3d_traits::get(point, orient); } - - struct y_p3d_set : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, void>::type - set(T& point, orientation_3d orient, coordinate_type value) { point_3d_mutable_traits::set(point, orient, value); } - - struct y_p3d_set2 : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, void>::type - set(T& point, orientation_2d orient, coordinate_type value) { point_3d_mutable_traits::set(point, orient, value); } - - struct y_p3d_construct : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, T>::type - construct(coordinate_type1 x_value, coordinate_type2 y_value, coordinate_type3 z_value) { - return point_3d_mutable_traits::construct(x_value, y_value, z_value); } - - struct y_p3d_assign : gtl_yes {}; - - template - typename enable_if< - typename gtl_and_3::type>::type, - typename is_point_3d_concept::type>::type>::type, - point_3d_type_1>::type & - assign(point_3d_type_1& lvalue, const point_3d_type_2& rvalue) { - set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); - set(lvalue, VERTICAL, get(rvalue, VERTICAL)); - set(lvalue, PROXIMAL, get(rvalue, PROXIMAL)); - return lvalue; - } - - struct y_p3d_z : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_3d_coordinate_type::type >::type - z(const point_type& point) { return get(point, PROXIMAL); } - - struct y_p3d_x : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, void>::type - x(point_type& point, coordinate_type value) { set(point, HORIZONTAL, value); } - - struct y_p3d_y : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, void>::type - y(point_type& point, coordinate_type value) { set(point, VERTICAL, value); } - - struct y_p3d_z2 : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, void>::type - z(point_type& point, coordinate_type value) { set(point, PROXIMAL, value); } - - struct y_p3d_equiv : gtl_yes {}; - - template - typename enable_if< - typename gtl_and_3::type>::type, - typename gtl_same_type::type>::type>::type, - bool>::type - equivalence(const T& point1, const T2& point2) { - return x(point1) == x(point2) && y(point1) == y(point2) && z(point1) == z(point2); - } - - struct y_p3d_dist : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3::type>::type, - typename is_point_3d_concept::type>::type>::type, - typename point_3d_difference_type::type>::type - euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_3d orient) { - typedef typename coordinate_traits::type>::coordinate_difference return_type; - return_type return_value = - (return_type)get(point1, orient) - (return_type)get(point2, orient); - return return_value < 0 ? -return_value : return_value; - } - - struct y_p3d_man_dist : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3::type>::type, - typename gtl_same_type::type>::type>::type, - typename point_3d_difference_type::type>::type - manhattan_distance(const point_type_1& point1, const point_type_2& point2) { - return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL) - + euclidean_distance(point1, point2, PROXIMAL); - } - - struct y_p3d_dist2 : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< y_p3d_dist2, - typename gtl_same_type::type>::type, - typename gtl_same_type::type>::type>::type, - typename point_3d_distance_type::type>::type - euclidean_distance(const point_type_1& point1, const point_type_2& point2) { - typedef typename coordinate_traits::type>::coordinate_distance return_value; - return_value pdist = (return_value)euclidean_distance(point1, point2, PROXIMAL); - pdist *= pdist; - return std::sqrt((double)(distance_squared(point1, point2) + pdist)); - } - - struct y_p3d_convolve : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< y_p3d_convolve, - typename is_mutable_point_3d_concept::type>::type, - typename gtl_same_type::type>::type>::type, - point_type_1>::type & - convolve(point_type_1& lvalue, const point_type_2& rvalue) { - x(lvalue, x(lvalue) + x(rvalue)); - y(lvalue, y(lvalue) + y(rvalue)); - z(lvalue, z(lvalue) + z(rvalue)); - return lvalue; - } - - struct y_p3d_deconvolve : gtl_yes {}; - - template - typename enable_if< - typename gtl_and_3::type>::type, - typename gtl_same_type::type>::type>::type, - point_type_1>::type & - deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { - x(lvalue, x(lvalue) - x(rvalue)); - y(lvalue, y(lvalue) - y(rvalue)); - z(lvalue, z(lvalue) - z(rvalue)); - return lvalue; - } - - struct y_p3d_scale_up : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale_up(point_type& point, - typename coordinate_traits::type>::unsigned_area_type factor) { - x(point, x(point) * (typename point_3d_coordinate_type::type)factor); - y(point, y(point) * (typename point_3d_coordinate_type::type)factor); - z(point, z(point) * (typename point_3d_coordinate_type::type)factor); - return point; - } - - struct y_p3d_scale_down : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale_down(point_type& point, - typename coordinate_traits::type>::unsigned_area_type factor) { - typedef typename point_3d_coordinate_type::type Unit; - typedef typename coordinate_traits::coordinate_distance dt; - x(point, scaling_policy::round((dt)(x(point)) / (dt)factor)); - y(point, scaling_policy::round((dt)(y(point)) / (dt)factor)); - z(point, scaling_policy::round((dt)(z(point)) / (dt)factor)); - return point; - } - - struct y_p3d_scale : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale(point_type& point, - const scaling_type& scaling) { - typedef typename point_3d_coordinate_type::type Unit; - Unit x_(x(point)), y_(y(point)), z_(z(point)); - scaling.scale(x_, y_, z_); - x(point, x_); - y(point, y_); - z(point, z_); - return point; - } - - struct y_p3d_transform : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - transform(point_type& point, const transformation_type& transformation) { - typedef typename point_3d_coordinate_type::type Unit; - Unit x_(x(point)), y_(y(point)), z_(z(point)); - transformation.transform(x_, y_, z_); - x(point, x_); - y(point, y_); - z(point, z_); - return point; - } - - template - struct geometry_concept > { - typedef point_3d_concept type; - }; -} -} -#endif - diff --git a/include/boost/polygon/point_3d_data.hpp b/include/boost/polygon/point_3d_data.hpp deleted file mode 100644 index 24a01af..0000000 --- a/include/boost/polygon/point_3d_data.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2008 Intel Corporation - - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ -#ifndef BOOST_POLYGON_POINT_3D_DATA_HPP -#define BOOST_POLYGON_POINT_3D_DATA_HPP -namespace boost { namespace polygon{ - template - class point_3d_data { - public: - typedef T coordinate_type; - inline point_3d_data():coords_(){} - inline point_3d_data(coordinate_type x, coordinate_type y):coords_() { - coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = 0; } - inline point_3d_data(coordinate_type x, coordinate_type y, coordinate_type z) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { - coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; coords_[PROXIMAL] = z; } - inline point_3d_data(const point_3d_data& that):coords_() { (*this) = that; } - inline point_3d_data& operator=(const point_3d_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; - coords_[2] = that.coords_[2]; return *this; } - template - inline point_3d_data& operator=(const T2& rvalue); - inline bool operator==(const point_3d_data& that) const { - return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1] && coords_[2] == that.coords_[2]; - } - inline bool operator!=(const point_3d_data& that) const { - return !((*this) == that); - } - inline coordinate_type get(orientation_2d orient) const { - return coords_[orient.to_int()]; } - inline coordinate_type get(orientation_3d orient) const { - return coords_[orient.to_int()]; } - inline void set(orientation_2d orient, coordinate_type value) { - coords_[orient.to_int()] = value; } - inline void set(orientation_3d orient, coordinate_type value) { - coords_[orient.to_int()] = value; } - private: - coordinate_type coords_[3]; - }; -} -} -#endif diff --git a/include/boost/polygon/point_3d_traits.hpp b/include/boost/polygon/point_3d_traits.hpp deleted file mode 100644 index 3de97cc..0000000 --- a/include/boost/polygon/point_3d_traits.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright 2008 Intel Corporation - - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ -#ifndef BOOST_POLYGON_POINT_3D_TRAITS_HPP -#define BOOST_POLYGON_POINT_3D_TRAITS_HPP - -#include "isotropy.hpp" - -namespace boost { namespace polygon{ - template - struct point_3d_traits { - typedef typename T::coordinate_type coordinate_type; - - static inline coordinate_type get(const T& point, orientation_3d orient) { - return point.get(orient); } - }; - - template - struct point_3d_mutable_traits { - static inline void set(T& point, orientation_3d orient, typename point_3d_traits::coordinate_type value) { - point.set(orient, value); } - - static inline T construct(typename point_3d_traits::coordinate_type x_value, - typename point_3d_traits::coordinate_type y_value, - typename point_3d_traits::coordinate_type z_value) { - return T(x_value, y_value, z_value); } - }; -} -} -#endif diff --git a/include/boost/polygon/point_concept.hpp b/include/boost/polygon/point_concept.hpp index e4f42f9..4d4c1dd 100644 --- a/include/boost/polygon/point_concept.hpp +++ b/include/boost/polygon/point_concept.hpp @@ -1,316 +1,469 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library point_concept.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_POINT_CONCEPT_HPP #define BOOST_POLYGON_POINT_CONCEPT_HPP + #include "isotropy.hpp" -#include "point_data.hpp" #include "point_traits.hpp" -namespace boost { namespace polygon{ - struct point_concept {}; +namespace boost { +namespace polygon { - template - struct is_point_concept { typedef gtl_no type; }; - template <> - struct is_point_concept { typedef gtl_yes type; }; +struct point_concept {}; - struct point_3d_concept; - template <> - struct is_point_concept { typedef gtl_yes type; }; +template +struct is_point_concept { + typedef gtl_no type; +}; - template - struct is_mutable_point_concept { typedef gtl_no type; }; - template <> - struct is_mutable_point_concept { typedef gtl_yes type; }; +template <> +struct is_point_concept { + typedef gtl_yes type; +}; - template - struct point_coordinate_type_by_concept { typedef void type; }; - template - struct point_coordinate_type_by_concept { typedef typename point_traits::coordinate_type type; }; +template +struct is_mutable_point_concept { + typedef gtl_no type; +}; - template - struct point_coordinate_type { - typedef typename point_coordinate_type_by_concept::type>::type>::type type; - }; +template <> +struct is_mutable_point_concept { + typedef gtl_yes type; +}; - template - struct point_difference_type_by_concept { typedef void type; }; - template - struct point_difference_type_by_concept { - typedef typename coordinate_traits::type>::coordinate_difference type; }; +template +struct point_coordinate_type_by_concept { + typedef void type; +}; - template - struct point_difference_type { - typedef typename point_difference_type_by_concept< - T, typename is_point_concept::type>::type>::type type; - }; +template +struct point_coordinate_type_by_concept { + typedef typename point_traits::coordinate_type type; +}; - template - struct point_distance_type_by_concept { typedef void type; }; - template - struct point_distance_type_by_concept { - typedef typename coordinate_traits::type>::coordinate_distance type; }; +template +struct point_coordinate_type { + typedef typename point_coordinate_type_by_concept< + GeometryType, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type type; +}; - template - struct point_distance_type { - typedef typename point_distance_type_by_concept< - T, typename is_point_concept::type>::type>::type type; - }; +template +struct point_difference_type_by_concept { + typedef void type; +}; - struct y_pt_get : gtl_yes {}; +template +struct point_difference_type_by_concept { + typedef typename coordinate_traits< + typename point_traits::coordinate_type + >::coordinate_difference type; +}; - template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_coordinate_type::type >::type - get(const T& point, orientation_2d orient) { - return point_traits::get(point, orient); - } +template +struct point_difference_type { + typedef typename point_difference_type_by_concept< + GeometryType, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type type; +}; - struct y_pt_set : gtl_yes {}; +template +struct point_distance_type_by_concept { + typedef void type; +}; - template - typename enable_if< typename gtl_and::type>::type>::type, - void>::type - set(T& point, orientation_2d orient, coordinate_type value) { - point_mutable_traits::set(point, orient, value); - } +template +struct point_distance_type_by_concept { + typedef typename coordinate_traits< + typename point_coordinate_type::type + >::coordinate_distance type; +}; - struct y_pt_construct : gtl_yes {}; +template +struct point_distance_type { + typedef typename point_distance_type_by_concept< + GeometryType, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type type; +}; - template - typename enable_if< typename gtl_and::type>::type>::type, - T>::type - construct(coordinate_type1 x_value, coordinate_type2 y_value) { - return point_mutable_traits::construct(x_value, y_value); - } +struct y_pt_get : gtl_yes {}; - struct y_pt_assign : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_pt_get, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + typename point_coordinate_type::type +>::type get(const PointType& point, orientation_2d orient) { + return point_traits::get(point, orient); +} - template - typename enable_if::type>::type, - typename is_point_concept::type>::type>::type, - T1>::type & - assign(T1& lvalue, const T2& rvalue) { - set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); - set(lvalue, VERTICAL, get(rvalue, VERTICAL)); - return lvalue; - } +struct y_pt_set : gtl_yes {}; - struct y_p_x : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_pt_set, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, + void +>::type set(PointType& point, orientation_2d orient, + typename point_mutable_traits::coordinate_type value) { + point_mutable_traits::set(point, orient, value); +} - template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_coordinate_type::type >::type - x(const point_type& point) { - return get(point, HORIZONTAL); - } +struct y_pt_construct : gtl_yes {}; - struct y_p_y : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_pt_construct, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type construct( + typename point_mutable_traits::coordinate_type x, + typename point_mutable_traits::coordinate_type y) { + return point_mutable_traits::construct(x, y); +} - template - typename enable_if< typename gtl_and::type>::type>::type, - typename point_coordinate_type::type >::type - y(const point_type& point) { - return get(point, VERTICAL); - } +struct y_pt_assign : gtl_yes {}; - struct y_p_sx : gtl_yes {}; +template +typename enable_if< + typename gtl_and_3< + y_pt_assign, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type +>::type, +PointType1>::type& assign(PointType1& lvalue, const PointType2& rvalue) { + set(lvalue, HORIZONTAL, get(rvalue, HORIZONTAL)); + set(lvalue, VERTICAL, get(rvalue, VERTICAL)); + return lvalue; +} - template - typename enable_if::type>::type>::type, - void>::type - x(point_type& point, coordinate_type value) { - set(point, HORIZONTAL, value); - } +struct y_p_x : gtl_yes {}; - struct y_p_sy : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_p_x, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + typename point_coordinate_type::type +>::type x(const PointType& point) { + return get(point, HORIZONTAL); +} - template - typename enable_if::type>::type>::type, - void>::type - y(point_type& point, coordinate_type value) { - set(point, VERTICAL, value); - } +struct y_p_y : gtl_yes {}; - struct y_pt_equiv : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_p_y, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, + typename point_coordinate_type::type +>::type y(const PointType& point) { + return get(point, VERTICAL); +} - template - typename enable_if::type>::type, - typename is_point_concept::type>::type>::type, - bool>::type - equivalence(const T& point1, const T2& point2) { - typename point_coordinate_type::type x1 = x(point1); - typename point_coordinate_type::type x2 = get(point2, HORIZONTAL); - typename point_coordinate_type::type y1 = get(point1, VERTICAL); - typename point_coordinate_type::type y2 = y(point2); - return x1 == x2 && y1 == y2; - } +struct y_p_sx : gtl_yes {}; - struct y_pt_man_dist : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_p_sx, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +void>::type x(PointType& point, + typename point_mutable_traits::coordinate_type value) { + set(point, HORIZONTAL, value); +} - template - typename enable_if< typename gtl_and_3< - y_pt_man_dist, - typename gtl_same_type::type>::type, - typename is_point_concept::type>::type>::type, - typename point_difference_type::type>::type - manhattan_distance(const point_type_1& point1, const point_type_2& point2) { - return euclidean_distance(point1, point2, HORIZONTAL) + euclidean_distance(point1, point2, VERTICAL); - } +struct y_p_sy : gtl_yes {}; - struct y_pt_ed1 : gtl_yes {}; +template +typename enable_if< + typename gtl_and< + y_p_sy, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +void>::type y(PointType& point, + typename point_mutable_traits::coordinate_type value) { + set(point, VERTICAL, value); +} - template - typename enable_if< typename gtl_and_3::type>::type, - typename is_point_concept::type>::type>::type, - typename point_difference_type::type>::type - euclidean_distance(const point_type_1& point1, const point_type_2& point2, orientation_2d orient) { - typename coordinate_traits::type>::coordinate_difference return_value = +struct y_pt_equiv : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_equiv, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +bool>::type equivalence( + const PointType1& point1, const PointType2& point2) { + return (x(point1) == x(point2)) && (y(point1) == y(point2)); +} + +struct y_pt_man_dist : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_man_dist, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +typename point_difference_type::type>::type +manhattan_distance(const PointType1& point1, const PointType2& point2) { + return euclidean_distance(point1, point2, HORIZONTAL) + + euclidean_distance(point1, point2, VERTICAL); +} + +struct y_pt_ed1 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_ed1, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +typename point_difference_type::type>::type +euclidean_distance( + const PointType1& point1, + const PointType2& point2, + orientation_2d orient) { + typename point_difference_type::type dif = get(point1, orient) - get(point2, orient); - return return_value < 0 ? (typename coordinate_traits::type>::coordinate_difference)-return_value : return_value; - } - - struct y_pt_ed2 : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3::type>::type, - typename gtl_same_type::type>::type>::type, - typename point_distance_type::type>::type - euclidean_distance(const point_type_1& point1, const point_type_2& point2) { - typedef typename point_coordinate_type::type Unit; - return std::sqrt((double)(distance_squared(point1, point2))); - } - - struct y_pt_eds : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_pt_eds, - typename is_point_concept::type>::type, - typename is_point_concept::type>::type>::type, - typename point_difference_type::type>::type - distance_squared(const point_type_1& point1, const point_type_2& point2) { - typedef typename point_coordinate_type::type Unit; - typename coordinate_traits::coordinate_difference dx = euclidean_distance(point1, point2, HORIZONTAL); - typename coordinate_traits::coordinate_difference dy = euclidean_distance(point1, point2, VERTICAL); - dx *= dx; - dy *= dy; - return dx + dy; - } - - struct y_pt_convolve : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_pt_convolve, - typename is_mutable_point_concept::type>::type, - typename is_point_concept::type>::type>::type, - point_type_1>::type & - convolve(point_type_1& lvalue, const point_type_2& rvalue) { - x(lvalue, x(lvalue) + x(rvalue)); - y(lvalue, y(lvalue) + y(rvalue)); - return lvalue; - } - - struct y_pt_deconvolve : gtl_yes {}; - - template - typename enable_if< typename gtl_and_3< - y_pt_deconvolve, - typename is_mutable_point_concept::type>::type, - typename is_point_concept::type>::type>::type, - point_type_1>::type & - deconvolve(point_type_1& lvalue, const point_type_2& rvalue) { - x(lvalue, x(lvalue) - x(rvalue)); - y(lvalue, y(lvalue) - y(rvalue)); - return lvalue; - } - - struct y_pt_scale_up : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale_up(point_type& point, coord_type factor) { - typedef typename point_coordinate_type::type Unit; - x(point, x(point) * (Unit)factor); - y(point, y(point) * (Unit)factor); - return point; - } - - struct y_pt_scale_down : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale_down(point_type& point, coord_type factor) { - typedef typename point_coordinate_type::type Unit; - typedef typename coordinate_traits::coordinate_distance dt; - x(point, scaling_policy::round((dt)((dt)(x(point)) / (dt)factor))); - y(point, scaling_policy::round((dt)((dt)(y(point)) / (dt)factor))); - return point; - } - - struct y_pt_scale : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - scale(point_type& point, const scaling_type& scaling) { - typedef typename point_coordinate_type::type Unit; - Unit x_(x(point)), y_(y(point)); - scaling.scale(x_, y_); - x(point, x_); - y(point, y_); - return point; - } - - struct y_pt_transform : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - transform(point_type& point, const transformation_type& transformation) { - typedef typename point_coordinate_type::type Unit; - Unit x_(x(point)), y_(y(point)); - transformation.transform(x_, y_); - x(point, x_); - y(point, y_); - return point; - } - - struct y_pt_move : gtl_yes {}; - - template - typename enable_if< typename gtl_and::type>::type>::type, - point_type>::type & - move(point_type& point, orientation_2d orient, - typename point_coordinate_type::type displacement) { - typedef typename point_coordinate_type::type Unit; - Unit v(get(point, orient)); - set(point, orient, v + displacement); - return point; - } - - template - template - point_data& point_data::operator=(const T2& rvalue) { - assign(*this, rvalue); - return *this; - } - - template - struct geometry_concept > { - typedef point_concept type; - }; + return (dif < 0) ? -dif : dif; } + +struct y_pt_eds : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_eds, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +typename point_difference_type::type>::type +distance_squared(const PointType1& point1, const PointType2& point2) { + typename point_difference_type::type dx = + euclidean_distance(point1, point2, HORIZONTAL); + typename point_difference_type::type dy = + euclidean_distance(point1, point2, VERTICAL); + dx *= dx; + dy *= dy; + return dx + dy; } -#endif + +struct y_pt_ed2 : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_ed2, + typename is_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +typename point_distance_type::type>::type +euclidean_distance(const PointType1& point1, const PointType2& point2) { + return (std::sqrt)( + static_cast(distance_squared(point1, point2))); +} + +struct y_pt_convolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_convolve, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType1>::type& convolve(PointType1& lvalue, const PointType2& rvalue) { + x(lvalue, x(lvalue) + x(rvalue)); + y(lvalue, y(lvalue) + y(rvalue)); + return lvalue; +} + +struct y_pt_deconvolve : gtl_yes {}; + +template +typename enable_if< + typename gtl_and_3< + y_pt_deconvolve, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type, + typename is_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType1>::type& deconvolve(PointType1& lvalue, const PointType2& rvalue) { + x(lvalue, x(lvalue) - x(rvalue)); + y(lvalue, y(lvalue) - y(rvalue)); + return lvalue; +} + +struct y_pt_scale_up : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_pt_scale_up, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type& scale_up(PointType& point, CType factor) { + typedef typename point_coordinate_type::type Unit; + x(point, x(point) * (Unit)factor); + y(point, y(point) * (Unit)factor); + return point; +} + +struct y_pt_scale_down : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_pt_scale_down, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type& scale_down(PointType& point, CType factor) { + typedef typename point_coordinate_type::type Unit; + typedef typename coordinate_traits::coordinate_distance dt; + x(point, scaling_policy::round((dt)(x(point)) / (dt)factor)); + y(point, scaling_policy::round((dt)(y(point)) / (dt)factor)); + return point; +} + +struct y_pt_scale : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_pt_scale, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type& scale(PointType& point, const ScaleType& scaling) { + typedef typename point_coordinate_type::type Unit; + Unit x_coord(x(point)); + Unit y_coord(y(point)); + scaling.scale(x_coord, y_coord); + x(point, x_coord); + y(point, y_coord); + return point; +} + +struct y_pt_transform : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_pt_transform, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type& transform(PointType& point, const TransformType& transform) { + typedef typename point_coordinate_type::type Unit; + Unit x_coord(x(point)); + Unit y_coord(y(point)); + transform.transform(x_coord, y_coord); + x(point, x_coord); + y(point, y_coord); + return point; +} + +struct y_pt_move : gtl_yes {}; + +template +typename enable_if< + typename gtl_and< + y_pt_move, + typename is_mutable_point_concept< + typename geometry_concept::type + >::type + >::type, +PointType>::type& move(PointType& point, orientation_2d orient, + typename point_coordinate_type::type displacement) { + typedef typename point_coordinate_type::type Unit; + Unit coord = get(point, orient); + set(point, orient, coord + displacement); + return point; +} +} // polygon +} // boost + +#endif // BOOST_POLYGON_POINT_CONCEPT_HPP diff --git a/include/boost/polygon/point_data.hpp b/include/boost/polygon/point_data.hpp index 0ed55cf..8ec6c5b 100644 --- a/include/boost/polygon/point_data.hpp +++ b/include/boost/polygon/point_data.hpp @@ -1,104 +1,132 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library point_data.hpp header file - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ -#ifndef GTLPOINT_DATA_HPP -#define GTLPOINT_DATA_HPP +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_POLYGON_POINT_DATA_HPP +#define BOOST_POLYGON_POINT_DATA_HPP #include "isotropy.hpp" +#include "point_concept.hpp" -namespace boost { namespace polygon{ +namespace boost { +namespace polygon { - template - class point_data { - public: - typedef T coordinate_type; - inline point_data() -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - {} - inline point_data(coordinate_type x, coordinate_type y) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { - coords_[HORIZONTAL] = x; coords_[VERTICAL] = y; - } - inline point_data(const point_data& that) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { (*this) = that; } - template - point_data(const other& that) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { (*this) = that; } - inline point_data& operator=(const point_data& that) { - coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; return *this; - } - template - inline point_data(const T1& x, const T2& y) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { - coords_[HORIZONTAL] = (coordinate_type)x; - coords_[VERTICAL] = (coordinate_type)y; - } - template - inline point_data(const point_data& rvalue) -#ifndef BOOST_POLYGON_MSVC - :coords_() -#endif - { - coords_[HORIZONTAL] = (coordinate_type)(rvalue.x()); - coords_[VERTICAL] = (coordinate_type)(rvalue.y()); - } - template - inline point_data& operator=(const T2& rvalue); - inline bool operator==(const point_data& that) const { - return coords_[0] == that.coords_[0] && coords_[1] == that.coords_[1]; - } - inline bool operator!=(const point_data& that) const { - return !((*this) == that); - } - inline bool operator<(const point_data& that) const { - return coords_[0] < that.coords_[0] || - (coords_[0] == that.coords_[0] && coords_[1] < that.coords_[1]); - } - inline bool operator<=(const point_data& that) const { return !(that < *this); } - inline bool operator>(const point_data& that) const { return that < *this; } - inline bool operator>=(const point_data& that) const { return !((*this) < that); } - inline coordinate_type get(orientation_2d orient) const { - return coords_[orient.to_int()]; - } - inline void set(orientation_2d orient, coordinate_type value) { - coords_[orient.to_int()] = value; - } - inline coordinate_type x() const { - return coords_[HORIZONTAL]; - } - inline coordinate_type y() const { - return coords_[VERTICAL]; - } - inline point_data& x(coordinate_type value) { - coords_[HORIZONTAL] = value; - return *this; - } - inline point_data& y(coordinate_type value) { - coords_[VERTICAL] = value; - return *this; - } - private: - coordinate_type coords_[2]; - }; +template +class point_data { + public: + typedef T coordinate_type; -} -} + point_data() +#ifndef BOOST_POLYGON_MSVC + : coords_() #endif + {} + + point_data(coordinate_type x, coordinate_type y) { + coords_[HORIZONTAL] = x; + coords_[VERTICAL] = y; + } + + explicit point_data(const point_data& that) { + coords_[0] = that.coords_[0]; + coords_[1] = that.coords_[1]; + } + + point_data& operator=(const point_data& that) { + coords_[0] = that.coords_[0]; + coords_[1] = that.coords_[1]; + return *this; + } + + // TODO(asydorchuk): Deprecated. + template + explicit point_data(const PointType& that) { + *this = that; + } + + // TODO(asydorchuk): Deprecated. + template + point_data& operator=(const PointType& that) { + assign(*this, that); + return *this; + } + + // TODO(asydorchuk): Deprecated. + template + point_data(const point_data& that) { + coords_[HORIZONTAL] = (coordinate_type)that.x(); + coords_[VERTICAL] = (coordinate_type)that.y(); + } + + coordinate_type get(orientation_2d orient) const { + return coords_[orient.to_int()]; + } + + void set(orientation_2d orient, coordinate_type value) { + coords_[orient.to_int()] = value; + } + + coordinate_type x() const { + return coords_[HORIZONTAL]; + } + + point_data& x(coordinate_type value) { + coords_[HORIZONTAL] = value; + return *this; + } + + coordinate_type y() const { + return coords_[VERTICAL]; + } + + point_data& y(coordinate_type value) { + coords_[VERTICAL] = value; + return *this; + } + + bool operator==(const point_data& that) const { + return (coords_[0] == that.coords_[0]) && + (coords_[1] == that.coords_[1]); + } + + bool operator!=(const point_data& that) const { + return !(*this == that); + } + + bool operator<(const point_data& that) const { + return (coords_[0] < that.coords_[0]) || + ((coords_[0] == that.coords_[0]) && + (coords_[1] < that.coords_[1])); + } + + bool operator<=(const point_data& that) const { + return !(that < *this); + } + + bool operator>(const point_data& that) const { + return that < *this; + } + + bool operator>=(const point_data& that) const { + return !(*this < that); + } + + private: + coordinate_type coords_[2]; +}; + +template +struct geometry_concept< point_data > { + typedef point_concept type; +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_POINT_DATA_HPP diff --git a/include/boost/polygon/point_traits.hpp b/include/boost/polygon/point_traits.hpp index 6604d2c..5bc43d1 100644 --- a/include/boost/polygon/point_traits.hpp +++ b/include/boost/polygon/point_traits.hpp @@ -1,34 +1,48 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library point_traits.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_POINT_TRAITS_HPP #define BOOST_POLYGON_POINT_TRAITS_HPP #include "isotropy.hpp" -namespace boost { namespace polygon{ - template - struct point_traits { - typedef typename T::coordinate_type coordinate_type; +namespace boost { +namespace polygon { - static inline coordinate_type get(const T& point, orientation_2d orient) { - return point.get(orient); - } - }; +template +struct point_traits { + typedef PointType point_type; + typedef typename point_type::coordinate_type coordinate_type; - template - struct point_mutable_traits { - static inline void set(T& point, orientation_2d orient, typename point_traits::coordinate_type value) { - point.set(orient, value); - } - static inline T construct(typename point_traits::coordinate_type x_value, typename point_traits::coordinate_type y_value) { - return T(x_value, y_value); - } - }; -} -} -#endif + static coordinate_type get( + const point_type& point, orientation_2d orient) { + return point.get(orient); + } +}; + +template +struct point_mutable_traits { + typedef PointType point_type; + typedef typename point_type::coordinate_type coordinate_type; + + static void set( + point_type& point, orientation_2d orient, coordinate_type value) { + point.set(orient, value); + } + + static point_type construct(coordinate_type x, coordinate_type y) { + return point_type(x, y); + } +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_POINT_TRAITS_HPP diff --git a/include/boost/polygon/polygon.hpp b/include/boost/polygon/polygon.hpp index ddbc08d..90a7c1f 100644 --- a/include/boost/polygon/polygon.hpp +++ b/include/boost/polygon/polygon.hpp @@ -16,13 +16,7 @@ #include "point_traits.hpp" #include "point_concept.hpp" -//point 3d -#include "point_3d_data.hpp" -#include "point_3d_traits.hpp" -#include "point_3d_concept.hpp" - #include "transform.hpp" -#include "detail/transform_detail.hpp" //interval #include "interval_data.hpp" diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp index 042c3ca..abd85b4 100644 --- a/include/boost/polygon/polygon_90_set_data.hpp +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -9,7 +9,6 @@ #define BOOST_POLYGON_POLYGON_90_SET_DATA_HPP #include "isotropy.hpp" #include "point_concept.hpp" -#include "point_3d_concept.hpp" #include "transform.hpp" #include "interval_concept.hpp" #include "rectangle_concept.hpp" diff --git a/include/boost/polygon/polygon_90_set_traits.hpp b/include/boost/polygon/polygon_90_set_traits.hpp index debcf57..c1312e8 100644 --- a/include/boost/polygon/polygon_90_set_traits.hpp +++ b/include/boost/polygon/polygon_90_set_traits.hpp @@ -20,8 +20,6 @@ namespace boost { namespace polygon{ template struct traits_by_concept { typedef point_traits type; }; template - struct traits_by_concept { typedef point_3d_traits type; }; - template struct traits_by_concept { typedef rectangle_traits type; }; template struct traits_by_concept { typedef segment_traits type; }; diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index 5595adf..de4de80 100644 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1136,42 +1136,36 @@ namespace boost { namespace polygon{ typedef typename polygon_traits::coordinate_type coordinate_type; typedef typename polygon_traits::iterator_type iterator; typedef typename std::iterator_traits::value_type point_type; - iterator iter, iter_end; - iter_end = end_points(polygon); - iter = begin_points(polygon); - point_type prev_pt = *iter; - std::size_t num = size(polygon); - std::size_t counts[2] = {0, 0}; - for(std::size_t i = 0; i < num; ++i) { - if(i == num-1) iter = begin_points(polygon); - else ++iter; - point_type current_pt = *iter; - if(x(current_pt) == - x(prev_pt)) { - unsigned int index = x(current_pt) > - x(point); - std::size_t increment = 0; - interval_data ivl(y(current_pt), - y(prev_pt)); - if(contains(ivl, y(point), true)) { - if(x(current_pt) == - x(point)) return consider_touch; - ++increment; - if(y(current_pt) != - y(point) && - y(prev_pt) != - y(point)) { - ++increment; + coordinate_type point_x = x(point); + coordinate_type point_y = y(point); + bool inside = false; + for (iterator iter = begin_points(polygon); iter != end_points(polygon);) { + point_type curr_point = *iter; + ++iter; + point_type next_point = (iter == end_points(polygon)) ? *begin_points(polygon) : *iter; + if (x(curr_point) == x(next_point)) { + if (x(curr_point) > point_x) { + continue; + } + coordinate_type min_y = (std::min)(y(curr_point), y(next_point)); + coordinate_type max_y = (std::max)(y(curr_point), y(next_point)); + if (point_y > min_y && point_y < max_y) { + if (x(curr_point) == point_x) { + return consider_touch; + } + inside ^= true; + } + } else { + coordinate_type min_x = (std::min)(x(curr_point), x(next_point)); + coordinate_type max_x = (std::max)(x(curr_point), x(next_point)); + if (point_x >= min_x && point_x <= max_x) { + if (y(curr_point) == point_y) { + return consider_touch; } - counts[index] += increment; } } - prev_pt = current_pt; } - //odd count implies boundary condition - if(counts[0] % 2 || counts[1] % 2) return consider_touch; - //an odd number of edges to the left implies interior pt - return counts[winding(polygon) == COUNTERCLOCKWISE ? 0 : 1] % 4 != 0; + return inside; } //TODO: refactor to expose as user APIs diff --git a/include/boost/polygon/segment_concept.hpp b/include/boost/polygon/segment_concept.hpp index 8d8aaa1..2f41c1b 100644 --- a/include/boost/polygon/segment_concept.hpp +++ b/include/boost/polygon/segment_concept.hpp @@ -1,23 +1,27 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library segment_concept.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_SEGMENT_CONCEPT_HPP #define BOOST_POLYGON_SEGMENT_CONCEPT_HPP #include "isotropy.hpp" -#include "segment_data.hpp" #include "segment_traits.hpp" #include "rectangle_concept.hpp" namespace boost { namespace polygon { + struct segment_concept {}; -template +template struct is_segment_concept { typedef gtl_no type; }; @@ -27,7 +31,7 @@ struct is_segment_concept { typedef gtl_yes type; }; -template +template struct is_mutable_segment_concept { typedef gtl_no type; }; @@ -37,64 +41,64 @@ struct is_mutable_segment_concept { typedef gtl_yes type; }; -template +template struct segment_distance_type_by_concept { typedef void type; }; -template -struct segment_distance_type_by_concept { +template +struct segment_distance_type_by_concept { typedef typename coordinate_traits< - typename segment_traits::coordinate_type + typename segment_traits::coordinate_type >::coordinate_distance type; }; -template +template struct segment_distance_type { typedef typename segment_distance_type_by_concept< - Segment, + GeometryType, typename is_segment_concept< - typename geometry_concept::type + typename geometry_concept::type >::type >::type type; }; -template +template struct segment_point_type_by_concept { typedef void type; }; -template -struct segment_point_type_by_concept { - typedef typename segment_traits::point_type type; +template +struct segment_point_type_by_concept { + typedef typename segment_traits::point_type type; }; -template +template struct segment_point_type { typedef typename segment_point_type_by_concept< - Segment, + GeometryType, typename is_segment_concept< - typename geometry_concept::type + typename geometry_concept::type >::type >::type type; }; -template +template struct segment_coordinate_type_by_concept { typedef void type; }; -template -struct segment_coordinate_type_by_concept { - typedef typename segment_traits::coordinate_type type; +template +struct segment_coordinate_type_by_concept { + typedef typename segment_traits::coordinate_type type; }; -template +template struct segment_coordinate_type { typedef typename segment_coordinate_type_by_concept< - Segment, + GeometryType, typename is_segment_concept< - typename geometry_concept::type + typename geometry_concept::type >::type >::type type; }; @@ -109,8 +113,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_point_type::type ->::type +typename segment_point_type::type>::type get(const Segment& segment, direction_1d dir) { return segment_traits::get(segment, dir); } @@ -128,9 +131,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - void ->::type -set(Segment& segment, direction_1d dir, const Point& point) { +void>::type set(Segment& segment, direction_1d dir, const Point& point) { segment_mutable_traits::set(segment, dir, point); } @@ -150,9 +151,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type -construct(const Point1& low, const Point2& high) { +Segment>::type construct(const Point1& low, const Point2& high) { return segment_mutable_traits::construct(low, high); } @@ -169,9 +168,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment1 ->::type -copy_construct(const Segment2& segment) { +Segment1>::type copy_construct(const Segment2& segment) { return construct(get(segment, LOW), get(segment, HIGH)); } @@ -188,9 +185,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment1 ->::type & -assign(Segment1& segment1, const Segment2& segment2) { +Segment1>::type& assign(Segment1& segment1, const Segment2& segment2) { return segment1 = copy_construct(segment2); } @@ -207,9 +202,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -equivalence(const Segment1& segment1, const Segment2& segment2) { +bool>::type equivalence(const Segment1& segment1, const Segment2& segment2) { return get(segment1, LOW) == get(segment2, LOW) && get(segment1, HIGH) == get(segment2, HIGH); } @@ -224,9 +217,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_point_type::type ->::type -low(const Segment& segment) { +typename segment_point_type::type>::type low(const Segment& segment) { return get(segment, LOW); } @@ -240,9 +231,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_point_type::type ->::type -high(const Segment& segment) { +typename segment_point_type::type>::type high(const Segment& segment) { return get(segment, HIGH); } @@ -256,8 +245,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_point_type::type ->::type +typename segment_point_type::type>::type center(const Segment& segment) { return construct::type>( (x(high(segment)) + x(low(segment)))/2, @@ -277,9 +265,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - void ->::type -low(Segment& segment, const Point& point) { +void>::type low(Segment& segment, const Point& point) { set(segment, LOW, point); } @@ -296,9 +282,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - void ->::type -high(Segment& segment, const Point& point) { +void>::type high(Segment& segment, const Point& point) { set(segment, HIGH, point); } @@ -316,9 +300,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - int ->::type -orientation(const Segment1& segment1, const Segment2& segment2) { +int>::type orientation(const Segment1& segment1, const Segment2& segment2) { typedef typename coordinate_traits< typename segment_traits::coordinate_type >::manhattan_area_type int_x2; @@ -360,9 +342,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - int ->::type -orientation(const Segment& segment, const Point& point) { +int>::type orientation(const Segment& segment, const Point& point) { Segment segment2 = construct(high(segment), point); return orientation(segment, segment2); } @@ -380,11 +360,8 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -contains(const Segment& segment, - const Point& point, - bool consider_touch = true ) { +bool>::type contains(const Segment& segment, + const Point& point, bool consider_touch = true ) { if (orientation(segment, point)) return false; rectangle_data::type> rect; @@ -411,11 +388,8 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -contains(const Segment1& segment1, - const Segment2& segment2, - bool consider_touch = true) { +bool>::type contains(const Segment1& segment1, + const Segment2& segment2, bool consider_touch = true) { return contains(segment1, get(segment2, LOW), consider_touch) && contains(segment1, get(segment2, HIGH), consider_touch); } @@ -430,8 +404,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_distance_type::type ->::type +typename segment_distance_type::type>::type length(const Segment& segment) { return euclidean_distance(low(segment), high(segment)); } @@ -446,12 +419,10 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -scale_up(Segment& segment, - typename coordinate_traits< - typename segment_coordinate_type::type - >::unsigned_area_type factor) { +Segment>::type& scale_up(Segment& segment, + typename coordinate_traits< + typename segment_coordinate_type::type + >::unsigned_area_type factor) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, scale_up(l, factor)); @@ -469,12 +440,10 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -scale_down(Segment& segment, - typename coordinate_traits< - typename segment_coordinate_type::type - >::unsigned_area_type factor) { +Segment>::type& scale_down(Segment& segment, + typename coordinate_traits< + typename segment_coordinate_type::type + >::unsigned_area_type factor) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, scale_down(l, factor)); @@ -492,9 +461,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -scale(Segment& segment, const Scale& sc) { +Segment>::type& scale(Segment& segment, const Scale& sc) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, scale(l, sc)); @@ -512,9 +479,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -transform(Segment& segment, const Transform& tr) { +Segment>::type& transform(Segment& segment, const Transform& tr) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, transform(l, tr)); @@ -532,10 +497,8 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -move(Segment& segment, orientation_2d orient, - typename segment_coordinate_type::type displacement) { +Segment>::type& move(Segment& segment, orientation_2d orient, + typename segment_coordinate_type::type displacement) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, move(l, orient, displacement)); @@ -556,9 +519,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -convolve(Segment& segment, const Point& point) { +Segment>::type& convolve(Segment& segment, const Point& point) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, convolve(l, point)); @@ -579,9 +540,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - Segment ->::type & -deconvolve(Segment& segment, const Point& point) { +Segment>::type& deconvolve(Segment& segment, const Point& point) { typename segment_point_type::type l = low(segment); typename segment_point_type::type h = high(segment); low(segment, deconvolve(l, point)); @@ -602,9 +561,8 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -abuts(const Segment1& segment1, const Segment2& segment2, direction_1d dir) { +bool>::type abuts(const Segment1& segment1, + const Segment2& segment2, direction_1d dir) { return dir.to_int() ? equivalence(low(segment2) , high(segment1)) : equivalence(low(segment1) , high(segment2)); } @@ -622,9 +580,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -abuts(const Segment1& segment1, const Segment2& segment2) { +bool>::type abuts(const Segment1& segment1, const Segment2& segment2) { return abuts(segment1, segment2, HIGH) || abuts(segment1, segment2, LOW); } @@ -641,10 +597,9 @@ typename enable_if< typename geometry_concept::type >::type >::type, - bool ->::type -intersects(const Segment1& segment1, const Segment2& segment2, - bool consider_touch = true) { +bool +>::type intersects(const Segment1& segment1, const Segment2& segment2, + bool consider_touch = true) { rectangle_data::type> rect1, rect2; set_points(rect1, low(segment1), high(segment1)); set_points(rect2, low(segment2), high(segment2)); @@ -680,8 +635,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_distance_type::type ->::type +typename segment_distance_type::type>::type euclidean_distance(const Segment& segment, const Point& point) { typedef typename segment_distance_type::type Unit; Unit x1 = x(low(segment)); @@ -721,8 +675,7 @@ typename enable_if< typename geometry_concept::type >::type >::type, - typename segment_distance_type::type ->::type +typename segment_distance_type::type>::type euclidean_distance(const Segment1& segment1, const Segment2& segment2) { if (intersects(segment1, segment2)) return 0.0; @@ -737,18 +690,7 @@ euclidean_distance(const Segment1& segment1, const Segment2& segment2) { result3 = result4; return (result1 < result3) ? result1 : result3; } +} // polygon +} // boost -template -template -segment_data& segment_data::operator=(const Segment& rvalue) { - assign(*this, rvalue); - return *this; -} - -template -struct geometry_concept > { - typedef segment_concept type; -}; -} -} -#endif +#endif // BOOST_POLYGON_SEGMENT_CONCEPT_HPP diff --git a/include/boost/polygon/segment_data.hpp b/include/boost/polygon/segment_data.hpp index 7d1fa05..43dbcc8 100644 --- a/include/boost/polygon/segment_data.hpp +++ b/include/boost/polygon/segment_data.hpp @@ -1,108 +1,115 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library segment_data.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_SEGMENT_DATA_HPP #define BOOST_POLYGON_SEGMENT_DATA_HPP #include "isotropy.hpp" +#include "segment_concept.hpp" namespace boost { namespace polygon { + template class segment_data { public: typedef T coordinate_type; typedef point_data point_type; - inline segment_data() + segment_data() #ifndef BOOST_POLYGON_MSVC - :points_() + : points_() #endif {} - inline segment_data(const point_type& low, const point_type& high) -#ifndef BOOST_POLYGON_MSVC - :points_() -#endif - { + segment_data(const point_type& low, const point_type& high) { points_[LOW] = low; points_[HIGH] = high; } - inline segment_data(const segment_data& that) -#ifndef BOOST_POLYGON_MSVC - :points_() -#endif - { - (*this) = that; + segment_data(const segment_data& that) { + points_[0] = that.points_[0]; + points_[1] = that.points_[1]; } - inline segment_data& operator=(const segment_data& that) { + segment_data& operator=(const segment_data& that) { points_[0] = that.points_[0]; points_[1] = that.points_[1]; return *this; } - template - inline segment_data& operator=(const Segment& that); - - inline point_type get(direction_1d dir) const { + point_type get(direction_1d dir) const { return points_[dir.to_int()]; } - inline void set(direction_1d dir, const point_type& point) { + void set(direction_1d dir, const point_type& point) { points_[dir.to_int()] = point; } - inline point_type low() const { return points_[0]; } + point_type low() const { + return points_[LOW]; + } - inline segment_data& low(const point_type& point) { - points_[0] = point; + segment_data& low(const point_type& point) { + points_[LOW] = point; return *this; } - inline point_type high() const {return points_[1]; } + point_type high() const { + return points_[HIGH]; + } - inline segment_data& high(const point_type& point) { - points_[1] = point; + segment_data& high(const point_type& point) { + points_[HIGH] = point; return *this; } - inline bool operator==(const segment_data& that) const { - return low() == that.low() && high() == that.high(); + bool operator==(const segment_data& that) const { + return (points_[0] == that.points_[0]) && + (points_[1] == that.points_[1]); } - inline bool operator!=(const segment_data& that) const { - return low() != that.low() || high() != that.high(); + bool operator!=(const segment_data& that) const { + return (points_[0] != that.points_[0]) || + (points_[1] != that.points_[1]); } - inline bool operator<(const segment_data& that) const { - if (points_[0] < that.points_[0]) - return true; - if (points_[0] > that.points_[0]) - return false; + bool operator<(const segment_data& that) const { + if (points_[0] != that.points_[0]) { + points_[0] < that.points_[0]; + } return points_[1] < that.points_[1]; } - inline bool operator<=(const segment_data& that) const { + bool operator<=(const segment_data& that) const { return !(that < *this); } - inline bool operator>(const segment_data& that) const { + bool operator>(const segment_data& that) const { return that < *this; } - inline bool operator>=(const segment_data& that) const { + bool operator>=(const segment_data& that) const { return !((*this) < that); } private: point_type points_[2]; }; -} -} -#endif + +template +struct geometry_concept > { + typedef segment_concept type; +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_SEGMENT_DATA_HPP diff --git a/include/boost/polygon/segment_traits.hpp b/include/boost/polygon/segment_traits.hpp index 956c0d2..cb092bd 100644 --- a/include/boost/polygon/segment_traits.hpp +++ b/include/boost/polygon/segment_traits.hpp @@ -1,38 +1,50 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library segment_traits.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_SEGMENT_TRAITS_HPP #define BOOST_POLYGON_SEGMENT_TRAITS_HPP + +#include "isotropy.hpp" + namespace boost { namespace polygon { - template - struct segment_traits { - typedef typename Segment::coordinate_type coordinate_type; - typedef typename Segment::point_type point_type; - static inline point_type get(const Segment& segment, direction_1d dir) { - return segment.get(dir); - } - }; +template +struct segment_traits { + typedef Segment segment_type; + typedef typename segment_type::point_type point_type; + typedef typename segment_type::coordinate_type coordinate_type; - template - struct segment_mutable_traits { - typedef typename segment_traits::point_type point_type; + static point_type get( + const segment_type& segment, direction_1d dir) { + return segment.get(dir); + } +}; - static inline void set( - Segment& segment, direction_1d dir, const point_type& point) { - segment.set(dir, point); - } +template +struct segment_mutable_traits { + typedef Segment segment_type; + typedef typename segment_type::point_type point_type; + typedef typename segment_type::coordinate_type coordinate_type; - static inline Segment construct( - const point_type& low, const point_type& high) { - return Segment(low, high); - } - }; -} -} -#endif + static void set( + segment_type& segment, direction_1d dir, const point_type& point) { + segment.set(dir, point); + } + + static segment_type construct(const point_type& low, const point_type& high) { + return segment_type(low, high); + } +}; +} // polygon +} // boost + +#endif // BOOST_POLYGON_SEGMENT_TRAITS_HPP diff --git a/include/boost/polygon/transform.hpp b/include/boost/polygon/transform.hpp index ed75ddd..2612525 100644 --- a/include/boost/polygon/transform.hpp +++ b/include/boost/polygon/transform.hpp @@ -1,195 +1,58 @@ -/* - Copyright 2008 Intel Corporation +// Boost.Polygon library point_data.hpp header file + +// Copyright (c) Intel Corporation 2008. +// Copyright (c) 2008-2012 Simonson Lucanus. +// Copyright (c) 2012-2012 Andrii Sydorchuk. + +// See http://www.boost.org for updates, documentation, and revision history. +// Use, modification and distribution is subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) - Use, modification and distribution are subject to the Boost Software License, - Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt). -*/ #ifndef BOOST_POLYGON_TRANSFORM_HPP #define BOOST_POLYGON_TRANSFORM_HPP + #include "isotropy.hpp" -#include "point_3d_concept.hpp" -namespace boost { namespace polygon{ -// Transformation of Coordinate Systems + +namespace boost { +namespace polygon { +// Transformation of Coordinate System. // Enum meaning: -// Select which direction_3d to change the positive direction of each +// Select which direction_2d to change the positive direction of each // axis in the old coordinate system to map it to the new coordiante system. -// The first direction_3d listed for each enum is the direction to map the +// The first direction_2d listed for each enum is the direction to map the // positive horizontal direction to. -// The second direction_3d listed for each enum is the direction to map the +// The second direction_2d listed for each enum is the direction to map the // positive vertical direction to. -// The third direction_3d listed for each enum is the direction to map the -// positive proximal direction to. // The zero position bit (LSB) indicates whether the horizontal axis flips // when transformed. // The 1st postion bit indicates whether the vertical axis flips when // transformed. // The 2nd position bit indicates whether the horizontal and vertical axis // swap positions when transformed. -// Note that the first eight values are the complete set of 2D transforms. -// The 3rd position bit indicates whether the proximal axis flips when -// transformed. -// The 4th position bit indicates whether the proximal and horizontal axis are -// swapped when transformed. It changes the meaning of the 2nd position bit -// to mean that the horizontal and vertical axis are swapped in their new -// positions, naturally. -// The 5th position bit (MSB) indicates whether the proximal and vertical axis -// are swapped when transformed. It is mutually exclusive with the 4th postion -// bit, making the maximum legal value 48 (decimal). It similarly changes the -// meaning of the 2nd position bit to mean that the horizontal and vertical are -// swapped in their new positions. // Enum Values: -// 000000 EAST NORTH UP -// 000001 WEST NORTH UP -// 000010 EAST SOUTH UP -// 000011 WEST SOUTH UP -// 000100 NORTH EAST UP -// 000101 SOUTH EAST UP -// 000110 NORTH WEST UP -// 000111 SOUTH WEST UP -// 001000 EAST NORTH DOWN -// 001001 WEST NORTH DOWN -// 001010 EAST SOUTH DOWN -// 001011 WEST SOUTH DOWN -// 001100 NORTH EAST DOWN -// 001101 SOUTH EAST DOWN -// 001110 NORTH WEST DOWN -// 001111 SOUTH WEST DOWN -// 010000 UP NORTH EAST -// 010001 DOWN NORTH EAST -// 010010 UP SOUTH EAST -// 010011 DOWN SOUTH EAST -// 010100 NORTH UP EAST -// 010101 SOUTH UP EAST -// 010110 NORTH DOWN EAST -// 010111 SOUTH DOWN EAST -// 011000 UP NORTH WEST -// 011001 DOWN NORTH WEST -// 011010 UP SOUTH WEST -// 011011 DOWN SOUTH WEST -// 011100 NORTH UP WEST -// 011101 SOUTH UP WEST -// 011110 NORTH DOWN WEST -// 011111 SOUTH DOWN WEST -// 100000 EAST UP NORTH -// 100001 WEST UP NORTH -// 100010 EAST DOWN NORTH -// 100011 WEST DOWN NORTH -// 100100 UP EAST NORTH -// 100101 DOWN EAST NORTH -// 100110 UP WEST NORTH -// 100111 DOWN WEST NORTH -// 101000 EAST UP SOUTH -// 101001 WEST UP SOUTH -// 101010 EAST DOWN SOUTH -// 101011 WEST DOWN SOUTH -// 101100 UP EAST SOUTH -// 101101 DOWN EAST SOUTH -// 101110 UP WEST SOUTH -// 101111 DOWN WEST SOUTH +// 000 EAST NORTH +// 001 WEST NORTH +// 010 EAST SOUTH +// 011 WEST SOUTH +// 100 NORTH EAST +// 101 SOUTH EAST +// 110 NORTH WEST +// 111 SOUTH WEST class axis_transformation { -public: - // Enum Names and values - // NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, - // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, - // WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, - // ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, - // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, - // NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, - // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, - // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, - // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, - // END_2D_TRANSFORM = 7, - // END = 8, EAST_NORTH_DOWN = 8, - // WND = 9, WEST_NORTH_DOWN = 9, - // ESD = 10, EAST_SOUTH_DOWN = 10, - // WSD = 11, WEST_SOUTH_DOWN = 11, - // NED = 12, NORTH_EAST_DOWN = 12, - // SED = 13, SOUTH_EAST_DOWN = 13, - // NWD = 14, NORTH_WEST_DOWN = 14, - // SWD = 15, SOUTH_WEST_DOWN = 15, - // UNE = 16, UP_NORTH_EAST = 16, - // DNE = 17, DOWN_NORTH_EAST = 17, - // USE = 18, UP_SOUTH_EAST = 18, - // DSE = 19, DOWN_SOUTH_EAST = 19, - // NUE = 20, NORTH_UP_EAST = 20, - // SUE = 21, SOUTH_UP_EAST = 21, - // NDE = 22, NORTH_DOWN_EAST = 22, - // SDE = 23, SOUTH_DOWN_EAST = 23, - // UNW = 24, UP_NORTH_WEST = 24, - // DNW = 25, DOWN_NORTH_WEST = 25, - // USW = 26, UP_SOUTH_WEST = 26, - // DSW = 27, DOWN_SOUTH_WEST = 27, - // NUW = 28, NORTH_UP_WEST = 28, - // SUW = 29, SOUTH_UP_WEST = 29, - // NDW = 30, NORTH_DOWN_WEST = 30, - // SDW = 31, SOUTH_DOWN_WEST = 31, - // EUN = 32, EAST_UP_NORTH = 32, - // WUN = 33, WEST_UP_NORTH = 33, - // EDN = 34, EAST_DOWN_NORTH = 34, - // WDN = 35, WEST_DOWN_NORTH = 35, - // UEN = 36, UP_EAST_NORTH = 36, - // DEN = 37, DOWN_EAST_NORTH = 37, - // UWN = 38, UP_WEST_NORTH = 38, - // DWN = 39, DOWN_WEST_NORTH = 39, - // EUS = 40, EAST_UP_SOUTH = 40, - // WUS = 41, WEST_UP_SOUTH = 41, - // EDS = 42, EAST_DOWN_SOUTH = 42, - // WDS = 43, WEST_DOWN_SOUTH = 43, - // UES = 44, UP_EAST_SOUTH = 44, - // DES = 45, DOWN_EAST_SOUTH = 45, - // UWS = 46, UP_WEST_SOUTH = 46, - // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + public: enum ATR { - NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0, - ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0, - WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1, - ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, - WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, - NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4, - SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, - NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, - SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_2D_TRANSFORM = 7, - END = 8, EAST_NORTH_DOWN = 8, FLIP_Z = 8, - WND = 9, WEST_NORTH_DOWN = 9, - ESD = 10, EAST_SOUTH_DOWN = 10, - WSD = 11, WEST_SOUTH_DOWN = 11, - NED = 12, NORTH_EAST_DOWN = 12, - SED = 13, SOUTH_EAST_DOWN = 13, - NWD = 14, NORTH_WEST_DOWN = 14, - SWD = 15, SOUTH_WEST_DOWN = 15, - UNE = 16, UP_NORTH_EAST = 16, - DNE = 17, DOWN_NORTH_EAST = 17, - USE = 18, UP_SOUTH_EAST = 18, - DSE = 19, DOWN_SOUTH_EAST = 19, - NUE = 20, NORTH_UP_EAST = 20, - SUE = 21, SOUTH_UP_EAST = 21, - NDE = 22, NORTH_DOWN_EAST = 22, - SDE = 23, SOUTH_DOWN_EAST = 23, - UNW = 24, UP_NORTH_WEST = 24, - DNW = 25, DOWN_NORTH_WEST = 25, - USW = 26, UP_SOUTH_WEST = 26, - DSW = 27, DOWN_SOUTH_WEST = 27, - NUW = 28, NORTH_UP_WEST = 28, - SUW = 29, SOUTH_UP_WEST = 29, - NDW = 30, NORTH_DOWN_WEST = 30, - SDW = 31, SOUTH_DOWN_WEST = 31, - EUN = 32, EAST_UP_NORTH = 32, - WUN = 33, WEST_UP_NORTH = 33, - EDN = 34, EAST_DOWN_NORTH = 34, - WDN = 35, WEST_DOWN_NORTH = 35, - UEN = 36, UP_EAST_NORTH = 36, - DEN = 37, DOWN_EAST_NORTH = 37, - UWN = 38, UP_WEST_NORTH = 38, - DWN = 39, DOWN_WEST_NORTH = 39, - EUS = 40, EAST_UP_SOUTH = 40, - WUS = 41, WEST_UP_SOUTH = 41, - EDS = 42, EAST_DOWN_SOUTH = 42, - WDS = 43, WEST_DOWN_SOUTH = 43, - UES = 44, UP_EAST_SOUTH = 44, - DES = 45, DOWN_EAST_SOUTH = 45, - UWS = 46, UP_WEST_SOUTH = 46, - DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47 + NULL_TRANSFORM = 0, + BEGIN_TRANSFORM = 0, + EN = 0, EAST_NORTH = 0, + WN = 1, WEST_NORTH = 1, FLIP_X = 1, + ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, + NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, + NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, + SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, + END_TRANSFORM = 7 }; // Individual axis enum values indicate which axis an implicit individual @@ -205,54 +68,106 @@ public: // NX: map to negative x axis // PY: map to positive y axis // NY: map to negative y axis - // PZ: map to positive z axis - // NZ: map to negative z axis enum INDIVIDUAL_AXIS { PX = 0, NX = 1, PY = 2, - NY = 3, - PZ = 4, - NZ = 5 + NY = 3 }; - inline axis_transformation() : atr_(NULL_TRANSFORM) {} - inline axis_transformation(ATR atr) : atr_(atr) {} - inline axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} - explicit axis_transformation(const orientation_3d& orient); - explicit axis_transformation(const direction_3d& dir); - explicit axis_transformation(const orientation_2d& orient); - explicit axis_transformation(const direction_2d& dir); + axis_transformation() : atr_(NULL_TRANSFORM) {} + explicit axis_transformation(ATR atr) : atr_(atr) {} + axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} + + explicit axis_transformation(const orientation_2d& orient) { + const ATR tmp[2] = { + NORTH_EAST, // sort x, then y + EAST_NORTH // sort y, then x + }; + atr_ = tmp[orient.to_int()]; + } + + explicit axis_transformation(const direction_2d& dir) { + const ATR tmp[4] = { + SOUTH_EAST, // sort x, then y + NORTH_EAST, // sort x, then y + EAST_SOUTH, // sort y, then x + EAST_NORTH // sort y, then x + }; + atr_ = tmp[dir.to_int()]; + } // assignment operator - axis_transformation& operator=(const axis_transformation& a); + axis_transformation& operator=(const axis_transformation& a) { + atr_ = a.atr_; + return *this; + } // assignment operator - axis_transformation& operator=(const ATR& atr); + axis_transformation& operator=(const ATR& atr) { + atr_ = atr; + return *this; + } // equivalence operator - bool operator==(const axis_transformation& a) const; + bool operator==(const axis_transformation& a) const { + return atr_ == a.atr_; + } // inequivalence operator - bool operator!=(const axis_transformation& a) const; + bool operator!=(const axis_transformation& a) const { + return !(*this == a); + } // ordering - bool operator<(const axis_transformation& a) const; - - // concatenation operator - axis_transformation operator+(const axis_transformation& a) const; + bool operator<(const axis_transformation& a) const { + return atr_ < a.atr_; + } // concatenate this with that - axis_transformation& operator+=(const axis_transformation& a); + axis_transformation& operator+=(const axis_transformation& a) { + bool abit2 = (a.atr_ & 4) != 0; + bool abit1 = (a.atr_ & 2) != 0; + bool abit0 = (a.atr_ & 1) != 0; + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + int indexes[2][2] = { + { (int)bit2, (int)(!bit2) }, + { (int)abit2, (int)(!abit2) } + }; + int zero_bits[2][2] = { + {bit0, bit1}, {abit0, abit1} + }; + int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; + int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; + indexes[0][0] = indexes[1][indexes[0][0]]; + indexes[0][1] = indexes[1][indexes[0][1]]; + int nbit2 = indexes[0][0] & 1; // swap xy + atr_ = (ATR)((nbit2 << 2) + (nbit1 << 1) + nbit0); + return *this; + } + + // concatenation operator + axis_transformation operator+(const axis_transformation& a) const { + axis_transformation retval(*this); + return retval+=a; + } // populate_axis_array writes the three INDIVIDUAL_AXIS values that the // ATR enum value of 'this' represent into axis_array - void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const; + void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { + bool bit2 = (atr_ & 4) != 0; + bool bit1 = (atr_ & 2) != 0; + bool bit0 = (atr_ & 1) != 0; + axis_array[1] = (INDIVIDUAL_AXIS)(((int)(!bit2) << 1) + bit1); + axis_array[0] = (INDIVIDUAL_AXIS)(((int)(bit2) << 1) + bit0); + } // it is recommended that the directions stored in an array // in the caller code for easier isotropic access by orientation value - inline void get_directions(direction_2d& horizontal_dir, - direction_2d& vertical_dir) const { + void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { bool bit2 = (atr_ & 4) != 0; bool bit1 = (atr_ & 2) != 0; bool bit0 = (atr_ & 1) != 0; @@ -260,241 +175,292 @@ public: horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); } - // it is recommended that the directions stored in an array - // in the caller code for easier isotropic access by orientation value - inline void get_directions(direction_3d& horizontal_dir, - direction_3d& vertical_dir, - direction_3d& proximal_dir) const { - bool bit5 = (atr_ & 32) != 0; - bool bit4 = (atr_ & 16) != 0; - bool bit3 = (atr_ & 8) != 0; - bool bit2 = (atr_ & 4) != 0; - bool bit1 = (atr_ & 2) != 0; - bool bit0 = (atr_ & 1) != 0; - proximal_dir = direction_3d((direction_2d_enum)((((int)(!bit4 & !bit5)) << 2) + - ((int)(bit5) << 1) + - !bit3)); - vertical_dir = direction_3d((direction_2d_enum)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+ - ((int)(!bit5 & !bit2) << 1) + - !bit1)); - horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) | - (bit4 & !bit2))) << 2) + - ((int)(bit2 & !bit5) << 1) + - !bit0)); - } - // combine_axis_arrays concatenates this_array and that_array overwriting // the result into this_array - static void combine_axis_arrays (INDIVIDUAL_AXIS this_array[], - const INDIVIDUAL_AXIS that_array[]); + static void combine_axis_arrays(INDIVIDUAL_AXIS this_array[], + const INDIVIDUAL_AXIS that_array[]) { + int indexes[2] = { this_array[0] >> 1, this_array[1] >> 1 }; + int zero_bits[2][2] = { + { this_array[0] & 1, this_array[1] & 1 }, + { that_array[0] & 1, that_array[1] & 1 } + }; + this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | + ((int)zero_bits[0][0] ^ + (int)zero_bits[1][indexes[0]])); + this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | + ((int)zero_bits[0][1] ^ + (int)zero_bits[1][indexes[1]])); + } // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values // to the ATR enum value and sets 'this' to that value - void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]); + void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { + int bit2 = ((int)this_array[0] & 2) != 0; // swap xy + int bit1 = ((int)this_array[1] & 1); + int bit0 = ((int)this_array[0] & 1); + atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); + } // behavior is deterministic but undefined in the case where illegal // combinations of directions are passed in. axis_transformation& set_directions(const direction_2d& horizontal_dir, - const direction_2d& vertical_dir); - // behavior is deterministic but undefined in the case where illegal - // combinations of directions are passed in. - axis_transformation& set_directions(const direction_3d& horizontal_dir, - const direction_3d& vertical_dir, - const direction_3d& proximal_dir); - - // transform the two coordinates by reference using the 2D portion of this - template - void transform(coordinate_type& x, coordinate_type& y) const; + const direction_2d& vertical_dir) { + int bit2 = (static_cast(horizontal_dir).to_int()) != 0; + int bit1 = !(vertical_dir.to_int() & 1); + int bit0 = !(horizontal_dir.to_int() & 1); + atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); + return *this; + } // transform the three coordinates by reference template - void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; - - // invert the 2D portion of this - axis_transformation& invert_2d(); - - // get the inverse of the 2D portion of this - axis_transformation inverse_2d() const; + void transform(coordinate_type& x, coordinate_type& y) const { + int bit2 = (atr_ & 4) != 0; + int bit1 = (atr_ & 2) != 0; + int bit0 = (atr_ & 1) != 0; + x *= -((bit0 << 1) - 1); + y *= -((bit1 << 1) - 1); + predicated_swap(bit2 != 0, x, y); + } // invert this axis_transformation - axis_transformation& invert(); + axis_transformation& invert() { + int bit2 = ((atr_ & 4) != 0); + int bit1 = ((atr_ & 2) != 0); + int bit0 = ((atr_ & 1) != 0); + // swap bit 0 and bit 1 if bit2 is 1 + predicated_swap(bit2 != 0, bit0, bit1); + bit1 = bit1 << 1; + atr_ = (ATR)(atr_ & (32+16+8+4)); // mask away bit0 and bit1 + atr_ = (ATR)(atr_ | bit0 | bit1); + return *this; + } // get the inverse axis_transformation of this - axis_transformation inverse() const; + axis_transformation inverse() const { + axis_transformation retval(*this); + return retval.invert(); + } - //friend std::ostream& operator<< (std::ostream& o, const axis_transformation& r); - //friend std::istream& operator>> (std::istream& i, axis_transformation& r); - -private: + private: ATR atr_; }; - -// Scaling object to be used to store the scale factor for each axis - +// Scaling object to be used to store the scale factor for each axis. // For use by the transformation object, in that context the scale factor // is the amount that each axis scales by when transformed. -// If the horizontal value of the Scale is 10 that means the horizontal -// axis of the input is multiplied by 10 when the transformation is applied. template class anisotropic_scale_factor { -public: - inline anisotropic_scale_factor() -#ifndef BOOST_POLYGON_MSVC - : scale_() -#endif - { + public: + anisotropic_scale_factor() { scale_[0] = 1; scale_[1] = 1; - scale_[2] = 1; } - inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale) -#ifndef BOOST_POLYGON_MSVC - : scale_() -#endif - { + anisotropic_scale_factor(scale_factor_type xscale, + scale_factor_type yscale) { scale_[0] = xscale; scale_[1] = yscale; - scale_[2] = 1; - } - inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale) -#ifndef BOOST_POLYGON_MSVC - : scale_() -#endif - { - scale_[0] = xscale; - scale_[1] = yscale; - scale_[2] = zscale; } // get a component of the anisotropic_scale_factor by orientation - scale_factor_type get(orientation_3d orient) const; - scale_factor_type get(orientation_2d orient) const { return get(orientation_3d(orient)); } + scale_factor_type get(orientation_2d orient) const { + return scale_[orient.to_int()]; + } // set a component of the anisotropic_scale_factor by orientation - void set(orientation_3d orient, scale_factor_type value); - void set(orientation_2d orient, scale_factor_type value) { set(orientation_3d(orient), value); } + void set(orientation_2d orient, scale_factor_type value) { + scale_[orient.to_int()] = value; + } - scale_factor_type x() const; - scale_factor_type y() const; - scale_factor_type z() const; - void x(scale_factor_type value); - void y(scale_factor_type value); - void z(scale_factor_type value); + scale_factor_type x() const { + return scale_[HORIZONTAL]; + } + + scale_factor_type y() const { + return scale_[VERTICAL]; + } + + void x(scale_factor_type value) { + scale_[HORIZONTAL] = value; + } + + void y(scale_factor_type value) { + scale_[VERTICAL] = value; + } // concatination operator (convolve scale factors) - anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const; + anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const { + anisotropic_scale_factor retval(*this); + return retval += s; + } // concatinate this with that - const anisotropic_scale_factor& operator+=(const anisotropic_scale_factor& s); + const anisotropic_scale_factor& operator+=( + const anisotropic_scale_factor& s) { + scale_[0] *= s.scale_[0]; + scale_[1] *= s.scale_[1]; + return *this; + } // transform this scale with an axis_transform - anisotropic_scale_factor& transform(axis_transformation atr); + anisotropic_scale_factor& transform(axis_transformation atr) { + direction_2d dirs[2]; + atr.get_directions(dirs[0], dirs[1]); + scale_factor_type tmp[2] = {scale_[0], scale_[1]}; + for (int i = 0; i < 2; ++i) { + scale_[orientation_2d(dirs[i]).to_int()] = tmp[i]; + } + return *this; + } // scale the two coordinates template - void scale(coordinate_type& x, coordinate_type& y) const; - - // scale the three coordinates - template - void scale(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + void scale(coordinate_type& x, coordinate_type& y) const { + x = scaling_policy::round( + (scale_factor_type)x * get(HORIZONTAL)); + y = scaling_policy::round( + (scale_factor_type)y * get(HORIZONTAL)); + } // invert this scale factor to give the reverse scale factor - anisotropic_scale_factor& invert(); + anisotropic_scale_factor& invert() { + x(1/x()); + y(1/y()); + return *this; + } -private: - scale_factor_type scale_[3]; - - //friend std::ostream& operator<< (std::ostream& o, const Scale& r); - //friend std::istream& operator>> (std::istream& i, Scale& r); + private: + scale_factor_type scale_[2]; }; -// Transformation object, stores and provides services for transformations - -// Transformation object stores an axistransformation, a scale factor and a translation. -// The tranlation is the position of the origin of the new system of coordinates in the old system. -// The scale scales the coordinates before they are transformed. +// Transformation object, stores and provides services for transformations. +// Consits of axis transformation, scale factor and translation. +// The tranlation is the position of the origin of the new coordinate system of +// in the old system. Coordinates are scaled before they are transformed. template class transformation { -public: - transformation(); - transformation(axis_transformation atr); - transformation(axis_transformation::ATR atr); + public: + transformation() : atr_(), p_(0, 0) {} + explicit transformation(axis_transformation atr) : atr_(atr), p_(0, 0) {} + explicit transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0) {} + transformation(const transformation& tr) : atr_(tr.atr_), p_(tr.p_) {} + template - transformation(const point_type& p); + explicit transformation(const point_type& p) : atr_(), p_(0, 0) { + set_translation(p); + } + template - transformation(axis_transformation atr, const point_type& p); + transformation(axis_transformation atr, + const point_type& p) : atr_(atr), p_(0, 0) { + set_translation(p); + } + template - transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt); - transformation(const transformation& tr); + transformation(axis_transformation atr, + const point_type& referencePt, + const point_type& destinationPt) : atr_(), p_(0, 0) { + transformation tmp(referencePt); + transformation rotRef(atr); + transformation tmpInverse = tmp.inverse(); + point_type decon(referencePt); + deconvolve(decon, destinationPt); + transformation displacement(decon); + tmp += rotRef; + tmp += tmpInverse; + tmp += displacement; + (*this) = tmp; + } // equivalence operator - bool operator==(const transformation& tr) const; + bool operator==(const transformation& tr) const { + return (atr_ == tr.atr_) && (p_ == tr.p_); + } // inequivalence operator - bool operator!=(const transformation& tr) const; + bool operator!=(const transformation& tr) const { + return !(*this == tr); + } // ordering - bool operator<(const transformation& tr) const; + bool operator<(const transformation& tr) const { + return (atr_ < tr.atr_) || ((atr_ == tr.atr_) && (p_ < tr.p_)); + } // concatenation operator - transformation operator+(const transformation& tr) const; + transformation operator+(const transformation& tr) const { + transformation retval(*this); + return retval+=tr; + } // concatenate this with that - const transformation& operator+=(const transformation& tr); + const transformation& operator+=(const transformation& tr) { + coordinate_type x, y; + transformation inv = inverse(); + inv.transform(x, y); + p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); + p_.set(VERTICAL, p_.get(VERTICAL) + y); + // concatenate axis transforms + atr_ += tr.atr_; + return *this; + } // get the axis_transformation portion of this - inline axis_transformation get_axis_transformation() const {return atr_;} + axis_transformation get_axis_transformation() const { + return atr_; + } // set the axis_transformation portion of this - void set_axis_transformation(const axis_transformation& atr); + void set_axis_transformation(const axis_transformation& atr) { + atr_ = atr; + } - // get the translation portion of this as a point3d + // get the translation template - void get_translation(point_type& translation) const; + void get_translation(point_type& p) const { + assign(p, p_); + } - // set the translation portion of this with a point3d + // set the translation template - void set_translation(const point_type& p); + void set_translation(const point_type& p) { + assign(p_, p); + } // apply the 2D portion of this transformation to the two coordinates given - void transform(coordinate_type& x, coordinate_type& y) const; - - // apply this transformation to the three coordinates given - void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const; + void transform(coordinate_type& x, coordinate_type& y) const { + y -= p_.get(VERTICAL); + x -= p_.get(HORIZONTAL); + atr_.transform(x, y); + } // invert this transformation - transformation& invert(); + transformation& invert() { + coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL); + atr_.transform(x, y); + x *= -1; + y *= -1; + p_ = point_data(x, y); + atr_.invert(); + return *this; + } // get the inverse of this transformation - transformation inverse() const; + transformation inverse() const { + transformation ret_val(*this); + return ret_val.invert(); + } - inline void get_directions(direction_2d& horizontal_dir, - direction_2d& vertical_dir) const { - return atr_.get_directions(horizontal_dir, vertical_dir); } + void get_directions(direction_2d& horizontal_dir, + direction_2d& vertical_dir) const { + return atr_.get_directions(horizontal_dir, vertical_dir); + } - inline void get_directions(direction_3d& horizontal_dir, - direction_3d& vertical_dir, - direction_3d& proximal_dir) const { - return atr_.get_directions(horizontal_dir, vertical_dir, proximal_dir); } - -private: + private: axis_transformation atr_; - point_3d_data p_; - - template - void construct_dispatch(axis_transformation atr, point_type p, point_concept tag); - template - void construct_dispatch(axis_transformation atr, point_type p, point_3d_concept tag); - template - void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_concept tag); - template - void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_3d_concept tag); - - //friend std::ostream& operator<< (std::ostream& o, const transformation& tr); - //friend std::istream& operator>> (std::istream& i, transformation& tr); + point_data p_; }; -} -} -#include "detail/transform_detail.hpp" -#endif +} // polygon +} // boost + +#endif // BOOST_POLYGON_TRANSFORM_HPP diff --git a/include/boost/polygon/voronoi_geometry_type.hpp b/include/boost/polygon/voronoi_geometry_type.hpp index 0b66626..a03570e 100644 --- a/include/boost/polygon/voronoi_geometry_type.hpp +++ b/include/boost/polygon/voronoi_geometry_type.hpp @@ -33,7 +33,7 @@ enum SourceCategory { SOURCE_CATEGORY_BITMASK = 0x1F }; -bool belongs( +inline bool belongs( SourceCategory source_category, GeometryCategory geometry_category) { return (static_cast(source_category) >> diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c970b59..3b010c5 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -18,7 +18,9 @@ project polygon-test test-suite polygon-unit : + [ run polygon_point_test.cpp ] [ run polygon_segment_test.cpp ] + [ run polygon_interval_test.cpp ] [ run gtl_boost_unit_test.cpp ] ; diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index ea4d289..b108a1f 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -733,64 +733,6 @@ namespace boost { namespace polygon{ } using namespace gtl; -bool testInterval() { - interval_data interval(0, 10), interval2(10, 20); - if(!abuts(interval, interval2)) return false; - if(!boundaries_intersect(interval, interval2)) return false; - if(boundaries_intersect(interval, interval2, false)) return false; - if(intersect(interval, interval2, false)) return false; - if(!intersect(interval, interval2)) return false; - if(euclidean_distance(interval, interval2) != 0) return false; - encompass(interval, interval2); - set(interval, LOW, 0); - high(interval, 10); - scale(interval, 2.0f); - scale(interval, 0.5f); - if(low(interval) != 0) return false; - if(high(interval) != 10) return false; - move(interval, 10); - if(!equivalence(interval, interval2)) return false; - flip(interval, 10); - bloat(interval, -2); - shrink(interval, -2); - flip(interval, 10); - if(!equivalence(interval, interval2)) return false; - interval_data half = get_half(interval, LOW); - if(high(half) != 15) return false; - convolve(interval, interval2); - if(high(interval) != 40) return false; - deconvolve(interval, interval2); - if(!equivalence(interval, interval2)) return false; - reflected_convolve(interval, interval2); - if(low(interval) != -10) return false; - reflected_deconvolve(interval, interval2); - if(!equivalence(interval, interval2)) return false; - euclidean_distance(interval, 0); - move(interval, 20); - if(euclidean_distance(interval, interval2) != 10) return false; - interval = interval2; - move(interval, -5); - if(!intersects(interval, interval2)) return false; - move(interval, 15); - if(!abuts(interval, interval2)) return false; - if(abuts(interval, interval2, HIGH)) return false; - move(interval, 10); - generalized_intersect(interval, interval2); - move(interval, -10); - if(!equivalence(interval, interval2)) return false; - if(get(interval, LOW) != low(interval)) return false; - if(get(interval, HIGH) != high(interval)) return false; - if(center(interval2) != 15) return false; - if(delta(interval2) != 10) return false; - assign(interval, interval2); - low(interval, 0); - if(low(interval) != 0) return false; - high(interval, 10); - join_with(interval, interval2); - if(high(interval) != high(interval2)) return false; - return true; -} - bool testRectangle() { rectangle_data rect, rect2; #ifdef BOOST_POLYGON_MSVC @@ -2544,7 +2486,6 @@ int main() { p + pwh; p90 + pwh; p45 + pwh; - std::cout << testInterval() << std::endl; std::cout << testRectangle() << std::endl; std::cout << testPolygon() << std::endl; std::cout << testPropertyMerge() << std::endl; @@ -3112,37 +3053,6 @@ int main() { assign(pwhs, polys); std::cout << equivalence(pwhs, polys) << std::endl; } - { - typedef point_3d_data Point3D; - Point3D p3d1(0, 1, 3), p3d2(0, 1, 2); - if(equivalence(p3d1, p3d2)) return 1; - if(euclidean_distance(p3d1, p3d2) != 1) return 1; - if(euclidean_distance(p3d1, p3d2, PROXIMAL) != 1) return 1; - if(manhattan_distance(p3d1, p3d2) != 1) return 1; - assign(p3d1, p3d2); - if(!equivalence(p3d1, p3d2)) return 1; - p3d1 = construct(x(p3d1), y(p3d1), z(p3d1)); - if(!equivalence(p3d1, p3d2)) return 1; - convolve(p3d1, p3d2); - if(equivalence(p3d1, p3d2)) return 1; - deconvolve(p3d1, p3d2); - if(!equivalence(p3d1, p3d2)) return 1; - if(get(p3d1, PROXIMAL) != 2) return 1; - scale(p3d1, anisotropic_scale_factor(2, 2, 2)); - if(equivalence(p3d1, p3d2)) return 1; - scale_down(p3d1, 2); - if(!equivalence(p3d1, p3d2)) return 1; - scale_up(p3d1, 2); - if(equivalence(p3d1, p3d2)) return 1; - scale_down(p3d1, 2); - set(p3d1, PROXIMAL, 3); - if(equivalence(p3d1, p3d2)) return 1; - axis_transformation atr = axis_transformation::END; - transform(p3d1, atr); - if(z(p3d1) != -3) return 1; - z(p3d1, 2); - if(!equivalence(p3d1, p3d2)) return 1; - } { polygon_90_set_data ps1(HORIZONTAL), ps2(VERTICAL); ps1 += rectangle_data(0, 0, 10, 120); @@ -3237,16 +3147,6 @@ int main() { polygon_with_holes_data pwh; snap_to_45(pwh); } - { - point_data pt(1,2); - point_3d_data pt3d(1,2,3); - equivalence(pt, pt3d); - deconvolve(pt, pt3d); - manhattan_distance(pt, pt3d); - move(pt, HORIZONTAL, 1); - scale(pt, anisotropic_scale_factor(2, 2, 2)); - pt = pt3d; - } { polygon_90_set_data ps90_1, ps90_2; ps90_1.insert(rectangle_data(0, 0, 10, 10)); @@ -3261,8 +3161,8 @@ int main() { bloat(ps90_1, 1); scale_up(ps90_1, 2); scale_down(ps90_1, 2); - scale(ps90_1, anisotropic_scale_factor(2, 2, 2)); - scale(ps90_1, anisotropic_scale_factor(0.5, 0.5, 0.5)); + scale(ps90_1, anisotropic_scale_factor(2, 2)); + scale(ps90_1, anisotropic_scale_factor(0.5, 0.5)); axis_transformation atr; transform(ps90_1, atr); std::cout << area(ps90_1) << std::endl; @@ -3710,7 +3610,6 @@ int main() { segment_data sarray[2]; sarray[0] = segment_data(point_data(0,0), point_data(10,10)); sarray[1] = segment_data(point_data(10,0), point_data(0,10)); - std::iterator_traits*>::value_type s = sarray[0]; intersect_segments(segs, sarray, sarray+2); std::cout << segs.size() << std::endl; assert_s(segs.size() == 4, "intersection3"); diff --git a/test/polygon_interval_test.cpp b/test/polygon_interval_test.cpp new file mode 100644 index 0000000..55fc3cf --- /dev/null +++ b/test/polygon_interval_test.cpp @@ -0,0 +1,258 @@ +// Boost.Polygon library polygon_interval_test.cpp file + +// Copyright Andrii Sydorchuk 2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#define BOOST_TEST_MODULE POLYGON_INTERVAL_TEST +#include +#include + +#include "boost/polygon/interval_concept.hpp" +#include "boost/polygon/interval_data.hpp" +#include "boost/polygon/interval_traits.hpp" +using namespace boost::polygon; + +typedef boost::mpl::list test_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_data_test, T, test_types) { + typedef interval_data interval_type; + interval_type interval1(1, 2); + interval_type interval2; + interval2 = interval1; + + BOOST_CHECK_EQUAL(interval1.low(), 1); + BOOST_CHECK_EQUAL(interval1.high(), 2); + BOOST_CHECK_EQUAL(interval1.get(LOW), 1); + BOOST_CHECK_EQUAL(interval1.get(HIGH), 2); + BOOST_CHECK(interval1 == interval2); + BOOST_CHECK(!(interval1 != interval2)); + BOOST_CHECK(!(interval1 < interval2)); + BOOST_CHECK(!(interval1 > interval2)); + BOOST_CHECK(interval1 <= interval2); + BOOST_CHECK(interval1 >= interval2); + + interval1.low(2); + interval1.high(1); + BOOST_CHECK_EQUAL(interval1.low(), 2); + BOOST_CHECK_EQUAL(interval1.high(), 1); + BOOST_CHECK(!(interval1 == interval2)); + BOOST_CHECK(interval1 != interval2); + + interval2.set(LOW, 2); + interval2.set(HIGH, 1); + BOOST_CHECK(interval1 == interval2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_traits_test, T, test_types) { + typedef interval_data interval_type; + + interval_type interval = interval_mutable_traits::construct(1, 2); + BOOST_CHECK_EQUAL(interval_traits::get(interval, LOW), 1); + BOOST_CHECK_EQUAL(interval_traits::get(interval, HIGH), 2); + + interval_mutable_traits::set(interval, LOW, 3); + interval_mutable_traits::set(interval, HIGH, 4); + BOOST_CHECK_EQUAL(interval_traits::get(interval, LOW), 3); + BOOST_CHECK_EQUAL(interval_traits::get(interval, HIGH), 4); +} + +template +struct Interval { + T left; + T right; +}; + +namespace boost { +namespace polygon { + template + struct geometry_concept< Interval > { + typedef interval_concept type; + }; + + template + struct interval_traits< Interval > { + typedef T coordinate_type; + + static coordinate_type get(const Interval& interval, direction_1d dir) { + return (dir == LOW) ? interval.left : interval.right; + } + }; + + template + struct interval_mutable_traits< Interval > { + typedef T coordinate_type; + + static void set(Interval& interval, direction_1d dir, T value) { + (dir == LOW) ? interval.left = value : interval.right = value; + } + + static Interval construct(coordinate_type left, coordinate_type right) { + Interval interval; + interval.left = left; + interval.right = right; + return interval; + } + }; +} // polygon +} // boost + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test1, T, test_types) { + typedef Interval interval_type; + + interval_type interval1 = construct(2, 1); + BOOST_CHECK_EQUAL(interval1.left, 1); + BOOST_CHECK_EQUAL(interval1.right, 2); + + set(interval1, LOW, 3); + set(interval1, HIGH, 4); + BOOST_CHECK_EQUAL(get(interval1, LOW), 3); + BOOST_CHECK_EQUAL(get(interval1, HIGH), 4); + + interval_type interval2 = copy_construct(interval1); + BOOST_CHECK(equivalence(interval1, interval2)); + + low(interval2, 1); + high(interval2, 2); + BOOST_CHECK_EQUAL(low(interval2), 1); + BOOST_CHECK_EQUAL(high(interval2), 2); + + assign(interval1, interval2); + BOOST_CHECK(equivalence(interval1, interval2)); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test2, T, test_types) { + typedef Interval interval_type; + + interval_type interval1 = construct(1, 3); + BOOST_CHECK_EQUAL(center(interval1), 2); + BOOST_CHECK_EQUAL(delta(interval1), 2); + + flip(interval1, -1); + BOOST_CHECK_EQUAL(low(interval1), -5); + BOOST_CHECK_EQUAL(high(interval1), -3); + + scale_up(interval1, 2); + BOOST_CHECK_EQUAL(low(interval1), -10); + BOOST_CHECK_EQUAL(high(interval1), -6); + + scale_down(interval1, 2); + BOOST_CHECK_EQUAL(low(interval1), -5); + BOOST_CHECK_EQUAL(high(interval1), -3); + + move(interval1, 5); + BOOST_CHECK_EQUAL(low(interval1), 0); + BOOST_CHECK_EQUAL(high(interval1), 2); + + convolve(interval1, 1); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 3); + + deconvolve(interval1, 2); + BOOST_CHECK_EQUAL(low(interval1), -1); + BOOST_CHECK_EQUAL(high(interval1), 1); + + interval_type interval2 = construct(-1, 2); + convolve(interval1, interval2); + BOOST_CHECK_EQUAL(low(interval1), -2); + BOOST_CHECK_EQUAL(high(interval1), 3); + + deconvolve(interval1, interval2); + BOOST_CHECK_EQUAL(low(interval1), -1); + BOOST_CHECK_EQUAL(high(interval1), 1); + + reflected_convolve(interval1, interval2); + BOOST_CHECK_EQUAL(low(interval1), -3); + BOOST_CHECK_EQUAL(high(interval1), 2); + + reflected_deconvolve(interval1, interval2); + BOOST_CHECK_EQUAL(low(interval1), -1); + BOOST_CHECK_EQUAL(high(interval1), 1); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test3, T, test_types) { + typedef Interval interval_type; + + interval_type interval1 = construct(1, 3); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, -2), 3); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, 2), 0); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, 4), 1); + + interval_type interval2 = construct(-1, 0); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval2), 1); + BOOST_CHECK(!intersects(interval1, interval2)); + BOOST_CHECK(!boundaries_intersect(interval1, interval2)); + BOOST_CHECK(!intersect(interval2, interval1)); + BOOST_CHECK_EQUAL(low(interval2), -1); + BOOST_CHECK_EQUAL(high(interval2), 0); + + interval_type interval3 = construct(-1, 6); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval3), 0); + BOOST_CHECK(intersects(interval1, interval3)); + BOOST_CHECK(!boundaries_intersect(interval1, interval3)); + BOOST_CHECK(intersect(interval3, interval1)); + BOOST_CHECK_EQUAL(low(interval3), 1); + BOOST_CHECK_EQUAL(high(interval3), 3); + + interval_type interval4 = construct(5, 6); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval4), 2); + BOOST_CHECK(!intersects(interval1, interval4)); + BOOST_CHECK(!boundaries_intersect(interval1, interval4)); + BOOST_CHECK(!intersect(interval4, interval1)); + BOOST_CHECK_EQUAL(low(interval4), 5); + BOOST_CHECK_EQUAL(high(interval4), 6); + + interval_type interval5 = construct(3, 5); + BOOST_CHECK_EQUAL(euclidean_distance(interval1, interval5), 0); + BOOST_CHECK(!intersects(interval1, interval5, false)); + BOOST_CHECK(boundaries_intersect(interval1, interval5)); + BOOST_CHECK(intersect(interval5, interval1)); + BOOST_CHECK_EQUAL(low(interval5), 3); + BOOST_CHECK_EQUAL(high(interval5), 3); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(interval_concept_test4, T, test_types) { + typedef Interval interval_type; + + interval_type interval1 = construct(1, 3); + interval_type interval2 = construct(3, 5); + BOOST_CHECK(!abuts(interval1, interval2, LOW)); + BOOST_CHECK(abuts(interval1, interval2, HIGH)); + BOOST_CHECK(abuts(interval1, interval2)); + + bloat(interval1, 1); + BOOST_CHECK_EQUAL(low(interval1), 0); + BOOST_CHECK_EQUAL(high(interval1), 4); + BOOST_CHECK(!abuts(interval1, interval2)); + + bloat(interval1, LOW, 1); + BOOST_CHECK_EQUAL(low(interval1), -1); + BOOST_CHECK_EQUAL(high(interval1), 4); + + shrink(interval1, LOW, 1); + BOOST_CHECK_EQUAL(low(interval1), 0); + BOOST_CHECK_EQUAL(high(interval1), 4); + + shrink(interval1, 1); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 3); + + BOOST_CHECK(encompass(interval1, 4)); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 4); + + BOOST_CHECK(encompass(interval1, interval2)); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 5); + + interval1 = get_half(interval1, LOW); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 3); + + BOOST_CHECK(join_with(interval1, interval2)); + BOOST_CHECK_EQUAL(low(interval1), 1); + BOOST_CHECK_EQUAL(high(interval1), 5); +} diff --git a/test/polygon_point_test.cpp b/test/polygon_point_test.cpp new file mode 100644 index 0000000..1a33ff9 --- /dev/null +++ b/test/polygon_point_test.cpp @@ -0,0 +1,192 @@ +// Boost.Polygon library polygon_point_test.cpp file + +// Copyright Andrii Sydorchuk 2012. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#define BOOST_TEST_MODULE POLYGON_POINT_TEST +#include +#include + +#include "boost/polygon/point_concept.hpp" +#include "boost/polygon/point_data.hpp" +#include "boost/polygon/point_traits.hpp" +using namespace boost::polygon; + +typedef boost::mpl::list test_types; + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_data_test, T, test_types) { + typedef point_data point_type; + + point_type point1(1, 2); + point_type point2; + point2 = point1; + BOOST_CHECK_EQUAL(point1.x(), 1); + BOOST_CHECK_EQUAL(point1.y(), 2); + BOOST_CHECK_EQUAL(point2.x(), 1); + BOOST_CHECK_EQUAL(point2.y(), 2); + BOOST_CHECK(point1 == point2); + BOOST_CHECK(!(point1 != point2)); + BOOST_CHECK(!(point1 < point2)); + BOOST_CHECK(!(point1 > point2)); + BOOST_CHECK(point1 <= point2); + BOOST_CHECK(point1 >= point2); + + point2.x(2); + point2.y(1); + BOOST_CHECK_EQUAL(point2.x(), 2); + BOOST_CHECK_EQUAL(point2.y(), 1); + BOOST_CHECK(!(point1 == point2)); + BOOST_CHECK(point1 != point2); + BOOST_CHECK(point1 < point2); + BOOST_CHECK(!(point1 > point2)); + BOOST_CHECK(point1 <= point2); + BOOST_CHECK(!(point1 >= point2)); + + point2.set(HORIZONTAL, 1); + point2.set(VERTICAL, 2); + BOOST_CHECK(point1 == point2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_traits_test, T, test_types) { + typedef point_data point_type; + + point_type point = point_mutable_traits::construct(1, 2); + BOOST_CHECK_EQUAL(point_traits::get(point, HORIZONTAL), 1); + BOOST_CHECK_EQUAL(point_traits::get(point, VERTICAL), 2); + + point_mutable_traits::set(point, HORIZONTAL, 3); + point_mutable_traits::set(point, VERTICAL, 4); + BOOST_CHECK_EQUAL(point_traits::get(point, HORIZONTAL), 3); + BOOST_CHECK_EQUAL(point_traits::get(point, VERTICAL), 4); +} + +template +struct Point { + T x; + T y; +}; + +namespace boost { +namespace polygon { + template + struct geometry_concept< Point > { + typedef point_concept type; + }; + + template + struct point_traits< Point > { + typedef T coordinate_type; + + static coordinate_type get(const Point& point, orientation_2d orient) { + return (orient == HORIZONTAL) ? point.x : point.y; + } + }; + + template + struct point_mutable_traits< Point > { + typedef T coordinate_type; + + static void set(Point& point, orientation_2d orient, T value) { + (orient == HORIZONTAL) ? point.x = value : point.y = value; + } + + static Point construct(coordinate_type x, coordinate_type y) { + Point point; + point.x = x; + point.y = y; + return point; + } + }; +} // polygon +} // boost + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_concept_test1, T, test_types) { + typedef Point point_type; + + point_type point1 = construct(1, 2); + BOOST_CHECK_EQUAL(point1.x, 1); + BOOST_CHECK_EQUAL(point1.y, 2); + + set(point1, HORIZONTAL, 3); + set(point1, VERTICAL, 4); + BOOST_CHECK_EQUAL(get(point1, HORIZONTAL), 3); + BOOST_CHECK_EQUAL(get(point1, VERTICAL), 4); + + point_type point2; + assign(point2, point1); + BOOST_CHECK(equivalence(point1, point2)); + + x(point2, 1); + y(point2, 2); + BOOST_CHECK_EQUAL(x(point2), 1); + BOOST_CHECK_EQUAL(y(point2), 2); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_concept_test2, T, test_types) { + typedef Point point_type; + + point_type point1 = construct(1, 2); + point_type point2 = construct(5, 5); + BOOST_CHECK_EQUAL(euclidean_distance(point1, point2, HORIZONTAL), 4); + BOOST_CHECK_EQUAL(euclidean_distance(point1, point2, VERTICAL), 3); + BOOST_CHECK_EQUAL(manhattan_distance(point1, point2), 7); + BOOST_CHECK_EQUAL(euclidean_distance(point1, point2), 5.0); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_concept_test3, T, test_types) { + typedef Point point_type; + + point_type point = construct(1, 2); + point_type shift = construct(4, 3); + convolve(point, shift); + BOOST_CHECK_EQUAL(x(point), 5); + BOOST_CHECK_EQUAL(y(point), 5); + + deconvolve(point, shift); + BOOST_CHECK_EQUAL(x(point), 1); + BOOST_CHECK_EQUAL(y(point), 2); + + scale_up(point, 5); + BOOST_CHECK_EQUAL(x(point), 5); + BOOST_CHECK_EQUAL(y(point), 10); + + scale_down(point, 5); + BOOST_CHECK_EQUAL(x(point), 1); + BOOST_CHECK_EQUAL(y(point), 2); + + move(point, HORIZONTAL, 2); + move(point, VERTICAL, 3); + BOOST_CHECK_EQUAL(x(point), 3); + BOOST_CHECK_EQUAL(y(point), 5); +} + +template +struct Transformer { + void scale(T& x, T& y) const { + x *= 2; + y *= 2; + } + + void transform(T& x, T& y) const { + T tmp = x; + x = y; + y = tmp; + } +}; + +BOOST_AUTO_TEST_CASE_TEMPLATE(point_concept_test4, T, test_types) { + typedef Point point_type; + + point_type point = construct(1, 2); + scale(point, Transformer()); + BOOST_CHECK_EQUAL(x(point), 2); + BOOST_CHECK_EQUAL(y(point), 4); + + transform(point, Transformer()); + BOOST_CHECK_EQUAL(x(point), 4); + BOOST_CHECK_EQUAL(y(point), 2); +} diff --git a/test/polygon_segment_test.cpp b/test/polygon_segment_test.cpp index 665fe4a..5e3d620 100644 --- a/test/polygon_segment_test.cpp +++ b/test/polygon_segment_test.cpp @@ -7,14 +7,13 @@ // See http://www.boost.org for updates, documentation, and revision history. -#include -#include - #define BOOST_TEST_MODULE POLYGON_SEGMENT_TEST #include #include -#include "boost/polygon/polygon.hpp" +#include "boost/polygon/segment_concept.hpp" +#include "boost/polygon/segment_data.hpp" +#include "boost/polygon/segment_traits.hpp" using namespace boost::polygon; typedef boost::mpl::list test_types; @@ -25,7 +24,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_data_test, T, test_types) { point_type point1(1, 2); point_type point2(3, 4); segment_type segment1(point1, point2); - segment_type segment2 = segment1; + segment_type segment2; + segment2 = segment1; BOOST_CHECK(segment1.low() == point1); BOOST_CHECK(segment1.high() == point2); @@ -56,14 +56,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_traits_test, T, test_types) { point_type point1(1, 2); point_type point2(3, 4); - segment_type segment = segment_mutable_traits::construct(point1, point2); + segment_type segment = + segment_mutable_traits::construct(point1, point2); BOOST_CHECK(segment_traits::get(segment, LOW) == point1); BOOST_CHECK(segment_traits::get(segment, HIGH) == point2); segment_mutable_traits::set(segment, LOW, point2); segment_mutable_traits::set(segment, HIGH, point1); - BOOST_CHECK(segment_traits::get(segment, LOW) == point2); BOOST_CHECK(segment_traits::get(segment, HIGH) == point1); } @@ -95,15 +95,13 @@ namespace polygon { struct segment_mutable_traits< Segment > { typedef point_data point_type; - static inline void set(Segment& segment, direction_1d dir, const point_type& point) { - if (dir.to_int()) { - segment.p1 = point; - } else { - segment.p0 = point; - } + static void set( + Segment& segment, direction_1d dir, const point_type& point) { + dir.to_int() ? segment.p1 = point : segment.p0 = point;; } - static inline Segment construct(const point_type& point1, const point_type& point2) { + static Segment construct( + const point_type& point1, const point_type& point2) { Segment segment; segment.p0 = point1; segment.p1 = point2; @@ -190,11 +188,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test3, T, test_types) { typedef point_data point_type; typedef Segment segment_type; - segment_type segment1 = construct(point_type(0, 0), point_type(1, 2)); - segment_type segment2 = construct(point_type(0, 0), point_type(2, 4)); - segment_type segment3 = construct(point_type(0, 0), point_type(2, 3)); - segment_type segment4 = construct(point_type(0, 0), point_type(2, 5)); - segment_type segment5 = construct(point_type(0, 2), point_type(2, 0)); + segment_type segment1 = construct( + point_type(0, 0), point_type(1, 2)); + segment_type segment2 = construct( + point_type(0, 0), point_type(2, 4)); + segment_type segment3 = construct( + point_type(0, 0), point_type(2, 3)); + segment_type segment4 = construct( + point_type(0, 0), point_type(2, 5)); + segment_type segment5 = construct( + point_type(0, 2), point_type(2, 0)); BOOST_CHECK(orientation(segment1, segment2) == 0); BOOST_CHECK(orientation(segment1, segment3) == -1); @@ -325,10 +328,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test8, T, test_types) { typedef point_data point_type; typedef Segment segment_type; - segment_type segment1 = construct(point_type(0, 0), point_type(1, 2)); - segment_type segment2 = construct(point_type(1, 2), point_type(2, 4)); - segment_type segment3 = construct(point_type(2, 4), point_type(0, 4)); - segment_type segment4 = construct(point_type(0, 4), point_type(0, 0)); + segment_type segment1 = construct( + point_type(0, 0), point_type(1, 2)); + segment_type segment2 = construct( + point_type(1, 2), point_type(2, 4)); + segment_type segment3 = construct( + point_type(2, 4), point_type(0, 4)); + segment_type segment4 = construct( + point_type(0, 4), point_type(0, 0)); BOOST_CHECK(abuts(segment1, segment2, HIGH)); BOOST_CHECK(abuts(segment2, segment3, HIGH)); @@ -353,11 +360,16 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test9, T, test_types) { typedef point_data point_type; typedef Segment segment_type; - segment_type segment1 = construct(point_type(0, 0), point_type(2, 2)); - segment_type segment2 = construct(point_type(1, 1), point_type(3, 3)); - segment_type segment3 = construct(point_type(2, 2), point_type(-1, -1)); - segment_type segment4 = construct(point_type(1, 3), point_type(3, 1)); - segment_type segment5 = construct(point_type(2, 2), point_type(1, 3)); + segment_type segment1 = construct( + point_type(0, 0), point_type(2, 2)); + segment_type segment2 = construct( + point_type(1, 1), point_type(3, 3)); + segment_type segment3 = construct( + point_type(2, 2), point_type(-1, -1)); + segment_type segment4 = construct( + point_type(1, 3), point_type(3, 1)); + segment_type segment5 = construct( + point_type(2, 2), point_type(1, 3)); BOOST_CHECK(intersects(segment1, segment2, false)); BOOST_CHECK(intersects(segment1, segment2, true)); @@ -377,12 +389,18 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test10, T, test_types) { typedef point_data point_type; typedef Segment segment_type; - segment_type segment1 = construct(point_type(0, 0), point_type(0, 2)); - segment_type segment2 = construct(point_type(0, 1), point_type(0, 3)); - segment_type segment3 = construct(point_type(0, 1), point_type(0, 2)); - segment_type segment4 = construct(point_type(0, 2), point_type(0, 3)); - segment_type segment5 = construct(point_type(0, 2), point_type(2, 2)); - segment_type segment6 = construct(point_type(0, 1), point_type(1, 1)); + segment_type segment1 = construct( + point_type(0, 0), point_type(0, 2)); + segment_type segment2 = construct( + point_type(0, 1), point_type(0, 3)); + segment_type segment3 = construct( + point_type(0, 1), point_type(0, 2)); + segment_type segment4 = construct( + point_type(0, 2), point_type(0, 3)); + segment_type segment5 = construct( + point_type(0, 2), point_type(2, 2)); + segment_type segment6 = construct( + point_type(0, 1), point_type(1, 1)); BOOST_CHECK(intersects(segment1, segment1, false)); BOOST_CHECK(intersects(segment1, segment1, true)); @@ -420,10 +438,14 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_concept_test12, T, test_types) { typedef point_data point_type; typedef Segment segment_type; - segment_type segment1 = construct(point_type(0, 0), point_type(3, 4)); - segment_type segment2 = construct(point_type(2, 0), point_type(0, 2)); - segment_type segment3 = construct(point_type(1, -7), point_type(10, 5)); - segment_type segment4 = construct(point_type(7, 7), point_type(10, 11)); + segment_type segment1 = construct( + point_type(0, 0), point_type(3, 4)); + segment_type segment2 = construct( + point_type(2, 0), point_type(0, 2)); + segment_type segment3 = construct( + point_type(1, -7), point_type(10, 5)); + segment_type segment4 = construct( + point_type(7, 7), point_type(10, 11)); BOOST_CHECK(euclidean_distance(segment1, segment2) == 0.0); BOOST_CHECK(euclidean_distance(segment1, segment3) == 5.0); From 75f3c81ac46456e35cd568dc4fe9bc7c859f6026 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Mon, 17 Dec 2012 00:10:26 +0000 Subject: [PATCH 23/32] Polygon: fixing duplicate bookmark in the documentation. [SVN r82041] --- doc/gtl_segment_concept.htm | 6 +++--- include/boost/polygon/interval_data.hpp | 12 ++---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/doc/gtl_segment_concept.htm b/doc/gtl_segment_concept.htm index f183d59..4dcff30 100644 --- a/doc/gtl_segment_concept.htm +++ b/doc/gtl_segment_concept.htm @@ -480,7 +480,7 @@ const through several interfaces to allow it to be used with any collection or sequence of objects that model the segment_concept.

      Functions

      -
      geometry_typepoint_concept
      coordinate_typeTT
      point_data()Default constructs the two coordinate - values of the point.Default constructs the two coordinate + values of the point.
      point_data(T x, T y)Constructs an interval with two - coordinates.Constructs an interval with two + coordinates.
      point_data(const point_data* + point_data(const point_data& that)Copy constructCopy construct
      point_data& operator=(const @@ -322,44 +319,39 @@ convenient to use with the library traits.

      Assignment operator.
      template <typename T2>  -
      point_data& operator=(const T2& that) const
      template <typename PointType>
      +point_data& operator=(const PointType& that) const
      Assign from an object that is a model of point.
      template <typename T2> -
      bool - operator==(const T2& that) const
      Compare equality to an object that is a model of point.bool + operator==(const point_data& that) constEquality operator overload.
      +
      template <typename T2> -
      bool - operator!=(const T2& that) const
      Compare inequality to an object that is a model of point.bool + operator!=(const point_data& that) constInequality operator overload.
      template <typename T2> -
      bool - operator<(const T2& that) const
      bool + operator<(const point_data& that) const Compares y coordinates then x coordinates to break ties.
      template <typename T2> -
      bool - operator<=(const T2& that) const
      bool + operator<=(const point_data& that) const Compares y coordinates then x coordinates to break ties.
      template <typename T2> -
      bool - operator>(const T2& that) const
      bool + operator>(const point_data& that) const Compares low coordinates then high coordinates to break ties.
      template <typename T2> -
      bool - operator>=(const T2& that) const
      bool + operator>=(const point_data& that) const Compares low coordinates then high coordinates to break ties.
      template -<typename Segment>
      -
      segment_data& operator=(const Segment& that) +<typename SegmentType>
      +
      segment_data& operator=(const
      SegmentType& that) const
      Assign from an object that is a model of segment.
      +
      @@ -550,7 +550,7 @@ respectively. Linear runtime.
        - +
      @@ -570,4 +570,4 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright:
      - \ No newline at end of file + diff --git a/include/boost/polygon/interval_data.hpp b/include/boost/polygon/interval_data.hpp index b538b3e..91c064b 100644 --- a/include/boost/polygon/interval_data.hpp +++ b/include/boost/polygon/interval_data.hpp @@ -29,20 +29,12 @@ class interval_data { #endif {} - interval_data(coordinate_type low, coordinate_type high) -#ifndef BOOST_POLYGON_MSVC - : coords_() -#endif - { + interval_data(coordinate_type low, coordinate_type high) { coords_[LOW] = low; coords_[HIGH] = high; } - interval_data(const interval_data& that) -#ifndef BOOST_POLYGON_MSVC - : coords_() -#endif - { + interval_data(const interval_data& that) { coords_[0] = that.coords_[0]; coords_[1] = that.coords_[1]; } From 8b6bef77f004c018d3e53a0e1a36eaf5185a7d2f Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Mon, 17 Dec 2012 22:04:56 +0000 Subject: [PATCH 24/32] Polygon: Sync public interface of point/segment/interval data with documentation. [SVN r82058] --- include/boost/polygon/interval_data.hpp | 6 ++++++ include/boost/polygon/point_data.hpp | 2 -- include/boost/polygon/segment_data.hpp | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/boost/polygon/interval_data.hpp b/include/boost/polygon/interval_data.hpp index 91c064b..b297624 100644 --- a/include/boost/polygon/interval_data.hpp +++ b/include/boost/polygon/interval_data.hpp @@ -45,6 +45,12 @@ class interval_data { return *this; } + template + interval_data& operator=(const IntervalType& that) { + assign(*this, that); + return *this; + } + coordinate_type get(direction_1d dir) const { return coords_[dir.to_int()]; } diff --git a/include/boost/polygon/point_data.hpp b/include/boost/polygon/point_data.hpp index 8ec6c5b..e37f82f 100644 --- a/include/boost/polygon/point_data.hpp +++ b/include/boost/polygon/point_data.hpp @@ -45,13 +45,11 @@ class point_data { return *this; } - // TODO(asydorchuk): Deprecated. template explicit point_data(const PointType& that) { *this = that; } - // TODO(asydorchuk): Deprecated. template point_data& operator=(const PointType& that) { assign(*this, that); diff --git a/include/boost/polygon/segment_data.hpp b/include/boost/polygon/segment_data.hpp index 43dbcc8..dd317fc 100644 --- a/include/boost/polygon/segment_data.hpp +++ b/include/boost/polygon/segment_data.hpp @@ -46,6 +46,12 @@ class segment_data { return *this; } + template + segment_data& operator=(const SegmentType& that) { + assign(*this, that); + return *this; + } + point_type get(direction_1d dir) const { return points_[dir.to_int()]; } From 1d194a321494792573beda541660c71018d8f462 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Mon, 15 Apr 2013 22:27:46 +0000 Subject: [PATCH 25/32] [Polygon] Merging from trunk for the upcoming release: 1) Updated Voronoi documentation. 2) Fixed #8026, #8197, #8257. [SVN r83918] --- doc/analysis.htm | 296 +-- doc/gtl_connectivity_extraction.htm | 308 +-- doc/gtl_connectivity_extraction_45.htm | 308 +-- doc/gtl_connectivity_extraction_90.htm | 308 +-- doc/gtl_coordinate_concept.htm | 301 +-- doc/gtl_custom_point.htm | 26 +- doc/gtl_design_overview.htm | 398 ++-- doc/gtl_interval_concept.htm | 1073 +++++----- doc/gtl_isotropy.htm | 1049 +++++----- doc/gtl_point_concept.htm | 886 ++++---- doc/gtl_polygon_45_concept.htm | 738 +++---- doc/gtl_polygon_45_set_concept.htm | 1522 +++++++------- doc/gtl_polygon_45_with_holes_concept.htm | 820 ++++---- doc/gtl_polygon_90_concept.htm | 824 ++++---- doc/gtl_polygon_90_set_concept.htm | 1795 +++++++++-------- doc/gtl_polygon_90_with_holes_concept.htm | 924 +++++---- doc/gtl_polygon_concept.htm | 741 +++---- doc/gtl_polygon_set_concept.htm | 1324 ++++++------ doc/gtl_polygon_with_holes_concept.htm | 817 ++++---- doc/gtl_property_merge.htm | 315 +-- doc/gtl_property_merge_45.htm | 314 +-- doc/gtl_property_merge_90.htm | 314 +-- doc/gtl_rectangle_concept.htm | 1548 +++++++------- doc/gtl_segment_concept.htm | 701 ++++--- doc/images/voronoi1.png | Bin 0 -> 19532 bytes doc/index.htm | 534 ++--- doc/voronoi_benchmark.htm | 270 ++- doc/voronoi_builder.htm | 390 ++-- doc/voronoi_diagram.htm | 1115 +++++----- doc/voronoi_main.htm | 612 +++--- doc/voronoi_predicates.htm | 251 --- doc/voronoi_robust_fpt.htm | 212 -- example/input_data/primary/primary_072.txt | 5 + example/output_data/primary/primary_072.png | Bin 0 -> 4264 bytes .../boost/polygon/detail/boolean_op_45.hpp | 6 +- .../polygon/detail/polygon_45_set_view.hpp | 9 +- .../boost/polygon/detail/polygon_set_view.hpp | 5 +- .../boost/polygon/detail/scan_arbitrary.hpp | 11 +- .../polygon/detail/voronoi_predicates.hpp | 11 +- include/boost/polygon/gtl.hpp | 12 +- include/boost/polygon/polygon_45_set_data.hpp | 6 +- include/boost/polygon/polygon_traits.hpp | 3 +- include/boost/polygon/voronoi.hpp | 36 +- include/boost/polygon/voronoi_diagram.hpp | 2 +- test/gtl_boost_unit_test.cpp | 4 +- 45 files changed, 11061 insertions(+), 10083 deletions(-) create mode 100644 doc/images/voronoi1.png delete mode 100644 doc/voronoi_predicates.htm delete mode 100644 doc/voronoi_robust_fpt.htm create mode 100644 example/input_data/primary/primary_072.txt create mode 100644 example/output_data/primary/primary_072.png diff --git a/doc/analysis.htm b/doc/analysis.htm index 2f3d6c3..430eb80 100644 --- a/doc/analysis.htm +++ b/doc/analysis.htm @@ -1,20 +1,28 @@ -Boost Polygon Library: Performance Analysis - - - - - + + + + + + + +
      -
      - - -
      -
      - -
        +--> + Boost Polygon Library: Performance Analysis + + + + + + + + - - -
        + + - -
        - - -
        -
        - - - -
        -

        -

        Polygon Set Algorithms Analysis

        -

        Most non-trivial algorithms in the Boost.Polygon library are -instantiations of generic sweep-line algorithms that provide the capability to -perform Manhattan and 45-degree line segment intersection, n-layer map overlay, -connectivity graph extraction and clipping/Booleans.  These algorithms have O(n log n) -runtime complexity for n equal to input vertices plus intersection vertices.  The -arbitrary angle line segment intersection algorithm is not implemented as a -sweep-line due to complications related to achieving numerical robustness.  -The general line segment intersection algorithm is implemented as an recursive -adaptive heuristic divide and conquer in the y dimension followed by sorting -line segments in each subdivision by x coordinates and scanning left to right.  -By one-dimensional decomposition of the problem space in both x and y the -algorithm approximates the optimal O(n log n) Bentley-Ottmann line segment intersection -runtime complexity in the common case.  Specific examples of inputs that -defeat one dimensional decomposition of the problem space can result in -pathological quadratic runtime complexity to which the Bentley-Ottmann algorithm -is immune.

        -

        Below is shown a log-log plot of runtime versus input size for inputs that -increase quadratically in size.  The inputs were generated by -pseudo-randomly distributing small axis-parallel rectangles within a square area -proportional the the number of rectangles specified for each trial.  In -this way the probability of intersections being produced remains constant as the -input size grows.  Because intersection vertices are expected to be a -constant factor of input vertices we can examine runtime complexity in terms of -input vertices.  The operation performed was a union (Boolean OR) of the -input rectangles by each of the Manhattan, 45-degree and arbitrary angle -Booleans algorithms, which are labeled "boolean 90", "boolean 45" and "boolean".  -Also shown in the plot is the performance of the arbitrary angle Booleans -algorithm as prior to the addition of divide and conquer recursive subdivision, -which was described in the paper -presented at -boostcon 2009.  Finally, the -time required to sort the input points is shown as a common reference for O(n log n) -runtime to put the data into context.

        -We can see in the log-log plot that sorting and the three Booleans algorithms -provided by the Boost.Polygon library have nearly 45 degree "linear" -scaling with empirical exponents just slightly larger than 1.0 and can be -observed to scale proportional to O(n log n) for -these inputs.  The "old boolean" algorithm presented at boostcon 2009 -exhibits scaling close to the expected O(n1.5) -scaling.  Because the speedup provided by the divide and conquer approach -is algorithmic, the 10X potential performance improvement alluded to in the paper is -realized at inputs of 200,000 rectangles and larger.  Even for small inputs -of 2K rectangles the algorithm is 2X faster and now can be expected to be -roughly as fast as GPC at small scales, -while algorithmically faster at large scales.

        -

        - - -From the plot we can compare the constant factor performance of the various -Booleans algorithms with the runtime of std::sort as a baseline for O(n log n) -algorithms.  If you consider sort to be one unit of O(n log n) algorithmic -work we can see that Manhattan Booleans cost roughly five units of O(n log n) -work, 45-degree  Booleans cost roughly - - -ten units of O(n log n) work and arbitrary angle Booleans cost roughly -seventy units of O(n log n) work.  Sorting the input vertices is the first -step in a Booleans algorithm and therefore provides a hard lower bound for the -runtime of an optimal Booleans algorithm.

        - - -One final thing to note about performance of the arbitrary angle Booleans -algorithm is that the use of GMP - infinite precision rational data type for numerically robust -computations can be employed by including boost/polygon/gmp_override.hpp and linking -to lgmpxx and lgmp.  This provides -100% assurance that the algorithm will succeed and produce an output snapped to -the integer grid with a minimum of one integer grid of error on polygon -boundaries upon which intersection points are introduced.  However, the -infinite precision data type is never used for predicates (see the boostcon -presentation or paper for description of robust predicates) and is only used for -constructions of intersection coordinate values in the very rare case that long -double computation of the intersection of two line segments fails to produce an -intersection point within one integer unit of both line segments.  This -means that there is effectively no runtime penalty for the use of infinite -precision to ensure 100% robustness.  Most inputs will process through the -algorithm without ever resorting to GMP.

        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
      +
      + + +
      +
      +

      +

      +

      Polygon Set Algorithms Analysis

      +

      Most non-trivial algorithms in the Boost.Polygon library are +instantiations of generic sweep-line algorithms that provide the +capability to perform Manhattan and 45-degree line segment +intersection, n-layer map overlay, connectivity graph extraction and +clipping/Booleans.  These algorithms have O(n log n) runtime +complexity for n equal to input vertices plus intersection +vertices.  The arbitrary angle line segment intersection algorithm +is not implemented as a sweep-line due to complications related to +achieving numerical robustness.  The general line segment +intersection algorithm is implemented as an recursive adaptive +heuristic divide and conquer in the y dimension followed by sorting +line segments in each subdivision by x coordinates and scanning left to +right.  By one-dimensional decomposition of the problem space in +both x and y the algorithm approximates the optimal O(n log n) +Bentley-Ottmann line segment intersection runtime complexity in the +common case.  Specific examples of inputs that defeat one +dimensional decomposition of the problem space can result in +pathological quadratic runtime complexity to which the Bentley-Ottmann +algorithm is immune.

      +

      Below is shown a log-log plot of runtime versus input size for +inputs that increase quadratically in size.  The inputs were +generated by pseudo-randomly distributing small axis-parallel +rectangles within a square area proportional the the number of +rectangles specified for each trial.  In this way the probability +of intersections being produced remains constant as the input size +grows.  Because intersection vertices are expected to be a +constant factor of input vertices we can examine runtime complexity in +terms of input vertices.  The operation performed was a union +(Boolean OR) of the input rectangles by each of the Manhattan, +45-degree and arbitrary angle Booleans algorithms, which are labeled +"boolean 90", "boolean 45" and "boolean".  Also shown in the plot +is the performance of the arbitrary angle Booleans algorithm as prior +to the addition of divide and conquer recursive subdivision, which was +described in the paper presented at + boostcon 2009.  +Finally, the time required to sort the input points is shown as a +common reference for O(n log n) runtime to put the data into context.

      + +

      We can see in the log-log plot that sorting and the three +Booleans algorithms provided by the Boost.Polygon library have nearly +45 degree "linear" scaling with empirical exponents just slightly +larger than 1.0 and can be observed to scale proportional to O(n log n) +for these inputs.  The "old boolean" algorithm presented at +boostcon 2009 exhibits scaling close to the expected O(n1.5) scaling.  Because the speedup provided +by the divide and conquer approach is algorithmic, the 10X potential +performance improvement alluded to in the paper is realized at inputs +of 200,000 rectangles and larger.  Even for small inputs of 2K +rectangles the algorithm is 2X faster and now can be expected to be +roughly as fast as GPC +at small scales, while algorithmically faster at large scales.

      +

      +From the plot we can compare the constant factor performance of the +various Booleans algorithms with the runtime of std::sort as a baseline +for O(n log n) algorithms.  If you consider sort to be one unit of +O(n log n) algorithmic work we can see that Manhattan Booleans cost +roughly five units of O(n log n) work, 45-degree  Booleans cost +roughly +ten units of O(n log n) work and arbitrary angle Booleans cost roughly +seventy units of O(n log n) work.  Sorting the input vertices is +the first step in a Booleans algorithm and therefore provides a hard +lower bound for the runtime of an optimal Booleans algorithm.

      +

      One final thing to note about performance of the arbitrary +angle Booleans algorithm is that the use of GMP +infinite precision rational data type for numerically robust +computations can be employed by including +boost/polygon/gmp_override.hpp and linking to lgmpxx and lgmp.  +This provides 100% assurance that the algorithm will succeed and +produce an output snapped to the integer grid with a minimum of one +integer grid of error on polygon boundaries upon which intersection +points are introduced.  However, the infinite precision data type +is never used for predicates (see the boostcon presentation or paper +for description of robust predicates) and is only used for +constructions of intersection coordinate values in the very rare case +that long double computation of the intersection of two line segments +fails to produce an intersection point within one integer unit of both +line segments.  This means that there is effectively no runtime +penalty for the use of infinite precision to ensure 100% +robustness.  Most inputs will process through the algorithm +without ever resorting to GMP.

      +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_connectivity_extraction.htm b/doc/gtl_connectivity_extraction.htm index 2e52962..738cfa5 100644 --- a/doc/gtl_connectivity_extraction.htm +++ b/doc/gtl_connectivity_extraction.htm @@ -1,159 +1,185 @@ - + + Boost Polygon Library: Connectivity Extraction 45 - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_connectivity_extraction_45.htm b/doc/gtl_connectivity_extraction_45.htm index 3d54bad..121a8a3 100644 --- a/doc/gtl_connectivity_extraction_45.htm +++ b/doc/gtl_connectivity_extraction_45.htm @@ -1,159 +1,185 @@ - + + Boost Polygon Library: Connectivity Extraction 45 - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_connectivity_extraction_90.htm b/doc/gtl_connectivity_extraction_90.htm index f2f7be9..fedc4e6 100644 --- a/doc/gtl_connectivity_extraction_90.htm +++ b/doc/gtl_connectivity_extraction_90.htm @@ -1,159 +1,185 @@ - + + Boost Polygon Library: Connectivity Extraction 90 - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_coordinate_concept.htm b/doc/gtl_coordinate_concept.htm index ae5d3bb..1afa070 100644 --- a/doc/gtl_coordinate_concept.htm +++ b/doc/gtl_coordinate_concept.htm @@ -1,102 +1,114 @@ -Boost Polygon Library: Coordinate Concept - - - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Coordinate Concept + + + + + + + + - + - -
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Coordinate Concept

        - -

        -The coordinate concept tag is -coordinate_concept

        -To register a user defined type as a model of coordinate concept, specialize the -geometry concept meta-function for that type.  In the example below -CCoordinate is registered as a model of coordinate concept.

        -template <>
        -struct geometry_concept<CCoordinate> { typedef coordinate_concept type; };

        -The coordinate type is expected to be integral and built-in numerical data types -such as float and int already have concept type traits specializations in the -library.  In the coordinate traits are type definitions for related types -are provided to allow the library to choose the best type to cast to under -various circumstances.  The definition of coordinate_traits and its -specialization for int are shown below.

        -template <typename T>
        +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Coordinate Concept

        +

        The coordinate concept tag is +coordinate_concept

        +

        To register a user defined type as a model of coordinate +concept, specialize the geometry concept meta-function for that +type.  In the example below CCoordinate is registered as a model +of coordinate concept.

        +

        template <>
        +struct geometry_concept<CCoordinate> { typedef coordinate_concept +type; };

        +

        The coordinate type is expected to be integral and built-in +numerical data types such as float and int already have concept type +traits specializations in the library.  In the coordinate traits +are type definitions for related types are provided to allow the +library to choose the best type to cast to under various +circumstances.  The definition of coordinate_traits and its +specialization for int are shown below.

        +

        template <typename T>
        struct coordinate_traits {};
        -
        +
        template <>
        struct coordinate_traits<int> {
             typedef int coordinate_type;
        @@ -105,58 +117,71 @@ struct coordinate_traits<int> {
             typedef unsigned long long unsigned_area_type;
             typedef long long coordinate_difference;
             typedef long double coordinate_distance;
        -};

        -By making use of the coordinate traits of int the library is able to avoid -overflow and handle the normal issues encountered when programming integer -geometry.  For the out of the ordinary issues there is a special -meta-function that provides the library with a numerical type suitable for exact -numerical calculations.  It defaults to the highest precision data type -available in most compilers, long double, but can be overridden by specializing -for a particular coordinate type.  Use of gmp multi-precision rational or -similar data type is recommended for numerically robust calculations in the -general polygon algorithms.

        -template <typename T>
        +};

        +

        By making use of the coordinate traits of int the library is +able to avoid overflow and handle the normal issues encountered when +programming integer geometry.  For the out of the ordinary issues +there is a special meta-function that provides the library with a +numerical type suitable for exact numerical calculations.  It +defaults to the highest precision data type available in most +compilers, long double, but can be overridden by specializing for a +particular coordinate type.  Use of gmp multi-precision rational +or similar data type is recommended for numerically robust calculations +in the general polygon algorithms.

        +

        template <typename T>
        struct high_precision_type {
             typedef long double type;
        -};

        -There is only one generic function on coordinate concepts, Euclidean distance.

        -template <typename coordinate_type_1, typename -coordinate_type_2>
        -coordinate_difference euclidean_distance(coordinate_type_1, coordinate_type_2)

        -This function returns the absolution value of the difference between the two -coordinates.

        -Note: older versions of the stl define a fully generic distance(T, T) function -for computing the difference between two iterators.  We were forced to name -our distance function euclidean_distance to avoid name collision.

        -The - -Algorithmic C ac_int<128> is an example of a user defined coordinate data -type that satisfies the coordinate concept.  In general a data type should -define std::numeric_limits and be integer-like.  Floating point coordinate -types are not supported by all the algorithms and generally not suitable for use -with the library at present.

        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +};

        +

        There is only one generic function on coordinate concepts, +Euclidean distance.

        +

        template <typename +coordinate_type_1, typename coordinate_type_2>
        +coordinate_difference euclidean_distance(coordinate_type_1, +coordinate_type_2)

        +

        This function returns the absolution value of the difference +between the two coordinates.

        +

        Note: older versions of the stl define a fully generic +distance(T, T) function for computing the difference between two +iterators.  We were forced to name our distance function +euclidean_distance to avoid name collision.

        +

        The + +Algorithmic C ac_int<128> is an example of a user defined +coordinate data type that satisfies the coordinate concept.  In +general a data type should define std::numeric_limits and be +integer-like.  Floating point coordinate types are not supported +by all the algorithms and generally not suitable for use with the +library at present.

        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_custom_point.htm b/doc/gtl_custom_point.htm index f05f302..6aca7ed 100644 --- a/doc/gtl_custom_point.htm +++ b/doc/gtl_custom_point.htm @@ -1,11 +1,8 @@ - + + - - -Custom Point - - +Custom Point

      /*
      Copyright 2008 Intel Corporation
      @@ -95,7 +92,11 @@ return point.y;
          };
         
          template <>
          -struct point_mutable_traits<CPoint> {
          +struct point_mutable_traits<CPoint> {
      +        typedef int coordinate_type;
      +
      +

      +

              static inline void set(CPoint& point, orientation_2d orient, int value) {
              @@ -137,11 +138,12 @@ return 0;
      }
           

      - + +
      - + @@ -154,8 +156,6 @@ return 0;
      }
          http://www.boost.org/LICENSE_1_0.txt) -
      Copyright: Copyright © Intel Corporation 2008-2010.
      +
      - - - + \ No newline at end of file diff --git a/doc/gtl_design_overview.htm b/doc/gtl_design_overview.htm index 769d245..a5feed6 100644 --- a/doc/gtl_design_overview.htm +++ b/doc/gtl_design_overview.htm @@ -1,194 +1,224 @@ - + + Boost Polygon Library: Overview - - - - - + + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • - Point Concept
      • +--> + Boost Polygon Library: Overview + + + + + + + + - - -
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon Library Design Overview

        - -

        -

        The Polygon library uses C++-Concepts inspired template programming to -provide generic library functions overloaded on concept type.  There are -currently thirteen concepts in the Polygon library type system.  A concept -object in the Polygon library is just an empty struct similar to a tag that -would be used for tag dispatching.   These concepts are shown in the -refinement diagram below.

        - - -

        -The arrows between diagram bubbles show concept refinement relationships.  This is -similar, but not identical to, inheritance relationships between normal classes.  -A refinement of a concept narrows down the definition of a more general concept.  -For example, the rectangle concept is a refinement of a polygon concept because -it restricts the polygon to a four sided, axis-parallel, rectilinear figure.  A refinement -of a concept is always acceptable to an API that expects read only access to a -given concept, but never acceptable to an API that expects to write to that -concept.  There are three types of geometry in the polygon library, the -general case, the case restricted to angles that are multiples of 45 degrees, -and the Manhattan/rectilinear case where angles are restricted to multiples of -90 degrees.   The refinement diagram shows that 90 degree concepts are -refinements of 45 degree concepts, which are themselves refinements of the -general case.  This allows the compiler to choose between the three -implementations of algorithms to select the best algorithm for the conceptual -data types passed to an overload of a function including heterogeneous -combinations of 90, 45 and general case geometry.  To provide the -operator& that performs the intersection on any -pair of objects from the ten conceptual types related to each other through -refinement in the diagraph above fully one hundred distinct combinations of -conceptual types are supported by the library, but only three overloads are -required to implement the operator (one for 90, one for 45 and one for arbitrary -angle version of the intersection operation) because refinement generalizes the -implementation of the interface.  In this way a fully symmetric, complete -and internally consistent API is implemented to provide meaningful and correct -behaviors for all combinations of argument types in all APIs where those types -make sense.  For example, it doesn't make sense to copy data from a polygon -into a rectangle, so attempting to do so yields a syntax error, while copying a -rectangle into a polygon does make sense.  The -assign() function that is used to copy geometry data between concepts -instantiates for the 49 combinations of concepts that make sense, but not for -the 51 combinations that are illegal.  The syntax error you will see when -attempting an illegal assign operation is simple and clear because use of SFINAE -by the library to overload generic functions means no matching function is found -by the compiler in cases where no overload is provided.

        -

        -error: no matching function for call to 'assign(rectangle_data<int>&, -polygon_data<int>&)'

        -

        Associated with each concept is a traits struct that generally must be -specialized for a given data type to provide the concept mapping between the -interfaces of the data type and the expected behaviors of an object of that type -required by the library.  The library also provides its own data types for -each concept that conform to the default traits definition.  These library -provided data types are no more than dumb containers that provide access to -their data and rely on the generic library functions to enforce invariants and -provide useful behaviors specific to their type of geometry that would normally -be member functions of the data type in an OO design.  The library data -types conform to the default traits associated with their related geometry -concept and are registered as models of that concept.  When a data -type has been mapped to a concept through traits it needs to be registered -as that conceptual type with the library by -specializing the geometry_concept meta-function.  Once mapped and -registered, a user data type can be used interchangeably with library data types -in the generic free functions that are overloaded on concept.

        Traits for -mapping a data type to a concept are broken down into mutable and read only -traits.  Read only traits are specialized internally to work with any types -that are refinements of a concept.  The mutable traits are defined only for -objects that exactly model the concept.  Both read only traits and mutable -traits need to be defined for a type to model a concept, but a type can be used -without defining the mutable traits as long as no API that needs to modify the -object is used with that type.  For example, a triangle type could be -registered as a polygon_concept and the read only traits but not the mutable -traits defined for that triangle type.  This would allow the triangle type -to be passed into any API that expects a const reference to an object that models -polygon.  -

        An object that is a model of a given concept can usually be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restrictions of -those concepts.  This concept casting is accomplished through the -view_as<>() function.  For example if -an object of conceptual type polygon 90 has four sides it must be a rectangle, -and can be viewed as a rectangle with the following syntax:

        -

        view_as<rectangle_concept>(polygon_90_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.  The exception to this ability to -concept cast geometric objects is that polygon set objects cannot be viewed as -individual polygons or rectangles.

        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
      • Voronoi Advanced +Tutorial
      • +
      +
      + + +
      +
      +

      +

      +

      Polygon Library Design Overview

      +

      +

      The Polygon library uses C++-Concepts inspired template +programming to provide generic library functions overloaded on concept +type.  There are currently thirteen concepts in the Polygon +library type system.  A concept object in the Polygon library is +just an empty struct similar to a tag that would be used for tag +dispatching.   These concepts are shown in the refinement +diagram below.

      + +

      The arrows between diagram bubbles show concept refinement +relationships.  This is similar, but not identical to, inheritance +relationships between normal classes.  A refinement of a concept +narrows down the definition of a more general concept.  For +example, the rectangle concept is a refinement of a polygon concept +because it restricts the polygon to a four sided, axis-parallel, +rectilinear figure.  A refinement of a concept is always +acceptable to an API that expects read only access to a given concept, +but never acceptable to an API that expects to write to that +concept.  There are three types of geometry in the polygon +library, the general case, the case restricted to angles that are +multiples of 45 degrees, and the Manhattan/rectilinear case where +angles are restricted to multiples of 90 degrees.   The +refinement diagram shows that 90 degree concepts are refinements of 45 +degree concepts, which are themselves refinements of the general +case.  This allows the compiler to choose between the three +implementations of algorithms to select the best algorithm for the +conceptual data types passed to an overload of a function including +heterogeneous combinations of 90, 45 and general case geometry.  +To provide the + operator& that performs the +intersection on any pair of objects from the ten conceptual types +related to each other through refinement in the diagraph above fully +one hundred distinct combinations of conceptual types are supported by +the library, but only three overloads are required to implement the +operator (one for 90, one for 45 and one for arbitrary angle version of +the intersection operation) because refinement generalizes the +implementation of the interface.  In this way a fully symmetric, +complete and internally consistent API is implemented to provide +meaningful and correct behaviors for all combinations of argument types +in all APIs where those types make sense.  For example, it doesn't +make sense to copy data from a polygon into a rectangle, so attempting +to do so yields a syntax error, while copying a rectangle into a +polygon does make sense.  The +assign() function that is used to copy geometry data between +concepts instantiates for the 49 combinations of concepts that make +sense, but not for the 51 combinations that are illegal.  The +syntax error you will see when attempting an illegal assign operation +is simple and clear because use of SFINAE by the library to overload +generic functions means no matching function is found by the compiler +in cases where no overload is provided.

      +

      + error: no matching function for call to +'assign(rectangle_data<int>&, polygon_data<int>&)'

      +

      Associated with each concept is a traits struct that generally +must be specialized for a given data type to provide the concept +mapping between the interfaces of the data type and the expected +behaviors of an object of that type required by the library.  The +library also provides its own data types for each concept that conform +to the default traits definition.  These library provided data +types are no more than dumb containers that provide access to their +data and rely on the generic library functions to enforce invariants +and provide useful behaviors specific to their type of geometry that +would normally be member functions of the data type in an OO +design.  The library data types conform to the default traits +associated with their related geometry concept and are registered as +models of that concept.  When a data type has been mapped to a +concept through traits it needs to be registered as that conceptual +type with the library by specializing the geometry_concept +meta-function.  Once mapped and registered, a user data type can +be used interchangeably with library data types in the generic free +functions that are overloaded on concept.

      +

      Traits for mapping a data type to a concept are broken down +into mutable and read only traits.  Read only traits are +specialized internally to work with any types that are refinements of a +concept.  The mutable traits are defined only for objects that +exactly model the concept.  Both read only traits and mutable +traits need to be defined for a type to model a concept, but a type can +be used without defining the mutable traits as long as no API that +needs to modify the object is used with that type.  For example, a +triangle type could be registered as a polygon_concept and the read +only traits but not the mutable traits defined for that triangle +type.  This would allow the triangle type to be passed into any +API that expects a const reference to an object that models +polygon. 

      +

      An object that is a model of a given concept can usually be +viewed as a model of any of its refinements if it is determined at +runtime to conform to the restrictions of those concepts.  This +concept casting is accomplished through the + view_as<>() function.  +For example if an object of conceptual type polygon 90 has four sides +it must be a rectangle, and can be viewed as a rectangle with the +following syntax:

      +

      view_as<rectangle_concept>(polygon_90_object)

      +

      The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.  The +exception to this ability to concept cast geometric objects is that +polygon set objects cannot be viewed as individual polygons or +rectangles.

      +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_interval_concept.htm b/doc/gtl_interval_concept.htm index e690d84..8eb4d00 100644 --- a/doc/gtl_interval_concept.htm +++ b/doc/gtl_interval_concept.htm @@ -1,555 +1,620 @@ - + + Boost Polygon Library: Interval Concept - - - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Interval Concept + + + + + + + + - + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Interval Concept

        - -

        -

        The interval concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Interval Concept

        +

        +

        The interval concept tag is interval_concept

        -

        -To register a user defined type as a model of interval concept, specialize the -geometry concept meta-function for that type.  In the example below -CInterval is registered as a model of interval  concept.

        -template <>
        -struct geometry_concept<CInterval> { typedef interval_concept type; };

        -The semantic of an interval is that it has a low -and high coordinate and there is an invariant that low is less than or equal to -high.  This invariant is enforced by the generic library functions that -operate on intervals, and is not expected of the data type itself or the concept -mapping of that data type to the interval concept through its traits.  In -this way a std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> -could all be made models of interval by simply providing indirect access to their -elements through traits.

        -Below is shown the default interval traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.

        -template <typename T>
        +

        To register a user defined type as a model of interval +concept, specialize the geometry concept meta-function for that +type.  In the example below CInterval is registered as a model of +interval  concept.

        +

        template <>
        +struct geometry_concept<CInterval> { typedef interval_concept +type; };

        +

        The semantic of an interval is +that it has a low and high coordinate and there is an invariant that +low is less than or equal to high.  This invariant is enforced by +the generic library functions that operate on intervals, and is not +expected of the data type itself or the concept mapping of that data +type to the interval concept through its traits.  In this way a +std::pair<int, int>, boost::tuple<int, int> or +boost::array<int, 2> could all be made models of interval by +simply providing indirect access to their elements through traits.

        +

        Below is shown the default +interval traits.  Specialization of these traits is required for +types that don't conform to the default behavior.

        +

        template <typename T>
        struct interval_traits {
          typedef typename T::coordinate_type coordinate_type;
        -
        -  static inline coordinate_type get(const T& interval, direction_1d dir) {
        +
        +  static inline coordinate_type get(const T& interval, +direction_1d dir) {
            return interval.get(dir);
          }
        };
        -
        +
        template <typename T>
        struct interval_mutable_traits {
        typedef typename +T::coordinate_type coordinate_type;
        +
          static inline void set(T& interval, direction_1d dir,
        -
        -                         +
        +                          typename interval_traits<T>::coordinate_type value) {
            interval.set(dir, value);
          }
          -static inline T construct(typename interval_traits<T>::coordinate_type low_value, -
        +static inline T construct(typename +interval_traits<T>::coordinate_type low_value, +
                                    typename interval_traits<T>::coordinate_type high_value) {
            return T(low_value, high_value);
          }
        -};

        Functions

        - - - - - -
        template <typename T>
        - coordinate_type get(const T& interval, direction_1d)
        Expects a model of interval.  - Returns the low or high coordinate of the interval, depending on the - direction_1d value.
        +};

        +

        Functions

        + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template +<typename T>
        +coordinate_type get(const T& interval, direction_1d)
        Expects a model of +interval.  Returns the low or high coordinate of the interval, +depending on the direction_1d value.
         
        template <typename T, typename - coordinate_type>
        - void set(T& interval, direction_1d, coordinate_type)
        Expects a model of interval.   - Sets the low or high coordinate of the interval to the coordinate, - depending on the direction_1d value.  If low would be greater than - high after this change then both are set to the input coordinate value.
        template <typename T>
        - T construct(coordinate_type low, coordinate_type high)
        Construct an object that is a model of interval given low and high - coordinate values.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models interval into left object - that models interval.
        template <typename T, typename - T2>
        - bool equivalence(const T& interval1, const T2& interval2)
        Given two objects that model interval, compares and returns true if - their low and high values are respectively equal to each other.
        template <typename T>
        - bool contains(const T&, coordinate_type,
        -              - bool consider_touch=true)
        Given an object that models interval and a coordinate, returns true - if the interval contains the coordinate.  If the consider_touch - flag is true will return true if the coordinate is equal to one of the - interval ends.
        template <typename T1, typename - T2>
        - bool contains(const T1& a, const T2& b,
        -              - bool consider_touch = true)
        Returns true if model of interval a contains both ends of model of - interval b.  If the consider_touch flag is true will consider the - end of b contained within a even if it is equal to an end of a.
        template <typename - interval_type>
        - coordinate_type low(const interval_type& interval)
        Returns the low end of an object that models interval.
        template <typename - interval_type>
        - coordinate_type high(const interval_type& interval)
        Returns the high end of an object that models interval.
        // get the center coordinate
        - template <typename interval_type>
        - coordinate_type center(const interval_type& interval)
        Returns the center coordinate of an object that models interval.
        template <typename - interval_type>
        - void low(interval_type& interval, coordinate_type )
        Sets the low end of the object that models interval to the - coordinate value.  If the low end would be set to larger than high - end then both are set to the coordinate value.
        template <typename - interval_type>
        - void high(interval_type& interval, coordinate_type )
        Sets the high end of the object that models interval to the - coordinate value.  If the high end would be set to less than low - end then both are set to the coordinate value.
        template <typename - interval_type>
        - coordinate_difference delta(const interval_type& interval)
        Returns the distance from low to high end of an object that models - interval.
        template <typename - interval_type>
        - interval_type& flip(interval_type& interval,
        -                    - coordinate_type axis = 0)
        Flips an object that models interval about the axis coordinate.  - If no axis is provided the interval is flipped across the the origin.
        template <typename - interval_type>
        - interval_type& scale_up(interval_type& interval,
        +
        template +<typename T, typename coordinate_type>
        +void set(T& interval, direction_1d, coordinate_type)
        Expects a model of +interval.   Sets the low or high coordinate of the interval +to the coordinate, depending on the direction_1d value.  If low +would be greater than high after this change then both are set to the +input coordinate value.
        template +<typename T>
        +T construct(coordinate_type low, coordinate_type high)
        Construct an object that is a model of interval given +low and high coordinate values.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models interval into +left object that models interval.
        template +<typename T, typename T2>
        +bool equivalence(const T& interval1, const T2& +interval2)
        Given two objects that model interval, compares and +returns true if their low and high values are respectively equal to +each other.
        template +<typename T>
        +bool contains(const T&, coordinate_type,
        +              +bool consider_touch=true)
        Given an object that models interval and a coordinate, +returns true if the interval contains the coordinate.  If the +consider_touch flag is true will return true if the coordinate is equal +to one of the interval ends.
        template +<typename T1, typename T2>
        +bool contains(const T1& a, const T2& b,
        +              +bool consider_touch = true)
        Returns true if model of interval a contains both ends +of model of interval b.  If the consider_touch flag is true will +consider the end of b contained within a even if it is equal to an end +of a.
        template +<typename interval_type>
        +coordinate_type low(const interval_type& interval)
        Returns the low end of an object that models interval.
        template +<typename interval_type>
        +coordinate_type high(const interval_type& interval)
        Returns the high end of an object that models interval.
        // get the center +coordinate
        +template <typename interval_type>
        +coordinate_type center(const interval_type& interval)
        Returns the center coordinate of an object that models +interval.
        template +<typename interval_type>
        +void low(interval_type& interval, coordinate_type )
        Sets the low end of the object that models interval to +the coordinate value.  If the low end would be set to larger than +high end then both are set to the coordinate value.
        template +<typename interval_type>
        +void high(interval_type& interval, coordinate_type )
        Sets the high end of the object that models interval to +the coordinate value.  If the high end would be set to less than +low end then both are set to the coordinate value.
        template +<typename interval_type>
        +coordinate_difference delta(const interval_type& interval)
        Returns the distance from low to high end of an object +that models interval.
        template +<typename interval_type>
        +interval_type& flip(interval_type& interval,
        +                    +coordinate_type axis = 0)
        Flips an object that models interval about the axis +coordinate.  If no axis is provided the interval is flipped across +the the origin.
        template +<typename interval_type>
        +interval_type& scale_up(interval_type& interval,
                                unsigned_area_type factor)
        Multiplies low and high ends of an object that models interval by - unsigned factor.
        template <typename - interval_type>
        - interval_type& scale_down(interval_type& interval,
        +
        Multiplies low and high ends of an object that models +interval by unsigned factor.
        template +<typename interval_type>
        +interval_type& scale_down(interval_type& interval,
                                  unsigned_area_type factor)
        Divides low and high ends of an object that models interval by - unsigned factor.
        template <typename - interval_type>
        - interval_type& scale(interval_type& interval,
        -                     - double factor)
        Multiplies low and high ends of an object that models interval by - floating point value.
        template <typename - interval_type>
        - interval_type& move(interval_type& interval,
        -                    - coordinate_difference displacement)
        Adds displacement value to low and high ends of an object that - models interval.
        template <typename - interval_type>
        - interval_type& convolve(interval_type& interval,
        +
        Divides low and high ends of an object that models +interval by unsigned factor.
        template +<typename interval_type>
        +interval_type& scale(interval_type& interval,
        +                     +double factor)
        Multiplies low and high ends of an object that models +interval by floating point value.
        template +<typename interval_type>
        +interval_type& move(interval_type& interval,
        +                    +coordinate_difference displacement)
        Adds displacement value to low and high ends of an +object that models interval.
        template +<typename interval_type>
        +interval_type& convolve(interval_type& interval,
                                coordinate_type b)
        Adds coordinate value to low and high ends of an object that models - interval.
        template <typename - interval_type>
        - interval_type& deconvolve(interval_type& interval,
        +
        Adds coordinate value to low and high ends of an object +that models interval.
        template +<typename interval_type>
        +interval_type& deconvolve(interval_type& interval,
                                  coordinate_type b)
        Subtracts coordinate value from low and high ends of an object that - models interval.
        template <typename T1, typename - T2>
        - T1& convolve(T1& a, const T2& b)
        Adds low end of b to low end of a and adds high end of b to high end - of a.
        template <typename T1, typename - T2>
        - T1& deconvolve(T1& a, const T2& b)
        Subtracts low end of b from low end of a and subtracts high end of b - from high end of a.
        template <typename T1, typename - T2>
        - T1& reflected_convolve(T1& a, const T2& b)
        Adds high end of b to low end of a and adds low end of b to high end - of a.
        template <typename T1, typename - T2>
        - T1& reflected_deconvolve(T1& a, const T2& b)
        Subtracts high end of b from low end of a and subtracts low end of b - from high end of a.
        template <typename T>
        - coordinate_difference euclidean_distance(const T&,
        -                      - coordinate_type)
        Returns the distance from an object that models interval to a - coordinate.  Returns zero if the coordinate is equal to an end of - the interval or contained within the interval.
        template <typename T1, typename - T2>
        - bool intersects(const T1& interval, const T2& b,
        -                - bool consider_touch = true)
        Returns true if two objects that model interval overlap.  If - the consider_touch flag is true touching at the endpoints is considered - overlap.
        template <typename T1, typename - T2>
        - bool boundaries_intersect(const T1& interval, const T2& b,
        +
        Subtracts coordinate value from low and high ends of an +object that models interval.
        template +<typename T1, typename T2>
        +T1& convolve(T1& a, const T2& b)
        Adds low end of b to low end of a and adds high end of +b to high end of a.
        template +<typename T1, typename T2>
        +T1& deconvolve(T1& a, const T2& b)
        Subtracts low end of b from low end of a and subtracts +high end of b from high end of a.
        template +<typename T1, typename T2>
        +T1& reflected_convolve(T1& a, const T2& b)
        Adds high end of b to low end of a and adds low end of +b to high end of a.
        template +<typename T1, typename T2>
        +T1& reflected_deconvolve(T1& a, const T2& b)
        Subtracts high end of b from low end of a and subtracts +low end of b from high end of a.
        template +<typename T>
        +coordinate_difference euclidean_distance(const T&,
        +                      +coordinate_type)
        Returns the distance from an object that models +interval to a coordinate.  Returns zero if the coordinate is equal +to an end of the interval or contained within the interval.
        template +<typename T1, typename T2>
        +bool intersects(const T1& interval, const T2& b,
        +                +bool consider_touch = true)
        Returns true if two objects that model interval +overlap.  If the consider_touch flag is true touching at the +endpoints is considered overlap.
        template +<typename T1, typename T2>
        +bool boundaries_intersect(const T1& interval, const T2& +b,
                                  bool consider_touch = true)
        Returns true is two objects that model interval partially overlap - such that one end point of each is contained within the other.  If - the consider_touch flag is true a coordinate is considered contained - even if it is equal to an end.
        template <typename T1, typename - T2>
        - bool abuts(const T1& a, const T2& b,
        -           direction_1d dir) -
        Returns true if interval b abuts but down not overlap interval a on - the end of interval a specified by dir.
        template <typename T1, typename - T2>
        - bool abuts(const T1& a, const T2& b)
        Returns true if interval b abuts but down not overlap interval a.
        template <typename T1, typename - T2>
        - bool intersect(T1& a, const T2& b,
        -               - bool consider_touch = true)
        Sets interval a to the intersection of interval a and interval b and - return true.  If the two intervals do not intersect interval a is - unchanged and the function returns false.  If the flag - consider_touch is true intervals that abut are considered to intersect.
        template <typename T1, typename - T2>
        - T& generalized_intersect(T1& a, const T2& b)
        Same as intersect, but if they do not intersect set a to the - interval between a and b.
        template <typename T>
        - T& bloat(T& interval, coordinate_type)
        Adds the coordinate value to high end of interval and subtracts it - from low end of interval.
        template <typename T>
        - T& bloat(T& interval, direction_1d, coordinate_type)
        Adds the coordinate value to high end of interval or subtracts it - from low end of interval depending on the direction_1d.
        template <typename T>
        - T& shrink(T& interval, coordinate_type)
        Subtracts the coordinate value from high end of interval and adds it - to low end of interval.
        template <typename T>
        - T& shrink(T& interval, direction_1d, coordinate_type)
        Subtracts the coordinate value from high end of interval or adds it - to low end of interval depending on the direction_1d.
        template <typename T1, typename - T2>
        - bool encompass(T1& a, const T2& b)
        Sets low of a to min of low of a and low of b and sets high of a to - max of high of a and high of b.  Returns true if b was not - contained within a to begin with.
        template <typename T>
        - bool encompass(T& a, coordinate_type)
        Sets low of a to min of low of a and coordinate value and sets high - of a to max of high of a and coordinate value.  Returns true if - coordinate value was not contained within a to begin with.
        -

        Interval Data

        - -

        -

        The library provides a model of interval concept declared - -template<typename T> interval_data where T is the coordinate type.

        -

        This data type is used internally when an interval is needed and is available -to the library user who finds it convenient to use a library interval data type -instead of providing their own.  The data type is implemented to be -convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typeinterval_concept
        coordinate_typeT
        interval_data()Default constructs the two coordinate - values of the interval.
        interval_data(T low, T - high)Constructs an interval with two - coordinates.
        interval_data(const - interval_data& that)Copy construct
        interval_data& operator=(const - interval_data& that)Assignment operator.
        template <typename IntervalType>  -
        interval_data& operator=(
        const IntervalType& that) const
        Assign from an object that is a model of interval.
        bool - operator==(const interval_data& that) constEquality operator overload.
        bool - operator!=(const interval_data& that) constInequality operator overload.
        bool - operator<(const interval_data& that) constCompares low coordinates then high coordinates to break ties.
        bool - operator<=(const interval_data& that) constCompares low coordinates then high coordinates to break ties.
        bool - operator>(const interval_data& that) constCompares low coordinates then high coordinates to break ties.
        bool - operator>=(const interval_data& that) constCompares low coordinates then high coordinates to break ties.
        T get(direction_1d dir) - constGet the coordinate in the given direction.
        T low() constReturns true is two objects that model interval +partially overlap such that one end point of each is contained within +the other.  If the consider_touch flag is true a coordinate is +considered contained even if it is equal to an end.
        template +<typename T1, typename T2>
        +bool abuts(const T1& a, const T2& b,
        +           +direction_1d dir)
        Returns true if interval b abuts but down not overlap +interval a on the end of interval a specified by dir.
        template +<typename T1, typename T2>
        +bool abuts(const T1& a, const T2& b)
        Returns true if interval b abuts but down not overlap +interval a.
        template +<typename T1, typename T2>
        +bool intersect(T1& a, const T2& b,
        +               +bool consider_touch = true)
        Sets interval a to the intersection of interval a and +interval b and return true.  If the two intervals do not intersect +interval a is unchanged and the function returns false.  If the +flag consider_touch is true intervals that abut are considered to +intersect.
        template +<typename T1, typename T2>
        +T& generalized_intersect(T1& a, const T2& b)
        Same as intersect, but if they do not intersect set a +to the interval between a and b.
        template +<typename T>
        +T& bloat(T& interval, coordinate_type)
        Adds the coordinate value to high end of interval and +subtracts it from low end of interval.
        template +<typename T>
        +T& bloat(T& interval, direction_1d, coordinate_type)
        Adds the coordinate value to high end of interval or +subtracts it from low end of interval depending on the direction_1d.
        template +<typename T>
        +T& shrink(T& interval, coordinate_type)
        Subtracts the coordinate value from high end of +interval and adds it to low end of interval.
        template +<typename T>
        +T& shrink(T& interval, direction_1d, coordinate_type)
        Subtracts the coordinate value from high end of +interval or adds it to low end of interval depending on the +direction_1d.
        template +<typename T1, typename T2>
        +bool encompass(T1& a, const T2& b)
        Sets low of a to min of low of a and low of b and sets +high of a to max of high of a and high of b.  Returns true if b +was not contained within a to begin with.
        template +<typename T>
        +bool encompass(T& a, coordinate_type)
        Sets low of a to min of low of a and coordinate value +and sets high of a to max of high of a and coordinate value.  +Returns true if coordinate value was not contained within a to begin +with.
        +

        Interval Data

        +

        +

        The library provides a model of interval concept declared + template<typename T> interval_data + where T is the coordinate type.

        +

        This data type is used internally when an interval is needed +and is available to the library user who finds it convenient to use a +library interval data type instead of providing their own.  The +data type is implemented to be convenient to use with the library +traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - + + + + + + - + - -
        geometry_typeinterval_concept
        coordinate_typeT
        interval_data()Default constructs the two +coordinate values of the interval.
        interval_data(T +low, T high)Constructs an interval +with two coordinates.
        interval_data(const +interval_data& that)Copy construct
        interval_data& + operator=(const interval_data& that)Assignment operator.
        template +<typename IntervalType> 
        +
        interval_data& operator=(
        const IntervalType& +that) const
        Assign from an object that is a model of interval.
        bool +operator==(const interval_data& that) constEquality operator overload.
        bool operator!=(const + interval_data& that) constInequality operator overload.
        bool +operator<(const interval_data& that) constCompares low coordinates then high coordinates to break +ties.
        bool +operator<=(const interval_data& that) constCompares low coordinates then high coordinates to break +ties.
        bool +operator>(const interval_data& that) constCompares low coordinates then high coordinates to break +ties.
        bool +operator>=(const interval_data& that) constCompares low coordinates then high coordinates to break +ties.
        T get(direction_1d +dir) constGet the coordinate in the given direction.
        T + low() const Retrieves the low value.
        T high() constRetrieves the high endpoint.T + high() constRetrieves the high +endpoint.
        void set(direction_1d - dir, T value)Sets the coordinate in the given direction to the value.
        interval_data& low(T value)
        void set(direction_1d +dir, T value)Sets the coordinate in the given direction to the value.
        interval_data& + low(T value) Sets the low value.
        interval_data& high(T value)interval_data& + high(T value) Sets the high value.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_isotropy.htm b/doc/gtl_isotropy.htm index 778eb83..6f832d0 100755 --- a/doc/gtl_isotropy.htm +++ b/doc/gtl_isotropy.htm @@ -1,152 +1,174 @@ - + + Boost Polygon Library: Isotropy - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Isotropy + + + + + + + + - + + + + + + + + + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Isotropy

        - -

        -

        What is isotropy?

        - -
        -

        - Isotropy - Function: adjective Etymology: International - Scientific Vocabulary
        - : exhibiting properties (as velocity of light transmission) with the - same values when measured along axes in all directions <an isotropic - crystal>

        -

        In computational geometry things are often symmetric and -invariant to direction and orientation.  This invariance to direction is -called isotropy.  In such situations it is convenient to parameterize -direction or orientation and write code that is invariant to the direction or -orientation in which it is applied.  To do this effectively we provide an -internally consistent set of isotropic data types to represent program -data that describes orientations and directions.  These data types are:

        -
          -
        • direction_1d - has one of the following 2 states: LOW, HIGH
        • -
        • orientation_2d - has one of the following 2 states: HORIZONTAL, - VERTICAL
        • -
        • direction_2d - has one of the following 4 states: WEST, EAST, SOUTH, - NORTH
        • -
        • orientation_3d - has one of the following 3 states: HORIZONTAL, - VERTICAL, PROXIMAL
        • -
        • direction_3d - has one of the following 6 states: WEST, EAST, SOUTH, - NORTH, DOWN, UP
        • -
        - -

        The isotropic types create a system and interact with each other -in various ways, such as casting.  Together they create a language for -describing isotropic situations programmatically.  For instance, to get the -positive direction_2d from an orientation_2d you would call a member function of +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Isotropy

        +

        +

        What is isotropy?

        + + +
        +

        Isotropy - +Function: adjective Etymology: International Scientific +Vocabulary
        + : exhibiting properties (as velocity of light +transmission) with the same values when measured along axes in all +directions <an isotropic crystal>

        +
        +

        In computational geometry things are often +symmetric and invariant to direction and orientation.  This +invariance to direction is called isotropy.  In such situations it +is convenient to parameterize direction or orientation and write code +that is invariant to the direction or orientation in which it is +applied.  To do this effectively we provide an internally +consistent set of isotropic data types to represent program data that +describes orientations and directions.  These data types are:

        +
          +
        • direction_1d - has one of the following 2 states: LOW, HIGH +
        • +
        • orientation_2d - has one of the following 2 states: +HORIZONTAL, VERTICAL
        • +
        • direction_2d - has one of the following 4 states: WEST, +EAST, SOUTH, NORTH
        • +
        • orientation_3d - has one of the following 3 states: +HORIZONTAL, VERTICAL, PROXIMAL
        • +
        • direction_3d - has one of the following 6 states: WEST, +EAST, SOUTH, NORTH, DOWN, UP
        • +
        +

        The isotropic types create a system and interact +with each other in various ways, such as casting.  Together they +create a language for describing isotropic situations +programmatically.  For instance, to get the positive direction_2d +from an orientation_2d you would call a member function of orientation_2d and pass a direction_1d:

        -

        orientation_2d orient = HORIZONTAL;
        +

        orientation_2d orient = +HORIZONTAL;
        direction_2d dir = orient.get_direction(direction_1d(HIGH));
        assert(dir == EAST);

        -

        The motivation for providing isotropic data types is to -encourage programming at a higher level of abstraction where program behavior is -controlled by program data passed into function calls rather than flow control -syntax.  Isotropic programming style is particularly applicable to working -with points, intervals and rectangles.  Often times the implementation of -such logic is identical when implemented for the x or y coordinates, except that -the names of functions and data members are changed in a mechanical way leading -to code duplication and bloat that results in copy-paste programming errors and -maintenance problems where changes made to a given code block relating to x -coordiantes are not duplicated to the code block that refers to y.  -Isotropy therefore represents an opportunity to refactor and improve the quality -of low level geometry code especially in regard to inter-relating coordinates, -points, intervals and rectangles.

        -

        direction_1d

        - -

        -

        The direction_1d data type has two possible states.  These -are the positive and negative directions on a continuum such as the number line.   -These states can be described by one of several direction_1d_enum values:  -We make clockwise and counterclockwise winding orientation of polygons a -direction 1d value instead of providing a separate winding_orientation data -type.  This is because winding orientation can be thought of as positive -and negative directions in a 1d (although cyclic) space.  We assign -counterclockwise to be the positive direction of travel in the 1d cyclic space -to conform with the mathematical convention frequently described as the "right -hand rule" which assigns positive normal value to counterclockwise and negative -normal value to clockwise as well as the common convention that counterclockwise -polygon winding corresponds to positive polygonal regions where as clockwise -polygon winding corresponds to hole (negative) polygonal regions.

        -

        enum direction_1d_enum {LOW = 0, HIGH = -1,
                                +

        The motivation for providing isotropic data types +is to encourage programming at a higher level of abstraction where +program behavior is controlled by program data passed into function +calls rather than flow control syntax.  Isotropic programming +style is particularly applicable to working with points, intervals and +rectangles.  Often times the implementation of such logic is +identical when implemented for the x or y coordinates, except that the +names of functions and data members are changed in a mechanical way +leading to code duplication and bloat that results in copy-paste +programming errors and maintenance problems where changes made to a +given code block relating to x coordiantes are not duplicated to the +code block that refers to y.  Isotropy therefore represents an +opportunity to refactor and improve the quality of low level geometry +code especially in regard to inter-relating coordinates, points, +intervals and rectangles.

        +

        direction_1d

        +

        +

        The direction_1d data type has two possible +states.  These are the positive and negative directions on a +continuum such as the number line.   These states can be +described by one of several direction_1d_enum values:  We make +clockwise and counterclockwise winding orientation of polygons a +direction 1d value instead of providing a separate winding_orientation +data type.  This is because winding orientation can be thought of +as positive and negative directions in a 1d (although cyclic) +space.  We assign counterclockwise to be the positive direction of +travel in the 1d cyclic space to conform with the mathematical +convention frequently described as the "right hand rule" which assigns +positive normal value to counterclockwise and negative normal value to +clockwise as well as the common convention that counterclockwise +polygon winding corresponds to positive polygonal regions where as +clockwise polygon winding corresponds to hole (negative) polygonal +regions.

        +

        enum direction_1d_enum +{LOW = 0, HIGH = 1,
        +                        LEFT = 0, RIGHT = 1,
                                CLOCKWISE = 0, COUNTERCLOCKWISE = 1,
        @@ -154,383 +176,390 @@ CLOCKWISE = 0, COUNTERCLOCKWISE = 1,
        REVERSE = 0, FORWARD = 1,
                                NEGATIVE = 0, POSITIVE = 1 };

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - -
        direction_1d(direction_1d_enum - val = LOW)Constructor defaults to LOW.
        direction_1d(const - direction_1d& that)Copy construct.
        direction_1d(const - direction_2d& that)Down cast direction_2d, extracting out whether positive or negative
        direction_1d(const - direction_3d& that)Down cast direction_3d, extracting out whether positive or negative
        -direction_1d& operator=(const direction_1d dir)Assignment
        -direction_1d& operator==(const direction_1d dir) +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + - - - - - - - - - - - - - - -
        direction_1d(direction_1d_enum +val = LOW)Constructor defaults to LOW.
        direction_1d(const direction_1d& that)Copy construct.
        direction_1d(const direction_2d& that)Down cast direction_2d, extracting out whether positive +or negative
        direction_1d(const direction_3d& that)Down cast direction_3d, extracting out whether positive +or negative
        direction_1d& operator=(const +direction_1d dir)Assignment
        direction_1d& operator==(const +direction_1d dir) constEquivalence
        direction_1d& operator!=(const +direction_1d dir) constInequivalence
        unsigned int to_int() constEquivalence
        -direction_1d& operator!=(const direction_1d dir) + Convert to the integer enum value of current state to +use as index.  Auto-cast to int is disallowed for type safety +reasons.
        direction_1d& backward()Inverts direction.
        int get_sign() constInequivalence
        -unsigned int to_int() constConvert to the integer enum value of current state to use as index.  - Auto-cast to int is disallowed for type safety reasons.
        -direction_1d& backward()Inverts direction.
        -int get_sign() constReturns positive 1 if positive direction and negative one if - negative direction.
        -

        orientation_2d

        - -

        -

        The orientation_2d data type has two possible states.  -These are the horizontal and vertical axis of a 2d Cartesian coordinate system.   -These states can be described by one of the two orientation_2d_enum values:

        -

        enum orientation_2d_enum { HORIZONTAL = -0, VERTICAL = 1 };

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        orientation_2d(orientation_2d_enum - val = HORIZONTAL)Constructor defaults to HORIZONTAL.
        orientation_2d(const - orientation_2d& that)Copy construct.
        explicit - orientation_2d(const - direction_2d& that)Down cast direction_2d, extracting out whether horizontal or - vertical direction type
        -orientation_2d& operator=(const orientation_2d -o)Assignment
        -orientation_2d& operator==(const orientation_2d -o) constEquivalence
        -orientation_2d& operator!=(const orientation_2d -o) constInequivalence
        -unsigned int to_int() constConvert to the integer enum value of current state to use as index.  - Auto-cast to int is disallowed for type safety reasons
        -orientation_2d& turn_90()Change to orthogonal orientation
        -int get_perpendicular() constReturns orthogonal orientation
        -int get_direction(direction_1d dir) constReturns the positive or negative direction_2d depending on the value - of dir
        -

        direction_2d

        - -

        -

        The direction_2d data type has four possible states.  These -are the cardinal directions of the 2D Cartesian coordinate system.   -These states can be described by one of several direction_2d_enum values:

        -

        enum direction_2d_enum { WEST = 0, EAST -= 1, SOUTH = 2, NORTH = 3 };

        -

        Member Functions

        - - - - - - - - - - - - - - - + + +
        direction_2d(direction_2d_enum - val = WEST)Constructor defaults to WEST.
        direction_2d(const - direction_2d& that)Copy construct.
        -direction_1d& operator=(const direction_2d dir)Assignment
        -direction_1d& operator==(const direction_2d dir) + Returns positive 1 if positive direction and negative +one if negative direction.
        +

        orientation_2d

        +

        +

        The orientation_2d data type has two possible +states.  These are the horizontal and vertical axis of a 2d +Cartesian coordinate system.   These states can be described +by one of the two orientation_2d_enum values:

        +

        enum orientation_2d_enum +{ HORIZONTAL = 0, VERTICAL = 1 };

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        orientation_2d(orientation_2d_enum val = HORIZONTAL)Constructor defaults to HORIZONTAL.
        orientation_2d(const orientation_2d& that)Copy construct.
        explicit + orientation_2d(const direction_2d& that)Down cast direction_2d, extracting out whether +horizontal or vertical direction type
        orientation_2d& + operator=(const orientation_2d o)Assignment
        orientation_2d& + operator==(const orientation_2d o) constEquivalence
        orientation_2d& + operator!=(const orientation_2d o) constInequivalence
        unsigned int to_int() constEquivalence
        -direction_1d& operator!=(const direction_2d dir) + Convert to the integer enum value of current state to +use as index.  Auto-cast to int is disallowed for type safety +reasons
        orientation_2d& + turn_90()Change to orthogonal orientation
        int get_perpendicular() constInequivalence
        -unsigned int to_int() constConvert to the integer enum value of current state to use as index.  - Auto-cast to int is disallowed for type safety reasons.
        -direction_2d& backward()Inverts direction.
        -direction_2d& turn(direction_1d dir)Changes to direction_2d to the left if dir is LOW, to the right if - dir is HIGH
        -direction_2d& left()Changes to the direction_2d to the left
        -direction_2d& right()Changes to the direction_2d to the right
        -int is_positive() constReturns true if EAST or NORTH
        -int is_negative() constReturns true if WEST or SOUTH
        -int get_sign() constReturns positive 1 if positive direction and negative one if - negative direction.
        -

        orientation_3d

        - -

        -

        The orientation_3d data type has three possible states.  -These are the horizontal, vertical and proximal (x, y, z) axis of a 3d Cartesian -coordinate system.   These states can be described by one of the -orientation_2d_enum values or by the orientation_3d_enum value:

        -

        enum orientation_3d_enum { PROXIMAL = 2 -};

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        orientation_3d(orientation_2d_enum - val = HORIZONTAL)Constructor defaults to HORIZONTAL.
        orientation_3d(const - orientation_3d& that)Copy construct.
        explicit - orientation_3d(const - direction_2d& that)Extract out the orientation of the direction
        explicit - orientation_3d(const - direction_3d& that)Extract out the orientation of the direction
        orientation_3d(const - orientation_2d& that)Up cast orientation_2d to orientation_3d.
        orientation_3d(const - orientation_3d_enum& that)Construct from constant value
        -orientation_3d& operator=(const orientation_3d -o)Assignment
        -orientation_3d& operator==(const orientation_3d -o) constEquivalence
        -orientation_3d& operator!=(const orientation_3d -o) constInequivalence
        -unsigned int to_int() constConvert to the integer enum value of current state to use as index.  - Auto-cast to int is disallowed for type safety reasons
        -int get_direction(direction_1d dir) constReturns the positive or negative direction_2d depending on the value - of dir
        -

        direction_3d

        - -

        -

        The direction_3d data type has six possible states.  These -are the cardinal directions of the 3D Cartesian coordinate system.   -These states can be described by one of the direction_2d_enum values or the -direction_3d_enum values:

        -

        enum direction_3d_enum { DOWN = 4, UP = -5 };

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - + + + + + + +
        direction_3d(direction_2d_enum - val = WEST)Constructor defaults to LOW.
        direction_3d(direction_3d_enum that)Construct from constant value
        direction_3d(const - direction_3d& that)Copy construct
        direction_3d(direction_2d that)Up cast direction_2d to direction_3d
        -direction_3d& operator=(const direction_3d dir)Assignment
        -direction_3d& operator==(const direction_3d dir) + Returns orthogonal orientation
        int get_direction(direction_1d +dir) constReturns the positive or negative direction_2d depending +on the value of dir
        +

        direction_2d

        +

        +

        The direction_2d data type has four possible +states.  These are the cardinal directions of the 2D Cartesian +coordinate system.   These states can be described by one of +several direction_2d_enum values:

        +

        enum direction_2d_enum { +WEST = 0, EAST = 1, SOUTH = 2, NORTH = 3 };

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - -
        direction_2d(direction_2d_enum +val = WEST)Constructor defaults to WEST.
        direction_2d(const direction_2d& that)Copy construct.
        direction_1d& operator=(const +direction_2d dir)Assignment
        direction_1d& operator==(const +direction_2d dir) constEquivalence
        direction_1d& operator!=(const +direction_2d dir) constInequivalence
        unsigned int to_int() constEquivalence
        -direction_2d& operator!=(const direction_3d dir) + Convert to the integer enum value of current state to +use as index.  Auto-cast to int is disallowed for type safety +reasons.
        direction_2d& backward()Inverts direction.
        direction_2d& turn(direction_1d +dir)Changes to direction_2d to the left if dir is LOW, to +the right if dir is HIGH
        direction_2d& left()Changes to the direction_2d to the left
        direction_2d& right()Changes to the direction_2d to the right
        int is_positive() constInequivalence
        -unsigned int to_int() constConvert to the integer enum value of current state to use as index.  - Auto-cast to int is disallowed for type safety reasons.
        -direction_1d& backward()Inverts direction.
        -int is_positive() constReturns true if direction is EAST, NORTH or UP.
        -int is_negative() constReturns true if direction is WEST, SOUTH or DOWN
        -int get_sign() constReturns positive 1 if positive direction and negative one if - negative direction.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Returns true if EAST or NORTH
        int is_negative() +constReturns true if WEST or SOUTH
        int get_sign() +constReturns positive 1 if positive direction and negative +one if negative direction.
        +

        orientation_3d

        +

        +

        The orientation_3d data type has three possible +states.  These are the horizontal, vertical and proximal (x, y, z) +axis of a 3d Cartesian coordinate system.   These states can +be described by one of the orientation_2d_enum values or by the +orientation_3d_enum value:

        +

        enum orientation_3d_enum +{ PROXIMAL = 2 };

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        orientation_3d(orientation_2d_enum val = HORIZONTAL)Constructor defaults to HORIZONTAL.
        orientation_3d(const orientation_3d& that)Copy construct.
        explicit + orientation_3d(const direction_2d& that)Extract out the orientation of the direction
        explicit + orientation_3d(const direction_3d& that)Extract out the orientation of the direction
        orientation_3d(const orientation_2d& that)Up cast orientation_2d to orientation_3d.
        orientation_3d(const orientation_3d_enum& that)Construct from constant value
        orientation_3d& + operator=(const orientation_3d o)Assignment
        orientation_3d& + operator==(const orientation_3d o) constEquivalence
        orientation_3d& + operator!=(const orientation_3d o) constInequivalence
        unsigned int to_int() +constConvert to the integer enum value of current state to +use as index.  Auto-cast to int is disallowed for type safety +reasons
        int get_direction(direction_1d +dir) constReturns the positive or negative direction_2d depending +on the value of dir
        +

        direction_3d

        +

        +

        The direction_3d data type has six possible +states.  These are the cardinal directions of the 3D Cartesian +coordinate system.   These states can be described by one of +the direction_2d_enum values or the direction_3d_enum values:

        +

        enum direction_3d_enum { +DOWN = 4, UP = 5 };

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        direction_3d(direction_2d_enum +val = WEST)Constructor defaults to LOW.
        direction_3d(direction_3d_enum that)Construct from constant value
        direction_3d(const direction_3d& that)Copy construct
        direction_3d(direction_2d that)Up cast direction_2d to direction_3d
        direction_3d& operator=(const +direction_3d dir)Assignment
        direction_3d& operator==(const +direction_3d dir) constEquivalence
        direction_2d& operator!=(const +direction_3d dir) constInequivalence
        unsigned int to_int() +constConvert to the integer enum value of current state to +use as index.  Auto-cast to int is disallowed for type safety +reasons.
        direction_1d& backward()Inverts direction.
        int is_positive() +constReturns true if direction is EAST, NORTH or UP.
        int is_negative() +constReturns true if direction is WEST, SOUTH or DOWN
        int get_sign() +constReturns positive 1 if positive direction and negative +one if negative direction.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_point_concept.htm b/doc/gtl_point_concept.htm index 37b8a26..40f11c4 100644 --- a/doc/gtl_point_concept.htm +++ b/doc/gtl_point_concept.htm @@ -1,409 +1,535 @@ -Boost Polygon Library: Point Concept - - - - - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Point Concept + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Point Concept

        - -

        -

        -The point concept tag is -point_concept

        -To register a user defined type as a model of point concept, specialize the -geometry concept meta-function for that type.  In the example below CPoint is registered as a model of -point  concept.

        -template <>
        -struct geometry_concept<CPoint> { typedef point_concept type; };

        -The semantic of a point is that it has an x and y -coordinate.  A std::pair<int, int>, boost::tuple<int, int> or boost::array<int, 2> -could all be made models of point by simply providing indirect access to their -elements through traits, however, these objects cannot be made a model of both -point and interval in the same compilation unit, for obvious reason that -duplicate specialization of the geometry_concept struct is illegal, but also -because it would make overloading generic function by concept ambiguous if a -type modeled more than one concept.

        -Below is shown the default point traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.

        -

        -template <typename T>
        +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Point Concept

        +

        +

        The point concept tag is +point_concept

        +

        To register a user defined type as a model of point concept, +specialize the geometry concept meta-function for that type.  In +the example below CPoint is +registered as a model of point  concept.

        +

        template <>
        +struct geometry_concept<CPoint> { typedef point_concept type; };

        +

        The semantic of a point is that it has an x and y +coordinate.  A std::pair<int, int>, boost::tuple<int, +int> or boost::array<int, 2> could all be made models of point +by simply providing indirect access to their elements through traits, +however, these objects cannot be made a model of both point and +interval in the same compilation unit, for obvious reason that +duplicate specialization of the geometry_concept struct is illegal, but +also because it would make overloading generic function by concept +ambiguous if a type modeled more than one concept.

        +

        Below is shown the default point traits.  Specialization +of these traits is required for types that don't conform to the default +behavior.

        +

        template +<typename T>
        struct point_traits {
        -     typedef typename T::coordinate_type coordinate_type;
        -
        -     static coordinate_type get(const T& point, +     typedef typename T::coordinate_type +coordinate_type;
        +
        +     static coordinate_type get(const T& point, orientation_2d orient) {
        -          return point.get(orient); -
        +          return +point.get(orient); +
             }
        };
        -
        +
        template <typename T>
        struct point_mutable_traits {
        -     static void set(T& point, orientation_2d orient, -typename point_traits<T>::coordinate_type value) {
        -          point.set(orient, value); -
        +     typedef typename T::coordinate_type +coordinate_type;
        +
        +     static void set(T& point, orientation_2d +orient, typename point_traits<T>::coordinate_type value) {
        +          +point.set(orient, value); +
             }
        -     static T construct(typename point_traits<T>::coordinate_type -x_value, typename point_traits<T>::coordinate_type y_value) {
        -          return T(x_value, y_value); -
        +     static T construct(typename +point_traits<T>::coordinate_type x_value,
        +                        +typename point_traits<T>::coordinate_type y_value) {
        +          return +T(x_value, y_value); +
             }
        };

        -

        -Example code custom_point.cpp demonstrates -how to map a - user defined point class to the library point_concept

        Functions

        - - - - -
        template <typename PointType>
        - coordinate_type get(const PointType& point,
                            +

        Example code custom_point.cpp +demonstrates how to map a user defined point class to the library +point_concept

        +

        Functions

        + + + + - - - - + + - - - - + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - -
        template +<typename PointType>
        +coordinate_type get(const PointType& point,
        +                    orientation_2d)
        Expects a model of point. Returns - the x or y coordinate of the point, depending on the orientation_2d - value.
        - +
        Expects a model of point. Returns the x or y coordinate +of the point, depending on the orientation_2d value.
         
        template <typename PointType>
        - void set(PointType& point, orientation_2d,
        +
        template +<typename PointType>
        +void set(PointType& point, orientation_2d,
                 coordinate_type)
        Expects a model of point. Sets the x or y coordinate of the point to the coordinate, depending on - the orientation_2d  value.
        template <typename PointType>
        PointType construct(coordinate_type x,
        +
        Expects a model of point. Sets the x or y coordinate of +the point to the coordinate, depending on the orientation_2d  +value.
        template +<typename PointType>
        +PointType construct(coordinate_type x,
                            coordinate_type y)
        Construct an object that is a model of point given x and y - coordinate values.
        template <typename PointType1, typename PointType2>
        - PointType1& assign(PointType1& left,
        +
        Construct an object that is a model of point given x +and y coordinate values.
        template +<typename PointType1, typename PointType2>
        +PointType1& assign(PointType1& left,
                           const PointType2& right)
        Copies data from right object that models point into left object - that models point.
        template <typename PointType1, typename PointType2>
        - bool equivalence(const
        PointType1& point1,
        -                 const
        PointType2& point2)
        Given two objects that model point, compares and returns true if - their x and y values are respectively equal to each other.
        template <typename PointType>
        - coordinate_type x(const
        PointType& point)
        Returns the x coordinate of an object that models point.
        template <typename PointType>
        - coordinate_type y(const
        PointType& point)
        Returns the y coordinate of an object that models point.
        template <typename PointType>
        - void x(p
        PointType& point, coordinate_type )
        Sets the x coordinate of the object that models point to the - coordinate value. 
        template <typename PointType>
        - void y(
        PointType& point, coordinate_type )
        Sets the y coordinate of the object that models point to the - coordinate value. 
        template <typename PointType>
        - point_type& scale_up(
        PointType& point,
                             +
        Copies data from right object that models point into +left object that models point.
        template +<typename PointType1, typename PointType2>
        +bool equivalence(const
        PointType1& point1,
        +                 +const
        PointType2& point2)
        Given two objects that model point, compares and +returns true if their x and y values are respectively equal to each +other.
        template +<typename PointType>
        +coordinate_type x(const
        PointType& point)
        Returns the x coordinate of an object that models point.
        template +<typename PointType>
        +coordinate_type y(const
        PointType& point)
        Returns the y coordinate of an object that models point.
        template +<typename PointType>
        +void x(p
        PointType& point, coordinate_type )
        Sets the x coordinate of the object that models point +to the coordinate value. 
        template +<typename PointType>
        +void y(
        PointType& point, coordinate_type )
        Sets the y coordinate of the object that models point +to the coordinate value. 
        template +<typename PointType>
        +point_type& scale_up(
        PointType& point,
        +                     unsigned_area_type factor)
        Multiplies x and y coordinate of an object that models point by - unsigned factor.
        template <typename PointType>
        - point_type& scale_down(
        PointType& point,
                               +
        Multiplies x and y coordinate of an object that models +point by unsigned factor.
        template +<typename PointType>
        +point_type& scale_down(
        PointType& point,
        +                       unsigned_area_type factor)
        Divides x and y coordinate of an object that models point by - unsigned factor.
        template <typename PointType, - typename scaling_type>
        - point_type& scale(
        PointType& point,
        -                  - const scaling_type& factor)
        Calls the scale member function of scaling type on the x and y value - of an object that models point and sets the point to the scaled values.
        template <typename PointType, - typename transform_type>
        - point_type& transform(
        PointType& point,
        -                      - const transform_type& transform)
        Calls the transform member function of transform type on the x and y - value of an object that models point and sets the point to the - transformed values.
        template <typename PointType>
        - point_type& move(
        PointType& point, orientation_2d,
        -                 - coordinate_difference displacement)
        Adds displacement value to the coordinate of an object that models - point indicated by the orientation_2d.
        template <typename PointType1, typename PointType2>
        -
        PointType1& convolve(PointType1& a,
        -                     const
        PointType2& b)
        Adds x coordinate of b to x coordinate of a and adds y coordinate of - b to y coordinate of a.
        template <typename PointType1, typename PointType2>
        -
        PointType1,& deconvolve(PointType1& a,
        +
        Divides x and y coordinate of an object that models +point by unsigned factor.
        template +<typename PointType, typename scaling_type>
        +point_type& scale(
        PointType& point,
        +                  +const scaling_type& factor)
        Calls the scale member function of scaling type on the +x and y value of an object that models point and sets the point to the +scaled values.
        template +<typename PointType, typename transform_type>
        +point_type& transform(
        PointType& point,
        +                      +const transform_type& transform)
        Calls the transform member function of transform type +on the x and y value of an object that models point and sets the point +to the transformed values.
        template +<typename PointType>
        +point_type& move(
        PointType& point, orientation_2d,
        +                 +coordinate_difference displacement)
        Adds displacement value to the coordinate of an object +that models point indicated by the orientation_2d.
        template +<typename PointType1, typename PointType2>
        +
        PointType1& convolve(PointType1& a,
        +                     +const
        PointType2& b)
        Adds x coordinate of b to x coordinate of a and adds y +coordinate of b to y coordinate of a.
        template +<typename PointType1, typename PointType2>
        +
        PointType1,& deconvolve(PointType1& a,
                                -const
        PointType2>& b)
        Subtracts x coordinate of b from x coordinate of a and subtracts y - coordinate of b from y coordinate of a.
        template <typename PointType1, typename PointType2>
        distance_type euclidean_distance(
        -    const
        PointType1&, const PointType2&)
        Returns the distance from an object that models point to a second - object that models point.
        template <typename PointType1, typename PointType2>
        - coordinate_difference euclidean_distance(
        -    const
        PointType1&, const PointType2&, orientation_2d)
        Returns the distance from an object that models point to a - coordinate in the given orientation_2d.
        template <typename PointType1, typename PointType2>
        - coordinate_difference manhattan_distance(
        -   
        const PointType1&, const PointType2&)
        Returns the distance in x plus the distance in y from an object that - models point to a second object that models point.
        template <typename PointType1, typename PointType2>
        - coordinate_difference distance_squared(
        -   
        const PointType1&, const PointType2&)
        Returns the square of the distance in x plus the square of the - distance in y from an object that models point to a second object that - models point.
        -

        Point Data

        - -

        -

        The library provides a model of point concept declared - -template<typename T> point_data where T is the coordinate type.

        -

        This data type is used internally when a point is needed and is available to -the library user who finds it convenient to use a library point data type -instead of providing their own.  The data type is implemented to be -convenient to use with the library traits.

        -

        Example code point_usage.cpp demonstrates using the - library provided point data type and functions

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + +
        coordinate_typeT
        point_data()Default constructs the two coordinate - values of the point.
        point_data(T x, T y)Constructs an interval with two - coordinates.
        point_data(const point_data& - that)Copy construct
        point_data& operator=(const - point_data& that)Assignment operator.
        template <typename PointType>
        +const
        PointType2>& b)
        Subtracts x coordinate of b from x coordinate of a and +subtracts y coordinate of b from y coordinate of a.
        template +<typename PointType1, typename PointType2>
        +distance_type euclidean_distance(
        +    const
        PointType1&, const PointType2&)
        Returns the distance from an object that models point +to a second object that models point.
        template <typename PointType1, typename PointType2>
        +coordinate_difference euclidean_distance(
        +    const
        PointType1&, const PointType2&, orientation_2d)
        Returns the distance from an object that models point +to a coordinate in the given orientation_2d.
        template <typename PointType1, typename PointType2>
        +coordinate_difference manhattan_distance(
        +   
        const PointType1&, const +PointType2&)
        Returns the distance in x plus the distance in y from +an object that models point to a second object that models point.
        template <typename PointType1, typename PointType2>
        +coordinate_difference distance_squared(
        +   
        const PointType1&, const +PointType2&)
        Returns the square of the distance in x plus the square +of the distance in y from an object that models point to a second +object that models point.
        +

        Point Data

        +

        +

        The library provides a model of point concept declared + template<typename T> point_data where +T is the coordinate type.

        +

        This data type is used internally when a point is needed and +is available to the library user who finds it convenient to use a +library point data type instead of providing their own.  The data +type is implemented to be convenient to use with the library traits.

        +

        Example code point_usage.cpp +demonstrates using the library provided point data type and functions

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        coordinate_typeT
        point_data()Default constructs the two coordinate values of the +point.
        point_data(T +x, T y)Constructs an interval with two coordinates.
        point_data(const +point_data& that)Copy construct
        point_data& operator=(const +point_data& that)Assignment operator.
        template +<typename PointType>
        point_data& operator=(const PointType& that) const
        Assign from an object that is a model of point.
        bool - operator==(const point_data& that) constEquality operator overload.
        -
        bool - operator!=(const point_data& that) constInequality operator overload.
        bool - operator<(const point_data& that) constCompares y coordinates then x coordinates to break ties.
        bool - operator<=(const point_data& that) constCompares y coordinates then x coordinates to break ties.
        bool - operator>(const point_data& that) constCompares low coordinates then high coordinates to break ties.
        bool - operator>=(const point_data& that) constCompares low coordinates then high coordinates to break ties.
        T get(orientation_2d - orient) constGet the coordinate in the given orientation.
        T x() constGet the coordinate in the horizontal orientation.
        T y() constGet the coordinate in the vertical orientation.
        void set(orientation_2d - orient, T value)Sets the coordinate in the given orientation to the value.
        void x(T value)Sets the coordinate in the horizontal orientation to the value.
        void y(T value)Sets the coordinate in the vertical orientation to the value.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Assign from an object that is a model of point.
        bool operator==(const + point_data& that) constEquality operator overload.
        +
        bool operator!=(const + point_data& that) constInequality operator overload.
        bool +operator<(const point_data& that) constCompares y coordinates then x coordinates to break ties.
        bool +operator<=(const point_data& that) constCompares y coordinates then x coordinates to break ties.
        bool +operator>(const point_data& that) constCompares low coordinates then high coordinates to break +ties.
        bool +operator>=(const point_data& that) constCompares low coordinates then high coordinates to break +ties.
        T get(orientation_2d +orient) constGet the coordinate in the given orientation.
        T x() constGet the coordinate in the horizontal orientation.
        T y() constGet the coordinate in the vertical orientation.
        void set(orientation_2d +orient, T value)Sets the coordinate in the given orientation to the +value.
        void x(T +value)Sets the coordinate in the horizontal orientation to +the value.
        void y(T +value)Sets the coordinate in the vertical orientation to the +value.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_45_concept.htm b/doc/gtl_polygon_45_concept.htm index 8f5fb2d..befa5ff 100644 --- a/doc/gtl_polygon_45_concept.htm +++ b/doc/gtl_polygon_45_concept.htm @@ -1,376 +1,432 @@ - + + Boost Polygon Library: Polygon 45 Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 45 Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 45 Concept

        - -

        -

        The polygon_45 concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 45 Concept

        +

        +

        The polygon_45 concept tag is polygon_45_concept

        -

        -To register a user defined type as a model of -polygon_45 concept, specialize the -geometry concept meta-function for that type.  In the example below CPolygon45 is registered as a model of -polygon_45  concept.

        -template <>
        -struct geometry_concept<CPolygon45> { typedef polygon_45_concept type; };

        -The semantic of a polygon_45 is that it can provide -iterators over the points that represent its vertices, angles formed as these -vertices must be multiple of 45-degree relative to the coordinate axis.  It -is acceptable to have the last edge explict with the first and last point equal -to each other or implied by this segement that would connect the first and last -point.  A mutable polygon_45 must also be able to set its geometry based on -an interator range over such points.   A std::vector<point_data<int> > -or std::list<point_data<int> > -could be made models of polygon_45_concept by simply providing access to their -iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

        -Below is shown the default polygon traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.  Note that these traits are also used by several other -polygon concepts through SFINAE enable template parameter.  The SFINAE enable -parameter also allows the library to provide default specialization that work -for any object that models the 90 degree polygon concepts.

        -template <typename T, typename enable = gtl_yes>
        +

        To register a user defined type as a model of polygon_45 concept, specialize the +geometry concept meta-function for that type.  In the example +below CPolygon45 is registered as a model of polygon_45  concept.

        +

        template <>
        +struct geometry_concept<CPolygon45> { typedef polygon_45_concept +type; };

        +

        The semantic of a polygon_45 is +that it can provide iterators over the points that represent its +vertices, angles formed as these vertices must be multiple of 45-degree +relative to the coordinate axis.  It is acceptable to have the +last edge explict with the first and last point equal to each other or +implied by this segement that would connect the first and last +point.  A mutable polygon_45 must also be able to set its geometry +based on an interator range over such points.   A +std::vector<point_data<int> > or +std::list<point_data<int> > could be made models of +polygon_45_concept by simply providing access to their iterators +through traits.  Library functions that create polygon objects +require that those objects provide a default constructor.

        +

        Below is shown the default +polygon traits.  Specialization of these traits is required for +types that don't conform to the default behavior.  Note that these +traits are also used by several other polygon concepts through SFINAE +enable template parameter.  The SFINAE enable parameter also +allows the library to provide default specialization that work for any +object that models the 90 degree polygon concepts.

        +

        template <typename T, typename +enable = gtl_yes>
        struct polygon_traits {};
        -
        +
        template <typename T>
        struct polygon_traits<T,
          typename gtl_or_4<
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_45_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_45_with_holes_concept>::type
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_45_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_with_holes_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_45_with_holes_concept>::type
          >::type> {
        -     typedef typename T::coordinate_type coordinate_type;
        -     typedef typename T::iterator_type iterator_type;
        +     typedef typename T::coordinate_type +coordinate_type;
        +     typedef typename T::iterator_type +iterator_type;
             typedef typename T::point_type point_type;
        -     static inline iterator_type begin_points(const T& t) {
        +     static inline iterator_type begin_points(const +T& t) {
                  return t.begin();
             }
        -     static inline iterator_type end_points(const T& t) {
        +     static inline iterator_type end_points(const +T& t) {
                  return t.end();
             }
        -     static inline unsigned int size(const T& t) {
        +     static inline unsigned int size(const T& +t) {
                  return t.size();
             }
        -     static inline winding_direction winding(const T& t) {
        -          return unknown_winding;
        +     static inline winding_direction winding(const +T& t) {
        +          return +unknown_winding;
             }
        };

        -

        template <typename T, typename enable = void>
        +

        template <typename T, typename +enable = void>
        struct polygon_mutable_traits {
             template <typename iT>
        -     static inline T& set_points(T& t, iT input_begin, iT -input_end) {
        -          t.set(input_begin, -input_end);
        +     static inline T& set_points(T& t, iT +input_begin, iT input_end) {
        +          +t.set(input_begin, input_end);
                  return t;
             }
        };

        -

        An object that is a model of -polygon_45_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_45_object)
        -view_as<polygon_90_concept>(polygon_45_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of polygon_45.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of polygon_45.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of polygon_45.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a polygon.  Non-45 edges between successive input - points is disallowed.
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - polygon.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_45 into left object - that models polygon_45.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon_45 and an object that models - point, returns true - if the polygon contains the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon.  Linear wrt. vertices.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon_45.  Linear wrt. vertices.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon_45 and returns true.  Returns false and leaves - bbox unchanged if polygon is empty.  Linear wrt. vertices.
        template <typename T>
        - area_type area(const T& polygon)
        Returns the area of an object - that models polygon_45.  Linear wrt. vertices.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon_45, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  - Complexity depends upon winding trait.
        template <typename T>
        - coordinate_distance perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon_45.  Linear wrt. vertices.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Linear wrt. vertices.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models - polygon_45 by unsigned factor.  Linear wrt. vertices.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models - polygon_45 by unsigned factor.  Linear wrt. vertices.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon_45 by floating - point factor.  Linear wrt. vertices.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon_45.  Linear wrt. - vertices.
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               +

        An object that is a model of +polygon_45_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_45_object)
        + view_as<polygon_90_concept>(polygon_45_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon_45.  Returns the begin iterator over the range of points +that correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon_45.  Returns the end iterator over the range of points +that correspond to vertices of the polygon.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_45.   Sets the polygon to the point data range [b,e) +that corresponds to vertices of a polygon.  Non-45 edges between +successive input points is disallowed.
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the polygon.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_45 +into left object that models polygon_45.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon_45 and an object +that models point, returns true if the polygon contains the +point.  If the consider_touch flag is true will return true if the +point lies along the boundary of the polygon.  Linear wrt. +vertices.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon_45.  Linear wrt. +vertices.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon_45 and returns true.  Returns +false and leaves bbox unchanged if polygon is empty.  Linear wrt. +vertices.
        template +<typename T>
        +area_type area(const T& polygon)
        Returns the area of an object that models +polygon_45.  Linear wrt. vertices.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon_45, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity +depends upon winding trait.
        template +<typename T>
        +coordinate_distance perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon_45.  Linear wrt. vertices.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models +polygon_45 by unsigned factor.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models +polygon_45 by unsigned factor.  Linear wrt. vertices.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon_45 +by floating point factor.  Linear wrt. vertices.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon_45.  +Linear wrt. vertices.
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with vertices of an - object that models polygon_45.  Linear wrt. vertices.
        -

        Polygon 45 Data

        - -

        -

        The library provides a model of polygon 45 concept declared - -template<typename T> polygon_45_data where T is the coordinate type.

        -

        This data type is used internally when a 45-degree polygon is needed and is -available to the library user who finds it convenient to use a library polygon -data type instead of providing their own.  The data type is implemented to -be convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_45_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        polygon_45_data()Default constructs the polygon.
        polygon_45_data(const - polygon_45_data& that)Copy construct
        polygon_45_data& operator=(const - polygon_45_data& that)Assignment operator.
        template <typename T2>  -
        polygon_45_data& operator=(const T2& that) const
        Assign from an object that is a model of polygon 45.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  No check is - performed to ensure the points describe corners that are multiples of 45 - degrees relative to the coordinate axis.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with vertices of +an object that models polygon_45.  Linear wrt. vertices.
        +

        Polygon 45 Data

        +

        +

        The library provides a model of polygon 45 concept declared + template<typename T> +polygon_45_data where T is the coordinate type.

        +

        This data type is used internally when a 45-degree polygon is +needed and is available to the library user who finds it convenient to +use a library polygon data type instead of providing their own.  +The data type is implemented to be convenient to use with the library +traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_45_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        polygon_45_data()Default constructs the polygon.
        polygon_45_data(const +polygon_45_data& that)Copy construct
        polygon_45_data& + operator=(const polygon_45_data& that)Assignment operator.
        template +<typename T2> 
        +
        polygon_45_data& operator=(const T2& +that) const
        Assign from an object that is a model of polygon 45.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  +No check is performed to ensure the points describe corners that are +multiples of 45 degrees relative to the coordinate axis.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_45_set_concept.htm b/doc/gtl_polygon_45_set_concept.htm index d96b40c..3a3a7ec 100644 --- a/doc/gtl_polygon_45_set_concept.htm +++ b/doc/gtl_polygon_45_set_concept.htm @@ -1,758 +1,842 @@ - + + Boost Polygon Library: Polygon 45 Set Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 45 Set Concept + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 45 Set Concept

        - -

        -

        The polygon_45_set concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 45 Set Concept

        +

        +

        The polygon_45_set concept tag is polygon_45_set_concept

        -

        -The semantic of a polygon_45_set is zero or more -geometry regions which have angles at the vertices that are multiples of -45-degrees relative to the coordinate axis.  A Polygon 45 Set Concept makes -no sense in floating point, but currently does not provide a static assert to -prevent it from being used with floating point coordinates.  The result of -such use is undefined.  When the intersection of two 45 degree edges -results in a vertex that is off the integer grid that case is handled by -inserting a unit length edge between the two 45 degree edges near the off grid -intersection point.  In the case that data represented contains no -45-degree angles and is Manhattan a runtime check will default to the Manhattan -algorithm.  The results of which are identical to what the 45-degree -algorithm would do, but obtained more efficiently.

        -The motivation for providing the polygon_45_set is -to extend the special case of Manhattan geometry capability of the library to -encompass the slightly less common, but still important special case of geometry -that is described by angles that are multiples of 45-degress with respect to the -coordinate axis.  This simplifies the implementation of geometry algorithms -and affords many opportunities for optimization.  45-degree algorithms can -be 50X faster than arbitrary angle algorithms and are required to provide a -complete feature set that meets the performance requirements of application -domains in which Manhattan and 45-degree geometry are a common special case.

        Users are recommended to use std::vector and std::list of user defined polygons -or library provided polygon_45_set_data<coordinate_type> objects.  Lists -and vectors of models of polygon_45_concept or polygon_45_with_holes_concept are automatically models of polygon_45_set_concept.

        -

        An object that is a model of -polygon_45_set_concept can be viewed as a model of -polygon_90_set_concept if it is determined at runtime to conform to the -restriction that all edges are axis-parallel.  This concept casting is -accomplished through the view_as<>() function.

        -

        view_as<polygon_90_set_concept>(polygon_set_object)

        -

        The return value of view_as<>() can be passed -into any interface that expects an object of the conceptual type specified in -its template parameter.  Polygon sets cannot be viewed as single polygons -or rectangles since it generally cannot be known whether a polygon set contains -only a single polygon without converting to polygons.

        -

        Operators

        -

        The return type of some operators is the polygon_45_set_view -operator template type.  This type is itself a model of the polygon 90 set -concept, but furthermore can be used as an argument to the polygon_45_set_data -constructor and assignment operator.  The operator template exists to -eliminate temp copies of intermediate results when Boolean operators are chained +

        The semantic of a +polygon_45_set is zero or more geometry regions which have angles at +the vertices that are multiples of 45-degrees relative to the +coordinate axis.  A Polygon 45 Set Concept makes no sense in +floating point, but currently does not provide a static assert to +prevent it from being used with floating point coordinates.  The +result of such use is undefined.  When the intersection of two 45 +degree edges results in a vertex that is off the integer grid that case +is handled by inserting a unit length edge between the two 45 degree +edges near the off grid intersection point.  In the case that data +represented contains no 45-degree angles and is Manhattan a runtime +check will default to the Manhattan algorithm.  The results of +which are identical to what the 45-degree algorithm would do, but +obtained more efficiently.

        +

        The motivation for providing +the polygon_45_set is to extend the special case of Manhattan geometry +capability of the library to encompass the slightly less common, but +still important special case of geometry that is described by angles +that are multiples of 45-degress with respect to the coordinate +axis.  This simplifies the implementation of geometry algorithms +and affords many opportunities for optimization.  45-degree +algorithms can be 50X faster than arbitrary angle algorithms and are +required to provide a complete feature set that meets the performance +requirements of application domains in which Manhattan and 45-degree +geometry are a common special case.

        +

        Users are recommended to use std::vector and std::list of user +defined polygons or library provided +polygon_45_set_data<coordinate_type> objects.  Lists and +vectors of models of polygon_45_concept or +polygon_45_with_holes_concept are automatically models of +polygon_45_set_concept.

        +

        An object that is a model of +polygon_45_set_concept can be viewed as a model of +polygon_90_set_concept if it is determined at runtime to conform +to the restriction that all edges are axis-parallel.  This concept +casting is accomplished through the view_as<>() +function.

        +

        view_as<polygon_90_set_concept>(polygon_set_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.  Polygon sets +cannot be viewed as single polygons or rectangles since it generally +cannot be known whether a polygon set contains only a single polygon +without converting to polygons.

        +

        Operators

        +

        The return type of some operators is the polygon_45_set_view operator template +type.  This type is itself a model of the polygon 90 set concept, +but furthermore can be used as an argument to the polygon_45_set_data constructor and +assignment operator.  The operator template exists to eliminate +temp copies of intermediate results when Boolean operators are chained together.

        -

        Operators are declared inside the namespace boost::polygon::operators.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T1, typename - T2>
        - polygon_45_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts two objects - that model polygon_45_set or one of its refinements.  Returns an - operator template that performs the operation on demand when chained or - or nested in a library function call such as assign().  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_45_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for OR - operations in Boolean logic expressions.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_45_set_view operator&(const T1& l, const T2& r)
        Boolean AND operation (polygon set intersection).  Accepts two - objects that model polygon_45_set or one of its refinements.  O( n - log n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_45_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol is also used for - AND operations in Boolean logic expressions.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_45_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set disjoint-union).  Accepts - two objects that model polygon_45_set or one of its refinements.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T1, typename - T2>
        - polygon_45_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set difference).  Accepts - two objects that model polygon_45_set or one of its refinements.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T1, typename - T2>
        - T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left operand must model - polygon_45_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1>
        - T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Note: returns - result by value.  O( n log n) runtime complexity and O(n) memory - wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Note: returns - result by value.  O( n log n) runtime complexity and O(n) memory - wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Returns - reference to modified argument.  O( n log n) runtime complexity and - O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Returns - reference to modified argument.  O( n log n) runtime complexity and - O(n) memory wrt vertices + intersections.
        -

        Functions

        - - - - - - - - - - - - - - - + + + +
        template <typename T1, typename - T2>
        - T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an object that - models polygon_45_set or any of its refinements into an object that - models polygon_45_set.  O( n log n) runtime complexity and O(n) - memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_45_set or one of its - refinements covers the exact same geometric regions as another object - that models polygon_45_set or one of its refinements.  For example: - two of polygon_45 objects.  O( n log n) runtime complexity and O(n) - memory wrt vertices + intersections.
        template <typename - output_container_type, typename T>
        - void get_trapezoids(output_container_type& output,
        -                    - const T& polygon_set)
        Output container is expected to be a standard container.  - Slices geometry of an object that models polygon_45_set or one of its - refinements into non overlapping trapezoids along a vertical slicing - orientation and appends them to the - output, which must have a value type that models polygon_45, - polygon_45_with_holes, polygon or polygon_with_holes.   O( n - log n) runtime complexity and O(n) memory wrt vertices.
        template <typename - output_container_type, typename T>
        - void get_trapezoids(output_container_type& output,
        -                    - const T& polygon_set,
        +

        Operators are declared inside the namespace boost::polygon::operators.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        template +<typename T1, typename T2>
        +polygon_45_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts +two objects that model polygon_45_set or one of its refinements.  +Returns an operator template that performs the operation on demand when +chained or or nested in a library function call such as assign().  +O( n log n) runtime complexity and O(n) memory wrt vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_45_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for +OR operations in Boolean logic expressions.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_45_set_view operator&(const T1& l, const +T2& r)
        Boolean AND operation (polygon set intersection).  +Accepts two objects that model polygon_45_set or one of its +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_45_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol +is also used for AND operations in Boolean logic expressions.  O( +n log n) runtime complexity and O(n) memory wrt vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_45_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set +disjoint-union).  Accepts two objects that model polygon_45_set or +one of its refinements.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_45_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set +difference).  Accepts two objects that model polygon_45_set or one +of its refinements.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left +operand must model polygon_45_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1>
        +T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Note: returns result by value.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Note: returns result by value.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Returns reference to modified argument.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Returns reference to modified argument.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        +

        Functions

        + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + + - - -
        template +<typename T1, typename T2>
        +T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an +object that models polygon_45_set or any of its refinements into an +object that models polygon_45_set.  O( n log n) runtime complexity +and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_45_set or +one of its refinements covers the exact same geometric regions as +another object that models polygon_45_set or one of its +refinements.  For example: two of polygon_45 objects.  O( n +log n) runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename output_container_type, typename T>
        +void get_trapezoids(output_container_type& output,
        +                    +const T& polygon_set)
        Output container is expected to be a standard +container.  Slices geometry of an object that models +polygon_45_set or one of its refinements into non overlapping +trapezoids along a vertical slicing orientation and appends them to the +output, which must have a value type that models polygon_45, +polygon_45_with_holes, polygon or polygon_with_holes.   O( n +log n) runtime complexity and O(n) memory wrt vertices.
        template +<typename output_container_type, typename T>
        +void get_trapezoids(output_container_type& output,
        +                    +const T& polygon_set,
                            orientation_2d orient)
        Output container is expected to be a standard container.  - Slices geometry of an object that models polygon_45_set or one of its - refinements into non overlapping trapezoids along a the specified slicing - orientation and appends them to the - output, which must have a value type that models polygon_45, - polygon_45_with_holes, polygon or polygon_with_holes.   O( n - log n) runtime complexity and O(n) memory wrt vertices.
        template <typename - polygon_set_type>
        - void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template <typename - polygon_set_type>
        - bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  Polygons that - are completely covered by holes will result in empty returning true.   - O( n log n) runtime complexity and O(n) memory wrt vertices.
        template <typename T, typename - rectangle_type>
        - bool extents(rectangle_type& extents_rectangle,
        -             const - T& polygon_set)
        Computes bounding box of an object that models polygon_45_set and - stores it in an object that models rectangle.  If the polygon set - is empty returns false.  If there are holes outside of shells they - do not contribute to the extents of the polygon set.   O( n - log n) runtime complexity and O(n) memory wrt vertices.
        template <typename T>
        - area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that models - polygon_45_set.   O( n log n) runtime complexity and O(n) - memory wrt vertices.
        template <typename T1, typename - T2>
        - T1& interact(T1& a, const T2& b)
        Given an object that models polygon_45_set and an object that models - polygon_45_set or one of its refinements, modifies a to retain only - regions that overlap or touch regions in b.   O( n log n) - runtime complexity and O(n) memory wrt vertices plus intersections.
        template <typename T>
        - T& self_intersect(T& polygon_set)
        Given an object that models polygon_45_set that has self overlapping - regions, modifies the argument to contain only the regions of overlap.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        - T& self_xor(T& polygon_set)
        Given an object that models polygon_45_set that has self overlapping - regions, modifies the argument to contain only the regions that do not - overlap.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the polygons, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the polygons, shrinking them and overwriting - the polygon set with the resulting regions.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T, typename - coord_type>
        - T& resize(T& polygon_set, coord_type resizing,
        -           - RoundingOption rounding = CLOSEST,
                  CornerOption corner = INTERSECTION)
        Same as bloat if resizing is positive, same as shrink if resizing is - negative.  RoundingOption is an enum that controls snapping of - non-integer results of resizing 45 degree edges.  CornerOption is - an enum that controls how corner filling is performed.  - polygon_45_set_data.hpp defines these enums.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        +
        Output container is expected to be a standard +container.  Slices geometry of an object that models +polygon_45_set or one of its refinements into non overlapping +trapezoids along a the specified slicing orientation and appends them +to the output, which must have a value type that models polygon_45, +polygon_45_with_holes, polygon or polygon_with_holes.   O( n +log n) runtime complexity and O(n) memory wrt vertices.
        template +<typename polygon_set_type>
        +void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template +<typename polygon_set_type>
        +bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  +Polygons that are completely covered by holes will result in empty +returning true.   O( n log n) runtime complexity and O(n) +memory wrt vertices.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& extents_rectangle,
        +             +const T& polygon_set)
        Computes bounding box of an object that models +polygon_45_set and stores it in an object that models rectangle.  +If the polygon set is empty returns false.  If there are holes +outside of shells they do not contribute to the extents of the polygon +set.   O( n log n) runtime complexity and O(n) memory wrt +vertices.
        template +<typename T>
        +area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that +models polygon_45_set.   O( n log n) runtime complexity and +O(n) memory wrt vertices.
        template +<typename T1, typename T2>
        +T1& interact(T1& a, const T2& b)
        Given an object that models polygon_45_set and an +object that models polygon_45_set or one of its refinements, modifies a +to retain only regions that overlap or touch regions in b.   +O( n log n) runtime complexity and O(n) memory wrt vertices plus +intersections.
        template +<typename T>
        +T& self_intersect(T& polygon_set)
        Given an object that models polygon_45_set that has +self overlapping regions, modifies the argument to contain only the +regions of overlap.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& self_xor(T& polygon_set)
        Given an object that models polygon_45_set that has +self overlapping regions, modifies the argument to contain only the +regions that do not overlap.  O( n log n) runtime complexity and +O(n) memory wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the polygons, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the polygons, shrinking them and +overwriting the polygon set with the resulting regions.  O( n log +n) runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename T, typename coord_type>
        +T& resize(T& polygon_set, coord_type resizing,
        +          RoundingOption +rounding = CLOSEST,
        +          CornerOption +corner = INTERSECTION)
        Same as bloat if resizing is positive, same as shrink +if resizing is negative.  RoundingOption is an enum that controls +snapping of non-integer results of resizing 45 degree edges.  +CornerOption is an enum that controls how corner filling is +performed.  polygon_45_set_data.hpp defines these enums.  O( +n log n) runtime complexity and O(n) memory wrt vertices + +intersections.
        template +<typename T>
        T& grow_and(T& polygon_set, unsigned_area_type bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& scale_up(T& polygon_set, unsigned_area_type factor)
        Scales geometry up by unsigned factor.  O( n log n) runtime - complexity and O(n) memory wrt vertices.
        template <typename T>
        +
        Scales geometry up by unsigned factor.  O( n log +n) runtime complexity and O(n) memory wrt vertices.
        template +<typename T>
        T& scale_down(T& polygon_set, unsigned_area_type factor)
        Scales geometry down by unsigned factor.  Snaps 45 degree edges - back to 45 degrees after division truncation leads to small changes in - angle.  O( n log n) runtime complexity and O(n) memory wrt - vertices.
        template <typename T, typename scaling_type>
        +
        Scales geometry down by unsigned factor.  Snaps 45 +degree edges back to 45 degrees after division truncation leads to +small changes in angle.  O( n log n) runtime complexity and O(n) +memory wrt vertices.
        template +<typename T, typename scaling_type>
        T& scale(polygon_set_type& polygon_set, double scaling)
        Scales geometry by multiplying by floating point factor.   - Snaps 45 degree edges back to 45 degrees after truncation of fractional - results of multiply leads to small changes in angle.  O( n log n) - runtime complexity and O(n) memory wrt vertices.
        template <typename T, typename transformation_type>
        +
        Scales geometry by multiplying by floating point +factor.   Snaps 45 degree edges back to 45 degrees after +truncation of fractional results of multiply leads to small changes in +angle.  O( n log n) runtime complexity and O(n) memory wrt +vertices.
        template +<typename T, typename transformation_type>
        T& transform(T& polygon_set,
        -             const -transformation_type& transformation)
        Applies transformation.transform() on all vertices.  O( n log - n) runtime complexity and O(n) memory wrt vertices.
        template <typename T>
        +             +const transformation_type& transformation)
        Applies transformation.transform() on all +vertices.  O( n log n) runtime complexity and O(n) memory wrt +vertices.
        template +<typename T>
        T& keep(T& polygon_set,
                unsigned_area_type min_area,
                unsigned_area_type max_area,
                unsigned_area_type min_width,
                unsigned_area_type max_width,
        -        unsigned_area_type min_height,
        -        unsigned_area_type max_height)
        Retains only regions that satisfy the min/max criteria in the - argument list.  Note: useful for visualization to cull too small - polygons.  O( n log n) runtime complexity and O(n) memory wrt - vertices.
        -

        Polygon 45 Set Data Object

        - -

        -

        The polygon 45 set data type encapsulates the internal data format that -serves as the input to the sweep-line algorithm that implements polygon-clipping -Boolean operations.  It also internally keeps track of whether that data -has been sorted or scanned and maintains the invariant that when its flags -indicate that the data is sorted or scanned the data has not been changed to -violate that assumption.  Using the Polygon 45 Set Data type directly can -be more efficient than using lists and vectors of polygons in the functions -above because of the invariants it can enforce which provide the opportunity to -maintain the data is sorted form rather than going all the way out to polygons -then resorting those vertices for a subsequent operation.

        -

        The declaration of Polygon 45 Set Data is the following:

        -

        template <typename T>
        +        unsigned_area_type +min_height,
        +        unsigned_area_type +max_height)

        Retains only regions that satisfy the min/max criteria +in the argument list.  Note: useful for visualization to cull too +small polygons.  O( n log n) runtime complexity and O(n) memory +wrt vertices.
        +

        Polygon 45 Set Data Object

        +

        +

        The polygon 45 set data type encapsulates the internal data +format that serves as the input to the sweep-line algorithm that +implements polygon-clipping Boolean operations.  It also +internally keeps track of whether that data has been sorted or scanned +and maintains the invariant that when its flags indicate that the data +is sorted or scanned the data has not been changed to violate that +assumption.  Using the Polygon 45 Set Data type directly can be +more efficient than using lists and vectors of polygons in the +functions above because of the invariants it can enforce which provide +the opportunity to maintain the data is sorted form rather than going +all the way out to polygons then resorting those vertices for a +subsequent operation.

        +

        The declaration of Polygon 45 Set Data is the following:

        +

        template <typename T>
        class polygon_45_set_data;

        -

        The class is parameterized on the coordinate data type.  Algorithms that -benefit from knowledge of the invariants enforced by the class are implemented -as member functions to provide them access to information about those -invariants. 

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - -
        polygon_45_set_data()Default constructor.
        template <typename iT>
        - polygon_45_set_data(iT input_begin, iT - input_end)
        Construct from an iterator range of - insertable objects.
        - polygon_45_set_data(const polygon_45_set_data& that)Copy construct.
        -template <typename l, typename r, typename op>
        -polygon_45_set_data(const polygon_45_set_view<l,r,op>& -t)
        Copy construct from a Boolean operator template.
        -polygon_45_set_data&
        operator=(const polygon_45_set_data& that)
        Assignment from another polygon set, may change scanning - orientation.
        -template <typename l, typename r, typename op>
        -polygon_45_set_data&
        operator=(const polygon_45_set_view<l, r, +

        The class is parameterized on the coordinate data type.  +Algorithms that benefit from knowledge of the invariants enforced by +the class are implemented as member functions to provide them access to +information about those invariants. 

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        polygon_45_set_data()Default constructor.
        template +<typename iT>
        + polygon_45_set_data(iT input_begin, iT input_end)
        Construct from an iterator range of insertable objects.
        polygon_45_set_data(const +polygon_45_set_data& that)Copy construct.
        template +<typename l, typename r, typename op>
        + polygon_45_set_data(const +polygon_45_set_view<l,r,op>& t)
        Copy construct from a Boolean operator template.
        polygon_45_set_data& +
        + operator=(const polygon_45_set_data& that)
        Assignment from another polygon set, may change +scanning orientation.
        template +<typename l, typename r, typename op>
        +polygon_45_set_data&
        + operator=(const polygon_45_set_view<l, r, op>& that)
        Assignment from a Boolean operator template.
        template <typename geometry_object>
        -polygon_45_set_data& operator=(const geometry_object& geo)
        Assignment from an insertable object.
        - + Assignment from a Boolean operator template.
        template +<typename geometry_object>
        +polygon_45_set_data& operator=(const geometry_object& +geo)
        Assignment from an insertable object.
        template <typename iT>
        -void insert(iT input_begin, iT input_end,
                    bool is_hole = false)
        Insert objects of an iterator range.  If is_hole is true - inserts subtractive regions.  Linear wrt the number of vertices - added.
        - -void insert(const polygon_45_set_data& polygon_set,
                    bool is_hole -= false)
        Insert a polygon set.  Linear wrt the number of vertices added.
        - +void insert(iT input_begin, iT input_end,
        +            bool +is_hole = false)
        Insert objects of an iterator range.  If is_hole +is true inserts subtractive regions.  Linear wrt the number of +vertices added.
        +void insert(const polygon_45_set_data& polygon_set,
        +            bool +is_hole = false)
        Insert a polygon set.  Linear wrt the number of +vertices added.
        template <typename geometry_type>
        -void insert(const geometry_type& geometry_object,
                    bool is_hole -= false)
        Insert a geometry object, if is_hole is true then the inserted - region is subtractive rather than additive.  Linear wrt the number - of vertices added.
        -template <typename output_container>
        +void insert(const geometry_type& geometry_object,
        +            bool +is_hole = false)
        Insert a geometry object, if is_hole is true then the +inserted region is subtractive rather than additive.  Linear wrt +the number of vertices added.
        template +<typename output_container>
        void get(output_container& output) const
        Expects a standard container of geometry objects.  Will scan - and eliminate overlaps.  Converts polygon set geometry to objects - of that type and appends them to the container.  Polygons will be - output with counterclockwise winding, hole polygons will be output with - clockwise winding.  The last vertex of an output polygon is not the - duplicate of the first, and the number of points is equal to the number - of edges.  O(n log n) runtime and O(n) memory wrt. vertices + - intersections.
        -template <typename output_container>
        +
        Expects a standard container of geometry objects.  +Will scan and eliminate overlaps.  Converts polygon set geometry +to objects of that type and appends them to the container.  +Polygons will be output with counterclockwise winding, hole polygons +will be output with clockwise winding.  The last vertex of an +output polygon is not the duplicate of the first, and the number of +points is equal to the number of edges.  O(n log n) runtime and +O(n) memory wrt. vertices + intersections.
        template +<typename output_container>
        void get_polygons(output_container& output) const
        Expects a standard container of polygon objects.  Will scan and - eliminate overlaps.  Converts polygon set geometry to polygons and - appends them to the container.  Polygons will have holes fractured - out to the outer boundary along the positive y direction.  O(n log - n) runtime and O(n) memory wrt. vertices + intersections.
        -template <typename output_container>
        +
        Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Converts polygon set geometry +to polygons and appends them to the container.  Polygons will have +holes fractured out to the outer boundary along the positive y +direction.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections.
        template +<typename output_container>
        void get_polygons_with_holes(output_container& o) const
        Expects a standard container of polygon with holes objects.  Will scan and - eliminate overlaps.  Converts polygon set geometry to polygons and - appends them to the container.  O(n log n) runtime and O(n) memory - wrt. vertices + intersections.
        -template <typename output_container>
        +
        Expects a standard container of polygon with holes +objects.  Will scan and eliminate overlaps.  Converts polygon +set geometry to polygons and appends them to the container.  O(n +log n) runtime and O(n) memory wrt. vertices + intersections.
        template +<typename output_container>
        void get_trapezoids(output_container& output) const
        Expects a standard container of polygon objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to trapezoids - vertically and appends them to the container.  O(n log n) runtime - and O(n) memory wrt. vertices + intersections.
        - + Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Slices polygon set geometry to +trapezoids vertically and appends them to the container.  O(n log +n) runtime and O(n) memory wrt. vertices + intersections.
        template <typename output_container>
        -void get_trapezoids(output_container& output,
          orientation_2d -slicing_orientation) const
        -
        Expects a standard container of polygon objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to trapezoids - along the given orientation and appends them to the container.  O(n - log n) runtime and O(n) memory wrt. vertices + intersections.
        - +void get_trapezoids(output_container& output,
        +  orientation_2d slicing_orientation) const
        Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Slices polygon set geometry to +trapezoids along the given orientation and appends them to the +container.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections.
        bool operator==(const polygon_45_set_data& p) constOnce scanned the data representation of geometry within a polygon - set is in a mathematically canonical form.  Comparison between two - sets is therefore a linear time operation once they are in the scanned - state. Will scan and eliminate overlaps in both polygon sets.  O(n - log n) runtime and O(n) memory wrt. vertices + intersections the first - time and linear runtime and constant memory subsequently. 
        -bool operator!=(const polygon_45_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not de-allocate memory.  - Use shrink to fit idiom and assign default constructed polygon set to - de-allocate.
        bool empty() const - Check whether the polygon set contains no geometry.  Will scan - and eliminate overlaps because subtractive regions might make the - polygon set empty.  O(n log n) runtime and O(n) memory wrt. - vertices + intersections the first time and linear runtime and constant - memory subsequently. 
        bool is_manhattan() - constReturns in constant time the information about whether the geometry - contains only Manhattan (axis-parallel rectilinear) edges.  - Constant time.
        void clean() constScan and eliminate overlaps.  O(n log n) runtime and O(n) - memory wrt. vertices + intersections the first time and linear runtime - and constant memory subsequently. 
        -template <typename input_iterator_type>
        -void set(input_iterator_type input_begin,
                 input_iterator_type input_end)
        -
        Overwrite geometry in polygon set with insertable objects in the - iterator range. 
        -template <typename rectangle_type>
        +
        Once scanned the data representation of geometry within +a polygon set is in a mathematically canonical form.  Comparison +between two sets is therefore a linear time operation once they are in +the scanned state. Will scan and eliminate overlaps in both polygon +sets.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections the first time and linear runtime and constant memory +subsequently. 
        bool operator!=(const +polygon_45_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not +de-allocate memory.  Use shrink to fit idiom and assign default +constructed polygon set to de-allocate.
        bool empty() +const Check whether the polygon set contains no +geometry.  Will scan and eliminate overlaps because subtractive +regions might make the polygon set empty.  O(n log n) runtime and +O(n) memory wrt. vertices + intersections the first time and linear +runtime and constant memory subsequently. 
        bool is_manhattan() +constReturns in constant time the information about whether +the geometry contains only Manhattan (axis-parallel rectilinear) +edges.  Constant time.
        void clean() +constScan and eliminate overlaps.  O(n log n) runtime +and O(n) memory wrt. vertices + intersections the first time and linear +runtime and constant memory subsequently. 
        template +<typename input_iterator_type>
        +void set(input_iterator_type input_begin,
        +         input_iterator_type +input_end)
        Overwrite geometry in polygon set with insertable +objects in the iterator range. 
        template +<typename rectangle_type>
        bool extents(rectangle_type& extents_rectangle) const
        Given an object that models rectangle, scans and eliminates overlaps - in the polygon set because subtractive regions may alter its extents - then computes the bounding box and assigns it to extents_rectangle.  - O(n log n) runtime and O(n) memory wrt. vertices the first time and - linear runtime and constant memory subsequently. 
        -polygon_45_set_data&
        -resize(coord_type resizing,
        -        RoundingOption rounding = CLOSEST,
               CornerOption - corner = INTERSECTION)
        Same as bloat if resizing is positive, same as shrink if resizing is - negative.  RoundingOption is an enum that controls snapping of - non-integer results of resizing 45 degree edges.  CornerOption is - an enum that controls how corner filling is performed.  - polygon_45_set_data.hpp defines these enums.  O(n log n) runtime - and O(n) memory wrt. vertices + intersections.
        -template <typename transformation_type>
        -polygon_45_set_data&
        transform(const transformation_type& transformation)
        -
        Applies transformation.transform() on vertices stored within the - polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + - intersections.
        -polygon_45_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  - Linear wrt vertices.
        -polygon_45_set_data& scale_down(unsigned_area_type -factor) Scales vertices stored within the polygon set down by factor.  - Linear wrt vertices.
        polygon_45_set_data& scale(double factor) Scales vertices stored within the polygon set by floating point - factor.  Linear wrt vertices.
        polygon_45_set_data& self_xor()Retain only non-overlapping regions of geometry within polygon set.  - O(n log n) runtime and O(n) memory wrt. vertices + intersections.
        polygon_45_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  - O(n log n) runtime and O(n) memory wrt. vertices + intersections.
        bool has_error_data() - const Returns true if non-integer intersections resulted in small - artifacts in the output of a boolean.  Constant time.
        std::size_t error_count() - constReturns the number of artifacts that may potentially be present in - the output due to non-integer intersections.  Constant time.
        void get_error_data(polygon_45_set_data& - p) constPopulates the input polygon set with 1x1 unit squares that bound the - error that may be present in the output due to non-integer - intersections.  Linear wrt. vertices of error data.
        polygon_45_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  - O(n log n) runtime and O(n) memory wrt. vertices + intersections.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Given an object that models rectangle, scans and +eliminates overlaps in the polygon set because subtractive regions may +alter its extents then computes the bounding box and assigns it to +extents_rectangle.  O(n log n) runtime and O(n) memory wrt. +vertices the first time and linear runtime and constant memory +subsequently. 
        polygon_45_set_data&
        + resize(coord_type resizing,
        +       RoundingOption rounding = CLOSEST, +
        +       CornerOption corner = INTERSECTION)
        Same as bloat if resizing is positive, same as shrink +if resizing is negative.  RoundingOption is an enum that controls +snapping of non-integer results of resizing 45 degree edges.  +CornerOption is an enum that controls how corner filling is +performed.  polygon_45_set_data.hpp defines these enums.  O(n +log n) runtime and O(n) memory wrt. vertices + intersections.
        template +<typename transformation_type>
        +polygon_45_set_data&
        + transform(const transformation_type& +transformation)
        Applies transformation.transform() on vertices stored +within the polygon set.  O(n log n) runtime and O(n) memory wrt. +vertices + intersections.
        polygon_45_set_data& + scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by +factor.  Linear wrt vertices.
        polygon_45_set_data& + scale_down(unsigned_area_type factor) Scales vertices stored within the polygon set down by +factor.  Linear wrt vertices.
        polygon_45_set_data& + scale(double factor) Scales vertices stored within the polygon set by +floating point factor.  Linear wrt vertices.
        polygon_45_set_data& + self_xor()Retain only non-overlapping regions of geometry within +polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections.
        polygon_45_set_data& + self_intersect()Retain only overlapping regions of geometry within a +polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections.
        bool has_error_data() +const Returns true if non-integer intersections resulted in +small artifacts in the output of a boolean.  Constant time.
        std::size_t error_count() +constReturns the number of artifacts that may potentially be +present in the output due to non-integer intersections.  Constant +time.
        void get_error_data(polygon_45_set_data& +p) constPopulates the input polygon set with 1x1 unit squares +that bound the error that may be present in the output due to +non-integer intersections.  Linear wrt. vertices of error data.
        polygon_45_set_data& + self_intersect()Retain only overlapping regions of geometry within a +polygon set.  O(n log n) runtime and O(n) memory wrt. vertices + +intersections.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_45_with_holes_concept.htm b/doc/gtl_polygon_45_with_holes_concept.htm index f0096a2..4fd8724 100644 --- a/doc/gtl_polygon_45_with_holes_concept.htm +++ b/doc/gtl_polygon_45_with_holes_concept.htm @@ -1,415 +1,461 @@ - + + Boost Polygon Library: Polygon 45 With Holes Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 45 With Holes Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 45 With Holes Concept

        - -

        -

        The polygon_45_with_holes concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 45 With Holes Concept

        +

        +

        The polygon_45_with_holes concept tag is polygon_45_with_holes_concept

        -

        -To register a user defined type as a model of -polygon_45_with_holes concept, specialize -the geometry concept meta-function for that type.  In the example below -CPolygon45WithHoles is registered as a model of polygon_45_with_holes  concept.

        -template <>
        -struct geometry_concept<CPolygon45WithHoles> { typedef polygon_45_with_holes_concept type; };

        -The semantic of a polygon_45_with_holes is a -polygon_45 that it can provide iterators over holes that are also polygon_45.  -A mutable polygon_45_with_holes must also be able to set its geometry based on -an interator range over polygon_45 holes.  There is no convention of -winding of holes enforced within the library.

        -Below is shown the default polygon with holes -traits.  Specialization of these traits is required for types that don't -conform to the default behavior.

        template <typename -T, typename enable = void>
        +

        To register a user defined type as a model of polygon_45_with_holes concept, +specialize the geometry concept meta-function for that type.  In +the example below CPolygon45WithHoles is registered as a model of +polygon_45_with_holes  concept.

        +

        template <>
        +struct geometry_concept<CPolygon45WithHoles> { typedef +polygon_45_with_holes_concept type; };

        +

        The semantic of a +polygon_45_with_holes is a polygon_45 that it can provide iterators +over holes that are also polygon_45.  A mutable +polygon_45_with_holes must also be able to set its geometry based on an +interator range over polygon_45 holes.  There is no convention of +winding of holes enforced within the library.

        +

        Below is shown the default +polygon with holes traits.  Specialization of these traits is +required for types that don't conform to the default behavior.

        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_traits {
        -     typedef typename T::iterator_holes_type +     typedef typename T::iterator_holes_type iterator_holes_type;
             typedef typename T::hole_type hole_type;
        -     static inline iterator_holes_type begin_holes(const T& -t) {
        -          return t.begin_holes();
        +     static inline iterator_holes_type +begin_holes(const T& t) {
        +          return +t.begin_holes();
             }
        -     static inline iterator_holes_type end_holes(const T& t) -{
        -          return t.end_holes();
        +     static inline iterator_holes_type +end_holes(const T& t) {
        +          return +t.end_holes();
             }
        -     static inline unsigned int size_holes(const T& t) {
        -          return t.size_holes();
        +     static inline unsigned int size_holes(const +T& t) {
        +          return +t.size_holes();
             }
        };

        -

        template <typename T, typename enable = void>
        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_mutable_traits {
             template <typename iT>
        -     static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
        -          t.set_holes(inputBegin, -inputEnd);
        +     static inline T& set_holes(T& t, iT +inputBegin, iT inputEnd) {
        +          +t.set_holes(inputBegin, inputEnd);
                  return t;
             }
        };

        -

        An object that is a model of -polygon_45_with_holes_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_45_with_holes_object)
        -view_as<polygon_90_concept>(polygon_45_with_holes_object)
        -view_as<polygon_90_with_holes_concept>(polygon_45_with_holes_object)
        -view_as<polygon_45_concept>(polygon_45_with_holes_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of - polygon_45_with_holes.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of - polygon_45_with_holes.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - hole_iterator_type begin_holes(const T& polygon)
        Expects a model of - polygon_45_with_holes.  - Returns the begin iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - hole_iterator_type end_holes(const T& polygon)
        Expects a model of - polygon_45_with_holes.  - Returns the end iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of - polygon_45_with_holes.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a polygon. 
        template <typename T, typename - iterator>
        - void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of - polygon_45_with_holes.   - Sets the polygon holes to the hole data range [b,e)
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - outer shell of the polygon_45_with_holes.  Does not include sizes - of the holes.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_45_with_holes or - one of its refinements into left object - that models polygon_45_with_holes.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon_45_with_holes and an object that models - point, returns true - if the polygon shell contains the point and one of its holes does not - contain the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon or one of its holes.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon_45_with_holes.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon_45_with_holes and returns true.  Returns false - and leaves bbox unchanged if polygon is empty.
        template <typename T>
        - manhattan_area_type area(const T& polygon)
        Returns the area of an object - that models polygon_45_with_holes including subtracting the area of its - holes from the area of the outer shell polygon.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon_45_with_holes, LOW == CLOCKWISE, HIGH = - COUNTERCLOCKWISE.
        template <typename T>
        - coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon_45, including the perimeters of the holes.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Also applies transform() on the holes - of the polygon.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that models - polygon_45 by unsigned factor.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that models - polygon_45 by unsigned factor.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models polygon_45 by - floating point factor.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon_45 .
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               +

        An object that is a model of +polygon_45_with_holes_concept can be viewed as a model of any of +its refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_45_with_holes_object)
        + view_as<polygon_90_concept>(polygon_45_with_holes_object)
        + view_as<polygon_90_with_holes_concept>(polygon_45_with_holes_object)
        + view_as<polygon_45_concept>(polygon_45_with_holes_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon_45_with_holes.  Returns the begin iterator over the range +of points that correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon_45_with_holes.  Returns the end iterator over the range of +points that correspond to vertices of the polygon.
        template +<typename T>
        +hole_iterator_type begin_holes(const T& polygon)
        Expects a model of +polygon_45_with_holes.  Returns the begin iterator over the range +of coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +hole_iterator_type end_holes(const T& polygon)
        Expects a model of +polygon_45_with_holes.  Returns the end iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_45_with_holes.   Sets the polygon to the point data +range [b,e) that corresponds to vertices of a polygon. 
        template +<typename T, typename iterator>
        +void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_45_with_holes.   Sets the polygon holes to the hole +data range [b,e)
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the outer shell of the polygon_45_with_holes.  Does not +include sizes of the holes.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models +polygon_45_with_holes or one of its refinements into left object that +models polygon_45_with_holes.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon_45_with_holes and +an object that models point, returns true if the polygon shell contains +the point and one of its holes does not contain the point.  If the +consider_touch flag is true will return true if the point lies along +the boundary of the polygon or one of its holes.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon_45_with_holes.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon_45_with_holes and returns true.  +Returns false and leaves bbox unchanged if polygon is empty.
        template +<typename T>
        +manhattan_area_type area(const T& polygon)
        Returns the area of an object that models +polygon_45_with_holes including subtracting the area of its holes from +the area of the outer shell polygon.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon_45_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
        template +<typename T>
        +coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon_45, including the perimeters of the holes.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Also applies transform() on the holes of the polygon.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that +models polygon_45 by unsigned factor.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that +models polygon_45 by unsigned factor.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models +polygon_45 by floating point factor.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon_45 .
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with the outer shell and holes of an - object that models polygon_45_with_holes.
        -

        Polygon 45 With Holes Data

        - -

        -

        The library provides a model of polygon 45 with holes concept declared - -template<typename T> polygon_45_with_holes_data where T is the -coordinate type.

        -

        This data type is used internally when a 45 degree polygon with holes is -needed and is available to the library user who finds it convenient to use a -library polygon data type instead of providing their own.  The data type is -implemented to be convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_45_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        iterator_holes_typeIterator over hole polygons of type - polygon_45_data<T>.
        polygon_45_with_holes_data()Default constructs the polygon.
        polygon_45_with_holes_data(const - polygon_45_with_holes_data& that)Copy construct
        polygon_45_with_holes_data& -
        operator=
        (const polygon_45_with_holes_data& that)
        Assignment operator.
        template <typename T2> - polygon_45_with_holes_data&  -
        operator=
        (const T2& that) const
        Assign from an object that is a model of polygon 45 with holes.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        iterator_hole_type begin_holes() - constGet the begin compact iterator over non-redundant coordinates of the - polygon.
        iterator_hole_type end_holes() - constGet the end compact iterator over non-redundant coordinates of the - polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        std::size_t size_holes() constGet the number of holes in the polygon
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  No check is - performed to ensure the points describe a 45 degree figure.
        template <typename iT>  -
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole polygons.  These - polygons in the input range may be either polygon_45_data or - polygon_45_with_holes_data or any type that provides begin and end - member functions to iterate over point_data<T>.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with the outer +shell and holes of an object that models polygon_45_with_holes.
        +

        Polygon 45 With Holes Data

        +

        +

        The library provides a model of polygon 45 with holes concept +declared + template<typename T> +polygon_45_with_holes_data where T is the coordinate type.

        +

        This data type is used internally when a 45 degree polygon +with holes is needed and is available to the library user who finds it +convenient to use a library polygon data type instead of providing +their own.  The data type is implemented to be convenient to use +with the library traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_45_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        iterator_holes_typeIterator over hole +polygons of type polygon_45_data<T>.
        polygon_45_with_holes_data()Default constructs the polygon.
        polygon_45_with_holes_data(const +polygon_45_with_holes_data& that)Copy construct
        polygon_45_with_holes_data& +
        +operator=
        (const polygon_45_with_holes_data& that)
        Assignment operator.
        template +<typename T2> polygon_45_with_holes_data& 
        +operator=
        (const T2& that) const
        Assign from an object that is a model of polygon 45 +with holes.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        iterator_hole_type + begin_holes() constGet the begin compact iterator over non-redundant +coordinates of the polygon.
        iterator_hole_type + end_holes() constGet the end compact iterator over non-redundant +coordinates of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        std::size_t size_holes() +constGet the number of holes in the polygon
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  +No check is performed to ensure the points describe a 45 degree figure.
        template +<typename iT> 
        +
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole +polygons.  These polygons in the input range may be either +polygon_45_data or polygon_45_with_holes_data or any type that provides +begin and end member functions to iterate over point_data<T>.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_90_concept.htm b/doc/gtl_polygon_90_concept.htm index 9247068..4a5c18c 100644 --- a/doc/gtl_polygon_90_concept.htm +++ b/doc/gtl_polygon_90_concept.htm @@ -1,411 +1,469 @@ - + + Boost Polygon Library: Polygon 90 Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 90 Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 90 Concept

        - -

        -

        The polygon_90 concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 90 Concept

        +

        +

        The polygon_90 concept tag is polygon_90_concept

        -

        -To register a user defined type as a model of -polygon_90 concept, specialize the -geometry concept meta-function for that type.  In the example below CPolygon90 is registered as a model of -polygon_90  concept.

        -template <>
        -struct geometry_concept<CPolygon90> { typedef polygon_90_concept type; };

        -The semantic of a polygon_90 is that it can provide -iterators over the x and y coordinates that correspond to its horizontal and -vertical sides, starting with an x coordinate.  A mutable polygon_90 must -also be able to set its geometry based on an interator range over such -coordinates.  Since most polygons use vertex points in internal storage -iterator adaptors for converting to and from point sequences are provided in -iterator_points_to_compact.hpp and iterator_compact_to_points.hpp to aid in the -specialization of polygon_90_traits.  A std::vector<int> or std::list<int> -could be made models of polygon_90_concept by simply providing access to their -iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

        -Below is shown the default polygon traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.  Note that these traits are also used by the -polygon_90_with_holes concept.

        template <typename -T>
        +

        To register a user defined type as a model of polygon_90 concept, specialize the +geometry concept meta-function for that type.  In the example +below CPolygon90 is registered as a model of polygon_90  concept.

        +

        template <>
        +struct geometry_concept<CPolygon90> { typedef polygon_90_concept +type; };

        +

        The semantic of a polygon_90 is +that it can provide iterators over the x and y coordinates that +correspond to its horizontal and vertical sides, starting with an x +coordinate.  A mutable polygon_90 must also be able to set its +geometry based on an interator range over such coordinates.  Since +most polygons use vertex points in internal storage iterator adaptors +for converting to and from point sequences are provided in +iterator_points_to_compact.hpp and iterator_compact_to_points.hpp to +aid in the specialization of polygon_90_traits.  A +std::vector<int> or std::list<int> could be made models of +polygon_90_concept by simply providing access to their iterators +through traits.  Library functions that create polygon objects +require that those objects provide a default constructor.

        +

        Below is shown the default +polygon traits.  Specialization of these traits is required for +types that don't conform to the default behavior.  Note that these +traits are also used by the polygon_90_with_holes concept.

        +

        template <typename T>
        struct polygon_90_traits {
        -     typedef typename T::coordinate_type coordinate_type;
        -     typedef typename T::compact_iterator_type +     typedef typename T::coordinate_type +coordinate_type;
        +     typedef typename T::compact_iterator_type compact_iterator_type;
        -     static inline compact_iterator_type begin_compact(const -T& t) {
        -          return t.begin_compact();
        +     static inline compact_iterator_type +begin_compact(const T& t) {
        +          return +t.begin_compact();
             }
        -     static inline compact_iterator_type end_compact(const -T& t) {
        -          return t.end_compact();
        +     static inline compact_iterator_type +end_compact(const T& t) {
        +          return +t.end_compact();
             }
        -     static inline unsigned int size(const T& t) {
        +     static inline unsigned int size(const T& +t) {
                  return t.size();
             }
        -     static inline winding_direction winding(const T& t) {
        -          return unknown_winding;
        +     static inline winding_direction winding(const +T& t) {
        +          return +unknown_winding;
             }
        };

        -

        template <typename T>
        +

        template <typename T>
        struct polygon_90_mutable_traits {
             template <typename iT>
        -     static inline T& set_compact(T& t, iT input_begin, iT -input_end) {
        -          t.set_compact(input_begin, -input_end);
        +     static inline T& set_compact(T& t, iT +input_begin, iT input_end) {
        +          +t.set_compact(input_begin, input_end);
                  return t;
             }

        -};

        -

        An object that is a model of -polygon_90_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_90_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - compact_iterator_type begin_compact(const T& polygon)
        Expects a model of polygon_90.  - Returns the begin iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - compact_iterator_type end_compact(const T& polygon)
        Expects a model of polygon_90.  - Returns the end iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of polygon_90.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of polygon_90.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T, typename - iterator>
        - void set_compact(T& polygon, iterator b, iterator e)
        Expects a model of polygon_90.   - Sets the polygon to the coordinate data range [b,e) that corresponds to - .horizontal and vertical edges.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of polygon_90.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a manhattan polygon.  Non-manhattan edges between - successive input points results in undefined behavior.
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - polygon.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_90 into left object - that models polygon_90.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon_90 and an object that models - point, returns true - if the polygon contains the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon.  Linear wrt. vertices.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon_90.  Linear wrt. vertices.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon_90 and returns true.  Returns false and leaves - bbox unchanged if polygon is empty.  Linear wrt. vertices.
        template <typename T>
        - manhattan_area_type area(const T& polygon)
        Returns the area of an object - that models polygon_90.  Linear wrt. vertices.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon_90, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  - Complexity depends upon winding trait.
        template <typename T>
        - coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon_90.  Linear wrt. vertices.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Linear wrt. vertices.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models - polygon_90 by unsigned factor.  Linear wrt. vertices.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models - polygon_90 by unsigned factor.  Linear wrt. vertices.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon_90 by floating - point factor.  Linear wrt. vertices.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon_90 .  Linear wrt. - vertices.
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               + };

        +

        An object that is a model of +polygon_90_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_90_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +compact_iterator_type begin_compact(const T& polygon)
        Expects a model of +polygon_90.  Returns the begin iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +compact_iterator_type end_compact(const T& polygon)
        Expects a model of +polygon_90.  Returns the end iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon_90.  Returns the begin iterator over the range of points +that correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon_90.  Returns the end iterator over the range of points +that correspond to vertices of the polygon.
        template +<typename T, typename iterator>
        +void set_compact(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_90.   Sets the polygon to the coordinate data range +[b,e) that corresponds to .horizontal and vertical edges.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_90.   Sets the polygon to the point data range [b,e) +that corresponds to vertices of a manhattan polygon.  +Non-manhattan edges between successive input points results in +undefined behavior.
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the polygon.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_90 +into left object that models polygon_90.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon_90 and an object +that models point, returns true if the polygon contains the +point.  If the consider_touch flag is true will return true if the +point lies along the boundary of the polygon.  Linear wrt. +vertices.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon_90.  Linear wrt. +vertices.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon_90 and returns true.  Returns +false and leaves bbox unchanged if polygon is empty.  Linear wrt. +vertices.
        template +<typename T>
        +manhattan_area_type area(const T& polygon)
        Returns the area of an object that models +polygon_90.  Linear wrt. vertices.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon_90, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity +depends upon winding trait.
        template +<typename T>
        +coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon_90.  Linear wrt. vertices.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models +polygon_90 by unsigned factor.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models +polygon_90 by unsigned factor.  Linear wrt. vertices.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon_90 +by floating point factor.  Linear wrt. vertices.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon_90 .  +Linear wrt. vertices.
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with vertices of an - object that models polygon_90.  Linear wrt. vertices.
        -

        Polygon 90 Data

        - -

        -

        The library provides a model of polygon 90 concept declared - -template<typename T> polygon_90_data where T is the coordinate type.

        -

        This data type is used internally when a Manhattan polygon is needed and is -available to the library user who finds it convenient to use a library polygon -data type instead of providing their own.  The data type is implemented to -be convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_90_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        compact_iterator_typeIterator over non-redundant coordinates - of the polygon, alternating x, y, x, y starting with an x, where each x - corresponds to a vertical edge and each y corresponds to a horizontal - edge.
        polygon_90_data()Default constructs the polygon.
        polygon_90_data(const - polygon_90_data& that)Copy construct
        polygon_90_data& operator=(const - polygon_90_data& that)Assignment operator.
        template <typename T2>  -
        polygon_90_data& operator=(const T2& that) const
        Assign from an object that is a model of polygon 90.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        compact_iterator_type - begin_compact() constGet the begin compact iterator over non-redundant coordinates of the - polygon.
        compact_iterator_type - end_compact() constGet the end compact iterator over non-redundant coordinates of the - polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  No check is - performed to ensure the points describe a Manhattan figure, every other - x and y value of the points is used to initialize the polygon.
        template <typename iT>  -
        void set_compact(iT begin_coords, iT end_coords)
        Sets the polygon to the iterator range of coordinates.  These - coordinates correspond to the x values of vertical edges and y values of - horizontal edges.  It is expected that the sequence start with an x - value and proceed x then y then x then y.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with vertices of +an object that models polygon_90.  Linear wrt. vertices.
        +

        Polygon 90 Data

        +

        +

        The library provides a model of polygon 90 concept declared + template<typename T> +polygon_90_data where T is the coordinate type.

        +

        This data type is used internally when a Manhattan polygon is +needed and is available to the library user who finds it convenient to +use a library polygon data type instead of providing their own.  +The data type is implemented to be convenient to use with the library +traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_90_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        compact_iterator_typeIterator over +non-redundant coordinates of the polygon, alternating x, y, x, y +starting with an x, where each x corresponds to a vertical edge and +each y corresponds to a horizontal edge.
        polygon_90_data()Default constructs the polygon.
        polygon_90_data(const +polygon_90_data& that)Copy construct
        polygon_90_data& + operator=(const polygon_90_data& that)Assignment operator.
        template +<typename T2> 
        +
        polygon_90_data& operator=(const T2& +that) const
        Assign from an object that is a model of polygon 90.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        compact_iterator_type + begin_compact() constGet the begin compact iterator over non-redundant +coordinates of the polygon.
        compact_iterator_type + end_compact() constGet the end compact iterator over non-redundant +coordinates of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  +No check is performed to ensure the points describe a Manhattan figure, +every other x and y value of the points is used to initialize the +polygon.
        template +<typename iT> 
        +
        void set_compact(iT begin_coords, iT end_coords)
        Sets the polygon to the iterator range of +coordinates.  These coordinates correspond to the x values of +vertical edges and y values of horizontal edges.  It is expected +that the sequence start with an x value and proceed x then y then x +then y.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_90_set_concept.htm b/doc/gtl_polygon_90_set_concept.htm index 156e5ca..127d5c4 100644 --- a/doc/gtl_polygon_90_set_concept.htm +++ b/doc/gtl_polygon_90_set_concept.htm @@ -1,917 +1,1016 @@ - + + Boost Polygon Library: Polygon 90 Set Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 90 Set Concept + + + + + + + + - + + + + + + + + + + + + + + + + + + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 90 Set Concept

        - -

        -

        The polygon_90_set concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 90 Set Concept

        +

        +

        The polygon_90_set concept tag is polygon_90_set_concept

        -

        -The semantic of a polygon_90_set is zero or more -Manhattan geometry regions.

        -The motivation for providing the -polygon_90_set_concept is that it is a very common special case of planar -geometry which afford the implementation of a variety of optimizations on the -general planar geometry algorithms.  Manhattan geometry processing by the -polygon_90_set_concept can be 100X faster than arbitrary angle polygon -manipulation.  Because the performance benefits are so large and the -special case is important enough, the library provides these performance -benefits for those application domains that require them.

        Users are recommended to use std::vector and std::list of user defined polygons -or library provided polygon_90_set_data<coordinate_type> objects.  Lists -and vectors of models of polygon_90_concept or polygon_90_with_holes_concept or -rectangle_concept are automatically models of polygon_90_set_concept.

        -

        Operators

        -

        The return type of some operators is the polygon_90_set_view -operator template type.  This type is itself a model of the polygon_90_set -concept, but furthermore can be used as an argument to the polygon_90_set_data -constructor and assignment operator.  The operator template exists to -eliminate temp copies of intermediate results when Boolean operators are chained +

        The semantic of a +polygon_90_set is zero or more Manhattan geometry regions.

        +

        The motivation for providing +the polygon_90_set_concept is that it is a very common special case of +planar geometry which afford the implementation of a variety of +optimizations on the general planar geometry algorithms.  +Manhattan geometry processing by the polygon_90_set_concept can be 100X +faster than arbitrary angle polygon manipulation.  Because the +performance benefits are so large and the special case is important +enough, the library provides these performance benefits for those +application domains that require them.

        +

        Users are recommended to use std::vector and std::list of user +defined polygons or library provided +polygon_90_set_data<coordinate_type> objects.  Lists and +vectors of models of polygon_90_concept or +polygon_90_with_holes_concept or rectangle_concept are automatically +models of polygon_90_set_concept.

        +

        Operators

        +

        The return type of some operators is the polygon_90_set_view operator template +type.  This type is itself a model of the polygon_90_set concept, +but furthermore can be used as an argument to the polygon_90_set_data constructor and +assignment operator.  The operator template exists to eliminate +temp copies of intermediate results when Boolean operators are chained together.

        -

        Operators are declared inside the namespace boost::polygon::operators.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T1, typename - T2>
        - polygon_90_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts two objects - that model polygon_90_set or one of its refinements.  Returns an - operator template that performs the operation on demand when chained or - or nested in a library function call such as assign().  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_90_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for OR - operations in Boolean logic expressions.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_90_set_view operator&(const T1& l, const T2& r)
        Boolean AND operation (polygon set intersection).  Accepts two - objects that model polygon_90_set or one of its refinements.  O( n - log n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_90_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol is also used for - AND operations in Boolean logic expressions.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_90_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set disjoint-union).  Accepts - two objects that model polygon_90_set or one of its refinements.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_90_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set difference).  Accepts - two objects that model polygon_90_set or one of its refinements.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T1, typename - T2>
        - T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left operand must model - polygon_90_set and not one of it's refinements.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T1>
        - T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Note: returns - result by value.  O( n log n) runtime complexity and O(n) memory - wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Note: returns - result by value.  O( n log n) runtime complexity and O(n) memory - wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Returns - reference to modified argument.  O( n log n) runtime complexity and - O(n) memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Returns - reference to modified argument.  O( n log n) runtime complexity and - O(n) memory wrt vertices + intersections.
        -

        Functions

        - - - - - - - - - - - - - - - + + + +
        template <typename T1, typename - T2>
        - T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an object that - models polygon_90_set or any of its refinements into an object that - models polygon_90_set.  O( n log n) runtime complexity and O(n) - memory wrt vertices + intersections.
        template <typename T1, typename - T2>
        - bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_90_set or one of its - refinements covers the exact same geometric regions as another object - that models polygon_90_set or one of its refinements.  For example: - two of polygon_90 objects.  O( n log n) runtime complexity and O(n) - memory wrt vertices + intersections.
        template <typename - output_container_type, typename T>
        - void get_rectangles(output_container_type& output,
        -                    - const T& polygon_set)
        Output container is expected to be a standard container.  - Slices geometry of an object that models polygon_90_set or one of its - refinements into non overlapping rectangles and appends them to the - output.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename - output_container_type, typename T>
        - void get_max_rectangles(output_container_type& output,
                                +

        Operators are declared inside the namespace boost::polygon::operators.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        template +<typename T1, typename T2>
        +polygon_90_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts +two objects that model polygon_90_set or one of its refinements.  +Returns an operator template that performs the operation on demand when +chained or or nested in a library function call such as assign().  +O( n log n) runtime complexity and O(n) memory wrt vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_90_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for +OR operations in Boolean logic expressions.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_90_set_view operator&(const T1& l, const +T2& r)
        Boolean AND operation (polygon set intersection).  +Accepts two objects that model polygon_90_set or one of its +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_90_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol +is also used for AND operations in Boolean logic expressions.  O( +n log n) runtime complexity and O(n) memory wrt vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_90_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set +disjoint-union).  Accepts two objects that model polygon_90_set or +one of its refinements.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_90_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set +difference).  Accepts two objects that model polygon_90_set or one +of its refinements.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left +operand must model polygon_90_set and not one of it's +refinements.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T1>
        +T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Note: returns result by value.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Note: returns result by value.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Returns reference to modified argument.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Returns reference to modified argument.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        +

        Functions

        + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + + - - - - + + + + - - - - + + + - - - - + + + + - - -
        template +<typename T1, typename T2>
        +T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an +object that models polygon_90_set or any of its refinements into an +object that models polygon_90_set.  O( n log n) runtime complexity +and O(n) memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_90_set or +one of its refinements covers the exact same geometric regions as +another object that models polygon_90_set or one of its +refinements.  For example: two of polygon_90 objects.  O( n +log n) runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename output_container_type, typename T>
        +void get_rectangles(output_container_type& output,
        +                    const T& polygon_set)
        Output container is expected to be a standard container.  Given - an object that models polygon_90_set or one of its refinements finds all - overlapping rectangles that are maximal in area and appends them to the - output.  Expected n log n runtime, worst case quadratic rutnime.
        template <typename - polygon_set_type>
        - void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template <typename - polygon_set_type>
        - bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  Polygons that - are completely covered by holes will result in empty returning true.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T, typename - rectangle_type>
        - bool extents(rectangle_type& extents_rectangle,
        -             const - T& polygon_set)
        Computes bounding box of an object that models polygon_90_set and - stores it in an object that models rectangle.  If the polygon set - is empty returns false.  If there are holes outside of shells they - do not contribute to the extents of the polygon set.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - manhattan_area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that models - polygon_90_set.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename T1, typename - T2>
        - T1& interact(T1& a, const T2& b)
        Given an object that models polygon_90_set and an object that models - polygon_90_set or one of its refinements, modifies a to retain only - regions that overlap or touch regions in b.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - T& self_intersect(T& polygon_set)
        Given an object that models polygon_90_set that has self overlapping - regions, modifies the argument to contain only the regions of overlap.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        - T& self_xor(T& polygon_set)
        Given an object that models polygon_90_set that has self overlapping - regions, modifies the argument to contain only the regions that do not - overlap.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the rectangles, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, orientation_2d orient,
        -         unsigned_area_type bloating)
        Same as getting all the rectangles, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, orientation_2d orient,
        -         unsigned_area_type low_bloating,
        -         unsigned_area_type - high_bloating)
        Same as getting all the rectangles, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, direction_2d dir,
        -         unsigned_area_type bloating)
        Same as getting all the rectangles, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& bloat(T& polygon_set,
        -         unsigned_area_type - west_bloating,
        -         unsigned_area_type - east_bloating,
        -         unsigned_area_type - south_bloating,
        -         unsigned_area_type - north_bloating)
        Same as getting all the rectangles, bloating them and putting them - back.  O( n log n) runtime complexity and O(n) memory wrt vertices - + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the rectangles of the inverse, bloating them and overwriting - the polygon set with the resulting regions then negating.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, orientation_2d orient,
        -          unsigned_area_type - shrinking)
        Same as getting all the rectangles of the inverse, bloating them and overwriting - the polygon set with the resulting regions then negating.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, orientation_2d orient,
        -          unsigned_area_type - low_shrinking,
        -          unsigned_area_type - high_shrinking)
        Same as getting all the rectangles of the inverse, bloating them and overwriting - the polygon set with the resulting regions then negating.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, direction_2d dir,
        -          unsigned_area_type - shrinking)
        Same as getting all the rectangles of the inverse, bloating them and overwriting - the polygon set with the resulting regions then negating.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        - T& shrink(T& polygon_set,
        -          unsigned_area_type - west_shrinking,
        -          unsigned_area_type - east_shrinking,
        -          unsigned_area_type - south_shrinking,
        -          unsigned_area_type - north_shrinking)
        Same as getting all the rectangles of the inverse, bloating them and overwriting - the polygon set with the resulting regions then negating.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T, typename - coord_type>
        - T& resize(T& polygon_set, coord_type resizing)
        Same as bloat if resizing is positive, same as shrink if resizing is - negative.
        template <typename T, typename - coord_type>
        - T& resize(polygon_set_type& polygon_set,
        -          coord_type west, coord_type east, -
                  coord_type south, coord_type north)
        Same as bloat if resizing is positive, same as shrink if resizing is - negative.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        template <typename T>
        +
        Output container is expected to be a standard +container.  Slices geometry of an object that models +polygon_90_set or one of its refinements into non overlapping +rectangles and appends them to the output.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename output_container_type, typename T>
        +void get_max_rectangles(output_container_type& output,
        +                        +const T& polygon_set)
        Output container is expected to be a standard +container.  Given an object that models polygon_90_set or one of +its refinements finds all overlapping rectangles that are maximal in +area and appends them to the output.  Expected n log n runtime, +worst case quadratic rutnime.
        template +<typename polygon_set_type>
        +void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template +<typename polygon_set_type>
        +bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  +Polygons that are completely covered by holes will result in empty +returning true.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& extents_rectangle,
        +             +const T& polygon_set)
        Computes bounding box of an object that models +polygon_90_set and stores it in an object that models rectangle.  +If the polygon set is empty returns false.  If there are holes +outside of shells they do not contribute to the extents of the polygon +set.  O( n log n) runtime complexity and O(n) memory wrt vertices ++ intersections.
        template +<typename T>
        +manhattan_area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that +models polygon_90_set.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T1, typename T2>
        +T1& interact(T1& a, const T2& b)
        Given an object that models polygon_90_set and an +object that models polygon_90_set or one of its refinements, modifies a +to retain only regions that overlap or touch regions in b.  O( n +log n) runtime complexity and O(n) memory wrt vertices + intersections. +
        template +<typename T>
        +T& self_intersect(T& polygon_set)
        Given an object that models polygon_90_set that has +self overlapping regions, modifies the argument to contain only the +regions of overlap.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& self_xor(T& polygon_set)
        Given an object that models polygon_90_set that has +self overlapping regions, modifies the argument to contain only the +regions that do not overlap.  O( n log n) runtime complexity and +O(n) memory wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the rectangles, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, orientation_2d orient,
        +         unsigned_area_type +bloating)
        Same as getting all the rectangles, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, orientation_2d orient,
        +         unsigned_area_type +low_bloating,
        +         unsigned_area_type +high_bloating)
        Same as getting all the rectangles, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, direction_2d dir,
        +         unsigned_area_type +bloating)
        Same as getting all the rectangles, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set,
        +         unsigned_area_type +west_bloating,
        +         unsigned_area_type +east_bloating,
        +         unsigned_area_type +south_bloating,
        +         unsigned_area_type +north_bloating)
        Same as getting all the rectangles, bloating them and +putting them back.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the rectangles of the inverse, +bloating them and overwriting the polygon set with the resulting +regions then negating.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, orientation_2d orient,
        +          +unsigned_area_type shrinking)
        Same as getting all the rectangles of the inverse, +bloating them and overwriting the polygon set with the resulting +regions then negating.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, orientation_2d orient,
        +          +unsigned_area_type low_shrinking,
        +          +unsigned_area_type high_shrinking)
        Same as getting all the rectangles of the inverse, +bloating them and overwriting the polygon set with the resulting +regions then negating.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, direction_2d dir,
        +          +unsigned_area_type shrinking)
        Same as getting all the rectangles of the inverse, +bloating them and overwriting the polygon set with the resulting +regions then negating.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set,
        +          +unsigned_area_type west_shrinking,
        +          +unsigned_area_type east_shrinking,
        +          +unsigned_area_type south_shrinking,
        +          +unsigned_area_type north_shrinking)
        Same as getting all the rectangles of the inverse, +bloating them and overwriting the polygon set with the resulting +regions then negating.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T, typename coord_type>
        +T& resize(T& polygon_set, coord_type resizing)
        Same as bloat if resizing is positive, same as shrink +if resizing is negative.
        template +<typename T, typename coord_type>
        +T& resize(polygon_set_type& polygon_set,
        +          coord_type west, +coord_type east,
        +          coord_type +south, coord_type north)
        Same as bloat if resizing is positive, same as shrink +if resizing is negative.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T>
        T& grow_and(T& polygon_set, unsigned_area_type bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& grow_and(T& polygon_set, orientation_2d orient,
        -            +            unsigned_area_type bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& grow_and(T& polygon_set, orientation_2d orient,
        -            +            unsigned_area_type low_bloating,
        -            +            unsigned_area_type high_bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& grow_and(T& polygon_set, direction_2d dir,
        -            +            unsigned_area_type bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& grow_and(T& polygon_set,
        -            +            unsigned_area_type west_bloating,
        -            +            unsigned_area_type east_bloating,
        -            +            unsigned_area_type south_bloating,
        -            +            unsigned_area_type north_bloating)
        Same as bloating non-overlapping regions and then applying self - intersect to retain only the overlaps introduced by the bloat.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T>
        +
        Same as bloating non-overlapping regions and then +applying self intersect to retain only the overlaps introduced by the +bloat.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& scale_up(T& polygon_set, unsigned_area_type factor)
        Scales geometry up by unsigned factor.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        +
        Scales geometry up by unsigned factor.  O( n log +n) runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename T>
        T& scale_down(T& polygon_set, unsigned_area_type factor)
        Scales geometry down by unsigned factor.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        template <typename T, typename scaling_type>
        +
        Scales geometry down by unsigned factor.  O( n log +n) runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename T, typename scaling_type>
        T& scale(polygon_set_type& polygon_set,
        -         const scaling_type& scaling)
        Scales geometry by applying scaling.scale() on all vertices.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T, typename coord_type>
        +         const +scaling_type& scaling)
        Scales geometry by applying scaling.scale() on all +vertices.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T, typename coord_type>
        T& move(T& polygon_set,
        -        orientation_2d orient, coord_type -displacement)
        Moves geometry by displacement amount in the orientation.    - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        template <typename T, typename coord_type>
        +        orientation_2d orient, +coord_type displacement)
        Moves geometry by displacement amount in the +orientation.    O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template +<typename T, typename coord_type>
        T& move(T& polygon_set, coord_type x_displacement,
                coord_type y_displacement)
        Moves the geometry by x_dispacement in x and y_displacement in y.  - Note: for consistency should be convolve(polygon_set, point).  O( n - log n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T, typename transformation_type>
        +
        Moves the geometry by x_dispacement in x and +y_displacement in y.  Note: for consistency should be +convolve(polygon_set, point).  O( n log n) runtime complexity and +O(n) memory wrt vertices + intersections.
        template +<typename T, typename transformation_type>
        T& transform(T& polygon_set,
        -             const -transformation_type& transformation)
        Applies transformation.transform() on all vertices.  O( n log - n) runtime complexity and O(n) memory wrt vertices + intersections.
        template <typename T>
        +             +const transformation_type& transformation)
        Applies transformation.transform() on all +vertices.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        template +<typename T>
        T& keep(T& polygon_set,
                unsigned_area_type min_area,
                unsigned_area_type max_area,
                unsigned_area_type min_width,
                unsigned_area_type max_width,
        -        unsigned_area_type min_height,
        -        unsigned_area_type max_height)
        Retains only regions that satisfy the min/max criteria in the - argument list.  Note: useful for visualization to cull too small - polygons.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        -

        Polygon 90 Set Data Object

        - -

        -

        The polygon 90 set data type encapsulates the internal data format that -serves as the input to the sweep-line algorithm that implements polygon-clipping -boolean operations.  It also internally keeps track of whether that data -has been sorted or scanned and maintains the invariant that when its flags -indicate that the data is sorted or scanned the data has not been changed to -violate that assumption.  Using the Polygon 90 Set Data type directly can -be more efficient than using lists and vectors of polygons in the functions -above because of the invariants it can enforce which provide the opportunity to -maintain the data is sorted form rather than going all the way out to polygons -then resorting those vertices for a subsequent operation.

        -

        The declaration of Polygon 90 Set Data is the following:

        -

        template <typename T>
        +        unsigned_area_type +min_height,
        +        unsigned_area_type +max_height)

        Retains only regions that satisfy the min/max criteria +in the argument list.  Note: useful for visualization to cull too +small polygons.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        +

        Polygon 90 Set Data Object

        +

        +

        The polygon 90 set data type encapsulates the internal data +format that serves as the input to the sweep-line algorithm that +implements polygon-clipping boolean operations.  It also +internally keeps track of whether that data has been sorted or scanned +and maintains the invariant that when its flags indicate that the data +is sorted or scanned the data has not been changed to violate that +assumption.  Using the Polygon 90 Set Data type directly can be +more efficient than using lists and vectors of polygons in the +functions above because of the invariants it can enforce which provide +the opportunity to maintain the data is sorted form rather than going +all the way out to polygons then resorting those vertices for a +subsequent operation.

        +

        The declaration of Polygon 90 Set Data is the following:

        +

        template <typename T>
        class polygon_90_set_data;

        -

        The class is parameterized on the coordinate data type.  Algorithms that -benefit from knowledge of the invariants enforced by the class are implemented -as member functions to provide them access to information about those -invariants. 

        -

        Member Functions

        - - - - - - - - - - - - -
        polygon_90_set_data()Default constructor.  Scanning orientation defaults to - HORIZONTAL
        polygon_90_set_data(orientation_2d - orient)Construct with scanning orientation.
        template <typename iT>
        - polygon_90_set_data(orientation_2d orient,
                            +

        The class is parameterized on the coordinate data type.  +Algorithms that benefit from knowledge of the invariants enforced by +the class are implemented as member functions to provide them access to +information about those invariants. 

        +

        Member Functions

        + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + - - - - + + + - - - - + + + - - - - + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        polygon_90_set_data()Default constructor.  Scanning orientation +defaults to HORIZONTAL
        polygon_90_set_data(orientation_2d +orient)Construct with scanning orientation.
        template +<typename iT>
        + polygon_90_set_data(orientation_2d orient,
        +                    iT input_begin, iT input_end)
        Construct with scanning orientation from an iterator range of - insertable objects.
        - polygon_90_set_data(const polygon_90_set_data& that)Copy construct.
        -template <typename l, typename r, typename op>
        -polygon_90_set_data(const polygon_90_set_view<l,r,op>& -t)
        Copy construct from a Boolean operator template.
        - -polygon_90_set_data(orientation_2d orient,
                            +
        Construct with scanning orientation from an iterator +range of insertable objects.
        polygon_90_set_data(const +polygon_90_set_data& that)Copy construct.
        template +<typename l, typename r, typename op>
        + polygon_90_set_data(const +polygon_90_set_view<l,r,op>& t)
        Copy construct from a Boolean operator template.
        + polygon_90_set_data(orientation_2d orient,
        +                    const polygon_90_set_data& that)
        Construct with scanning orientation and copy from another polygon - set.
        -polygon_90_set_data&
        operator=(const polygon_90_set_data& that)
        Assignment from another polygon set, may change scanning - orientation.
        -template <typename l, typename r, typename op>
        -polygon_90_set_data&
        operator=(const polygon_90_set_view<l, r, +
        Construct with scanning orientation and copy from +another polygon set.
        polygon_90_set_data& +
        + operator=(const polygon_90_set_data& that)
        Assignment from another polygon set, may change +scanning orientation.
        template +<typename l, typename r, typename op>
        +polygon_90_set_data&
        + operator=(const polygon_90_set_view<l, r, op>& that)
        Assignment from a Boolean operator template.
        template <typename geometry_object>
        -polygon_90_set_data& operator=(const geometry_object& geo)
        Assignment from an insertable object.
        - + Assignment from a Boolean operator template.
        template +<typename geometry_object>
        +polygon_90_set_data& operator=(const geometry_object& +geo)
        Assignment from an insertable object.
        template <typename iT>
        void insert(iT input_begin, iT input_end)
        Insert objects of an iterator range.  Linear wrt. inserted - vertices.
        - + Insert objects of an iterator range.  Linear wrt. +inserted vertices.
        void insert(const polygon_90_set_data& polygon_set)Insert a polygon set.  Linear wrt. inserted vertices.
        - + Insert a polygon set.  Linear wrt. inserted +vertices.
        template <typename geometry_type>
        -void insert(const geometry_type& geometry_object,
                    bool is_hole -= false)
        Insert a geometry object, if is_hole is true then the inserted - region is subtractive rather than additive.  Linear wrt. inserted - vertices.
        -template <typename output_container>
        +void insert(const geometry_type& geometry_object,
        +            bool +is_hole = false)
        Insert a geometry object, if is_hole is true then the +inserted region is subtractive rather than additive.  Linear wrt. +inserted vertices.
        template +<typename output_container>
        void get(output_container& output) const
        Expects a standard container of geometry objects.  Will scan - and eliminate overlaps.  Converts polygon set geometry to objects - of that type and appends them to the container.  Polygons will be - output with counterclockwise winding, hole polygons will be output with - clockwise winding.  The last vertex of an output polygon is not the - duplicate of the first, and the number of points is equal to the number - of edges.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        -template <typename output_container>
        +
        Expects a standard container of geometry objects.  +Will scan and eliminate overlaps.  Converts polygon set geometry +to objects of that type and appends them to the container.  +Polygons will be output with counterclockwise winding, hole polygons +will be output with clockwise winding.  The last vertex of an +output polygon is not the duplicate of the first, and the number of +points is equal to the number of edges.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
        template +<typename output_container>
        void get_polygons(output_container& output) const
        Expects a standard container of polygon objects.  Will scan and - eliminate overlaps.  Converts polygon set geometry to polygons and - appends them to the container.  Polygons will have holes fractured - out to the outer boundary along the positive direction of the scanline - orientation of the polygon set.  O( n log n) runtime complexity and - O(n) memory wrt vertices + intersections.
        -template <typename output_container>
        +
        Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Converts polygon set geometry +to polygons and appends them to the container.  Polygons will have +holes fractured out to the outer boundary along the positive direction +of the scanline orientation of the polygon set.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        template +<typename output_container>
        void get_rectangles(output_container& output) const
        Expects a standard container of rectangle objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to rectangles - along the scanning orientation and appends them to the container.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        - + Expects a standard container of rectangle +objects.  Will scan and eliminate overlaps.  Slices polygon +set geometry to rectangles along the scanning orientation and appends +them to the container.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        template <typename output_container>
        -void get_rectangles(output_container& output,
          orientation_2d -slicing_orientation) const
        -
        Expects a standard container of rectangle objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to rectangles - along the given orientation and appends them to the container.  O( - n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        - +void get_rectangles(output_container& output,
        +  orientation_2d slicing_orientation) const
        Expects a standard container of rectangle +objects.  Will scan and eliminate overlaps.  Slices polygon +set geometry to rectangles along the given orientation and appends them +to the container.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        bool operator==(const polygon_90_set_data& p) constOnce scanned the data representation of geometry within a polygon - set is in a mathematically canonical form.  Comparison between two - sets is therefore a linear time operation once they are in the scanned - state. Will scan and eliminate overlaps in both polygon sets.  O( n - log n) runtime complexity and O(n) memory wrt vertices + intersections - the first time, linear subsequently.
        -bool operator!=(const polygon_90_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not de-allocate memory.  - Use shrink to fit idiom and assign default constructed polygon set to - de-allocate.
        bool empty() const - Check whether the polygon set contains no geometry.  Will scan - and eliminate overlaps because subtractive regions might make the - polygon set empty.  O( n log n) runtime complexity and O(n) memory - wrt vertices + intersections the first time, linear subsequently.
        orientation_2d orient() constGet the scanning orientation.  Depending on the data it is - sometimes more efficient to scan in a specific orientation.  This - is particularly true of Manhattan geometry data.  Constant time.
        void clean() constScan and eliminate overlaps.  O( n log n) runtime complexity - and O(n) memory wrt vertices + intersections the first time, constant - time subsequently.
        -template <typename input_iterator_type>
        -void set(input_iterator_type input_begin,
                 input_iterator_type input_end, -
                 orientation_2d orient)
        -
        Overwrite geometry in polygon set with insertable objects in the - iterator range.  Also sets the scanning orientation to that - specified.
        -template <typename rectangle_type>
        +
        Once scanned the data representation of geometry within +a polygon set is in a mathematically canonical form.  Comparison +between two sets is therefore a linear time operation once they are in +the scanned state. Will scan and eliminate overlaps in both polygon +sets.  O( n log n) runtime complexity and O(n) memory wrt vertices ++ intersections the first time, linear subsequently.
        bool operator!=(const +polygon_90_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not +de-allocate memory.  Use shrink to fit idiom and assign default +constructed polygon set to de-allocate.
        bool empty() +const Check whether the polygon set contains no +geometry.  Will scan and eliminate overlaps because subtractive +regions might make the polygon set empty.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections the first time, +linear subsequently.
        orientation_2d orient() +constGet the scanning orientation.  Depending on the +data it is sometimes more efficient to scan in a specific +orientation.  This is particularly true of Manhattan geometry +data.  Constant time.
        void clean() +constScan and eliminate overlaps.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections the first time, +constant time subsequently.
        template +<typename input_iterator_type>
        +void set(input_iterator_type input_begin,
        +         input_iterator_type +input_end,
        +         orientation_2d orient) +
        Overwrite geometry in polygon set with insertable +objects in the iterator range.  Also sets the scanning orientation +to that specified.
        template +<typename rectangle_type>
        bool extents(rectangle_type& extents_rectangle) const
        Given an object that models rectangle, scans and eliminates overlaps - in the polygon set because subtractive regions may alter its extents - then computes the bounding box and assigns it to extents_rectangle.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections the first time, linear subsequently.
        -polygon_90_set_data&
        -bloat(unsigned_area_type west_bloating,
        +
        Given an object that models rectangle, scans and +eliminates overlaps in the polygon set because subtractive regions may +alter its extents then computes the bounding box and assigns it to +extents_rectangle.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections the first time, linear subsequently.
        polygon_90_set_data&
        + bloat(unsigned_area_type west_bloating,
              unsigned_area_type east_bloating,
              unsigned_area_type south_bloating,
              unsigned_area_type north_bloating)
        Scans to eliminate overlaps and subtractive regions.  Inserts - rectangles of width specified by bloating values to the indicated side - of geometry within the polygon set and fills corners with rectangles of - the length and width specified for the adjacent sides.  O( n log n) - runtime complexity and O(n) memory wrt vertices + intersections.
        -polygon_90_set_data&
        -shrink(unsigned_area_type west_shrinking,
        +
        Scans to eliminate overlaps and subtractive +regions.  Inserts rectangles of width specified by bloating values +to the indicated side of geometry within the polygon set and fills +corners with rectangles of the length and width specified for the +adjacent sides.  O( n log n) runtime complexity and O(n) memory +wrt vertices + intersections.
        polygon_90_set_data&
        + shrink(unsigned_area_type west_shrinking,
               unsigned_area_type east_shrinking,
               unsigned_area_type south_shrinking,
               unsigned_area_type north_shrinking)
        Scans to eliminate overlaps and subtractive regions.  Inserts - subtractiive rectangles of width specified by bloating values to the - indicated side of geometry within the polygon set and subtractive - rectangle at convex corners of the length and width specified for the - adjacent sides.  Scans to eliminate overlapping subtractive - regions.  O( n log n) runtime complexity and O(n) memory wrt - vertices + intersections.
        + Scans to eliminate overlaps and subtractive +regions.  Inserts subtractiive rectangles of width specified by +bloating values to the indicated side of geometry within the polygon +set and subtractive rectangle at convex corners of the length and width +specified for the adjacent sides.  Scans to eliminate overlapping +subtractive regions.  O( n log n) runtime complexity and O(n) +memory wrt vertices + intersections.
        polygon_90_set_data&
        + resize(coordinate_type west, coordinate_type east,
        +       coordinate_type south, +coordinate_type north)
        Call bloat or shrink or shrink then bloat depending on +whether the resizing values are positive or negative.  O( n log n) +runtime complexity and O(n) memory wrt vertices + intersections.
        polygon_90_set_data& + move(coordinate_type x_delta,
        +                          +coordinate_type y_delta)
        Add x_delta to x values and y_delta to y values of +vertices stored within the polygon set.  Linear wrt. vertices.
        template +<typename transformation_type>
        +polygon_90_set_data&
        + transform(const transformation_type& +transformation)
        Applies transformation.transform() on vertices stored +within the polygon set.  Linear wrt. vertices.
        polygon_90_set_data& + scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by +factor.  Linear wrt. vertices.
        +

        polygon_90_set_data& scale_down(unsigned_area_type +factor) 

        +
        Scales vertices stored within the polygon set down by +factor.  Linear wrt. vertices.
        template +<typename scaling_type>
        polygon_90_set_data&
        -resize(coordinate_type west, coordinate_type east,
               coordinate_type south, coordinate_type north)
        Call bloat or shrink or shrink then bloat depending on whether the - resizing values are positive or negative.  O( n log n) runtime - complexity and O(n) memory wrt vertices + intersections.
        -polygon_90_set_data& move(coordinate_type x_delta,
                                  -coordinate_type y_delta)
        -
        Add x_delta to x values and y_delta to y values of vertices stored - within the polygon set.  Linear wrt. vertices.
        -template <typename transformation_type>
        -polygon_90_set_data&
        transform(const transformation_type& transformation)
        -
        Applies transformation.transform() on vertices stored within the - polygon set.  Linear wrt. vertices.
        -polygon_90_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  - Linear wrt. vertices.
        -

        polygon_90_set_data& scale_down(unsigned_area_type -factor) 

        Scales vertices stored within the polygon set down by factor.  - Linear wrt. vertices.
        -template <typename scaling_type>
        -polygon_90_set_data&
        scale(const anisotropic_scale_factor<scaling_type>& - f)
        Scales vertices stored within the polygon set by applying f.scale().  - Linear wrt. vertices.
        polygon_90_set_data& scale(double factor) Scales vertices stored within the polygon set by floating point - factor.  Linear wrt. vertices.
        polygon_90_set_data& self_xor()Retain only non-overlapping regions of geometry within polygon set.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        polygon_90_set_data& self_intersect()Retain only overlapping regions of geometry within a polygon set.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        polygon_90_set_data&
        interact(const polygon_90_set_data& that)
        Retain only regions that touch or overlap regions in argument.  - O( n log n) runtime complexity and O(n) memory wrt vertices + - intersections.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file + scale(const +anisotropic_scale_factor<scaling_type>& f)
        Scales vertices stored within the polygon set by +applying f.scale().  Linear wrt. vertices.
        polygon_90_set_data& + scale(double factor) Scales vertices stored within the polygon set by +floating point factor.  Linear wrt. vertices.
        polygon_90_set_data& + self_xor()Retain only non-overlapping regions of geometry within +polygon set.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        polygon_90_set_data& + self_intersect()Retain only overlapping regions of geometry within a +polygon set.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        polygon_90_set_data&
        + interact(const polygon_90_set_data& that)
        Retain only regions that touch or overlap regions in +argument.  O( n log n) runtime complexity and O(n) memory wrt +vertices + intersections.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_90_with_holes_concept.htm b/doc/gtl_polygon_90_with_holes_concept.htm index 5cfb22f..6982b2d 100644 --- a/doc/gtl_polygon_90_with_holes_concept.htm +++ b/doc/gtl_polygon_90_with_holes_concept.htm @@ -1,464 +1,516 @@ - + + Boost Polygon Library: Polygon 90 With Holes Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon 90 With Holes Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon 90 With Holes Concept

        - -

        -

        The polygon_90_with_holes concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon 90 With Holes Concept

        +

        +

        The polygon_90_with_holes concept tag is polygon_90_with_holes_concept

        -

        -To register a user defined type as a model of -polygon_90_with_holes concept, specialize the -geometry concept meta-function for that type.  In the example below CPolygon90WithHoles is registered as a model of -polygon_90_with_holes  concept.

        -template <>
        -struct geometry_concept<CPolygon90WithHoles> { typedef polygon_90_with_holes_concept type; };

        -The semantic of a polygon_90_with_holes is a -polygon_90 that it can provide iterators over holes that are also polygon_90.  -A mutable polygon_90_with_holes must also be able to set its geometry based on -an interator range over polygon_90 holes.  There is no convention of -winding of holes enforced within the library.

        -Below is shown the default polygon with holes -traits.  Specialization of these traits is required for types that don't -conform to the default behavior.

        template <typename -T, typename enable = void>
        +

        To register a user defined type as a model of polygon_90_with_holes concept, +specialize the geometry concept meta-function for that type.  In +the example below CPolygon90WithHoles is registered as a model of +polygon_90_with_holes  concept.

        +

        template <>
        +struct geometry_concept<CPolygon90WithHoles> { typedef +polygon_90_with_holes_concept type; };

        +

        The semantic of a +polygon_90_with_holes is a polygon_90 that it can provide iterators +over holes that are also polygon_90.  A mutable +polygon_90_with_holes must also be able to set its geometry based on an +interator range over polygon_90 holes.  There is no convention of +winding of holes enforced within the library.

        +

        Below is shown the default +polygon with holes traits.  Specialization of these traits is +required for types that don't conform to the default behavior.

        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_traits {
        -     typedef typename T::iterator_holes_type +     typedef typename T::iterator_holes_type iterator_holes_type;
             typedef typename T::hole_type hole_type;
        -     static inline iterator_holes_type begin_holes(const T& -t) {
        -          return t.begin_holes();
        +     static inline iterator_holes_type +begin_holes(const T& t) {
        +          return +t.begin_holes();
             }
        -     static inline iterator_holes_type end_holes(const T& t) -{
        -          return t.end_holes();
        +     static inline iterator_holes_type +end_holes(const T& t) {
        +          return +t.end_holes();
             }
        -     static inline unsigned int size_holes(const T& t) {
        -          return t.size_holes();
        +     static inline unsigned int size_holes(const +T& t) {
        +          return +t.size_holes();
             }
        };

        -

        template <typename T, typename enable = void>
        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_mutable_traits {
             template <typename iT>
        -     static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
        -          t.set_holes(inputBegin, -inputEnd);
        +     static inline T& set_holes(T& t, iT +inputBegin, iT inputEnd) {
        +          +t.set_holes(inputBegin, inputEnd);
                  return t;
             }
        };

        -

        An object that is a model of -polygon_90_with_holes_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_90_with_holes_object)
        -view_as<polygon_90_concept>(polygon_90_with_holes_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - compact_iterator_type begin_compact(const T& polygon)
        Expects a model of polygon_90.  - Returns the begin iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - compact_iterator_type end_compact(const T& polygon)
        Expects a model of polygon_90.  - Returns the end iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of - polygon_90_with_holes.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of - polygon_90_with_holes.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - hole_iterator_type begin_holes(const T& polygon)
        Expects a model of - polygon_90_with_holes.  - Returns the begin iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - hole_iterator_type end_holes(const T& polygon)
        Expects a model of - polygon_90_with_holes.  - Returns the end iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T, typename - iterator>
        - void set_compact(T& polygon, iterator b, iterator e)
        Expects a model of - polygon_90_with_holes.   - Sets the polygon to the coordinate data range [b,e) that corresponds to - .horizontal and vertical edges.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of - polygon_90_with_holes.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a manhattan polygon.  Non-manhattan edges between - successive input points results in undefined behavior.
        template <typename T, typename - iterator>
        - void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of - polygon_90_with_holes.   - Sets the polygon holes to the hole data range [b,e)
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - outer shell of the polygon_90_with_holes.  Does not include sizes - of the holes.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_90_with_holes or - one of its refinements into left object - that models polygon_90_with_holes.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon_90_with_holes and an object that models - point, returns true - if the polygon shell contains the point and one of its holes does not - contain the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon or one of its holes.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon_90_with_holes.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon_90_with_holes and returns true.  Returns false - and leaves bbox unchanged if polygon is empty.
        template <typename T>
        - manhattan_area_type area(const T& polygon)
        Returns the area of an object - that models polygon_90_with_holes including subtracting the area of its - holes from the area of the outer shell polygon.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon_90_with_holes, LOW == CLOCKWISE, HIGH = - COUNTERCLOCKWISE.
        template <typename T>
        - coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon_90, including the perimeters of the holes.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Also applies transform() on the holes - of the polygon.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that models - polygon_90 by unsigned factor.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that models - polygon_90 by unsigned factor.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models polygon_90 by - floating point factor.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon_90 .
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               +

        An object that is a model of +polygon_90_with_holes_concept can be viewed as a model of any of +its refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_90_with_holes_object)
        + view_as<polygon_90_concept>(polygon_90_with_holes_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +compact_iterator_type begin_compact(const T& polygon)
        Expects a model of +polygon_90.  Returns the begin iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +compact_iterator_type end_compact(const T& polygon)
        Expects a model of +polygon_90.  Returns the end iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon_90_with_holes.  Returns the begin iterator over the range +of points that correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon_90_with_holes.  Returns the end iterator over the range of +points that correspond to vertices of the polygon.
        template +<typename T>
        +hole_iterator_type begin_holes(const T& polygon)
        Expects a model of +polygon_90_with_holes.  Returns the begin iterator over the range +of coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +hole_iterator_type end_holes(const T& polygon)
        Expects a model of +polygon_90_with_holes.  Returns the end iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T, typename iterator>
        +void set_compact(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_90_with_holes.   Sets the polygon to the coordinate +data range [b,e) that corresponds to .horizontal and vertical edges.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_90_with_holes.   Sets the polygon to the point data +range [b,e) that corresponds to vertices of a manhattan polygon.  +Non-manhattan edges between successive input points results in +undefined behavior.
        template +<typename T, typename iterator>
        +void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_90_with_holes.   Sets the polygon holes to the hole +data range [b,e)
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the outer shell of the polygon_90_with_holes.  Does not +include sizes of the holes.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models +polygon_90_with_holes or one of its refinements into left object that +models polygon_90_with_holes.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon_90_with_holes and +an object that models point, returns true if the polygon shell contains +the point and one of its holes does not contain the point.  If the +consider_touch flag is true will return true if the point lies along +the boundary of the polygon or one of its holes.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon_90_with_holes.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon_90_with_holes and returns true.  +Returns false and leaves bbox unchanged if polygon is empty.
        template +<typename T>
        +manhattan_area_type area(const T& polygon)
        Returns the area of an object that models +polygon_90_with_holes including subtracting the area of its holes from +the area of the outer shell polygon.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon_90_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
        template +<typename T>
        +coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon_90, including the perimeters of the holes.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Also applies transform() on the holes of the polygon.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that +models polygon_90 by unsigned factor.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that +models polygon_90 by unsigned factor.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models +polygon_90 by floating point factor.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon_90 .
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with the outer shell and holes of an - object that models polygon_90_with_holes.
        -

        Polygon 90 With Holes Data

        - -

        -

        The library provides a model of polygon 90 with holes concept declared - -template<typename T> polygon_90_with_holes_data where T is the -coordinate type.

        -

        This data type is used internally when a Manhattan polygon with holes is -needed and is available to the library user who finds it convenient to use a -library polygon data type instead of providing their own.  The data type is -implemented to be convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_90_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        compact_iterator_typeIterator over non-redundant coordinates - of the polygon, alternating x, y, x, y starting with an x, where each x - corresponds to a vertical edge and each y corresponds to a horizontal - edge.
        iterator_holes_typeIterator over hole polygons of type - polygon_90_data<T>.
        polygon_90_with_holes_data()Default constructs the polygon.
        polygon_90_with_holes_data(const - polygon_90_with_holes_data& that)Copy construct
        polygon_90_with_holes_data& -
        operator=
        (const polygon_90_with_holes_data& that)
        Assignment operator.
        template <typename T2> polygon_90_with_holes_data&  -
        operator=
        (const T2& that) const
        Assign from an object that is a model of polygon 90 with holes.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        compact_iterator_type begin_compact() - constGet the begin compact iterator over non-redundant coordinates of the - polygon.
        compact_iterator_type end_compact() - constGet the end compact iterator over non-redundant coordinates of the - polygon.
        iterator_hole_type begin_holes() - constGet the begin compact iterator over non-redundant coordinates of the - polygon.
        iterator_hole_type end_holes() - constGet the end compact iterator over non-redundant coordinates of the - polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        std::size_t size_holes() constGet the number of holes in the polygon
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  No check is - performed to ensure the points describe a Manhattan figure, every other - x and y value of the points is used to initialize the polygon.
        template <typename iT>  -
        void set_compact(iT begin_coords, iT end_coords)
        Sets the polygon to the iterator range of coordinates.  These - coordinates correspond to the x values of vertical edges and y values of - horizontal edges.  It is expected that the sequence start with an x - value and proceed x then y then x then y.
        template <typename iT>  -
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole polygons.  These - polygons in the input range may be either polygon_90_data or - polygon_90_with_holes_data or any type that provides begin_compact and - end_compact member functions.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with the outer +shell and holes of an object that models polygon_90_with_holes.
        +

        Polygon 90 With Holes Data

        +

        +

        The library provides a model of polygon 90 with holes concept +declared + template<typename T> +polygon_90_with_holes_data where T is the coordinate type.

        +

        This data type is used internally when a Manhattan polygon +with holes is needed and is available to the library user who finds it +convenient to use a library polygon data type instead of providing +their own.  The data type is implemented to be convenient to use +with the library traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_90_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        compact_iterator_typeIterator over +non-redundant coordinates of the polygon, alternating x, y, x, y +starting with an x, where each x corresponds to a vertical edge and +each y corresponds to a horizontal edge.
        iterator_holes_typeIterator over hole +polygons of type polygon_90_data<T>.
        polygon_90_with_holes_data()Default constructs the polygon.
        polygon_90_with_holes_data(const +polygon_90_with_holes_data& that)Copy construct
        polygon_90_with_holes_data& +
        +operator=
        (const polygon_90_with_holes_data& that)
        Assignment operator.
        template +<typename T2> polygon_90_with_holes_data& 
        +operator=
        (const T2& that) const
        Assign from an object that is a model of polygon 90 +with holes.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        compact_iterator_type + begin_compact() constGet the begin compact iterator over non-redundant +coordinates of the polygon.
        compact_iterator_type + end_compact() constGet the end compact iterator over non-redundant +coordinates of the polygon.
        iterator_hole_type + begin_holes() constGet the begin compact iterator over non-redundant +coordinates of the polygon.
        iterator_hole_type + end_holes() constGet the end compact iterator over non-redundant +coordinates of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        std::size_t size_holes() +constGet the number of holes in the polygon
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  +No check is performed to ensure the points describe a Manhattan figure, +every other x and y value of the points is used to initialize the +polygon.
        template +<typename iT> 
        +
        void set_compact(iT begin_coords, iT end_coords)
        Sets the polygon to the iterator range of +coordinates.  These coordinates correspond to the x values of +vertical edges and y values of horizontal edges.  It is expected +that the sequence start with an x value and proceed x then y then x +then y.
        template +<typename iT> 
        +
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole +polygons.  These polygons in the input range may be either +polygon_90_data or polygon_90_with_holes_data or any type that provides +begin_compact and end_compact member functions.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_concept.htm b/doc/gtl_polygon_concept.htm index 57ac5c0..c88681f 100644 --- a/doc/gtl_polygon_concept.htm +++ b/doc/gtl_polygon_concept.htm @@ -1,378 +1,433 @@ - + + Boost Polygon Library: Polygon Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon Concept

        - -

        -

        The polygon concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon Concept

        +

        +

        The polygon concept tag is polygon_concept

        -

        -To register a user defined type as a model of -polygon concept, specialize the -geometry concept meta-function for that type.  In the example below CPolygon is registered as a model of -polygon  concept.

        -template <>
        -struct geometry_concept<CPolygon> { typedef polygon_concept type; };

        -The semantic of a polygon is that it can provide -iterators over the points that represent its vertices.  It is acceptable to -have the last edge explict with the first and last point equal to each other or -implied by this segement that would connect the first and last point.  A -mutable polygon must also be able to set its geometry based on an interator -range over such points.  A std::vector<point_data<int> > or std::list<point_data<int> -> -could be made models of polygon_concept by simply providing access to their -iterators through traits.  Library functions that create polygon objects -require that those objects provide a default constructor.

        -Below is shown the default polygon traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.  Note that these same traits are also used by several -other polygon concepts through SFINE enable template parameter.  The SFINE -enable parameter also allows the library to provide default specialization that -work for any object that models the 90 degree polygon concepts.

        -template <typename T, typename enable = gtl_yes>
        +

        To register a user defined type as a model of polygon concept, specialize the +geometry concept meta-function for that type.  In the example +below CPolygon is registered as a model of polygon  concept.

        +

        template <>
        +struct geometry_concept<CPolygon> { typedef polygon_concept type; +};

        +

        The semantic of a polygon is +that it can provide iterators over the points that represent its +vertices.  It is acceptable to have the last edge explict with the +first and last point equal to each other or implied by this segement +that would connect the first and last point.  A mutable polygon +must also be able to set its geometry based on an interator range over +such points.  A std::vector<point_data<int> > or +std::list<point_data<int> > could be made models of +polygon_concept by simply providing access to their iterators through +traits.  Library functions that create polygon objects require +that those objects provide a default constructor.

        +

        Below is shown the default +polygon traits.  Specialization of these traits is required for +types that don't conform to the default behavior.  Note that these +same traits are also used by several other polygon concepts through +SFINE enable template parameter.  The SFINE enable parameter also +allows the library to provide default specialization that work for any +object that models the 90 degree polygon concepts.

        +

        template <typename T, typename +enable = gtl_yes>
        struct polygon_traits {};
        -
        +
        template <typename T>
        struct polygon_traits<T,
          typename gtl_or_4<
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type,
        -    typename gtl_same_type<typename geometry_concept<T>::type, -polygon_with_holes_concept>::type
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_with_holes_concept>::type,
        +    typename gtl_same_type<typename +geometry_concept<T>::type, polygon_with_holes_concept>::type
          >::type> {
        -     typedef typename T::coordinate_type coordinate_type;
        -     typedef typename T::iterator_type iterator_type;
        +     typedef typename T::coordinate_type +coordinate_type;
        +     typedef typename T::iterator_type +iterator_type;
             typedef typename T::point_type point_type;
        -     static inline iterator_type begin_points(const T& t) {
        +     static inline iterator_type begin_points(const +T& t) {
                  return t.begin();
             }
        -     static inline iterator_type end_points(const T& t) {
        +     static inline iterator_type end_points(const +T& t) {
                  return t.end();
             }
        -     static inline unsigned int size(const T& t) {
        +     static inline unsigned int size(const T& +t) {
                  return t.size();
             }
        -     static inline winding_direction winding(const T& t) {
        -          return unknown_winding;
        +     static inline winding_direction winding(const +T& t) {
        +          return +unknown_winding;
             }
        };

        -

        template <typename T, typename enable = void>
        +

        template <typename T, typename +enable = void>
        struct polygon_mutable_traits {
             template <typename iT>
        -     static inline T& set_points(T& t, iT input_begin, iT -input_end) {
        -          t.set(input_begin, -input_end);
        +     static inline T& set_points(T& t, iT +input_begin, iT input_end) {
        +          +t.set(input_begin, input_end);
                  return t;
             }
        };

        -

        Example code custom_polygon.cpp -demonstrates mapping a - user defined polygon class to the library polygon_concept

        -

        An object that is a model of -polygon_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_object)
        -view_as<polygon_90_concept>(polygon_object)
        -view_as<polygon_45_concept>(polygon_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of polygon.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of polygon.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of polygon.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a manhattan polygon.
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - polygon.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon into left object - that models polygon.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon and an object that models - point, returns true - if the polygon contains the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon.  Linear wrt. vertices.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon.  Linear wrt. vertices.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon and returns true.  Returns false and leaves - bbox unchanged if polygon is empty.  Linear wrt. vertices.
        template <typename T>
        - area_type area(const T& polygon)
        Returns the area of an object - that models polygon.  Linear wrt. vertices.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  - Complexity depends upon winding trait.
        template <typename T>
        - coordinate_distance perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon.  Linear wrt. vertices.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Linear wrt. vertices.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models - polygon by unsigned factor.  Linear wrt. vertices.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models - polygon by unsigned factor.  Linear wrt. vertices.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon by floating - point factor.  Linear wrt. vertices.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon .  Linear wrt. vertices.
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               +

        Example code custom_polygon.cpp +demonstrates mapping a user defined polygon class to the library +polygon_concept

        +

        An object that is a model of +polygon_concept can be viewed as a model of any of its +refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_object)
        + view_as<polygon_90_concept>(polygon_object)
        + view_as<polygon_45_concept>(polygon_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon.  Returns the begin iterator over the range of points that +correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon.  Returns the end iterator over the range of points that +correspond to vertices of the polygon.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon.   Sets the polygon to the point data range [b,e) +that corresponds to vertices of a manhattan polygon.
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the polygon.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon into +left object that models polygon.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon and an object that +models point, returns true if the polygon contains the point.  If +the consider_touch flag is true will return true if the point lies +along the boundary of the polygon.  Linear wrt. vertices.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon.  Linear wrt. +vertices.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon and returns true.  Returns false +and leaves bbox unchanged if polygon is empty.  Linear wrt. +vertices.
        template +<typename T>
        +area_type area(const T& polygon)
        Returns the area of an object that models +polygon.  Linear wrt. vertices.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.  Complexity +depends upon winding trait.
        template +<typename T>
        +coordinate_distance perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon.  Linear wrt. vertices.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up coordinate of an object that models polygon +by unsigned factor.  Linear wrt. vertices.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down coordinates of an object that models +polygon by unsigned factor.  Linear wrt. vertices.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales coordinates of an object that models polygon by +floating point factor.  Linear wrt. vertices.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon .  +Linear wrt. vertices.
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with vertices of an - object that models polygon.  Linear wrt. vertices.
        -

        Polygon Data

        - -

        -

        The library provides a model of polygon concept declared - -template<typename T> polygon_data where T is the coordinate type.

        -

        This data type is used internally when a polygon is needed and is available -to the library user who finds it convenient to use a library polygon data type -instead of providing their own.  The data type is implemented to be -convenient to use with the library traits.

        -

        Example code polygon_usage.cpp -demonstrates using - the library provided polygon data types and functions

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        polygon_data()Default constructs the polygon.
        polygon_data(const - polygon_data& that)Copy construct
        polygon_data& operator=(const - polygon_data& that)Assignment operator.
        template <typename T2>  -
        polygon_data& operator=(const T2& that) const
        Assign from an object that is a model of polygon.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points. 
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with vertices of +an object that models polygon.  Linear wrt. vertices.
        +

        Polygon Data

        +

        +

        The library provides a model of polygon concept declared + template<typename T> polygon_data where +T is the coordinate type.

        +

        This data type is used internally when a polygon is needed and +is available to the library user who finds it convenient to use a +library polygon data type instead of providing their own.  The +data type is implemented to be convenient to use with the library +traits.

        +

        Example code polygon_usage.cpp +demonstrates using the library provided polygon data types and functions

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        polygon_data()Default constructs the polygon.
        polygon_data(const +polygon_data& that)Copy construct
        polygon_data& operator=(const +polygon_data& that)Assignment operator.
        template +<typename T2> 
        +
        polygon_data& operator=(const T2& that) +const
        Assign from an object that is a model of polygon.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.  +
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_set_concept.htm b/doc/gtl_polygon_set_concept.htm index 42a534f..07944ec 100644 --- a/doc/gtl_polygon_set_concept.htm +++ b/doc/gtl_polygon_set_concept.htm @@ -1,672 +1,732 @@ - + + Boost Polygon Library: Polygon Set Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon Set Concept + + + + + + + + - + + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon Set Concept

        - -

        -

        The polygon_set concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon Set Concept

        +

        +

        The polygon_set concept tag is polygon_set_concept

        -

        -The semantic of a polygon_set is zero or more -geometry regions.  A Polygon Set Concept may be defined with floating point -coordinates, but a snap rounding distance of one integer unit will still be -applied, furthermore, geometry outside the domain where one integer unit is -sufficient to provide robustness may lead to undefined behavior in algorithms.  -It is recommended to use integer coordinates for robust operations.  In the -case that data represented contains only Manhattan geometry a runtime check will -default to the Manhattan algorithm.  The results of which are identical to -what the general algorithm would do, but obtained more efficiently.  In the -case that the data represented contains only Manhattan and 45-degree geometry a -runtime check will default to the faster 45-degree algorithm.  The results -of which may differ slight from what the general algorithm would do because -non-integer intersections will be handled differently.

        Users are recommended to use std::vector and std::list of user defined polygons -or library provided polygon_set_data<coordinate_type> objects.  Lists -and vectors of models of polygon_concept or polygon_with_holes_concept are automatically models of polygon_set_concept.

        -

        Example code custom_polygon_set.cpp - demonstrates mapping a user defined class to the library polygon_set_concept

        -

        An object that is a model of -polygon_set_concept can be viewed as a model of +

        The semantic of a polygon_set +is zero or more geometry regions.  A Polygon Set Concept may be +defined with floating point coordinates, but a snap rounding distance +of one integer unit will still be applied, furthermore, geometry +outside the domain where one integer unit is sufficient to provide +robustness may lead to undefined behavior in algorithms.  It is +recommended to use integer coordinates for robust operations.  In +the case that data represented contains only Manhattan geometry a +runtime check will default to the Manhattan algorithm.  The +results of which are identical to what the general algorithm would do, +but obtained more efficiently.  In the case that the data +represented contains only Manhattan and 45-degree geometry a runtime +check will default to the faster 45-degree algorithm.  The results +of which may differ slight from what the general algorithm would do +because non-integer intersections will be handled differently.

        +

        Users are recommended to use std::vector and std::list of user +defined polygons or library provided +polygon_set_data<coordinate_type> objects.  Lists and +vectors of models of polygon_concept or polygon_with_holes_concept are +automatically models of polygon_set_concept.

        +

        Example code custom_polygon_set.cpp +demonstrates mapping a user defined class to the library +polygon_set_concept

        +

        An object that is a model of +polygon_set_concept can be viewed as a model of polygon_90_set_concept or -polygon_45_set_concept if it is determined at runtime to conform to the -restrictions of those concepts.  This concept casting is accomplished -through the view_as<>() function.

        -

        view_as<polygon_90_set_concept>(polygon_set_object)
        +polygon_45_set_concept
        if it is determined at runtime to conform +to the restrictions of those concepts.  This concept casting is +accomplished through the view_as<>() +function.

        +

        view_as<polygon_90_set_concept>(polygon_set_object)
        view_as<polygon_45_set_concept>(polygon_set_object)

        -

        The return value of view_as<>() can be passed -into any interface that expects an object of the conceptual type specified in -its template parameter.  Polygon sets cannot be viewed as single polygons -or rectangles since it generally cannot be known whether a polygon set contains -only a single polygon without converting to polygons.

        -

        Operators

        -

        The return type of some operators is the polygon_set_view -operator template type.  This type is itself a model of the polygon 90 set -concept, but furthermore can be used as an argument to the polygon_set_data -constructor and assignment operator.  The operator template exists to -eliminate temp copies of intermediate results when Boolean operators are chained -together.

        -

        Operators are declared inside the namespace boost::polygon::operators.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T1, typename - T2>
        - polygon_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts two objects - that model polygon_set or one of its refinements.  Returns an - operator template that performs the operation on demand when chained or - or nested in a library function call such as assign().  Expected n - log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T1, typename - T2>
        - polygon_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for OR - operations in Boolean logic expressions.  Expected n log n runtime, - worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_set_view operator&(const T1& l, const T2& r)
        Boolean AND operation (polygon set intersection).  Accepts two - objects that model polygon_set or one of its refinements.  Expected - n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T1, typename - T2>
        - polygon_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol is also used for - AND operations in Boolean logic expressions.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - polygon_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set disjoint-union).  Accepts - two objects that model polygon_set or one of its refinements.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T1, typename - T2>
        - polygon_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set difference).  Accepts - two objects that model polygon_set or one of its refinements.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T1, typename - T2>
        - T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left operand must model - polygon_set and not one of it's refinements.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T1>
        - T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Note: returns - result by value.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Note: returns - result by value.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating ammount.  If - negative the result is a shrink instead of bloat.  Returns - reference to modified argument.  Expected n log n runtime, worst - case quadratic runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating ammount.  If - negative the result is a bloat instead of shrink.  Returns - reference to modified argument.  Expected n log n runtime, worst - case quadratic runtime wrt. vertices + intersections.
        -

        Functions

        - - - - - - - - - - - - - - - + + + +
        template <typename T1, typename - T2>
        - T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an object that - models polygon_set or any of its refinements into an object that - models polygon_set.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        template <typename T1, typename - T2>
        - bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_set or one of its - refinements covers the exact same geometric regions as another object - that models polygon_set or one of its refinements.  For example: - two of polygon objects.  Expected n log n runtime, worst case - quadratic runtime wrt. vertices + intersections.
        template <typename - output_container_type, typename T>
        - void get_trapezoids(output_container_type& output,
        -                    - const T& polygon_set)
        Output container is expected to be a standard container.  - Slices geometry of an object that models polygon_set or one of its - refinements into non overlapping trapezoids along a vertical slicing - orientation and appends them to the - output, which must have a value type that models polygon or polygon_with_holes.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename - output_container_type, typename T>
        - void get_trapezoids(output_container_type& output,
        -                    - const T& polygon_set,
        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.  Polygon sets +cannot be viewed as single polygons or rectangles since it generally +cannot be known whether a polygon set contains only a single polygon +without converting to polygons.

        +

        Operators

        +

        The return type of some operators is the polygon_set_view operator template +type.  This type is itself a model of the polygon 90 set concept, +but furthermore can be used as an argument to the polygon_set_data constructor and assignment +operator.  The operator template exists to eliminate temp copies +of intermediate results when Boolean operators are chained together.

        +

        Operators are declared inside the namespace boost::polygon::operators.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        template +<typename T1, typename T2>
        +polygon_set_view operator|(const T1& l, const T2& r)
        Boolean OR operation (polygon set union).  Accepts +two objects that model polygon_set or one of its refinements.  +Returns an operator template that performs the operation on demand when +chained or or nested in a library function call such as assign().  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_set_view operator+(const T1& l, const T2& r)
        Same as operator|.  The plus sign is also used for +OR operations in Boolean logic expressions.  Expected n log n +runtime, worst case quadratic runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_set_view operator&(const T1& l, const T2& r)
        Boolean AND operation (polygon set intersection).  +Accepts two objects that model polygon_set or one of its +refinements.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_set_view operator*(const T1& l, const T2& r)
        Same as operator&.  The multiplication symbol +is also used for AND operations in Boolean logic expressions.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +polygon_set_view operator^(const T1& l, const T2& r)
        Boolean XOR operation (polygon set +disjoint-union).  Accepts two objects that model polygon_set or +one of its refinements.  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +polygon_set_view operator-(const T1& l, const T2& r)
        Boolean SUBTRACT operation (polygon set +difference).  Accepts two objects that model polygon_set or one of +its refinements.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator|=(const T1& l, const T2& r)
        Same as operator|, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(T1& l, const T2& r)
        Same as operator+, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator&=(const T1& l, const T2& r)
        Same as operator&, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator*=(T1& l, const T2& r)
        Same as operator*, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator^=(const T1& l, const T2& r)
        Same as operator^, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(T1& l, const T2& r)
        Same as operator-, but with self assignment, left +operand must model polygon_set and not one of it's refinements.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1>
        +T1 operator+(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Note: returns result by value.  Expected n log n +runtime, worst case quadratic runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +T1 operator-(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Note: returns result by value.  Expected n log n +runtime, worst case quadratic runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +T1& operator+=(const T1&, coordinate_type bloating)
        Performs resize operation, inflating by bloating +ammount.  If negative the result is a shrink instead of +bloat.  Returns reference to modified argument.  Expected n +log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T1, typename T2>
        +T1& operator-=(const T1&, coordinate_type shrinking)
        Performs resize operation, deflating by bloating +ammount.  If negative the result is a bloat instead of +shrink.  Returns reference to modified argument.  Expected n +log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        +

        Functions

        + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - + + + + - - -
        template +<typename T1, typename T2>
        +T1& assign(T1& lvalue, const T2& rvalue)
        Eliminates overlaps in geometry and copies from an +object that models polygon_set or any of its refinements into an object +that models polygon_set.  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        template +<typename T1, typename T2>
        +bool equivalence(const T1& lvalue, const T2& rvalue)
        Returns true if an object that models polygon_set or +one of its refinements covers the exact same geometric regions as +another object that models polygon_set or one of its refinements.  +For example: two of polygon objects.  Expected n log n runtime, +worst case quadratic runtime wrt. vertices + intersections.
        template +<typename output_container_type, typename T>
        +void get_trapezoids(output_container_type& output,
        +                    +const T& polygon_set)
        Output container is expected to be a standard +container.  Slices geometry of an object that models polygon_set +or one of its refinements into non overlapping trapezoids along a +vertical slicing orientation and appends them to the output, which must +have a value type that models polygon or polygon_with_holes.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename output_container_type, typename T>
        +void get_trapezoids(output_container_type& output,
        +                    +const T& polygon_set,
                            orientation_2d orient)
        Output container is expected to be a standard container.  - Slices geometry of an object that models polygon_set or one of its - refinements into non overlapping trapezoids along a the specified slicing - orientation and appends them to the - output, which must have a value type that models polygon or polygon_with_holes.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename - polygon_set_type>
        - void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template <typename - polygon_set_type>
        - bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  Polygons that - are completely covered by holes will result in empty returning true.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T, typename - rectangle_type>
        - bool extents(rectangle_type& extents_rectangle,
        -             const - T& polygon_set)
        Computes bounding box of an object that models polygon_set and - stores it in an object that models rectangle.  If the polygon set - is empty returns false.  If there are holes outside of shells they - do not contribute to the extents of the polygon set.  Expected n - log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T>
        - area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that models - polygon_set.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        template <typename T>
        - T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the polygons, bloating them and putting them - back.  Expected n log n runtime, worst case quadratic runtime wrt. - vertices + intersections.
        template <typename T>
        - T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the polygons, shrinking them and overwriting - the polygon set with the resulting regions.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T, typename - coord_type>
        - T& resize(T& polygon_set, coord_type resizing,
        -           - bool corner_fill_arc = false,
                  - unsigned int num_circle_segments = 0)
        Same as bloat if resizing is positive, same as shrink if resizing is - negative.  Original topology at acute angle vertices is preserved - by default, segmented circular arcs are inserted if corner_fill_arc is - true.  num_circle_segments specifies number of segments to - introduce on a full circle when filling acute angle corners with - circular arcs.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        template <typename T>
        +
        Output container is expected to be a standard +container.  Slices geometry of an object that models polygon_set +or one of its refinements into non overlapping trapezoids along a the +specified slicing orientation and appends them to the output, which +must have a value type that models polygon or polygon_with_holes.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename polygon_set_type>
        +void clear(polygon_set_type& polygon_set)
        Makes the object empty of geometry.
        template +<typename polygon_set_type>
        +bool empty(const polygon_set_type& polygon_set)
        Checks whether the object is empty of geometry.  +Polygons that are completely covered by holes will result in empty +returning true.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& extents_rectangle,
        +             +const T& polygon_set)
        Computes bounding box of an object that models +polygon_set and stores it in an object that models rectangle.  If +the polygon set is empty returns false.  If there are holes +outside of shells they do not contribute to the extents of the polygon +set.  Expected n log n runtime, worst case quadratic runtime wrt. +vertices + intersections.
        template +<typename T>
        +area_type area(const T& polygon_set)
        Computes the area covered by geometry in an object that +models polygon_set.  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        template +<typename T>
        +T& bloat(T& polygon_set, unsigned_area_type bloating)
        Same as getting all the polygons, bloating them and +putting them back.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections.
        template +<typename T>
        +T& shrink(T& polygon_set, unsigned_area_type shrinking)
        Same as getting all the polygons, shrinking them and +overwriting the polygon set with the resulting regions.  Expected +n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T, typename coord_type>
        +T& resize(T& polygon_set, coord_type resizing,
        +          bool +corner_fill_arc = false,
        +          unsigned int +num_circle_segments = 0)
        Same as bloat if resizing is positive, same as shrink +if resizing is negative.  Original topology at acute angle +vertices is preserved by default, segmented circular arcs are inserted +if corner_fill_arc is true.  num_circle_segments specifies number +of segments to introduce on a full circle when filling acute angle +corners with circular arcs.  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        template +<typename T>
        T& scale_up(T& polygon_set, unsigned_area_type factor)
        Scales geometry up by unsigned factor.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T>
        +
        Scales geometry up by unsigned factor.  Expected n +log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T>
        T& scale_down(T& polygon_set, unsigned_area_type factor)
        Scales geometry down by unsigned factor.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        template <typename T, typename transformation_type>
        +
        Scales geometry down by unsigned factor.  Expected +n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename T, typename transformation_type>
        T& transform(T& polygon_set,
        -             const -transformation_type& transformation)
        Applies transformation.transform() on all vertices.  Expected n - log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        template <typename T>
        +             +const transformation_type& transformation)
        Applies transformation.transform() on all +vertices.  Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections.
        template +<typename T>
        T& keep(T& polygon_set,
                unsigned_area_type min_area,
                unsigned_area_type max_area,
                unsigned_area_type min_width,
                unsigned_area_type max_width,
        -        unsigned_area_type min_height,
        -        unsigned_area_type max_height)
        Retains only regions that satisfy the min/max criteria in the - argument list.  Note: useful for visualization to cull too small - polygons.  Expected n log n runtime, worst case quadratic runtime - wrt. vertices + intersections.
        -

        Polygon Set Data Object

        - -

        -

        The polygon set data type encapsulates the internal data format that -serves as the input to the sweep-line algorithm that implements polygon-clipping -Boolean operations.  It also internally keeps track of whether that data -has been sorted or scanned and maintains the invariant that when its flags -indicate that the data is sorted or scanned the data has not been changed to -violate that assumption.  Using the Polygon Set Data type directly can -be more efficient than using lists and vectors of polygons in the functions -above because of the invariants it can enforce which provide the opportunity to -maintain the data is sorted form rather than going all the way out to polygons -then resorting those vertices for a subsequent operation.

        -

        The declaration of Polygon Set Data is the following:

        -

        template <typename T>
        +        unsigned_area_type +min_height,
        +        unsigned_area_type +max_height)

        Retains only regions that satisfy the min/max criteria +in the argument list.  Note: useful for visualization to cull too +small polygons.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections.
        +

        Polygon Set Data Object

        +

        +

        The polygon set data type encapsulates the internal data +format that serves as the input to the sweep-line algorithm that +implements polygon-clipping Boolean operations.  It also +internally keeps track of whether that data has been sorted or scanned +and maintains the invariant that when its flags indicate that the data +is sorted or scanned the data has not been changed to violate that +assumption.  Using the Polygon Set Data type directly can be more +efficient than using lists and vectors of polygons in the functions +above because of the invariants it can enforce which provide the +opportunity to maintain the data is sorted form rather than going all +the way out to polygons then resorting those vertices for a subsequent +operation.

        +

        The declaration of Polygon Set Data is the following:

        +

        template <typename T>
        class polygon_set_data;

        -

        The class is parameterized on the coordinate data type.  Algorithms that -benefit from knowledge of the invariants enforced by the class are implemented -as member functions to provide them access to information about those -invariants. 

        -

        Example code polygon_set_usage.cpp -demonstrates using - the library provided polygon set data types and functions

        -

        Member Functions

        - - - - - - - - - - - - - - - - - - - - - - - - -
        polygon_set_data()Default constructor.
        template <typename iT>
        - polygon_set_data(iT input_begin, iT - input_end)
        Construct with scanning orientation from an iterator range of - insertable objects.
        - polygon_set_data(const polygon_set_data& that)Copy construct.
        -template <typename l, typename r, typename op>
        -polygon_set_data(const polygon_set_view<l,r,op>& -t)
        Copy construct from a Boolean operator template.
        -polygon_set_data&
        operator=(const polygon_set_data& that)
        Assignment from another polygon set, may change scanning - orientation.
        -template <typename l, typename r, typename op>
        -polygon_set_data&
        operator=(const polygon_set_view<l, r, +

        The class is parameterized on the coordinate data type.  +Algorithms that benefit from knowledge of the invariants enforced by +the class are implemented as member functions to provide them access to +information about those invariants. 

        +

        Example code polygon_set_usage.cpp +demonstrates using the library provided polygon set data types and +functions

        +

        Member Functions

        + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + + - - - - + + + - - - - + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - -
        polygon_set_data()Default constructor.
        template +<typename iT>
        + polygon_set_data(iT input_begin, iT input_end)
        Construct with scanning orientation from an iterator +range of insertable objects.
        polygon_set_data(const +polygon_set_data& that)Copy construct.
        template +<typename l, typename r, typename op>
        + polygon_set_data(const +polygon_set_view<l,r,op>& t)
        Copy construct from a Boolean operator template.
        polygon_set_data& +
        + operator=(const polygon_set_data& that)
        Assignment from another polygon set, may change +scanning orientation.
        template +<typename l, typename r, typename op>
        +polygon_set_data&
        + operator=(const polygon_set_view<l, r, op>& that)
        Assignment from a Boolean operator template.
        template <typename geometry_object>
        +
        Assignment from a Boolean operator template.
        template +<typename geometry_object>
        polygon_set_data& operator=(const geometry_object& geo)
        Assignment from an insertable object.
        - + Assignment from an insertable object.
        template <typename iT>
        void insert(iT input_begin, iT input_end)
        Insert objects of an iterator range.  Linear wrt vertices - inserted.
        - + Insert objects of an iterator range.  Linear wrt +vertices inserted.
        void insert(const polygon_set_data& polygon_set)Insert a polygon set.  Linear wrt vertices inserted.
        - + Insert a polygon set.  Linear wrt vertices +inserted.
        template <typename geometry_type>
        -void insert(const geometry_type& geometry_object,
                    bool is_hole -= false)
        Insert a geometry object, if is_hole is true then the inserted - region is subtractive rather than additive.  Linear wrt vertices - inserted.
        -template <typename output_container>
        +void insert(const geometry_type& geometry_object,
        +            bool +is_hole = false)
        Insert a geometry object, if is_hole is true then the +inserted region is subtractive rather than additive.  Linear wrt +vertices inserted.
        template +<typename output_container>
        void get(output_container& output) const
        Expects a standard container of polygons objects.  Will scan - and eliminate overlaps.  Converts polygon set geometry to objects - of the polygon type and appends them to the container.  Polygons - will be output with counterclockwise winding, hole polygons will be - output with clockwise winding.  The last vertex of an output - polygon is the duplicate of the first, and the number of points is equal - to the number of edges plus 1.  If required by the output data - type, polygons will have holes fractured out to the outer boundary along - the positive y direction and off grid intersections on the outer - boundary introduced by this fracture will be truncated downward.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        -template <typename output_container>
        +
        Expects a standard container of polygons objects.  +Will scan and eliminate overlaps.  Converts polygon set geometry +to objects of the polygon type and appends them to the container.  +Polygons will be output with counterclockwise winding, hole polygons +will be output with clockwise winding.  The last vertex of an +output polygon is the duplicate of the first, and the number of points +is equal to the number of edges plus 1.  If required by the output +data type, polygons will have holes fractured out to the outer boundary +along the positive y direction and off grid intersections on the outer +boundary introduced by this fracture will be truncated downward.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename output_container>
        void get_trapezoids(output_container& output) const
        Expects a standard container of polygon objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to trapezoids - vertically and appends them to the container.  Expected n log n - runtime, worst case quadratic runtime wrt. vertices + intersections.
        - + Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Slices polygon set geometry to +trapezoids vertically and appends them to the container.  Expected +n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template <typename output_container>
        -void get_trapezoids(output_container& output,
          orientation_2d -slicing_orientation) const
        -
        Expects a standard container of polygon objects.  Will scan - and eliminate overlaps.  Slices polygon set geometry to trapezoids - along the given orientation and appends them to the container.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        - +void get_trapezoids(output_container& output,
        +  orientation_2d slicing_orientation) const
        Expects a standard container of polygon objects.  +Will scan and eliminate overlaps.  Slices polygon set geometry to +trapezoids along the given orientation and appends them to the +container.  Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections.
        bool operator==(const polygon_set_data& p) constOnce scanned the data representation of geometry within a polygon - set is in a mathematically canonical form.  Comparison between two - sets is therefore a linear time operation once they are in the scanned - state. Will scan and eliminate overlaps in both polygon sets.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections. 
        -bool operator!=(const polygon_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not de-allocate memory.  - Use shrink to fit idiom and assign default constructed polygon set to - de-allocate.
        bool empty() const - Check whether the polygon set contains no geometry.  Will scan - and eliminate overlaps because subtractive regions might make the - polygon set empty.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        void clean() constScan and eliminate overlaps.  Expected n log n runtime, worst - case quadratic runtime wrt. vertices + intersections the first time, - constant time subsequently.
        -template <typename input_iterator_type>
        -void set(input_iterator_type input_begin,
                 input_iterator_type input_end)
        -
        Overwrite geometry in polygon set with insertable objects in the - iterator range.
        -template <typename rectangle_type>
        +
        Once scanned the data representation of geometry within +a polygon set is in a mathematically canonical form.  Comparison +between two sets is therefore a linear time operation once they are in +the scanned state. Will scan and eliminate overlaps in both polygon +sets.  Expected n log n runtime, worst case quadratic runtime wrt. +vertices + intersections. 
        bool operator!=(const +polygon_set_data& p) constInverse logic of equivalence operator.
        void clear()Make the polygon set empty.  Note: does not +de-allocate memory.  Use shrink to fit idiom and assign default +constructed polygon set to de-allocate.
        bool empty() +const Check whether the polygon set contains no +geometry.  Will scan and eliminate overlaps because subtractive +regions might make the polygon set empty.  Expected n log n +runtime, worst case quadratic runtime wrt. vertices + intersections.
        void clean() +constScan and eliminate overlaps.  Expected n log n +runtime, worst case quadratic runtime wrt. vertices + intersections the +first time, constant time subsequently.
        template +<typename input_iterator_type>
        +void set(input_iterator_type input_begin,
        +         input_iterator_type +input_end)
        Overwrite geometry in polygon set with insertable +objects in the iterator range.
        template +<typename rectangle_type>
        bool extents(rectangle_type& extents_rectangle) const
        Given an object that models rectangle, scans and eliminates overlaps - in the polygon set because subtractive regions may alter its extents - then computes the bounding box and assigns it to extents_rectangle.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections the first time, linear subsequently.
        + Given an object that models rectangle, scans and +eliminates overlaps in the polygon set because subtractive regions may +alter its extents then computes the bounding box and assigns it to +extents_rectangle.  Expected n log n runtime, worst case quadratic +runtime wrt. vertices + intersections the first time, linear +subsequently.
        polygon_set_data&
        + resize(coord_type resizing,
        +       bool corner_fill_arc = false,
        +       unsigned int num_circle_segments = +0)
        Inflates if resizing is positive, deflates if resizing +is negative.  Original topology at acute angle vertices is +preserved by default, segmented circular arcs are inserted if +corner_fill_arc is true.  num_circle_segments specifies number of +segments to introduce on a full circle when filling acute angle corners +with circular arcs.  Specifying zero for num_circle_segments +results in only a single segment being inserted at acute corners.  +Expected n log n runtime, worst case quadratic runtime wrt. vertices + +intersections.
        template +<typename transformation_type>
        +polygon_set_data&
        + transform(const transformation_type& +transformation)
        Applies transformation.transform() on vertices stored +within the polygon set.  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        polygon_set_data& + scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by +factor.  Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections.
        polygon_set_data& + scale_down(unsigned_area_type factor) Scales vertices stored within the polygon set down by +factor.  Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections.
        template +<typename scaling_type>
        polygon_set_data&
        -resize(coord_type resizing,
        -        bool corner_fill_arc = false,
               - unsigned int num_circle_segments = 0)
        Inflates if resizing is positive, deflates if resizing is - negative.  Original topology at acute angle vertices is preserved - by default, segmented circular arcs are inserted if corner_fill_arc is - true.  num_circle_segments specifies number of segments to - introduce on a full circle when filling acute angle corners with - circular arcs.  Specifying zero for num_circle_segments results in - only a single segment being inserted at acute corners.  Expected n - log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        -template <typename transformation_type>
        -polygon_set_data&
        transform(const transformation_type& transformation)
        -
        Applies transformation.transform() on vertices stored within the - polygon set.  Expected n log n runtime, worst case quadratic - runtime wrt. vertices + intersections.
        -polygon_set_data& scale_up(unsigned_area_type factor)Scales vertices stored within the polygon set up by factor.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        -polygon_set_data& scale_down(unsigned_area_type -factor) Scales vertices stored within the polygon set down by factor.  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        -template <typename scaling_type>
        -polygon_set_data&
        scale(const scaling_type& - f)
        Scales vertices stored within the polygon set by applying f.scale().  - Expected n log n runtime, worst case quadratic runtime wrt. vertices + - intersections.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file + scale(const scaling_type& f)
        Scales vertices stored within the polygon set by +applying f.scale().  Expected n log n runtime, worst case +quadratic runtime wrt. vertices + intersections.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_polygon_with_holes_concept.htm b/doc/gtl_polygon_with_holes_concept.htm index f723452..187d756 100644 --- a/doc/gtl_polygon_with_holes_concept.htm +++ b/doc/gtl_polygon_with_holes_concept.htm @@ -1,411 +1,462 @@ - + + Boost Polygon Library: Polygon With Holes Concept - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Polygon With Holes Concept + + + + + + + + - + + + +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Polygon With Holes Concept

        - -

        -

        The polygon_with_holes concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Polygon With Holes Concept

        +

        +

        The polygon_with_holes concept tag is polygon_with_holes_concept

        -

        -To register a user defined type as a model of -polygon_with_holes concept, specialize the -geometry concept meta-function for that type.  In the example below -CPolygonWithHoles is registered as a model of polygon_with_holes  concept.

        -template <>
        -struct geometry_concept<CPolygonWithHoles> { typedef polygon_with_holes_concept type; };

        -The semantic of a polygon_with_holes is a polygon -that it can provide iterators over holes that are also polygon.  A mutable -polygon_with_holes must also be able to set its geometry based on an interator -range over polygon holes.  There is no convention of winding of holes -enforced within the library.

        -Below is shown the default polygon with holes -traits.  Specialization of these traits is required for types that don't -conform to the default behavior.  Note, these traits are used by all -polygon with holes concepts.

        template <typename -T, typename enable = void>
        +

        To register a user defined type as a model of polygon_with_holes concept, specialize +the geometry concept meta-function for that type.  In the example +below CPolygonWithHoles is registered as a model of polygon_with_holes  concept.

        +

        template <>
        +struct geometry_concept<CPolygonWithHoles> { typedef +polygon_with_holes_concept type; };

        +

        The semantic of a +polygon_with_holes is a polygon that it can provide iterators over +holes that are also polygon.  A mutable polygon_with_holes must +also be able to set its geometry based on an interator range over +polygon holes.  There is no convention of winding of holes +enforced within the library.

        +

        Below is shown the default +polygon with holes traits.  Specialization of these traits is +required for types that don't conform to the default behavior.  +Note, these traits are used by all polygon with holes concepts.

        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_traits {
        -     typedef typename T::iterator_holes_type +     typedef typename T::iterator_holes_type iterator_holes_type;
             typedef typename T::hole_type hole_type;
        -     static inline iterator_holes_type begin_holes(const T& -t) {
        -          return t.begin_holes();
        +     static inline iterator_holes_type +begin_holes(const T& t) {
        +          return +t.begin_holes();
             }
        -     static inline iterator_holes_type end_holes(const T& t) -{
        -          return t.end_holes();
        +     static inline iterator_holes_type +end_holes(const T& t) {
        +          return +t.end_holes();
             }
        -     static inline unsigned int size_holes(const T& t) {
        -          return t.size_holes();
        +     static inline unsigned int size_holes(const +T& t) {
        +          return +t.size_holes();
             }
        };

        -

        template <typename T, typename enable = void>
        +

        template <typename T, typename +enable = void>
        struct polygon_with_holes_mutable_traits {
             template <typename iT>
        -     static inline T& set_holes(T& t, iT inputBegin, iT -inputEnd) {
        -          t.set_holes(inputBegin, -inputEnd);
        +     static inline T& set_holes(T& t, iT +inputBegin, iT inputEnd) {
        +          +t.set_holes(inputBegin, inputEnd);
                  return t;
             }
        };

        -

        An object that is a model of -polygon_with_holes_concept can be viewed as a model of any of its -refinements if it is determined at runtime to conform to the restriction of -those concepts.  This concept casting is accomplished through the -view_as<>() function.

        -

        view_as<rectangle_concept>(polygon_with_holes_object)
        -view_as<polygon_90_concept>(polygon_with_holes_object)
        -view_as<polygon_90_with_holes_concept>(polygon_with_holes_object)
        -view_as<polygon_45_concept>(polygon_with_holes_object)
        -view_as<polygon_45_with_holes_concept>(polygon_with_holes_object)
        -view_as<polygon_concept>(polygon_with_holes_object)

        -

        The return value of view_as<>() can be -passed into any interface that expects an object of the conceptual type -specified in its template parameter.

        -

        Functions

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template <typename T>
        - point_iterator_type begin_points(const T& polygon)
        Expects a model of polygon_with_holes.  - Returns the begin iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - point_iterator_type end_points(const T& polygon)
        Expects a model of polygon_with_holes.  - Returns the end iterator over the range of points that correspond to - vertices of the polygon.
        template <typename T>
        - hole_iterator_type begin_holes(const T& polygon)
        Expects a model of polygon_with_holes.  - Returns the begin iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T>
        - hole_iterator_type end_holes(const T& polygon)
        Expects a model of polygon_with_holes.  - Returns the end iterator over the range of coordinates that correspond - to horizontal and vertical edges.
        template <typename T, typename - iterator>
        - void set_points(T& polygon, iterator b, iterator e)
        Expects a model of polygon_with_holes.   - Sets the polygon to the point data range [b,e) that corresponds to - vertices of a polygon. 
        template <typename T, typename - iterator>
        - void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of polygon_with_holes.   - Sets the polygon holes to the hole data range [b,e)
        template <typename T>
        - unsigned int size(const T& polygon)
        Returns the number of edges in the - outer shell of the polygon_with_holes.  Does not include sizes of - the holes.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models polygon_with_holes or one - of its refinements into left object - that models polygon_with_holes.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models polygon_with_holes and an object that models - point, returns true - if the polygon shell contains the point and one of its holes does not - contain the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the polygon or one of its holes.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of the bounding - box of an object that models polygon_with_holes.
        template <typename T, - typename rectangle_type>
        - bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box of an object - that models polygon_with_holes and returns true.  Returns false and - leaves bbox unchanged if polygon is empty.
        template <typename T>
        - manhattan_area_type area(const T& polygon)
        Returns the area of an object - that models polygon_with_holes including subtracting the area of its - holes from the area of the outer shell polygon.
        template <typename T>
        - direction_1d winding(const T& polygon)
        Returns the winding direction of an object - that models polygon_with_holes, LOW == CLOCKWISE, HIGH = - COUNTERCLOCKWISE.
        template <typename T>
        - coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object - that models polygon, including the perimeters of the holes.
        template <typename T, - typename transform_type>
        - T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets the polygon to that described by the result of - transforming its vertices.  Also applies transform() on the holes - of the polygon.
        template <typename T>
        - T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that models - polygon by unsigned factor.
        template <typename T>
        - T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that models - polygon by unsigned factor.
        template <typename T, scaling_type>
        - T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models polygon by - floating point factor.
        template <typename T>
        - T& move(T& polygon, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to coordinate indicated by orientation_2d of - vertices of an object that models polygon .
        template <typename polygon_type, typename point_type>
        - polygon_type& convolve(polygon_type& polygon,
                               +

        An object that is a model of +polygon_with_holes_concept can be viewed as a model of any of +its refinements if it is determined at runtime to conform to the +restriction of those concepts.  This concept casting is +accomplished through the + view_as<>() function.

        +

        view_as<rectangle_concept>(polygon_with_holes_object)
        + view_as<polygon_90_concept>(polygon_with_holes_object)
        + view_as<polygon_90_with_holes_concept>(polygon_with_holes_object)
        + view_as<polygon_45_concept>(polygon_with_holes_object)
        + view_as<polygon_45_with_holes_concept>(polygon_with_holes_object)
        + view_as<polygon_concept>(polygon_with_holes_object)

        +

        The return value of view_as<>() +can be passed into any interface that expects an object of the +conceptual type specified in its template parameter.

        +

        Functions

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -
        template +<typename T>
        +point_iterator_type begin_points(const T& polygon)
        Expects a model of +polygon_with_holes.  Returns the begin iterator over the range of +points that correspond to vertices of the polygon.
        template +<typename T>
        +point_iterator_type end_points(const T& polygon)
        Expects a model of +polygon_with_holes.  Returns the end iterator over the range of +points that correspond to vertices of the polygon.
        template +<typename T>
        +hole_iterator_type begin_holes(const T& polygon)
        Expects a model of +polygon_with_holes.  Returns the begin iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T>
        +hole_iterator_type end_holes(const T& polygon)
        Expects a model of +polygon_with_holes.  Returns the end iterator over the range of +coordinates that correspond to horizontal and vertical edges.
        template +<typename T, typename iterator>
        +void set_points(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_with_holes.   Sets the polygon to the point data +range [b,e) that corresponds to vertices of a polygon. 
        template +<typename T, typename iterator>
        +void set_holes(T& polygon, iterator b, iterator e)
        Expects a model of +polygon_with_holes.   Sets the polygon holes to the hole data +range [b,e)
        template +<typename T>
        +unsigned int size(const T& polygon)
        Returns the number of +edges in the outer shell of the polygon_with_holes.  Does not +include sizes of the holes.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models +polygon_with_holes or one of its refinements into left object that +models polygon_with_holes.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models polygon_with_holes and an +object that models point, returns true if the polygon shell contains +the point and one of its holes does not contain the point.  If the +consider_touch flag is true will return true if the point lies along +the boundary of the polygon or one of its holes.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& polygon)
        Sets object that models point to the center point of +the bounding box of an object that models polygon_with_holes.
        template +<typename T, typename rectangle_type>
        +bool extents(rectangle_type& bbox, const T& polygon)
        Sets object that models rectangle to the bounding box +of an object that models polygon_with_holes and returns true.  +Returns false and leaves bbox unchanged if polygon is empty.
        template +<typename T>
        +manhattan_area_type area(const T& polygon)
        Returns the area of an object that models +polygon_with_holes including subtracting the area of its holes from the +area of the outer shell polygon.
        template +<typename T>
        +direction_1d winding(const T& polygon)
        Returns the winding direction of an object that models +polygon_with_holes, LOW == CLOCKWISE, HIGH = COUNTERCLOCKWISE.
        template +<typename T>
        +coordinate_difference perimeter(const T& polygon)
        Returns the perimeter length of an object that models +polygon, including the perimeters of the holes.
        template +<typename T, typename transform_type>
        +T& transform(T& polygon, const transform_type&)
        Applies transform() on the vertices of polygon and sets +the polygon to that described by the result of transforming its +vertices.  Also applies transform() on the holes of the polygon.
        template +<typename T>
        +T& scale_up(T& polygon, unsigned_area_type factor)
        Scales up outer shell and holes of an object that +models polygon by unsigned factor.
        template +<typename T>
        +T& scale_down(T& polygon, unsigned_area_type factor)
        Scales down outer shell and holes of an object that +models polygon by unsigned factor.
        template +<typename T, scaling_type>
        +T& scale(T& rectangle, double scaling)
        Scales outer shell and holes of an object that models +polygon by floating point factor.
        template +<typename T>
        +T& move(T& polygon, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to coordinate indicated by +orientation_2d of vertices of an object that models polygon .
        template +<typename polygon_type, typename point_type>
        +polygon_type& convolve(polygon_type& polygon,
        +                       const point_type& point)
        Convolves coordinate values of point with the outer shell and holes of an - object that models polygon_with_holes.
        -

        Polygon With Holes Data

        - -

        -

        The library provides a model of polygon with holes concept declared - -template<typename T> polygon_with_holes_data where T is the -coordinate type.

        -

        This data type is used internally when a polygon with holes is -needed and is available to the library user who finds it convenient to use a -library polygon data type instead of providing their own.  The data type is -implemented to be convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typepolygon_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of polygon
        iterator_holes_typeIterator over hole polygons of type - polygon_data<T>.
        polygon_with_holes_data()Default constructs the polygon.
        polygon_with_holes_data(const - polygon_with_holes_data& that)Copy construct
        polygon_with_holes_data& -
        operator=
        (const polygon_with_holes_data& that)
        Assignment operator.
        template <typename T2> - polygon_with_holes_data&  -
        operator=
        (const T2& that) const
        Assign from an object that is a model of polygon with holes.
        iterator_type begin() - constGet the begin iterator over vertices of the polygon.
        iterator_type end() - constGet the end iterator over vertices of the polygon.
        iterator_hole_type begin_holes() - constGet the begin compact iterator over non-redundant coordinates of the - polygon.
        iterator_hole_type end_holes() - constGet the end compact iterator over non-redundant coordinates of the - polygon.
        std::size_t size() constGet the number of elements in the sequence stored to the polygon, - usually equal to the number of edges of the polygon.
        std::size_t size_holes() constGet the number of holes in the polygon
        template <typename iT>  -
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.
        template <typename iT>  -
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole polygons.  These - polygons in the input range may be either polygon_data or - polygon_with_holes_data or any type that provides begin and end member - functions to iterate over point_data<T>.
        -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +
        Convolves coordinate values of point with the outer +shell and holes of an object that models polygon_with_holes.
        +

        Polygon With Holes Data

        +

        +

        The library provides a model of polygon with holes concept +declared + template<typename T> +polygon_with_holes_data where T is the coordinate type.

        +

        This data type is used internally when a polygon with holes is +needed and is available to the library user who finds it convenient to +use a library polygon data type instead of providing their own.  +The data type is implemented to be convenient to use with the library +traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typepolygon_with_holes_concept
        coordinate_typeT
        iterator_typeIterator over vertices point_data<T> vertices of +polygon
        iterator_holes_typeIterator over hole +polygons of type polygon_data<T>.
        polygon_with_holes_data()Default constructs the polygon.
        polygon_with_holes_data(const +polygon_with_holes_data& that)Copy construct
        polygon_with_holes_data& +
        +operator=
        (const polygon_with_holes_data& that)
        Assignment operator.
        template +<typename T2> polygon_with_holes_data& 
        +operator=
        (const T2& that) const
        Assign from an object that is a model of polygon with +holes.
        iterator_type begin() +constGet the begin iterator over vertices of the polygon.
        iterator_type end() +constGet the end iterator over vertices of the polygon.
        iterator_hole_type + begin_holes() constGet the begin compact iterator over non-redundant +coordinates of the polygon.
        iterator_hole_type + end_holes() constGet the end compact iterator over non-redundant +coordinates of the polygon.
        std::size_t size() +constGet the number of elements in the sequence stored to +the polygon, usually equal to the number of edges of the polygon.
        std::size_t size_holes() +constGet the number of holes in the polygon
        template +<typename iT> 
        +
        void set(iT begin_points, iT end_points)
        Sets the polygon to the iterator range of points.
        template +<typename iT> 
        +
        void set_holes(iT begin_holes, iT end_choless)
        Sets the polygon holes the iterator range of hole +polygons.  These polygons in the input range may be either +polygon_data or polygon_with_holes_data or any type that provides begin +and end member functions to iterate over point_data<T>.
        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_property_merge.htm b/doc/gtl_property_merge.htm index c1459d2..f24f21f 100644 --- a/doc/gtl_property_merge.htm +++ b/doc/gtl_property_merge.htm @@ -1,163 +1,186 @@ - + + Boost Polygon Library: Property Merge - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_property_merge_45.htm b/doc/gtl_property_merge_45.htm index 1c0cb69..5889d77 100644 --- a/doc/gtl_property_merge_45.htm +++ b/doc/gtl_property_merge_45.htm @@ -1,162 +1,186 @@ - + + Boost Polygon Library: Property Merge 90 - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_property_merge_90.htm b/doc/gtl_property_merge_90.htm index 6ada100..d826ded 100644 --- a/doc/gtl_property_merge_90.htm +++ b/doc/gtl_property_merge_90.htm @@ -1,162 +1,186 @@ - + + Boost Polygon Library: Property Merge 90 - - - - - + + + + + + +
      -
      - - -
      -
      - -
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_rectangle_concept.htm b/doc/gtl_rectangle_concept.htm index 1cc27c2..a8ed2be 100644 --- a/doc/gtl_rectangle_concept.htm +++ b/doc/gtl_rectangle_concept.htm @@ -1,775 +1,859 @@ - + + Boost Polygon Library: Rectangle Concept - - - - - + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Rectangle Concept + + + + + + + + - +
        + +
        + + - - + + -
        - -
        - - -
        -
        - - - -
        -

        -

        Rectangle Concept

        - -

        -

        The rectangle concept tag is +

      • Voronoi Advanced +Tutorial
      • + + + + +
        +
        +

        +

        +

        Rectangle Concept

        +

        +

        The rectangle concept tag is rectangle_concept

        -

        -To register a user defined type as a model of -rectangle concept, specialize the -geometry concept meta-function for that type.  In the example below CRectangle is registered as a model of -rectangle  concept.

        -template <>
        -struct geometry_concept<CRectangle> { typedef rectangle_concept type; };

        -The semantic of a rectangle is that it has an x and -a y interval and these intervals conform to the semantic of an interval -including its invariant.  This invariant on the intervals of a rectangle is enforced by the generic library functions that -operate on rectangles, and is not expected of the data type itself or the concept -mapping of that data type to the rectangle concept through its traits.  In -this way a boost::tuple<int, int, int, int> or boost::array<int, 4> -could be made models of rectangle by simply providing indirect access to their -elements through traits.

        -Below is shown the default rectangle traits.  -Specialization of these traits is required for types that don't conform to the -default behavior.  The interested reader will note SFINAE is used on the -traits to allow only an object that provides a member type definition of -interval_type to work with the default read only traits.  This becomes -necessary when refinements of concepts are used and it is undesirable to attempt -to match default traits to non-rectangle types at compile time.  -Specializing rectangle_traits can be done easily by simply providing gtl_yes as -the enable parameter.

        -template <typename T, typename enable = gtl_yes>
        -struct rectangle_traits {};

        -template <typename T>
        +

        To register a user defined type as a model of rectangle concept, specialize the +geometry concept meta-function for that type.  In the example +below CRectangle is registered as a model of rectangle  concept.

        +

        template <>
        +struct geometry_concept<CRectangle> { typedef rectangle_concept +type; };

        +

        The semantic of a rectangle is +that it has an x and a y interval and these intervals conform to the +semantic of an interval including its invariant.  This invariant +on the intervals of a rectangle is enforced by the generic library +functions that operate on rectangles, and is not expected of the data +type itself or the concept mapping of that data type to the rectangle +concept through its traits.  In this way a boost::tuple<int, +int, int, int> or boost::array<int, 4> could be made models of +rectangle by simply providing indirect access to their elements through +traits.

        +

        Below is shown the default +rectangle traits.  Specialization of these traits is required for +types that don't conform to the default behavior.  The interested +reader will note SFINAE is used on the traits to allow only an object +that provides a member type definition of interval_type to work with +the default read only traits.  This becomes necessary when +refinements of concepts are used and it is undesirable to attempt to +match default traits to non-rectangle types at compile time.  +Specializing rectangle_traits can be done easily by simply providing +gtl_yes as the enable parameter.

        +

        template <typename T, typename +enable = gtl_yes>
        +struct rectangle_traits {};

        +

        template <typename T>
        struct rectangle_traits<T, gtl_no> {};
        -
        +
        template <typename T>
        -struct rectangle_traits<T, typename gtl_same_type<typename T::interval_type, -typename T::interval_type>::type> {
        -     typedef typename T::coordinate_type coordinate_type;
        -     typedef typename T::interval_type interval_type;
        -     static inline interval_type get(const T& rectangle, -orientation_2d orient) {
        -          return +struct rectangle_traits<T, typename gtl_same_type<typename +T::interval_type, typename T::interval_type>::type> {
        +     typedef typename T::coordinate_type +coordinate_type;
        +     typedef typename T::interval_type +interval_type;
        +     static inline interval_type get(const T& +rectangle, orientation_2d orient) {
        +          return rectangle.get(orient); }
        };
        -
        +
        template <typename T>
        struct rectangle_mutable_traits {
             template <typename T2>
        -     static inline void set(T& rectangle, orientation_2d -orient, const T2& interval) {
        -          rectangle.set(orient, -interval); }
        +     static inline void set(T& rectangle, +orientation_2d orient, const T2& interval) {
        +          +rectangle.set(orient, interval); }
             template <typename T2, typename T3>
        -     static inline T construct(const T2& interval_horizontal, -const T3& interval_vertical) {
        -          return +     static inline T construct(const T2& +interval_horizontal, const T3& interval_vertical) {
        +          return T(interval_horizontal, interval_vertical); }
        -};

        Functions

        - - - - - - + - - - - - - - -
        template <typename T>
        - interval_type get(const T& rectangle, orientation_2d)
        Expects a model of rectangle.  - Returns the x interval or y interval of the rectangle, depending on the - orientation_2d value.
        +};

        +

        Functions

        + + + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        template +<typename T>
        +interval_type get(const T& rectangle, orientation_2d)
        Expects a model of +rectangle.  Returns the x interval or y interval of the rectangle, +depending on the orientation_2d value.
         
        template <typename T, typename - coordinate_type>
        - void set(T& rectangle, orientation_2d, coordinate_type)
        Expects a model of rectangle.   - Sets the x interval or y interval of the rectangle to the - coordinate, depending on the orientation_2d value.
        template <typename T>
        - interval_type get(const T& rectangle, orientation_2d, -
                          direction_1d)
        Expects +
        template +<typename T, typename coordinate_type>
        +void set(T& rectangle, orientation_2d, coordinate_type)
        Expects a model of +rectangle.   Sets the x interval or y interval of the +rectangle to the coordinate, depending on the orientation_2d value.
        template +<typename T>
        +interval_type get(const T& rectangle, orientation_2d,
        +                  +direction_1d)
        Expects a model of rectangle.  Returns the coordinate specificed by the direction_1d value of the x interval or y interval of the rectangle, depending on the orientation_2d value.
         
        template <typename T, typename - coordinate_type>
        - void set(T& rectangle, orientation_2d, direction_1d,
                 coordinate_type)
        Expects a model of rectangle.   - Sets the coordinate specified by the direction_1d value of the x interval or y interval of the rectangle to the - coordinate, depending on the orientation_2d value.
        template <typename T, typename - T2>
        - T construct(const T2& h, const T2& v)
        Construct an object that is a model of rectangle given x interval - and y intervals.
        template <typename T, typename - T2>
        - T construct(coordinate_type xl, coordinate_type yl,
                    coordinate_type - xh, coordinate_type yh)
        Construct an object that is a model of rectangle given four coordinate values.
        template <typename T1, typename - T2>
        - T1& assign(T1& left, const T2& right)
        Copies data from right object that models rectangle into left object - that models rectangle.
        template <typename T, typename - T2>
        - bool equivalence(const T& rectangle1,
        -
                         const T2& rectangle2)
        Given two objects that model rectangle, compares and returns true if - their x and y intervals are respectively equivalent.
        template <typename T, - typename point_type>
        - bool contains(const T&, const point_type& point,
        -              - bool consider_touch=true)
        Given an object that models rectangle and an object that models - point, returns true - if the rectangle contains the point.  If the consider_touch - flag is true will return true if the point lies along the boundary of - the rectangle.
        template <typename T1, typename - T2>
        - bool contains(const T1& a, const T2& b,
        -              - bool consider_touch = true)
        Returns true if model of rectangle a contains both intervals of - model of rectangle b.  If the consider_touch flag is true will - consider rectangle b contained even if it touches the boundary of a.
        template <typename T>
        - interval_type horizontal(const T& rectangle)
        Returns the x interval of an object that models rectangle.
        template <typename T>
        - interval_type vertical(const T& rectangle)
        Returns the y interval of an object that models rectangle.
        template <typename T>
        - coordinate_type xl(const T& rectangle)
        Returns the west coordinate of an object that models rectangle.
        template <typename T>
        - coordinate_type xh(const T& rectangle)
        Returns the east coordinate of an object that models rectangle.
        template <typename T>
        - coordinate_type yl(const T& rectangle)
        Returns the south coordinate of an object that models rectangle.
        template <typename T>
        - coordinate_type yh(const T& rectangle)
        Returns the north coordinate of an object that models rectangle.
        template <typename T>
        - point_type ll(const T& rectangle)
        Returns the lower left corner point of an object that models rectangle.
        template <typename T>
        - point_type lr(const T& rectangle)
        Returns the lower right corner point of an object that models rectangle.
        template <typename T>
        - point_type ul(const T& rectangle)
        Returns the upper left corner point of an object that models rectangle.
        template <typename T>
        - point_type ur(const T& rectangle)
        Returns the upper right corner point of an object that models rectangle.
        // get the center coordinate
        - template <typename T, typename point_type>
        - void center(point_type& p, const T& rectangle)
        Sets object that models point to the center point of an object that models rectangle.
        template <typename T, - typename interval_type>
        - void horizontal(T& rectangle, const interval_type& i)
        Sets the x interval of the object that models rectangle to be equal - to the value of an object that models interval.
        template <typename T, - typename interval_type>
        - void vertical(T& rectangle, const interval_type& i )
        Sets the y interval of the object that models rectangle to be equal - to the value of an object that models interval.
        template <typename - rectangle_type>
        - void xl(rectangle_type& rectangle, coordinate_type )
        Sets the west coordinate of the object that models rectangle to be equal - to the coordinate value.
        template <typename - rectangle_type>
        - void xh(rectangle_type& rectangle, coordinate_type )
        Sets the east coordinate of the object that models rectangle to be equal - to the coordinate value.
        template <typename - rectangle_type>
        - void yl(rectangle_type& rectangle, coordinate_type )
        Sets the south coordinate of the object that models rectangle to be equal - to the coordinate value.
        template <typename - rectangle_type>
        - void yh(rectangle_type& rectangle, coordinate_type )
        Sets the north coordinate of the object that models rectangle to be equal - to the coordinate value.
        template <typename T, - typename T1, typename T2>
        - T& set_points(T& rectangle, const T1& p1, const T2& p2)
        Sets the rectangle to the rectangle fully described by the points p1 - and p2.
        template <typename T>
        - coordinate_difference delta(const T& rectangle, -
                                    +
        template +<typename T, typename coordinate_type>
        +void set(T& rectangle, orientation_2d, direction_1d,
        +         coordinate_type)
        Expects a model of +rectangle.   Sets the coordinate specified by the +direction_1d value of the x interval or y interval of the rectangle to +the coordinate, depending on the orientation_2d value.
        template +<typename T, typename T2>
        +T construct(const T2& h, const T2& v)
        Construct an object that is a model of rectangle given +x interval and y intervals.
        template +<typename T, typename T2>
        +T construct(coordinate_type xl, coordinate_type yl,
        +            +coordinate_type xh, coordinate_type yh)
        Construct an object that is a model of rectangle given +four coordinate values.
        template +<typename T1, typename T2>
        +T1& assign(T1& left, const T2& right)
        Copies data from right object that models rectangle +into left object that models rectangle.
        template +<typename T, typename T2>
        +bool equivalence(const T& rectangle1,

        +                  +const T2& rectangle2)
        Given two objects that model rectangle, compares and +returns true if their x and y intervals are respectively equivalent.
        template +<typename T, typename point_type>
        +bool contains(const T&, const point_type& point,
        +              +bool consider_touch=true)
        Given an object that models rectangle and an object +that models point, returns true if the rectangle contains the +point.  If the consider_touch flag is true will return true if the +point lies along the boundary of the rectangle.
        template +<typename T1, typename T2>
        +bool contains(const T1& a, const T2& b,
        +              +bool consider_touch = true)
        Returns true if model of rectangle a contains both +intervals of model of rectangle b.  If the consider_touch flag is +true will consider rectangle b contained even if it touches the +boundary of a.
        template +<typename T>
        +interval_type horizontal(const T& rectangle)
        Returns the x interval of an object that models +rectangle.
        template +<typename T>
        +interval_type vertical(const T& rectangle)
        Returns the y interval of an object that models +rectangle.
        template +<typename T>
        +coordinate_type xl(const T& rectangle)
        Returns the west coordinate of an object that models +rectangle.
        template +<typename T>
        +coordinate_type xh(const T& rectangle)
        Returns the east coordinate of an object that models +rectangle.
        template +<typename T>
        +coordinate_type yl(const T& rectangle)
        Returns the south coordinate of an object that models +rectangle.
        template +<typename T>
        +coordinate_type yh(const T& rectangle)
        Returns the north coordinate of an object that models +rectangle.
        template +<typename T>
        +point_type ll(const T& rectangle)
        Returns the lower left corner point of an object that +models rectangle.
        template +<typename T>
        +point_type lr(const T& rectangle)
        Returns the lower right corner point of an object that +models rectangle.
        template +<typename T>
        +point_type ul(const T& rectangle)
        Returns the upper left corner point of an object that +models rectangle.
        template +<typename T>
        +point_type ur(const T& rectangle)
        Returns the upper right corner point of an object that +models rectangle.
        // get the center +coordinate
        +template <typename T, typename point_type>
        +void center(point_type& p, const T& rectangle)
        Sets object that models point to the center point of an +object that models rectangle.
        template +<typename T, typename interval_type>
        +void horizontal(T& rectangle, const interval_type& i)
        Sets the x interval of the object that models rectangle +to be equal to the value of an object that models interval.
        template +<typename T, typename interval_type>
        +void vertical(T& rectangle, const interval_type& i )
        Sets the y interval of the object that models rectangle +to be equal to the value of an object that models interval.
        template +<typename rectangle_type>
        +void xl(rectangle_type& rectangle, coordinate_type )
        Sets the west coordinate of the object that models +rectangle to be equal to the coordinate value.
        template +<typename rectangle_type>
        +void xh(rectangle_type& rectangle, coordinate_type )
        Sets the east coordinate of the object that models +rectangle to be equal to the coordinate value.
        template +<typename rectangle_type>
        +void yl(rectangle_type& rectangle, coordinate_type )
        Sets the south coordinate of the object that models +rectangle to be equal to the coordinate value.
        template +<typename rectangle_type>
        +void yh(rectangle_type& rectangle, coordinate_type )
        Sets the north coordinate of the object that models +rectangle to be equal to the coordinate value.
        template +<typename T, typename T1, typename T2>
        +T& set_points(T& rectangle, const T1& p1, const +T2& p2)
        Sets the rectangle to the rectangle fully described by +the points p1 and p2.
        template +<typename T>
        +coordinate_difference delta(const T& rectangle,
        +                            orientation_2d)
        Returns the delta of the interval specified by orientation_2d of an object - that models rectangle.
        template <typename T>
        - manhattan_area_type area(const T& rectangle)
        Returns the area of an object - that models rectangle.
        template <typename T>
        - coordinate_difference half_perimeter(const T& rectangle)
        Returns the length plus width of an object - that models rectangle.
        template <typename T>
        - coordinate_difference perimeter(const T& rectangle)
        Returns the perimeter length of an object - that models rectangle.
        template <typename T>
        - orientation_2d quess_orientation(const T& rectangle)
        Returns the orientation in which the rectangle has a longer delta.  - Returns HORIZONTAL if the rectangle is a square.
        template <typename - rectangle_type>
        - rectangle_type& transform(rectangle_type& rectangle,
        +
        Returns the delta of the interval specified by +orientation_2d of an object that models rectangle.
        template +<typename T>
        +manhattan_area_type area(const T& rectangle)
        Returns the area of an object that models rectangle.
        template +<typename T>
        +coordinate_difference half_perimeter(const T& rectangle)
        Returns the length plus width of an object that models +rectangle.
        template +<typename T>
        +coordinate_difference perimeter(const T& rectangle)
        Returns the perimeter length of an object that models +rectangle.
        template +<typename T>
        +orientation_2d quess_orientation(const T& rectangle)
        Returns the orientation in which the rectangle has a +longer delta.  Returns HORIZONTAL if the rectangle is a square.
        template +<typename rectangle_type>
        +rectangle_type& transform(rectangle_type& rectangle,
                                  coordinate_type axis = 0)
        Applies transform() on the two points that fully describe the - rectangle and sets the rectangle to that described by the result of - transforming those points.
        template <typename - rectangle_type>
        - rectangle_type& scale_up(rectangle_type& rectangle,
        +
        Applies transform() on the two points that fully +describe the rectangle and sets the rectangle to that described by the +result of transforming those points.
        template +<typename rectangle_type>
        +rectangle_type& scale_up(rectangle_type& rectangle,
                                 unsigned_area_type factor)
        Scales up x interval and y interval  of an object that models - rectangle by unsigned factor.
        template <typename - rectangle_type>
        - rectangle_type& scale_down(rectangle_type& rectangle,
        +
        Scales up x interval and y interval  of an object +that models rectangle by unsigned factor.
        template +<typename rectangle_type>
        +rectangle_type& scale_down(rectangle_type& rectangle,
                                   unsigned_area_type factor)
        Scales down x interval and y interval  of an object that models - rectangle by unsigned factor.
        template <typename - rectangle_type, scaling_type>
        - rectangle_type& scale(rectangle_type& rectangle,
        -                      - const scaling_type& scaling)
        Applies scale() on the two points that fully describe the rectangle - and sets the rectangle to that described by the result of transforming - those points.
        template <typename T>
        - T& move(T& rectangle, orientation_2d,
        -        coordinate_difference displacement)
        Adds displacement value to interval indicated by orientation_2d of an - object that models rectangle.
        template <typename - rectangle_type, typename point_type>
        - rectangle_type& convolve(rectangle_type& rectangle,
        +
        Scales down x interval and y interval  of an +object that models rectangle by unsigned factor.
        template +<typename rectangle_type, scaling_type>
        +rectangle_type& scale(rectangle_type& rectangle,
        +                      +const scaling_type& scaling)
        Applies scale() on the two points that fully describe +the rectangle and sets the rectangle to that described by the result of +transforming those points.
        template +<typename T>
        +T& move(T& rectangle, orientation_2d,
        +        coordinate_difference +displacement)
        Adds displacement value to interval indicated by +orientation_2d of an object that models rectangle.
        template +<typename rectangle_type, typename point_type>
        +rectangle_type& convolve(rectangle_type& rectangle,
                                 const point_type& point)
        Convolves coordinate values of point with x interval and y interval  of an - object that models rectangle.
        template <typename - rectangle_type, typename point_type>
        - rectangle_type& deconvolve(rectangle_type& rectangle,
        +
        Convolves coordinate values of point with x interval +and y interval  of an object that models rectangle.
        template +<typename rectangle_type, typename point_type>
        +rectangle_type& deconvolve(rectangle_type& rectangle,
                                   const point_type& point)
        Deconvolves coordinate values of point withx interval and y interval  of - an object that models rectangle.
        template <typename T1, typename - T2>
        - T1& convolve(T1& a, const T2& b)
        Convolves x interval  of b with x interval  of a and - convolves y - interval  of b with y interval  of a.
        template <typename T1, typename - T2>
        - T1& deconvolve(T1& a, const T2& b)
        Deconvolves x interval  of b with x interval  of a and - deconvolves y interval  of b with y interval  of a.
        template <typename T1, typename - T2>
        - T1& reflected_convolve(T1& a, const T2& b)
        Reflected convolves y interval  of b with x interval  of a and - reflected convolves x - interval  of b with y interval  of a.
        template <typename T1, typename - T2>
        - T1& reflected_deconvolve(T1& a, const T2& b)
        Reflected deconvolves y interval  of b with x interval  of a and - reflected deconvolves x interval  of b with y interval  of a.
        template <typename T, - typename point_type>
        - coordinate_difference euclidean_distance(const T&,
        -        const point_type& point, - orienation_2d)
        Returns the distance from an object that models rectangle to an - object that models point along the given orientation.  Returns zero - if the point is contained within the rectangle along that orientation.
        template <typename T1, - typename T2>
        - coordinate_difference euclidean_distance(const T1& a,
        -        const T2& b, orienation_2d)
        Returns the distance from an object that models rectangle to an - object that models rectangle along the given orientation.  Returns - zero if the intervals of the rectangles overlap along that orientation.
        template <typename T, - typename point_type>
        - coordinate_difference square_euclidean_distance(const T&,
        -        const point_type& point)
        Returns the square of the Euclidean distance between a point and a - rectangle.  Returns zero if the point is contained within the - rectangle.
        template <typename T1, - typename T2>
        - coordinate_difference square_euclidean_distance
        -        (const T1& a, const T2& b)
        Returns the square of the Euclidean distance between rectangles a - and b.  Returns zero if the rectangles intersect.
        template <typename T, - typename point_type>
        - coordinate_difference manhattan_distance(const T&,
        -        const point_type& point)
        Returns the Manhattan distance between a point and a rectangle.  - Returns zero if the point is contained within the rectangle.
        template <typename T1, - typename T2>
        - coordinate_difference manhattan_distance(const T1& a,
        +
        Deconvolves coordinate values of point withx interval +and y interval  of an object that models rectangle.
        template +<typename T1, typename T2>
        +T1& convolve(T1& a, const T2& b)
        Convolves x interval  of b with x interval  +of a and convolves y interval  of b with y interval  of a.
        template +<typename T1, typename T2>
        +T1& deconvolve(T1& a, const T2& b)
        Deconvolves x interval  of b with x interval  +of a and deconvolves y interval  of b with y interval  of a.
        template +<typename T1, typename T2>
        +T1& reflected_convolve(T1& a, const T2& b)
        Reflected convolves y interval  of b with x +interval  of a and reflected convolves x interval  of b with +y interval  of a.
        template +<typename T1, typename T2>
        +T1& reflected_deconvolve(T1& a, const T2& b)
        Reflected deconvolves y interval  of b with x +interval  of a and reflected deconvolves x interval  of b +with y interval  of a.
        template +<typename T, typename point_type>
        +coordinate_difference euclidean_distance(const T&,
        +       const point_type& point, +orienation_2d)
        Returns the distance from an object that models +rectangle to an object that models point along the given +orientation.  Returns zero if the point is contained within the +rectangle along that orientation.
        template +<typename T1, typename T2>
        +coordinate_difference euclidean_distance(const T1& a,
        +       const T2& b, orienation_2d)
        Returns the distance from an object that models +rectangle to an object that models rectangle along the given +orientation.  Returns zero if the intervals of the rectangles +overlap along that orientation.
        template +<typename T, typename point_type>
        +coordinate_difference square_euclidean_distance(const T&,
        +       const point_type& point)
        Returns the square of the Euclidean distance between a +point and a rectangle.  Returns zero if the point is contained +within the rectangle.
        template +<typename T1, typename T2>
        +coordinate_difference square_euclidean_distance
        +       (const T1& a, const T2& b)
        Returns the square of the Euclidean distance between +rectangles a and b.  Returns zero if the rectangles intersect.
        template +<typename T, typename point_type>
        +coordinate_difference manhattan_distance(const T&,
        +       const point_type& point)
        Returns the Manhattan distance between a point and a +rectangle.  Returns zero if the point is contained within the +rectangle.
        template +<typename T1, typename T2>
        +coordinate_difference manhattan_distance(const T1& a,
                                                 const T2& b)
        Returns the Manhattan distance between rectangles a and b.  - Returns zero if the rectangles intersect.
        template <typename T, - typename point_type>
        - coordinate_distance euclidean_distance(const T&,
        -        const point_type& point)
        Returns the Euclidean distance between a point and a rectangle.  - Returns zero if the point is contained within the rectangle.
        template <typename T1, - typename T2>
        - coordinate_distance euclidean_distance(const T1& a,
        +
        Returns the Manhattan distance between rectangles a and +b.  Returns zero if the rectangles intersect.
        template +<typename T, typename point_type>
        +coordinate_distance euclidean_distance(const T&,
        +       const point_type& point)
        Returns the Euclidean distance between a point and a +rectangle.  Returns zero if the point is contained within the +rectangle.
        template +<typename T1, typename T2>
        +coordinate_distance euclidean_distance(const T1& a,
                                                 const T2& b)
        Returns the Euclidean distance between rectangles a and b.  - Returns zero if the rectangles intersect.
        template <typename T1, typename - T2>
        - bool intersects(const T1& a, const T2& b,
        -                - bool consider_touch = true)
        Returns true if two objects that model rectangle overlap.  If - the consider_touch flag is true touching at the sides or corners is - considered overlap.
        template <typename T1, typename - T2>
        - bool boundaries_intersect(const T1& a, const T2& b,
        +
        Returns the Euclidean distance between rectangles a and +b.  Returns zero if the rectangles intersect.
        template +<typename T1, typename T2>
        +bool intersects(const T1& a, const T2& b,
        +                +bool consider_touch = true)
        Returns true if two objects that model rectangle +overlap.  If the consider_touch flag is true touching at the sides +or corners is considered overlap.
        template +<typename T1, typename T2>
        +bool boundaries_intersect(const T1& a, const T2& b,
                                  bool consider_touch = true)
        Returns true is two objects that model rectangle partially overlap - such that one there is an intersection between the edges of the two - rectangles  If the consider_touch flag is true a coordinate is - considered contained even if the two rectangles touch only along a side - or corner.
        template <typename T1, typename - T2>
        - bool abuts(const T1& a, const T2& b,
        -           direction_2d dir) -
        Returns true if rectangle b abuts but down not overlap rectangle a - on the side of rectangle a specified by dir.
        template <typename T1, typename - T2>
        - bool abuts(const T1& a, const T2& b,
        -           orientation_2d) -
        Returns true if rectangle b abuts but down not overlap rectangle a - on either side of rectangle a specified by the orientation_2d.
        template <typename T1, typename - T2>
        - bool abuts(const T1& a, const T2& b)
        Returns true if rectangle b abuts but down not overlap rectangle a - on any side.
        template <typename T1, typename - T2>
        - bool intersect(T1& a, const T2& b, orientation_2d
        -               - bool consider_touch = true)
        Sets rectangle a to the intersection of rectangle a and interval b - along the orientation_2d - and returns true.  If the does not intersect the interval, the - rectangle is unchanged and the function returns false.  If the flag consider_touch is true - intervals that abut are considered to intersect.
        template <typename T1, typename - T2>
        - bool intersect(T1& a, const T2& b,
        -               - bool consider_touch = true)
        Sets rectangle a to the intersection of rectangle a and rectangle b - and return true.  If the two rectangles do not intersect rectangle - a is unchanged and the function returns false.  If the flag - consider_touch is true rectangles that abut are considered to intersect.
        template <typename T1, typename - T2>
        - T& generalized_intersect(T1& a, const T2& b)
        Same as intersect, but if they do not intersect set a to the - rectangle between a and b by applying generalized_intersect() on the - intervals of the rectangles.
        template <typename T>
        - T& bloat(T& rectangle, coordinate_type)
        Bloats x and y intervals of rectangle by coordinate value.
        template <typename T>
        - T& bloat(T& rectangle, direction_2d, coordinate_type)
        Bloats side of rectangle specified by direction_2d by coordinate - value.
        template <typename T>
        - T& bloat(T& rectangle, orientation_2d, coordinate_type)
        Bloats interval of rectangle specified by orientation_2d by - coordinate value.
        template <typename T>
        - T& shrink(T& rectangle, coordinate_type)
        Shrinks x and y intervals of rectangle by coordinate value.
        template <typename T>
        - T& shrink(T& rectangle, direction_2d, coordinate_type)
        Shrinks side of rectangle specified by direction_2d by coordinate - value.
        template <typename T>
        - T& shrink(T& rectangle, orientation_2d, coordinate_type)
        Shrinks interval of rectangle specified by orientation_2d by - coordinate value.
        template <typename T1, typename - T2>
        - bool encompass(T1& a, const T2& b)
        The x and y intervals of a are set to encompass the x and y - intervals of b respectively.
        template <typename T, typename - point_type>
        - bool encompass(T& rectangle, const point_type& point)
        The x and y intervals of rectangle are set to encompass the x and y - coordinates of point respectively.
        template <typename T, typename - interval_type>
        - bool encompass(T& rectangle, const interval_type& i, -
                       orientation_2d)
        The interval of rectangle specified by orientation_2d is set to encompass the - interval i.
        template <typename T, typename - point_type>
        - bool get_corner(point_type& point, const T& rectangle,  -
                        - direction_2d, direction_1d)
        Sets point to the corner of the rectangle you reach if you look at - its side specified by direction_2d from within the rectangle and turn in - the direction_1d direction (low == left, high = right).  Always - returns true.
        -

        Rectangle Data

        - -

        -

        The library provides a model of rectangle concept declared - -template<typename T> rectangle_data where T is the coordinate type.

        -

        This data type is used internally when a rectangle is needed and is available -to the library user who finds it convenient to use a library rectangle data type -instead of providing their own.  The data type is implemented to be -convenient to use with the library traits.

        -

        Members

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        geometry_typerectangle_concept
        coordinate_typeT
        interval_typeinterval_data<T>
        rectangle_data(T xl, T - yl, T xh, T yh)Constructs a rectangle with four - coordinates.
        template <typename T1, typename - T2>
        - rectangle_data
        (const T1& horizontal_interval,
        -               - const T2& vertical_interval)
        Constructs a rectangle with two objects - that model interval.
        rectangle_data(const - rectangle_data& that)Copy construct
        rectangle_data& operator=(const - rectangle_data& that)Assignment operator.
        template <typename T2> -
        rectangle_data& - operator=(const T2& that) const
        Assign from an object that is a model of rectangle.
        template <typename T2> -
        bool - operator==(const T2& that) const
        Compare equality to an object that is a model of rectangle.
        template <typename T2> -
        bool - operator!=(const T2& that) const
        Compare inequality to an object that is a model of rectangle.
        interval_data<T> get(orientation_2d - orient) constGet the interval in the given orientation.
        template <typename T2>
        - void set(orientation_2d orient, const T2& value)
        Sets the interval in the given orientation to the value of an object - that models interval.
        -
        -   - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Returns true is two objects that model rectangle +partially overlap such that one there is an intersection between the +edges of the two rectangles  If the consider_touch flag is true a +coordinate is considered contained even if the two rectangles touch +only along a side or corner.
        template +<typename T1, typename T2>
        +bool abuts(const T1& a, const T2& b,
        +           +direction_2d dir)
        Returns true if rectangle b abuts but down not overlap +rectangle a on the side of rectangle a specified by dir.
        template +<typename T1, typename T2>
        +bool abuts(const T1& a, const T2& b,
        +           +orientation_2d)
        Returns true if rectangle b abuts but down not overlap +rectangle a on either side of rectangle a specified by the +orientation_2d.
        template +<typename T1, typename T2>
        +bool abuts(const T1& a, const T2& b)
        Returns true if rectangle b abuts but down not overlap +rectangle a on any side.
        template +<typename T1, typename T2>
        +bool intersect(T1& a, const T2& b, orientation_2d
        +               +bool consider_touch = true)
        Sets rectangle a to the intersection of rectangle a and +interval b along the orientation_2d and returns true.  If the does +not intersect the interval, the rectangle is unchanged and the function +returns false.  If the flag consider_touch is true intervals that +abut are considered to intersect.
        template +<typename T1, typename T2>
        +bool intersect(T1& a, const T2& b,
        +               +bool consider_touch = true)
        Sets rectangle a to the intersection of rectangle a and +rectangle b and return true.  If the two rectangles do not +intersect rectangle a is unchanged and the function returns +false.  If the flag consider_touch is true rectangles that abut +are considered to intersect.
        template +<typename T1, typename T2>
        +T& generalized_intersect(T1& a, const T2& b)
        Same as intersect, but if they do not intersect set a +to the rectangle between a and b by applying generalized_intersect() on +the intervals of the rectangles.
        template +<typename T>
        +T& bloat(T& rectangle, coordinate_type)
        Bloats x and y intervals of rectangle by coordinate +value.
        template +<typename T>
        +T& bloat(T& rectangle, direction_2d, coordinate_type)
        Bloats side of rectangle specified by direction_2d by +coordinate value.
        template +<typename T>
        +T& bloat(T& rectangle, orientation_2d, coordinate_type)
        Bloats interval of rectangle specified by +orientation_2d by coordinate value.
        template +<typename T>
        +T& shrink(T& rectangle, coordinate_type)
        Shrinks x and y intervals of rectangle by coordinate +value.
        template +<typename T>
        +T& shrink(T& rectangle, direction_2d, coordinate_type)
        Shrinks side of rectangle specified by direction_2d by +coordinate value.
        template +<typename T>
        +T& shrink(T& rectangle, orientation_2d, coordinate_type)
        Shrinks interval of rectangle specified by +orientation_2d by coordinate value.
        template +<typename T1, typename T2>
        +bool encompass(T1& a, const T2& b)
        The x and y intervals of a are set to encompass the x +and y intervals of b respectively.
        template +<typename T, typename point_type>
        +bool encompass(T& rectangle, const point_type& point)
        The x and y intervals of rectangle are set to encompass +the x and y coordinates of point respectively.
        template +<typename T, typename interval_type>
        +bool encompass(T& rectangle, const interval_type& i,
        +               +orientation_2d)
        The interval of rectangle specified by orientation_2d +is set to encompass the interval i.
        template +<typename T, typename point_type>
        +bool get_corner(point_type& point, const T& +rectangle, 
        +                +direction_2d, direction_1d)
        Sets point to the corner of the rectangle you reach if +you look at its side specified by direction_2d from within the +rectangle and turn in the direction_1d direction (low == left, high = +right).  Always returns true.
        +

        Rectangle Data

        +

        +

        The library provides a model of rectangle concept declared + template<typename T> +rectangle_data where T is the coordinate type.

        +

        This data type is used internally when a rectangle is needed +and is available to the library user who finds it convenient to use a +library rectangle data type instead of providing their own.  The +data type is implemented to be convenient to use with the library +traits.

        +

        Members

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        geometry_typerectangle_concept
        coordinate_typeT
        interval_typeinterval_data<T>
        rectangle_data(T +xl, T yl, T xh, T yh)Constructs a rectangle +with four coordinates.
        template +<typename T1, typename T2>
        +rectangle_data
        (const T1& horizontal_interval,
        +               +const T2& vertical_interval)
        Constructs a rectangle +with two objects that model interval.
        rectangle_data(const +rectangle_data& that)Copy construct
        rectangle_data& + operator=(const rectangle_data& that)Assignment operator.
        template +<typename T2>
        +
        rectangle_data& operator=(const T2& +that) const
        Assign from an object that is a model of rectangle.
        template +<typename T2>
        +
        bool operator==(const T2& that) const
        Compare equality to an object that is a model of +rectangle.
        template +<typename T2>
        +
        bool operator!=(const T2& that) const
        Compare inequality to an object that is a model of +rectangle.
        interval_data<T> + get(orientation_2d orient) constGet the interval in the given orientation.
        template +<typename T2>
        +void set(orientation_2d orient, const T2& value)
        Sets the interval in the given orientation to the value +of an object that models interval.
        +
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        - \ No newline at end of file +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/gtl_segment_concept.htm b/doc/gtl_segment_concept.htm index 4dcff30..d026b2a 100644 --- a/doc/gtl_segment_concept.htm +++ b/doc/gtl_segment_concept.htm @@ -1,35 +1,28 @@ -Boost Polygon Library: Segment Concept - - - - - - - - - - - - - - - - - - - - - - - +--> + Boost Polygon Library: Segment Concept + + + + +
      - - - - +
      - + +
        @@ -91,9 +79,14 @@ Tutorial
      - +

      +

      Segment Concept

      @@ -102,13 +95,15 @@ Tutorial concept, specialize the geometry concept meta-function for that type.  In the example below CSegment is registered as a model of the segment concept.

      -

      template <>
      -struct geometry_concept<
      CSegment> -{ typedef segment_concept type; };

      +

      template +<>
      +struct geometry_concept<CSegment> +{ typedef segment_concept type; };

      The semantic of a segment is that it has a low and high point.  A std::pair<Point, Point>, -boost::tuple<Point, Point> or boost::array<Point, 2> could all be made models of +boost::tuple<Point, Point> or boost::array<Point, 2> could +all be made models of segment by simply providing indirect access to their elements through traits, however, these objects cannot be made a model of both segment and rectangle in the same compilation unit, for obvious reason that @@ -118,90 +113,155 @@ ambiguous if a type modeled more than one concept.

      Below is shown the default segment traits. Specialization of these traits is required for types that don't conform to the default behavior.

      - - -

      template <typename Segment>
      - struct segment_traits {
      -   typedef typename Segment::coordinate_type coordinate_type;
      -   typedef typename Segment::point_type point_type;
      +

      template +<typename Segment>
      + struct +segment_traits {
      +   +typedef typename Segment::coordinate_type coordinate_type;
      +   +typedef typename Segment::point_type point_type;

      -   static inline point_type get(const Segment& segment, direction_1d dir) {
      -     return segment.get(dir);
      -   }
      +   +static inline point_type get(const Segment& segment, direction_1d +dir) {
      +     +return segment.get(dir);
      +   }
      };
      -
      template <typename Segment>
      +
      + template +<typename Segment>
      struct segment_mutable_traits {
      -  typedef typename segment_traits<Segment>::point_type point_type;
      -
      -  static inline void set(Segment& segment, direction_1d dir, const point_type& point) {
      typedef typename +segment_traits<Segment>::coordinate_type coordinate_type;
      +   typedef +typename segment_traits<Segment>::point_type point_type;
      +
      +  static inline void set(Segment& segment, direction_1d dir, +const point_type& point) {
          segment.set(dir, p);
        }

      -  static inline Segment construct(const point_type& low, const point_type& high) {
      +  static inline Segment construct(const point_type& low, const +point_type& high) {
          return Segment(low, high);
        }
      -};

      Functions

      +};

      +

      Functions

      - + +<typename Segment, typename Point>
      +void set(
      Segment& segment, direction_1d dir,
      +         const Point&
      point) - - + - - + + - + - + +<typename Segment1, typename Segment1>
      +bool equivalence(const
      Segment1& segment1,
      +                 +const
      Segment1& segment2) - - + - - + - - - + - - - - + - - + - + - - + - - - - - - - - - - + +<typename Segment>
      +
      Segment& scale_down(Segment& segment,
      +    unsigned_area_type factor)
      + + + + +<typename Segment, typename Transform>
      +
      Segment& transform(Segment& segment, const Transform& tr) +on the low and high endpoints of an object that models segment and +updates the segment with the transformed endpoints. - - +<Segment, +Point>
      +
      Segment& convolve(Segment& segment, const Point& point) + - +<Segment, +Point>
      +
      Segment& deconvolve(Segment& segment, const Point& point) + - - + - - + + - - - - - - - - + + +to an object that models point. - - + + - - - -
      template -<typename Segment>
      point_type get(const Segment& segment, direction_1d dir)
      Returns the low or high endpoint of an object that models segment, depending on +<typename Segment>
      +point_type get(const Segment& segment, direction_1d dir)
      Returns the low or high endpoint of an object that +models segment, depending on the direction_1d value. 
      template -<typename Segment, typename Point>
      -void set(
      Segment& segment, direction_1d dir,
      -         const Point&
      point)
      Sets the low or high endpoint of an object that models segment to an object that models point, depending on the direction_1d value.
      template <typename Segment, typename Point1, typename Point2>
      +
      template +<typename Segment, typename Point1, typename Point2>
      Segment construct(const Point1& low, const Point2& high)
      Constructs an object that is a model of segment given the two objects that are models of point.Constructs an object that is a model of segment given +the two objects that are models of point.
      template <typename Segment1, typename Segment2>
      Segment1 copy_construct(const Segment2& segment)
      Copy constructs an object that models segment given another segment.template <typename +Segment1, typename Segment2>
      +
      Segment1 copy_construct(const + Segment2& segment)
      Copy constructs an object +that models segment given another segment.
      template -<typename Segment1, typename Segment2>
      - Segment1& assign(Segment1& segment1,
      -                 const
      Segment2& segment2)
      Copies data from the second object that models segment into +<typename Segment1, typename Segment2>
      + Segment1& assign(Segment1& segment1,
      +                 +const
      Segment2& segment2)
      Copies data from the second object that models segment +into the first object that models segment.
      template -<typename Segment1, typename Segment1>
      -bool equivalence(const
      Segment1& segment1,
      -                 const
      Segment1& segment2)
      Given two objects that model segment, compares and returns true if their low and high values are respectively equal.
      template <typename Segment, typename Point>
      - int orientation(const Segment& segment,
      -                 const Point& point)
      +
      template +<typename Segment, typename Point>
      + int + orientation(const Segment& segment,
      +                 +const Point& point)
      Implements a robust orientation test of two objects that model segment and point. Returns 0, if the point is collinear to the segment.
      Returns 1, if the point lies to the left of the segment.
      Returns -1, if the point lies to the right of the segment.
      -
      template <typename Segment1, typename Segment2>
      - - int orientation(const Segment1& segment1,
      - -                 const Segment2& segment2)
      template +<typename Segment1, typename Segment2>
      + int + orientation(const Segment1& segment1,
      +                 +const Segment2& segment2)
      Implements a robust orientation test of two objects that model segment. Note: segments are treated as math. vectors.
      @@ -210,174 +270,295 @@ Returns 1, if the second segment is CCW oriented to the first segment.
      Returns -1, if the second segment is CW oriented to the first segment.
      template <typename Segment, typename Point>
      - bool contains(const Segment& segment,
      -     const Point& value, bool consider_touch)
      +
      template +<typename Segment, typename Point>
      + bool + contains(const Segment& segment,
      +     +const Point& value, bool +consider_touch)
      Returns true if an object that models segment contains an object that models point, else false.
      +
      Returns true if an object that models segment contains +an object that models point, else false.
      template <typename Segment1, typename Segment2>
      - - bool contains(const Segment1& segment1,
      - -     const Segment2& segment2, bool consider_touch)
      Returns true if the first object contains the second one, else false. Both objects model segment.
      +
      template +<typename Segment1, typename Segment2>
      + bool + contains(const Segment1& segment1,
      +     +const Segment2& segment2, + bool +consider_touch)
      Returns true if the first object contains the second +one, else false. Both objects model segment.
      template <typename Segment>
      -point_type low(const Segment& segment)
      +
      template +<typename Segment>
      +point_type low(const Segment& +segment)
      Returns the low endpoint of an object that models segment.
      +
      Returns the low endpoint of an object that models +segment.
      template <typename Segment>
      -point_type high(const Segment& segment)
      Returns the high endpoint of an object that models segment.
      +
      template +<typename Segment>
      +point_type high(const Segment& +segment)
      Returns the high endpoint of an object that models +segment.
      template <typename Segment>
      -point_type center(const Segment& segment)
      Returns the central point of an object that models segment.
      +
      template +<typename Segment>
      +point_type center(const Segment& +segment)
      Returns the central point of an object that models +segment.
      template <typename Segment, typename Point>
      void low(Segment& segment, const Point& point)
      template +<typename Segment, +typename Point>
      +void low(Segment& +segment, const Point& point)
      Sets the low endpoint of an object that models segment.
      template <typename Segment, typename Point>
      -void high(Segment& segment, const Point& point)
      Sets the high endpoint of an object that models of segment.
      +
      template +<typename Segment, +typename Point>
      +void high(Segment& +segment, const Point& point)
      Sets the high endpoint of an object that models of +segment.
      template <typename Segment>
      - distance_type length(const Segment& segment)
      +
      template +<typename Segment>
      + distance_type + length(const Segment& segment)
      Returns length of an object that models segment.
      template -<typename Segment>
      Segment& scale_up(Segment& segment,
          unsigned_area_type factor)
      Multiplies x and y coordinates of both endpoints of an object that models segment by unsigned factor.
      template -<typename Segment>
      -
      Segment& scale_down(Segment& segment,
      +<typename
      Segment>
      +
      Segment& scale_up(Segment& segment,
          unsigned_area_type factor)
      Divides x and y coordinates of both endpoints of an object that models segment by unsigned factor.Multiplies x and y coordinates of both endpoints of an +object that models segment by unsigned factor.
      template -<typename Segment, typename Scale>
      -
      Segment& scale(Segment& segment, const Scale& sc)
      Divides x and y coordinates of both endpoints of an +object that models segment by unsigned factor.
      template +<typename Segment, typename Scale>
      +
      Segment& scale(Segment& segment, const Scale& sc)
      Calls -the scale member function of the scaling type on the low and high endpoint of +the scale member function of the scaling type on the low and high +endpoint of an object that models segment and updates the segment with the scaled endpoints.
      template -<typename Segment, typename Transform>
      Segment& transform(Segment& segment, const Transform& tr)
      Calls the transform member function of transform type -on the low and high endpoints of an object that models segment and updates the segment with the transformed endpoints.
      template -<typename Segment>
      -
      Segment& move(Segment& segment, orientation_2d
      +<typename
      Segment>
      +
      Segment& move(Segment& segment, orientation_2d
          coordinate_difference displacement)
      Adds displacement value to the x or y coordinates of both endpoints of an object + Adds displacement value to the x or y coordinates of +both endpoints of an object that models segment indicated by the orientation_2d.
      template -<Segment, Point>
      -
      Segment& convolve(Segment& segment, const Point& point)
      Convolves both endpoints of an object that models segment with an object that models a point.
      -
      Convolves both endpoints of an object that models +segment with an object that models a point.
      +
      template -<Segment, Point>
      -
      Segment& deconvolve(Segment& segment, const Point& point)
      Deconvolves both endpoints of an object that models segment with an object that models a point. Deconvolves both endpoints of an object that models +segment with an object that models a point.
      template <typename Segment1, typename Segment2>
      - - -bool abuts(const Segment1& segment1,
      - - +
      template +<typename Segment1, typename Segment2>
      +bool abuts(const Segment1& +segment1,
          const Segment2& segment2, direction_1d dir)
      Returns true if two objects that model segment abut, depending on the direction_1d value.Returns true if two objects that model segment abut, +depending on the direction_1d value.
      template <typename Segment1, typename Segment2>
      - -bool abuts(const Segment1& segment1,
      - -           const Segment2& segment2)
      Returns true if two objects that model segment abut: either the first one to the second one or vice versa.template +<typename Segment1, typename Segment2>
      +bool abuts(const Segment1& +segment1,
      +           const +Segment2& segment2)
      Returns true if two objects that model segment abut: +either the first one to the second one or vice versa.
      template <typename Segment1, typename Segment2>
      - bool intersects(const Segment1& segment1,
      -                 const Segment2& segment2,
      -                bool consider_touch)

      +
      template +<typename Segment1, typename Segment2>
      + bool + intersects(const +Segment1& segment1,
      +                 +const Segment2& segment2,
      +                +bool consider_touch)

      Returns true if two objects that model segment intersect, else false.
      +
      Returns true if two objects that model segment +intersect, else false.
      template -<typename Segment, typename Point>
      distance_type euclidean_distance(
      -    const
      Segment& segment, const Point& point) -
      template +<typename Segment, typename +Point>
      +distance_type euclidean_distance(
      +    const
      Segment& segment, const Point& point)
      Returns distance from an object that models segment -to an object that models point. -
      template -<typename Segment1, typename Segment2>
      distance_type euclidean_distance(
      -    const
      Segment1& segment1, const Segment2& segment2) -
      Returns distance between two objects that model segment. - template +<typename Segment1, typename Segment2>
      +distance_type euclidean_distance(
      +    const
      Segment1& segment1, const Segment2& +segment2)
      Returns distance between two objects that model +segment.

      Segment Data

      -

      The library provides a model of the segment concept declared template<typename T> segment_data, where +

      The library provides a model of the segment concept declared template<typename T> segment_data, +where T is the coordinate type.

      This data type is used internally when a segment is needed and is available to the library user, who finds it convenient to use a -library segment data type instead of providing their own.  The data -type is implemented to be convenient to use with the library traits.

      Members

      +library segment data type instead of providing their own.  The +data +type is implemented to be convenient to use with the library traits.

      +

      Members

      @@ -393,124 +574,152 @@ type is implemented to be convenient to use with the library traits.

      Memb

      - + - + - + - + - + - + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - +
      point_data<T>
      segment_data() Default constructor.
      segment_data(const point_type& low,
      -             const point_type& high)
      segment_data(const +point_type& low,
      +             +const point_type& high)
      Constructs a segment from the given endpoints.
      segment_data(const segment_data& that)segment_data(const +segment_data& that) Copy constructor.
      segment_data& operator=(const segment_data& that)segment_data& operator=(const +segment_data& that) Assignment operator.
      template <typename SegmentType>
      -
      segment_data& operator=(const
      SegmentType& that) + segment_data& operator=(const SegmentType& +that) const
      Assign from an object that is a model of segment.
      bool operator==(const segment_data& that) constbool operator==(const +segment_data& that) const Equality operator overload.
      bool operator!=(const segment_data& that) const bool +operator!=(const segment_data& that) const Inequality operator overload.
      bool operator<(const segment_data& that) constLess operator overload. Compares low endpoints then high endpoints to break ties.
      -
      bool +operator<(const segment_data& that) constLess operator overload. Compares low endpoints then +high endpoints to break ties.
      +
      bool operator<=(const segment_data& that) constLess or equal operator overload. Compares low endpoints then high endpoints to break ties.
      -
      bool +operator<=(const segment_data& that) constLess or equal operator overload. Compares low endpoints +then high endpoints to break ties.
      +
      bool operator>(const segment_data& that) constGreater operator overload. Compares low endpoints then high endpoints to break ties.
      -
      bool +operator>(const segment_data& that) constGreater operator overload. Compares low endpoints then +high endpoints to break ties.
      +
      bool operator>=(const segment_data& that) constGreater or equal operator overload. Compares low endpoints then high endpoints to break ties.
      -
      bool +operator>=(const segment_data& that) constGreater or equal operator overload. Compares low +endpoints then high endpoints to break ties.
      +
      point_type get(direction_1d dir) constRetrieves the low/high endpoint considering direction value.point_type get(direction_1d +dir) constRetrieves the low/high endpoint considering direction +value.
      point_type low() constpoint_type low() const Retrieves the low endpoint.
      point_type high() constpoint_type high() const Retrieves the high endpoint.
      void set(direction_1d dir, const point_type& point)void set(direction_1d dir, +const point_type& point) Sets the endpoint in the given direction.
      segment_data& low(const point_type& point)segment_data& low(const point_type& point) Sets the low endpoint.
      segment_data& high(const point_type& point)segment_data& high(const point_type& point) Sets the high endpoint.
      -

      Segment Utils

      -

      The library provides several algorithms for the manipulation of - sets of segment data. In particular, the generalize line segment - intersection algorithm used for polygon set operations is exposed - through several interfaces to allow it to be used with any - collection or sequence of objects that model the segment_concept. -

      Functions

      +

      The library provides several algorithms for the manipulation +of sets of segment data. In particular, the generalize line segment +intersection algorithm used for polygon set operations is exposed +through several interfaces to allow it to be used with any collection +or sequence of objects that model the segment_concept. +

      +

      Functions

      - - +    SegmentContainer* +result,
      +     SegmentIterator +first,
      +    SegmentIterator last)
      +type used by all the input structures should model segment +concept.Postconditions: no segments intersect except at their end +points. Useful to satisfy the precondition of voronoi diagram +construction. Expected n log n runtime, worst case quadratic runtime +wrt. vertices + intersections. - +     SegmentIterator first,
      +    SegmentIterator last
      ) - - - -
      template -<typename SegmentContainer,
      -          typename SegmentIterator
      >
      +<
      typename SegmentContainer,
      +          typename +SegmentIterator
      >
      void intersect_segments(
      -   
      SegmentContainer* result,
      - -    SegmentIterator first,
      -    SegmentIterator last) -
      Accumulates the result of splitting the segments in the iterator range at their intersection points into the result container. Preconditions: segment -type used by all the input structures should model segment concept.Postconditions: no segments intersect except at their end - points. Useful to satisfy the precondition of voronoi diagram - construction. - Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections. -
      template -<typename Segment,
      -         
      typename SegmentIterator>
      +<
      typename Segment,
      +         
      typename SegmentIterator>
      void intersect_segments(
      -   
      vector<pair<size_t, Segment>* result,
      - -    SegmentIterator first,
      +   
      vector<pair<size_t, +Segment>* result,
      +     SegmentIterator +first,
          SegmentIterator last)
      Accumulates the result of splitting the segments in the iterator range at their @@ -522,36 +731,36 @@ was split to produce it to associate the result segments with the inputs segments. Expected n log n runtime, worst case quadratic runtime wrt. vertices + intersections.
      template <typename Rectangle,
      -         
      typename SegmentIterator>
      +         
      typename SegmentIterator>
      void envelope_segments(
         
      Rectangle* rect,
      - -    SegmentIterator first,
          SegmentIterator last
      ) -
      Computes the bounding rectangle of the iterator range of line segments. Preconditions: segment type and rectangle type used by the input structures should model segment concept and rectangle concept respectively. Linear runtime.
      -
        +   - + @@ -559,7 +768,10 @@ respectively. Linear runtime. @@ -568,6 +780,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Intel Corporation 2008-2010.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - - + + diff --git a/doc/images/voronoi1.png b/doc/images/voronoi1.png new file mode 100644 index 0000000000000000000000000000000000000000..6a8a48ac545299fa8e255b9087e03e20ac8b02d1 GIT binary patch literal 19532 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 - + + Boost Polygon Library: Main Page - - - - - - - - - - - - - - - - - + + + + + + +
      -
      - - -
      -
      - -
        -
      • Boost.Polygon Main Page
      • -
      • Design Overview
      • -
      • Isotropy
      • -
      • Coordinate Concept
      • -
      • Interval Concept
      • -
      • Point Concept
      • +--> + Boost Polygon Library: Main Page + + + + + + + + - + - -
        + +
        + + - - -
        - -
        - - -
        -
        - - - -
        -

        -

        THE BOOST.POLYGON LIBRARY

        -

        The Boost.Polygon library provides algorithms focused on manipulating planar -polygon geometry data.  Specific algorithms provided are the polygon set -operations (intersection, union, difference, disjoint-union) and related -algorithms such as polygon connectivity graph extraction, offsetting and map-overlay.  -An example of the disjoint-union (XOR) of figure a and figure b is shown below -in figure c.  -These so-called Boolean algorithms are of significant interest in GIS (Geospatial Information -Systems), VLSI CAD as well all other fields of CAD, and many more application -areas, and providing them is the primary focus of this library.  The -Boost.Polygon library is not intended to cover all of computational -geometry in its scope, and provides a set of capabilities for working with -coordinates, points, intervals and rectangles that are needed to support -implementing and interacting with polygon data structures and algorithms. 

        -One of the important features of the library is the implementation of -the generic sweepline algorithm to construct Voronoi diagrams of points and linear segments in 2D (developed +

      • Voronoi Builder
      • +
      • Voronoi Diagram
      • + + + + + + +
        +
        +

        +

        +

        THE BOOST.POLYGON LIBRARY

        +

        The Boost.Polygon library provides algorithms focused on +manipulating planar polygon geometry data.  Specific algorithms +provided are the polygon set operations (intersection, union, +difference, disjoint-union) and related algorithms such as polygon +connectivity graph extraction, offsetting and map-overlay.  An +example of the disjoint-union (XOR) of figure a and figure b is shown +below in figure c.  These so-called Boolean algorithms are of +significant interest in GIS (Geospatial Information Systems), VLSI CAD +as well all other fields of CAD, and many more application areas, and +providing them is the primary focus of this library.  The +Boost.Polygon library is not intended to cover all of computational +geometry in its scope, and provides a set of capabilities for working +with coordinates, points, intervals and rectangles that are needed to +support implementing and interacting with polygon data structures and +algorithms. 

        + +

        One of the important features of the library is the +implementation of +the generic sweepline algorithm to construct Voronoi diagrams of points +and linear segments in 2D (developed as part of the GSoC 2010 program). Voronoi diagram data structure has applications in image segmentation, optical character recognition, -nearest neighbor queries execution. It is closely related with the other +nearest neighbor queries execution. It is closely related with the +other computational geometry concepts: Delaunay triangulation, medial axis, straight skeleton, the largest empty circle. The Boost.Polygon library provides interface to construct Voronoi diagram of points figure a and line segments figure b (the last could be used to discretize any -two-dimensional curve). Figure c contains the example of the medial axis of the -non-convex polygon. The implementation outperforms most of the known +two-dimensional curve). Figure c contains the example of the medial +axis of the +non-convex polygon. The implementation outperforms +most of the known commercial and non-commercial libraries in both efficiency and -numerical robustness aspects. You may find more details on the topic at the Voronoi main page.
        - -

        -

        -

        The coordinate data type is a template parameter of all data types +numerical robustness aspects. You may find more details on the topic at +the Voronoi main page.
        +

        +

        +

        The coordinate data type is a template parameter of all data +types and algorithms provided by the library, and is expected to be integral. Floating point coordinate data types are not supported by the algorithms implemented in the library due to the fact that the @@ -131,161 +135,161 @@ algorithms and generally platform specific assumptions about floating point representations.  For additional detailed discussion of the library and its implementation including benchmark comparisons with other open source -alternatives please see the paper and -presentation from -boostcon 2009 as well as a detailed -analysis of the runtime complexity of +alternatives please see the paper +and + presentation from + boostcon 2009 as well +as a detailed + analysis of the runtime complexity of the library's core algorithms.

        -

        The design philosophy behind the polygon library was to create an API for -invoking the library algorithms it provides on user geometry data types that is maximally -intuitive, minimally error-prone and easy to integrate into pre-existing -applications.  C++-concepts based template meta-programming combined with -generic operator overloading meets these design goals without sacrificing the -runtime or memory efficiency of the underlying algorithms.  The API is -intended to demonstrate what could be achieved with ease by a C++-concepts based -library interface, but is implemented based on current language features.  This API makes -the following code snippet that operates on non-library geometry types possible:

        - - -
        -
        - - - void foo(list<CPolygon>& result, const list<CPolygon>& a,
        -          - - - const list<CPolygon>& - b, int deflateValue) {
        -
        - -     - CBoundingBox domainExtent;
        -
        - - -      using namespace boost::polygon::operators;
        -
        - - -      - boost::polygon::extents(domainExtent, a);
        -
        - - -      result += (b & - domainExtent) ^ (a - deflateValue);
        -
        - - - }
        -
        -

        In the code snippet above the hypothetical polygon type CPolygon has been -mapped to the library polygon concept and is used with library APIs to clip -polygon list b against the bounding box of polygon list a and apply the -disjoint-union of that with polygon list a deflated by some integer amount.  -The end result is accumulated into a list of polygons with a union operation.  -It is considerably more typing to describe this usage of the API than to code -it, and the description is not much clearer than the code itself.  -A picture is worth a thousand words.

        -

        -

        In Boost.Polygon operations such as those shown above are free +

        The design philosophy behind the polygon library was to create +an API for invoking the library algorithms it provides on user geometry +data types that is maximally intuitive, minimally error-prone and easy +to integrate into pre-existing applications.  C++-concepts based +template meta-programming combined with generic operator overloading +meets these design goals without sacrificing the runtime or memory +efficiency of the underlying algorithms.  The API is intended to +demonstrate what could be achieved with ease by a C++-concepts based +library interface, but is implemented based on current language +features.  This API makes the following code snippet that operates +on non-library geometry types possible:

        + + +
        +
        void foo(list<CPolygon>& +result, const list<CPolygon>& a,
        +          + const +list<CPolygon>& b, int deflateValue) {
        +
             +CBoundingBox domainExtent;
        +
             +using namespace boost::polygon::operators;
        +
             +boost::polygon::extents(domainExtent, a);
        +
             + result += (b & domainExtent) ^ (a - deflateValue);
        +
        }
        +
        +

        In the code snippet above the hypothetical polygon type +CPolygon has been mapped to the library polygon concept and is used +with library APIs to clip polygon list b against the bounding +box of polygon list a and apply the disjoint-union of that with +polygon list a deflated by some integer amount.  The end +result is accumulated into a list of polygons with a union +operation.  It is considerably more typing to describe this usage +of the API than to code it, and the description is not much clearer +than the code itself.  A picture is worth a thousand words.

        +

        +

        In Boost.Polygon operations such as those shown above are free functions named for what they do, or are overloads of C++ operators that make it easy to infer from reading the code what to expect.  -Operators are contained in the namespace boost::polygon::operators -so that they can be used outside the boost::polygon -namespace without bringing in the entire boost::polygon -namespace.  Following the -principle of least astonishment, the inferred behavior should generally match -the actual behavior.  Conventions such as argument ordering (output -arguments come first) and consistently applying the same semantics across -different functions (accumulate) reduces the learning curve for new users while reducing the -need to memorize semantics and argument ordering of many different functions for -advanced users.

        -

        While the internal library code that implements this API is usually complex and -cryptic due to heavy use of template meta-programming, the application of the library -API in user code is usually simple and clear because it is free of any -extraneous syntax.  The one exception to this is the mapping of user types -to library concepts, which necessitates that the user perform some simple -template programming and understand some of the internals of how the library -concept type system works.  The examples below should aid the user in -performing these programming tasks.

        -
          - -
        • Example files: - - -
        • Tutorials: -
            -
          • Layout Versus Schematic Learn how to - apply Boost.Polygon capabilities to implement a simplified circuit - extraction application
          • -
          • Minkowski Sum Learn how to - apply Boost.Polygon capabilities to implement Minkowski sum of polygon sets
          • -
          • Voronoi Basic Tutorial Learn how - to construct, traverse, visualize, associate data with Voronoi diagrams without digging into the library details.
          • -
          • Voronoi Advanced Tutorial - Learn how to configure the Voronoi builder and Voronoi diagram - data structure with the user provided coordinate types.
          • -
          - -
        - - -

        We would like to thank: Thomas Klimpel, Frank Mori Hess, Barend Gehrels, -Andreas Fabri, Jeffrey Hellrung, Tim Keitt, Markus Werle, Paul A. Bristow, -Robert Stewart, Mathias Gaunard, Michael Fawcett, Steven Watanabe, Joachim -Faulhaber, John Bytheway, Sebastian Redl, Mika Heiskanen, John Phillips, Kai -Benndorf, Hartmut Kaiser, Arash Partow, Maurizio Vitale, Brandon Kohn, David -Abrahams, Gordon Woodhull, Daniel James, John Maddock, Tom Brinkman, Bo Persson, -Mateusz Loskot, Christian Henning, Jean-Sebastien Stoezel, for providing -feedback and or formal review of the library as part of the boost submission -process and Fernando Cacciola for graciously serving as review manager.

        - - -
        -   - - - - - - - - - - - - - - - -
        Copyright:Copyright © Intel Corporation 2008-2010.
        License:Distributed under the Boost Software License, - Version 1.0. (See accompanying file - LICENSE_1_0.txt or copy at - - http://www.boost.org/LICENSE_1_0.txt)
        - -
        \ No newline at end of file +Operators are contained in the namespace boost::polygon::operators +so that they can be used outside the boost::polygon +namespace without bringing in the entire boost::polygon +namespace.  Following the principle of least astonishment, the +inferred behavior should generally match the actual behavior.  +Conventions such as argument ordering (output arguments come first) and +consistently applying the same semantics across different functions +(accumulate) reduces the learning curve for new users while reducing +the need to memorize semantics and argument ordering of many different +functions for advanced users.

        +

        While the internal library code that implements this API is +usually complex and cryptic due to heavy use of template +meta-programming, the application of the library API in user code is +usually simple and clear because it is free of any extraneous +syntax.  The one exception to this is the mapping of user types to +library concepts, which necessitates that the user perform some simple +template programming and understand some of the internals of how the +library concept type system works.  The examples below should aid +the user in performing these programming tasks.

        +
          +
        • Example files: + +
        • +
        • Tutorials: +
            +
          • Layout Versus Schematic +Learn how to apply Boost.Polygon capabilities to implement a simplified +circuit extraction application
          • +
          • Minkowski Sum +Learn how to apply Boost.Polygon capabilities to implement Minkowski +sum of polygon sets
          • +
          • Voronoi Basic +Tutorial Learn how to construct, traverse, visualize, associate +data with Voronoi diagrams without digging into the library details.
          • +
          • Voronoi +Advanced Tutorial Learn how to configure the Voronoi builder and +Voronoi diagram data structure with the user provided coordinate types. +
          • +
          +
        • +
        +

        We would like to thank: Thomas Klimpel, Frank Mori Hess, +Barend Gehrels, Andreas Fabri, Jeffrey Hellrung, Tim Keitt, Markus +Werle, Paul A. Bristow, Robert Stewart, Mathias Gaunard, Michael +Fawcett, Steven Watanabe, Joachim Faulhaber, John Bytheway, Sebastian +Redl, Mika Heiskanen, John Phillips, Kai Benndorf, Hartmut Kaiser, +Arash Partow, Maurizio Vitale, Brandon Kohn, David Abrahams, Gordon +Woodhull, Daniel James, John Maddock, Tom Brinkman, Bo Persson, Mateusz +Loskot, Christian Henning, Jean-Sebastien Stoezel, for providing +feedback and or formal review of the library as part of the boost +submission process and Fernando Cacciola for graciously serving as +review manager.

        +
        + + + + + + + + + + + +
      Copyright:Copyright © Intel Corporation 2008-2010.
      License:Distributed under the Boost Software +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
      +
      + + diff --git a/doc/voronoi_benchmark.htm b/doc/voronoi_benchmark.htm index cb1aacc..3aedb0c 100644 --- a/doc/voronoi_benchmark.htm +++ b/doc/voronoi_benchmark.htm @@ -1,25 +1,22 @@ - - - - - - - - - - - + + - - - Voronoi Benchmark - - + + Voronoi Benchmark + + +
      - -
      - + + - +
      - +

      Voronoi Benchmark

      -There are not many known Voronoi libraries that are capable to satisfy the +There are not many known Voronoi libraries that are capable to satisfy +the following set of conditions:
      • could handle input data sets of points and segments
        -
      • +
      • give exact warranties about the algorithm robustness and output topology
      • -
      • compute coordinates of the output geometries within the fixed relative precision
        -
      • -
      Below is the list of libraries included in this benchmark sorted by the number of conditions each of them satisfies:
      -
        -
      • Boost.Polygon Voronoi - satisfies all the conditions above, implements sweep-line algorithm.
        +
      • compute coordinates of the output geometries within the +fixed relative precision
      • -
      • CGAL - satisfies the first two conditions, implements incremental algorithm. CGAL is a well-known +
      +Below is the list of libraries included in this benchmark sorted by the +number of conditions each of them satisfies:
      +
        +
      • Boost.Polygon Voronoi - satisfies all the conditions above, +implements sweep-line algorithm.
        +
      • +
      • CGAL - satisfies the first two conditions, implements +incremental algorithm. CGAL is a well-known library in the computational geometry area, especially for its robustness.
        -
      • +
      • S-Hull - doesn't satisfy any of the above conditions. S-Hull is a non-robust implementation of the sweep-hull algorithm used to construct Delaunay triangulation of a set of points.
      • -
      At the moment this benchmark includes only two robust implementations: + +At the moment this benchmark includes only two robust implementations: Boost.Polygon Voronoi and CGAL. Thus we are considering comparison of those two to be of the most interest.

      -Other libraries (OpenVoronoi, Triangle) would be added to this benchmark +Other libraries (OpenVoronoi, + Triangle) +would be added to this benchmark incrementally (we are open for suggestions).

      Important
      -

      While results of this benchmark show complete dominance of + +While results of this benchmark show complete dominance of the Boost.Polygon Voronoi over the CGAL Delaunay Graph implementation, we would like to make it clear that both libraries use different approach to construct Voronoi -diagram. Thus there are problems where the CGAL's incremental approach would +diagram. Thus there are problems where the CGAL's incremental approach +would be still more vital than the sweep-line algorithm (e.g. input sites are inserted as a live stream data).
      @@ -128,11 +134,15 @@ data).
      The benchmark consists of the two parts:
      -Below we list important benchmark details that should be considered while reviewing its results:
      +Below we list important benchmark details that should be considered +while reviewing its results:
      • We ensure that input data sets are the same for all libraries by initializing random generator with the same seed
      • @@ -142,11 +152,13 @@ don't contain intersections using Boost.Polygon functionality properly, thus those are eliminated before the algorithm execution explicitly (Boost.Polygon Voronoi and CGAL do that  implicitly)
        - -
      • There is no Voronoi diagram data structure in CGAL/S-Hull. That's why we use the segment Delaunay graph which is topologically +
      • There is no Voronoi diagram data structure in CGAL/S-Hull. +That's why we use the segment Delaunay graph which is topologically dual to the Voronoi diagram
      • -
      • CGAL's and S-Hull's output Delaunay triangulation doesn't contain information -about coordinates of the Voronoi vertices. We didn't include time to compute Voronoi vertices and memory +
      • CGAL's and S-Hull's output Delaunay triangulation doesn't +contain information +about coordinates of the Voronoi vertices. We didn't include time to +compute Voronoi vertices and memory storage required for those in this benchmark.
      • Both Boost.Polygon Voronoi and CGAL process each input @@ -155,10 +167,7 @@ as 3 input objects (segment itself and its endpoints), thus the running time and memory usage for Voronoi of segments would be at least 3 times slower than for Voronoi of points
      • - -
      - The benchmark was executed on the following two system configurations:

      Hardware: Intel i5-7600 2.8 GHz, 4GiB RAM.
      @@ -171,12 +180,16 @@ Libraries: Boost 1.48.0, CGAL-4.0, GMP 5.0.4, MPFR 3.1.0 + cumulative patch.

      Voronoi Benchmark Results

      Random Points Benchmark

      - +
      - - @@ -193,16 +206,18 @@ Win-32
      - - - + - - + - - + - - + - - + - - + - - +
      Test specification
      +
      Test specification
      Average construction + Average construction time (in secs)
      CGAL Win-32
      S-Hull Win-32
      +
      S-Hull +Win-32
      Boost + Boost Linux-64
      CGAL Linux-64
      -
      S-Hull Linux-64
      S-Hull +Linux-64
      +
      10
      @@ -215,12 +230,12 @@ Linux-64
      0.000043
      0.000013
      +
      0.000013
      0.000052
      -
      0.000012
      0.000012
      +
      100
      @@ -233,12 +248,12 @@ Linux-64
      0.000521
      0.000192
      +
      0.000192
       0.001150
      -
      0.000139
      0.000139
      +
      1000
      @@ -251,12 +266,12 @@ Linux-64
      0.007125
      0.002130
      +
      0.002130
      0.016680
      -
      0.002010
      0.002010
      +
      10000
      @@ -269,12 +284,12 @@ Linux-64
      0.091640
      0.022900
      +
      0.022900
      0.297900
      -
      0.028300
      0.028300
      +
      100000
      @@ -287,12 +302,12 @@ Linux-64
      1.218000
      0.274000
      +
      0.274000
      8.047000
      -
      0.432000
      0.432000
      +
      1000000
      @@ -305,45 +320,65 @@ Linux-64
      15.394000
      3.290000
      +
      3.290000
      315.740000
      -
      6.350000
      6.350000
      +

      - +
      - - + + - - + + - - + + - -

      +


      +

      Random Segments Benchmark

      - +
      - - @@ -453,24 +488,41 @@ Linux-64
      Test specification
      +
      Test specification
      Average construction + Average construction time (in secs)

      - +
      - - + + - - + + - - + + - - @@ -486,8 +538,8 @@ time it would take CGAL to compute coordinates of the Voronoi vertices. the Boost.Polygon Voronoi is faster than non-robust of S-Hull (except small input sets of around 100 points on Linux-64).
      - -
    10. Logarithmic execution time shows that Boost.Polygon Voronoi and S-Hull +
    11. Logarithmic execution time shows that Boost.Polygon Voronoi +and S-Hull have clear N*log(N) complexity, while this doesn't seem to be true for CGAL (at least for large input data sets).
    12. @@ -509,10 +561,14 @@ for those quantities. - - +

      +


      +

        +   - + @@ -520,7 +576,10 @@ for those quantities. @@ -529,6 +588,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Andrii Sydorchuk 2010-2012.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - - \ No newline at end of file + + diff --git a/doc/voronoi_builder.htm b/doc/voronoi_builder.htm index 94e0355..be80846 100644 --- a/doc/voronoi_builder.htm +++ b/doc/voronoi_builder.htm @@ -1,28 +1,22 @@ - - - - - - - - - - - - - - + + - - - Voronoi Builder - - + + Voronoi Builder + + +
      - - - - +
      - + + - +
      -

      Voronoi Builder
      -

      - -Voronoi builder is the event generator structure. It implements the sweepline -algorithm -that scans a 2D space and generates two types of events: -site events and circle events (we won't go into details what those are -exactly). Each event is reported to the output data structure builder. -The structure shares Voronoi name as the events generated by it -correspond to the Voronoi diagram edges and vertices, thus giving +

      +

      Voronoi Builder

      +The Voronoi builder is the event generator structure, that implements +the sweepline +algorithm, +scanning 2D space and spawning the two types of events: site +events and circle events. Each event is reported to the output data +structure builder. +The structure shares Voronoi name, as the events generated by it +provide enough information to construct the Voronoi diagram of a set of points -and linear segments. The requirements for the input/output -coordinate type of -the builder geometries are not the same as for the rest of the -Boost.Polygon library. The main differences are in the following:
      +and linear segments. The requirements for the coordinate type of +the input/output geometries, configured through the coordinate type +traits template argument, are the following:
        -
      • The input coordinate type is not required to be integral (while it +
      • The input coordinate type (for input points and enpoints of +the input segments) is not required to be integral +(while it still should be an integer type)
      • The output coordinate type (for Voronoi vertices) is required to be IEEE-754 floating point type

      Important

      - - -We encourage users to use default static methods defined in the voronoi.hpp -header to construct Voronoi diagram, however it's always possible to +The users are encouraged to use the default static methods defined in +the voronoi.hpp +header for the Voronoi diagram construction. However it's also possible +to use Voronoi builder explicitly, especially if the user wants to drop -the external dependencies such as MPL (metaprogramming library). So the -following include set woudn't depend on any heavy external headers (except STL and boost/cstdint.hpp), even -Boost.Polygon itself:
      - +the external dependencies such as MPL (metaprogramming library). The +following include set doesn't depend on any external headers +(except STL and boost/cstdint.hpp), even +the Boost.Polygon library:

      - - #include <voronoi_builder.hpp>
      - - #include <voronoi_diagram.hpp>
      + #include +<voronoi_builder.hpp>
      + #include +<voronoi_diagram.hpp>
      +

      Declaration

      +Header: boost/polygon/voronoi_builder.hpp

      -
      This -also gives a way to build Voronoi construction API on top of the -Voronoi builder data structure for the other Boost libraries.
      -

      Declaration
      -

      - - - - - template -<typename T,
      + template +<typename T,
                -typename CTT = detail::voronoi_ctype_traits<T>,
      +typename CTT = detail::voronoi_ctype_traits<T>,
                -typename VP = detail::voronoi_predicates<CTT> >
      +typename VP = detail::voronoi_predicates<CTT> >
      class voronoi_builder;

      T
      - specifies the coordinate type of the input geometries (points and segments).
      - - CTT -- defines input/output coordinate type traits used by Voronoi predicates (VP).
      - - VP -- predicate kernel, that provides builder with robust and + CTT +- defines the input/output coordinate type traits used by the Voronoi +predicates (VP).
      + VP +- the predicate kernel, that contains robust and efficient predicates and functors.
      - The Voronoi builder data structure is ready to use from the box with 32-bit signed integer input coordinate type. The user may extend the input coordinate range to the other integer types (e.g. 64-bit -integer), however this will also require manual set up of the -coordinate type traits. Default voronoi_predicates<CTT> -structure provides correct and efficient predicates as soon as types defined by CTT -satisfy the requirements explained at the end of this page. In case those -requirements are not satisfied for the user provided coordinate type traits, -the proper predicates kernel -implementation is required.
      -

      Member Functions

      - +integer), however this will also require manual setup of the +coordinate type traits. Default predicate kernel provides correct and +efficient predicates as long as types +defined by the coordinate type traits satisfy the requirements +explained at the end of this page. In case +those +requirements are not satisfied, +the proper predicate kernel +implementation is required.
      +

      Member Functions

      +
      - + - +const int_type& y) +Returns index of the inserted point. - - - +const int_type& y2) - - - - - - - - +Returns index of the inserted segment. - + + + + +list of the inserted geometries. Sets the input geometry index to +zero.
      -voronoi_builder()voronoi_builder() Default constructor.
      size_t insert_point(const int_type& x,
      +
      size_t insert_point(const int_type& x,
                          -const int_type& y)

      -
      Inserts a point object with the specified coordinates into the Voronoi builder.
      -Returns index number of the inserted site.
      - -
      size_t insert_segment(const int_type& x1,
                            -const int_type& y1,
                            +
      size_t insert_segment(const int_type& +x1,
      +                      +const int_type& y1,
      +                      const int_type& x2,
                            -const int_type& y2)

      -
      Inserts a segment object with the specified coordinates into the Voronoi builder.
      -Returns index number of the inserted site.
      - -
      -template <typename OUTPUT>
      -void construct(OUTPUT* output)
      -
      Runs sweepline -algorithm over the set of the inserted geometries, outputs site and -circle events to the OUTPUT data structure. It's responsibility of the -output data structure to process them.
      -
      -void clear()
      +
      template +<typename OUTPUT>
      +void construct(OUTPUT* output)
      Runs the sweepline +algorithm over the set of inserted geometries and generates site and +circle events to the OUTPUT data structure. It's the responsibility of +the +output data structure to process them.
      void + clear() Clears the -list of the inserted geometries. Sets index counter to zero.
      -

      Voronoi Coordinate Type Traits

      - - -

      The library provides the default coordinate type traits specialization for the +

      The library provides the default coordinate type traits +specialization for the 32-bit signed integer type:

      - - +

      template <typename T>
      struct voronoi_ctype_traits;

      @@ -246,136 +234,135 @@ efpt_type;
          typedef type_converter_fpt to_fpt_converter_type;
          typedef type_converter_efpt to_efpt_converter_type;
      };

      -
      - One +
      One of the most important features of the library is that Voronoi builder output geometries are constructed within defined relative error (64 -machine epsilons). That means the more mantissa bits the user provided -fpt_type has the better precision of the output geometries will be. In +machine epsilons). That means, the more mantissa bits the user provided +fpt_type has, the better precision of the output geometries will be. In order for the user defined traits to be consistent with the default -Voronoi builder predicates user should define following set of -coordinate types (the assumption is made that input geometries have +Voronoi builder predicate kernel user should define the following set +of traits (the assumption is made that input geometries have X-bit signed integer coordinate type):

      - +
      - +integer type. - +integer type. - +integer type. - +integer type if input dataset contains only points.
      +At least 64X-bit signed integer type if input dataset contains +segments. - +32X-bit unsigned integer type. - +64X-bit unsigned integer type. - - +(relative error range). - - +fpt_type using operator(). - - +operator().
      int_type
      +
      int_type At least X-bit signed -integer type.
      -
      -int_x2_type
      +
      int_x2_type At least 2X-bit signed -integer type.
      -
      -uint_x2_type
      +
      uint_x2_type At least 2X-bit unsigned -integer type.
      -
      -big_int_type
      +
      big_int_type At least 8X-bit signed -integer type for voronoi of points.
      -At least 64X-bit signed integer type for voronoi of segments.
      -
      -fpt_type
      +
      fpt_type IEEE-754 floating point type, with mantissa at least (X+16) bits and exponent able to handle -32X-bit unsigned integer type.
      -
      -efpt_type
      +
      efpt_type IEEE-754 floating point type, with mantissa at least (X+16) bits and exponent able to handle -64X-bit unsigned integer type.
      -
      -ulp_cmp_type
      +
      ulp_cmp_type Ulp comparison structure + Ulp comparison structure, that checks if two fpt_type values are within the given ulp range -(relative error range).
      -
      -to_fpt_converter_type
      +
      to_fpt_converter_type Type converter structure + Type converter structure, that converts any of the integer types above plus efpt_type to the -fpt_type using operator().
      -
      -to_efpt_converter_type
      +
      to_efpt_converter_type Type converter structure + Type converter structure, that converts any of the integer types above to the efpt_type using -operator().
      -
      -

      Notes:

      +

      Notes:

        -
      • -Four different integer types are used (instead of a single +
      • Four different integer types are used (instead of a single big_int_type) to slightly improve algorithm performance and memory usage.
      • -
      • As the maximum required size of the big_int_type is known in advance -(based on the size of the integer type), library provided -implementation of a fixed integer could be used (it is much faster than -heap-allocated big integers).
      • -
      • -Two separate floating-point types are defined because for the input +
      • As the maximum required size of the big_int_type is known +in advance, it's possible to use fixed, stack allocated, multiprecision +integer type.
      • +
      • Two separate floating-point types are defined, because for +the input geometries with -32-bit signed integer coordinates double won't be able to handle -2048-bit (64 * 32) integers as they will overflow its exponent. On the +32-bit signed integer coordinates, double type won't be able to handle +2048-bit (64 chunks of 32 bits each) integers, as they will +overflow its exponent. On the gcc compiler it's possible to use 80-bit long doubles for both fpt -types, however this is not supported by MSVC compiler.
      • -
      • efpt_type and to_efpt_converter_type are not used to construct Voronoi diagram of points (mocks will work fine).
      • -
      • -For an example of the user defined coordinate type traits -see advanced Voronoi tutorial.
      • +types, however this is not supported by the MSVC compiler. +
      • efpt_type and to_efpt_converter_type are not used to +construct the Voronoi diagram of a set of points (mock implementation +will work).
      • +
      • For an example of the user defined coordinate type traits +check the advanced Voronoi +tutorial.
      -
        +   - + - + @@ -384,6 +371,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.Copyright © Andrii Sydorchuk 2010-2013.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - - + + diff --git a/doc/voronoi_diagram.htm b/doc/voronoi_diagram.htm index e344da6..0913e23 100644 --- a/doc/voronoi_diagram.htm +++ b/doc/voronoi_diagram.htm @@ -1,36 +1,24 @@ - - - - - - - - - - - - - - + + - - - Voronoi Diagram - - - - + + Voronoi Diagram - - - - - + + + +
      - - - - +
      - + + - +
      - +

      Voronoi Diagram

      -Voronoi +A Voronoi diagram is the computational geometry concept that represents partition -of the given space onto regions, with bounds determined by distances to a -specified family of objects. The application area of this concept vary from -Archaeology to Zoology. The Boost.Polygon library provides implementation of -the Voronoi diagram data structure in 2D space. The internal representation +of the given space onto regions, with bounds determined by distances to +a +specified family of objects. The application area of this concept +varies from +Archaeology to Zoology. The Boost.Polygon Voronoi extension +provides +implementation of +the Voronoi diagram data structure in the 2D space. The internal +representation consists of the three arrays, that respectively contain: Voronoi cells -(represent the area around the input sites bounded by the Voronoi edges), Voronoi vertices +(represent the area around the input sites bounded by the Voronoi +edges), Voronoi vertices (points where three or more Voronoi edges intersect), Voronoi edges -(the one dimensional curves containing points equidistant from the two +(one dimensional curves containing points equidistant from the two closest input sites). Each of the primitives (cell, vertex, edge) contains pointers to the other linked primitives, so that it's always -possible to efficiently traverse Voronoi graph. The picture below shows +possible to efficiently traverse the Voronoi graph. The picture below +shows the Voronoi vertices in red, Voronoi edges in black, input sites that -correspond to the Voronoi cells in blue. It is considered that each +correspond to the Voronoi cells in blue. It is considered, that each input segment consists of the three sites: segment itself and its -endpoints. As the result two additional -Voronoi edges are constructed per each input segment. This is made to -simplify the representation of the Voronoi diagram.
      +endpoints. As the result, two additional Voronoi edges are constructed +per each input segment. This is made to +simplify the representation of the Voronoi diagram and Voronoi edges in +particular.

      - - -
      -

      Important

      All +
      +

      Important

      +All the Voronoi primitive data structures (edge, vertex, cell) contain mutable color member. Color type is equivalent to the std::size_t type, except that the upper five bits are reserved for the internal usage. -That would mean that the maximum supported value by color member is 32 +That means, that the maximum supported value by the color member is 32 times less than the one supported by std::size_t.
      -

      Declaration
      -

      - - - - - +

      Declaration

      +Header: boost/polygon/voronoi_diagram.hpp
      +
      template -<typename T, typename TRAITS = voronoi_diagram_traits<T> >
      +<typename T, typename TRAITS = voronoi_diagram_traits<T> >
      class voronoi_diagram;
      -
      -
      T -- specifies the coordinate type of the Voronoi vertices.
      - TRAITS -- Voronoi diagram traits (explained in the end of this chapter).
      +
      +T
      +- the coordinate type of the Voronoi vertices.
      + TRAITS +- the Voronoi diagram traits.

      Member Functions

      - - - - - + +
      - - + + - + clear() + +cell_container_type& cells() +const +reference to the cell container. +vertex_container_type& vertices() +const +reference to the vertex container. +edge_container_type& edges() +const +reference to the edge container. - - + + - + +Voronoi edges (half-edges) in the Voronoi diagram. - + +Voronoi vertices in the Voronoi diagram.
      voronoi_diagram()
      -
      Default constructor.
      -
      voronoi_diagram() Default constructor.
      void - clear()
      -
      Clears diagram.
      -
      Removes all primitives from the Voronoi diagram.
      const -cell_container_type& cells() const
      -
      Returns the const -reference to the cell container.
      -
      const -vertex_container_type& vertices() const
      -
      Returns the const -reference to the vertex container.
      -
      const -edge_container_type& edges() const
      -
      Returns the const -reference to the edge container.
      -
      size_t num_cells() const
      -
      Returns the number of the -cells in the Voronoi diagram.
      -This value should be the same as the size of the cell container.
      -
      size_t + num_cells() const Returns the number of the Voronoi +cells in the Voronoi diagram.
      size_t num_edges() const
      -
      size_t + num_edges() const Returns the number of the -edges (half-edges) in the Voronoi diagram.
      This value should be the same as the size of the edge container.
      -
      size_t num_vertices() const
      -
      size_t + num_vertices() +const Returns the number of the -vertices in the Voronoi diagram.
      -This value should be the same as the size of the vertex container.
      -
      -

      Member Types

      - +
      - - - - - - - + + - - + + - - + + - - - - - - - + + - - - - - - - + + - - + + - - - + + + + + + + + + + + + + +
      coordinate_type
      -
      Coordinate type.
      -
      cell_type
      -
      Voronoi cell.
      -
      coordinate_type Coordinate type.
      vertex_type
      -
      Voronoi vertex.
      -
      cell_type Voronoi cell.
      edge_type
      -
      Voronoi edge.
      -
      vertex_type Voronoi vertex.
      cell_container_type
      -
      Container of Voronoi cells.
      -
      const_cell_iterator
      -
      Const cell container iterator.
      -
      edge_type Voronoi edge.
      vertex_container_type
      -
      Container of Voronoi vertices.
      -
      const_vertex_iterator
      -
      Const vertex container iterator.
      -
      cell_container_type Container of the Voronoi cells.
      edge_container_type
      -
      Container of Voronoi edges.
      -
      const_cell_iterator Const cell container iterator.
      const_edge_iterator
      -
      Const edge container iterator.
      -
      vertex_container_type Container of the Voronoi vertices.
      const_vertex_iterator Const vertex container iterator.
      edge_container_type Container of the Voronoi edges.
      const_edge_iterator Const edge container iterator.
      - - - -

      Voronoi Geometry Type
      -

      -

      GeometryCategory
      -

      -Defines geometry type of the input objects.
      +

      Voronoi Geometry Type

      +The Voronoi +diagram data structure doesn't embed coordinates of the input +geometries. +Instead it links with those via source index and source category +methods +of the Voronoi cell primitive. Source index is incrementally given +(starting from zero) to each input site inserted into the Voronoi +builder. +Considering the fact, that each input segment is splitted onto three +separate sites with the same index, we distinguish between those using +source category. For more examples check the Voronoi basic tutorial.
      +

      GeometryCategory

      +Defines geometric category of the input object.
      +Header: boost/polygon/voronoi_geometry_type.hpp

      - enum GeometryCategory {
      -   GEOMETRY_CATEGORY_POINT = 0x0,
      -   GEOMETRY_CATEGORY_SEGMENT = 0x1
      + enum +GeometryCategory {
      +   +GEOMETRY_CATEGORY_POINT = 0x0,
      +   +GEOMETRY_CATEGORY_SEGMENT = 0x1
      };

      SourceCategory

      - -Defines category of the input site that forms Voronoi cell.
      +Defines semantic category of the input site.
      +Header: boost/polygon/voronoi_geometry_type.hpp

      - enum SourceCategory {
      -   // Point subtypes.
      -   SOURCE_CATEGORY_SINGLE_POINT = 0x0,
      -   SOURCE_CATEGORY_SEGMENT_START_POINT = 0x1,
      -   SOURCE_CATEGORY_SEGMENT_END_POINT = 0x2,
      + enum +SourceCategory {
      +   +// Point subtypes.
      +   +SOURCE_CATEGORY_SINGLE_POINT = 0x0,
      +   +SOURCE_CATEGORY_SEGMENT_START_POINT = 0x1,
      +   +SOURCE_CATEGORY_SEGMENT_END_POINT = 0x2,

      -   // Segment subtypes.
      -   SOURCE_CATEGORY_INITIAL_SEGMENT = 0x8,
      -   SOURCE_CATEGORY_REVERSE_SEGMENT = 0x9,
      +   +// Segment subtypes.
      +   +SOURCE_CATEGORY_INITIAL_SEGMENT = 0x8,
      +   +SOURCE_CATEGORY_REVERSE_SEGMENT = 0x9,

      -   SOURCE_CATEGORY_GEOMETRY_SHIFT = 0x3,
      -   SOURCE_CATEGORY_BITMASK = 0x1F
      +   +SOURCE_CATEGORY_GEOMETRY_SHIFT = 0x3,
      +   +SOURCE_CATEGORY_BITMASK = 0x1F
      };
      -
      -Voronoi -diagram data structure doesn't store coordinates of the input -geometries. -Instead it links with those via source index and source category method -of the Voronoi cell primitive. Source index is incrementally given -(starting from zero) to each input site inserted into Voronoi builder. -Considering the fact that each input segment is splitted onto three -separate sites with the same index, we distinguish between them using -SourceCategory. For the example see Voronoi basic tutorial.

      Member Functions

      - +
      - - + +
      bool belongs(
      -     SourceCategory source_category,
      -     GeometryCategory geometry_category)
      -
      Returns true if source category belongs to the given geometry category.
      -Returns false else.
      -
      bool belongs(
      +   +  SourceCategory source_category,
      +     +GeometryCategory geometry_category)
      Returns true if the +given source +category belongs to the given geometry category.
      +Returns false otherwise.

      Voronoi Edge

      - - -Voronoi edge is represented as enhanced classical half-edge -data structure.
      +A Voronoi edge is a one-dimenstion curve, that contains points +equidistant from the two closest input geometries. The Voronoi edge +data structure is implemented as the enhanced classical half-edge +data structure. On the image below, the Voronoi edges are drawn as +directed linear (e.g. AE) or curved (e.g. DE) dashed lines of either +green (e.g. AE) or black (e.g DE) color. The green edges are considered +to be secondary, as they are generated by an input segment and its +endpoint (e.g. edge EA, made by segment MN and its endpoint M). All the +other edges are considered to be primary (e.g. curved edge CD, made by +segment KL and point N). Apart from that, each edge can be finite (e.g. +ED) or infinite (e.g. edge starting at point B and going in the east +direction).
      +
      +Each Voronoi edge (consider directed edge BA) provides efficient access +to the following primitives:
      +
        +
      • Cell the edge belongs to (Voronoi cell P, with source +segment MN)
      • +
      • Start point of the edge (Voronoi vertex B, that is +equidistant from the following input sites: O, L, MN)
      • +
      • End point of the edge (Voronoi vertex A, that is +equidistant from the following input sites: O, M, MN)
      • +
      • Twin edge (Voronoi edge AB)
      • +
      • CCW next edge inside the Voronoi cell, that the edge +belongs to (green Voronoi edge AE)
      • +
      • CCW previous edge inside the Voronoi cell, that the edge +belongs to (Voronoi edge CB)
      • +
      • CCW rotated next edge around the start point of the edge +(Voronoi edge BC)
      • +
      • CCW rotated previous edge around the start point of the +edge (infinite Voronoi edge starting at the Voronoi vertex B and going +in the east direction)
      • +

      Declaration

      - - - +Header: boost/polygon/voronoi_diagram.hpp
      +
      template -<typename T>
      +<typename T>
      class voronoi_edge;

      T
      - coordinate type.

      Member Functions

      - - - - - + +
      - - - + + - - + + +that the edge belongs to. +voronoi_cell_type* cell() +const +to the Voronoi cell that the edge belongs to. + cell(voronoi_cell_type* +c) +pointer to the cell the current edge belongs to. - + +If the edge is infinite in that direction returns NULL. +voronoi_vertex_type* vertex0() +const +to the start point vertex of the edge.
      +If the edge is infinite in that direction returns NULL. + vertex0(voronoi_vertex_type* +v) +pointer of the edge. - + +If the edge is infinite in that direction returns NULL. +voronoi_vertex_type* vertex1() +const +If the edge is infinite in that direction returns NULL. - - + +twin edge. +voronoi_edge_type* twin() +const +to the twin edge. + twin(voronoi_edge_type* +e) +of the edge. - + +Edges not necessarily share a common vertex (e.g. infinite edges). +voronoi_edge_type* next() +const +Edges not necessarily share a common vertex (e.g. infinite edges). + next(voronoi_edge_type* +e) +pointer of the edge. - + +Edges not necessarily share a common vertex (e.g. infinite edges). +voronoi_edge_type* prev() +const +Edges not necessarily share a common vertex (e.g. infinite edges). + prev(voronoi_edge_type* +e) +pointer of the edge. - - + + - + +Allows to associate the user provided data with the primitive. - + +CCW next edge rotated around the edge start point.
      +Works for infinite edges as well. +voronoi_edge_type* rot_next() +const +to the CCW next edge rotated around the edge start point.
      +Works for infinite edges as well. - + +CCW prev edge rotated around the edge start point.
      +Works for infinite edges as well. +voronoi_edge_type* rot_prev() +const +to the CCW prev edge rotated around the edge start point.
      +Works for infinite edges as well. + is_finite() const +end points of the edge are finite, else false. - + + is_linear() const +is linear (segment, ray, line), else false. + is_curved() const +is curved (parabolic arc), else false. + is_primary() const - +goes through the endpoint of the segment site, else true. + + -
      voronoi_edge(bool is_linear, bool is_primary)
      -
      Voronoi edge constructor.
      -
      voronoi_edge(bool is_linear, bool +is_primary) Voronoi edge constructor.
      voronoi_cell_type* cell()
      -
      voronoi_cell_type* + cell() Returns the pointer to the Voronoi cell -that edge belongs to.
      -
      const -voronoi_cell_type* cell() const
      -
      Returns the const pointer -to the Voronoi cell that edge belongs to.
      -
      void - cell(voronoi_cell_type* c)
      -
      Sets the Voronoi cell -pointer for the cell current edge belongs to.
      -
      voronoi_vertex_type* vertex0()
      -
      voronoi_vertex_type* + vertex0() Returns the pointer to the start point of the edge.
      -If the edge is infinite in that direction returns NULL.
      -
      const -voronoi_vertex_type* vertex0() const
      -
      Returns the const pointer -to the point vertex of the edge.
      -If the edge is infinite in that direction returns NULL.
      -
      void - vertex0(voronoi_vertex_type* v)
      -
      Sets the start point -pointer of the edge.
      -
      voronoi_vertex_type* vertex1()
      -
      voronoi_vertex_type* + vertex1() Returns the pointer to the end point of the edge.
      -If the edge is infinite in that direction returns NULL.
      -
      const -voronoi_vertex_type* vertex1() const
      -
      Returns the const pointer to the end point of the edge.
      -If the edge is infinite in that direction returns NULL.
      -
      voronoi_edge_type* twin()
      -
      voronoi_edge_type* + twin() Returns the pointer to the -twin edge.
      -
      const -voronoi_edge_type* twin() const
      -
      Returns the const pointer -to the twin edge.
      -
      void - twin(voronoi_edge_type* e)
      -
      Sets the twin edge pointer -of the edge.
      -
      voronoi_edge_type* next()
      -
      voronoi_edge_type* + next() Returns the pointer to the CCW next edge within the corresponding Voronoi cell.
      -Edges not necessarily share a common vertex (e.g. infinite edges).
      -
      const -voronoi_edge_type* next() const
      -
      Returns the const pointer to the CCW next edge within the corresponding Voronoi cell.
      -Edges not necessarily share a common vertex (e.g. infinite edges).
      -
      void - next(voronoi_edge_type* e)
      -
      Sets the CCW next edge -pointer of the edge.
      -
      voronoi_edge_type* prev()
      -
      voronoi_edge_type* + prev() Returns the pointer to the CCW prev edge within the corresponding Voronoi cell.
      -Edges not necessarily share a common vertex (e.g. infinite edges).
      -
      const -voronoi_edge_type* prev() const
      -
      Returns the const pointer to the CCW prev edge within the corresponding Voronoi cell.
      -Edges not necessarily share a common vertex (e.g. infinite edges).
      -
      void - prev(voronoi_edge_type* e)
      -
      Sets the CCW prev edge -pointer of the edge.
      -
      color_type color() const
      -
      Returns the color value.
      -
      color_type + color() const Returns the color value.
      void color(color_type color) const
      -
      void + color(color_type +color) const Sets the color of the edge.
      -Allows to execute graph algorithms and associate data.
      -
      voronoi_edge_type* rot_next()
      -
      voronoi_edge_type* + rot_next() Returns the pointer to the -CCW next edge rotated around the edge start point.
      Works for infinite - edges as well.
      -
      const -voronoi_edge_type* rot_next() const
      -
      Returns the const pointer -to the CCW next edge rotated around the edge start point.
      Works for infinite edges as well.
      voronoi_edge_type* rot_prev()
      -
      voronoi_edge_type* + rot_prev() Returns the pointer to the -CCW prev edge rotated around the edge start point.
      Works for infinite edges as well.
      -
      const -voronoi_edge_type* rot_prev() const
      -
      Returns the const pointer -to the CCW prev edge rotated around the edge start point.
      Works for infinite edges as well.
      bool - is_finite() const
      -
      Returns true if the both -end points of the edge are finite, else false.
      -
      bool @@ -560,427 +561,436 @@ end points of the edge are finite, else false.
      Returns true if one of the end points of the edge is infinite, else false.
      bool - is_linear() const
      -
      Returns true if the edge -is linear (segment, ray, line), else false.
      -
      bool - is_curved() const
      -
      Returns true if the edge -is curved (parabolic arc), else false.
      -
      bool - is_primary() const
      -
      Returns false if the edge -goes through the endpoint of the segment site, else true.
      -
      bool is_secondary() const Returns true if the edge goes through the endpoint of the segment site, else false.
      -
      -
      All + All the above methods have O(1) complexity. The size of -the Voronoi edge structure is equal to: 5 * sizeof(void *) + sizeof(size_t).
      +the Voronoi edge structure is equal to: 5 * sizeof(void *) + +sizeof(size_t).

      Member Types

      - - +
      - - + + - - + + - - + + - - - - - + + + + + + -
      coordinate_type
      -
      Coordinate type.
      -
      coordinate_type Coordinate type.
      voronoi_cell_type
      -
      Voronoi cell type.
      -
      voronoi_cell_type Voronoi cell type.
      voronoi_vertex_type
      -
      Voronoi vertex type.
      -
      voronoi_vertex_type Voronoi vertex type.
      voronoi_edge_type
      -
      Voronoi edge type.
      -
      color_type
      -
      Color type (check the Important section).
      -
      voronoi_edge_type Voronoi edge type.
      color_type + Color type (check the +Important section).

      Voronoi Cell

      - -Voronoi cell is represented by a site the cell contains and a pointer -to the incident edge.
      +A Voronoi cell represents a region of the Voronoi diagram bounded by +the Voronoi edges. On the image below, there are 7 such regions: P, Q, +R, S, T, U, V. Each Voronoi cell can contain a point (e.g. cells Q, S, +T, U, V with corresponding input sources N, K, L, O, M respectively) or +a segment +(e.g. cells P and R with corresponding input sources MN and KL +respectively) as its +source. The Voronoi cell primitive doesn't contain coordinates of the +source geometry, instead it stores the index and category of the source +geometry. Source index corresponds to the unique id, issued to each +input geometry (e.g. incremental counter, used by the Voronoi builder). +Such an index uniquely identifies any input point (e.g. O), however +doesn't make any distinction between segment (e.g. MN) and both its end +points (e.g. M, N). In order to resolve possible ambiguity, the source +category is used, that specifies the semantic topology of the input +object (e.g. segment's startpoint, segment's endpoint or segment +itself). The Voronoi cell data structure also provides access to a +random Voronoi edge, located on the boundary of the cell (e.g. edge AE +for +the cell P).
      +

      Declaration

      - - - +Header: boost/polygon/voronoi_diagram.hpp
      +
      template <typename T>
      class voronoi_cell;

      -
      T - coordinate type.
      + T +- coordinate type.

      Member Functions

      - - - - - + +
      - - - - + + - - + + +Both segment and its end points will have the same index. - + +Allows to distinguish between segment site and its endpoints. - + +one of the boundary edges. +voronoi_edge_type* incident_edge() +const +to the one of the boundary edges. + incident_edge(voronoi_edge_type* +e) +edge pointer of the cell. - + - + +Allows to associate the user provided data with the primitive. + contains_point() +const + contains_segment() +const + is_degenerate() +const +Can happen if a few input segments share a common endpoint.
      voronoi_cell(source_index_type source_index,
      -             source_category_type source_category)

      -
      Voronoi cell constructor.
      -
      voronoi_cell(source_index_type +source_index,
      +             +source_category_type source_category)
      Voronoi cell constructor.
      source_index_type source_index() const
      -
      source_index_type + source_index() +const Returns input site index among the other sites.
      -Both segment endpoints and segment itself will have the same index.
      -
      source_category_type source_category() const
      -
      source_category_type + source_category() +const Returns input site category among the other sites.
      -Allows to distinguish between segment site and its endpoints.
      - -
      voronoi_edge_type* incident_edge()
      -
      voronoi_edge_type* + incident_edge() Returns the pointer to the -one of the boundary edges.
      -
      const -voronoi_edge_type* incident_edge() const
      -
      Returns the const pointer -to the one of the boundary edges.
      -
      void - incident_edge(voronoi_edge_type* e)
      -
      Sets the incident boundary -edge pointer of the cell.
      -
      color_type color() const
      -
      color_type + color() const Returns the color associated with the cell.
      void color(color_type color) const
      -
      void + color(color_type +color) const Sets the color of the cell.
      - -Allows to execute graph algorithms and associate data.
      -
      bool - contains_point() const Returns true if the cell contains a point site, else false.
      bool - contains_segment() const Returns true if the cell contains a segment site, else false.
      bool - is_degenerate() const Returns true if the cell doesn't have an incident edge.
      -Could happen if a few input segments share a common endpoint.
      -
      -
      All the above methods have O(1) complexity. The size of -the Voronoi cell structure is equal to: sizeof(void *) + 2 * sizeof(size_t). + All +the above methods have O(1) complexity. The size of +the Voronoi cell structure is equal to: sizeof(void *) + 2 * +sizeof(size_t).

      Member Types

      - - - - +
      - - + + - + - - + - + - + - - - + + +
      coordinate_type
      -
      Coordinate type.
      -
      coordinate_type Coordinate type.
      source_index_typeSource index type.
      -
      Source index type.
      source_category_type
      -
      Source category type.
      +
      source_category_type Source category type.
      voronoi_edge_type Voronoi edge type. - Voronoi edge type.
      color_type - Color type (check the Important section). -
      color_type Color type (check the Important section).

      Miscellaneous

      - -The following code snippet effectively traverses the Voronoi edges around the +The following code snippet effectively traverses the Voronoi edges +around the Voronoi cell:

      const voronoi_edge<double>* edge = cell->incident_edge();
      - do {
      + do {
        -edge = edge->next();
      +edge = edge->next();
        -// Do smth. with edge.
      +// Do smth. with edge.
      } while (edge != cell->incident_edge());

      Voronoi Vertex

      -Voronoi vertex is represented by a point that corresponds to the vertex -and a pointer to the incident edge.
      +A Voronoi vertex represents a point, that is equidistant from the three +or more input geometries. As a consequence, it corresponds to the point +of the intersection of the three or more Voronoi edges. On the image +below, there are 5 such vertices: A, B, C, D, E. The Voronoi vertex +data structure embeds the coordinates of the underlying point and +provides access to a random Voronoi edge originating from the vertex +(e.g. edge +BC for the vertex B).
      +

      Declaration

      - - - +Header: boost/polygon/voronoi_diagram.hpp
      +
      template -<typename T>
      +<typename T>
      class voronoi_vertex;

      -
      T - coordinate type.
      + T +- coordinate type.

      Member Functions

      - - - - - + +
      - - - + + - + - +point_type& x() const + - + - - + + +pointer. +voronoi_edge_type* incident_edge() +const +to the incident edge. + incident_edge(voronoi_edge_type* +e) +pointer. - + - + +Allows to associate the user provided data with the primitive.
      voronoi_vertex(const coordinate_type& x,
      -               const coordinate_type& y)

      -
      Voronoi vertex constructor.
      -
      voronoi_vertex(const +coordinate_type& x,
      +               +const coordinate_type& y)
      Voronoi vertex constructor.
      const -point_type& x() const
      -
      Returns the x-coordinate of the point that represents the vertex.
      -
      Returns the x-coordinate of the point that represents +the vertex.
      const point_type& y() constReturns the y-coordinate of the point that represents the vertex.
      -
      Returns the y-coordinate of the point that represents +the vertex.
      voronoi_edge_type* incident_edge()
      -
      voronoi_edge_type* + incident_edge() Returns the incident edge -pointer.
      -
      const -voronoi_edge_type* incident_edge() const
      -
      Returns the const pointer -to the incident edge.
      -
      void - incident_edge(voronoi_edge_type* e)
      -
      Sets the incident edge -pointer.
      -
      color_type color() const
      -
      color_type + color() const Returns the color associated with the vertex.
      void color(color_type color) const
      -
      void + color(color_type +color) const Sets the color of the vertex.
      -Allows to executegraph algorithms and associate data.
      -
      -
      All the above methods have O(1) complexity. The size of -the Voronoi vertex structure is equal to: sizeof(void *) + sizeof(size_t) + 2 * -sizeof(coordinate_type). + All +the above methods have O(1) complexity. The size of +the Voronoi vertex structure is equal to: sizeof(void *) + +sizeof(size_t) + 2 * +sizeof(coordinate_type).

      Member Types

      - +
      - - + + - - - + - - - + + +
      coordinate_type
      -
      Coordainte type.
      -
      coordinate_type Coordainte type.
      voronoi_edge_type
      -
      Voronoi edge type.
      +
      voronoi_edge_type Voronoi edge type.
      color_type - Color type (check the Important section). -
      color_type Color type (check the Important section).
      - -

      Miscellaneous

      The following code snippet effectively traverses the Voronoi edges around the +

      Miscellaneous

      +The following code snippet effectively traverses the Voronoi edges +around the Voronoi vertex:

      const voronoi_edge<double>* edge = vertex->incident_edge();
      - do {
      + do {
        -edge = edge->next();
      +edge = edge->next();
        -// Do smth. with edge.
      +// Do smth. with edge.
      } while -(edge != vertex->incident_edge());
      -
      -

      Voronoi Diagram Traits
      -

      -Voronoi diagram traits are used to configure Voronoi diagram data +(edge != vertex->incident_edge()); +

      Voronoi Diagram Traits

      +The Voronoi diagram traits are used to configure the Voronoi primitive +types and predicates, used by the Voronoi diagram +data structure.
      +The implementation includes default traits specialization for the +double output coordinate type.

      Declaration

      - - - +Header: boost/polygon/voronoi_diagram.hpp
      +
      template -<typename T>
      +<typename T>
      struct voronoi_diagram_traits;

      -
      T - coordinate type.
      + T +- coordinate type.

      Member Types

      - - - - - + +
      - - - - - - - - + - - + - - + - + + + + +true if the two points are considered to be equal.
      +False otherwise. It is used to unite nearby Voronoi vertices.
      coordinate_type
      -
      The main coordinate type -of the Voronoi diagram primitives.
      -
      cell_type
      -
      Voronoi cell type.
      +
      coordinate_type Coordinate type +of the Voronoi diagram primitives.
      vertex_type
      -
      Voronoi vertex_type.
      +
      cell_type Voronoi cell type.
      edge_type
      -
      Voronoi edge_type.
      +
      vertex_type Voronoi vertex type.
      vertex_equality_predicate_type
      +
      edge_type + Voronoi edge type.
      vertex_equality_predicate_type Predicate that returns -true if two points are considered to be equal.
      -This is used to unite nearby Voronoi vertices.
      -
        +   - + - + @@ -989,6 +999,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.Copyright © Andrii Sydorchuk 2010-2013.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - - \ No newline at end of file + + diff --git a/doc/voronoi_main.htm b/doc/voronoi_main.htm index 3aa40ce..2fc913b 100644 --- a/doc/voronoi_main.htm +++ b/doc/voronoi_main.htm @@ -1,44 +1,26 @@ - - - - - - - - - - - - - - - - - - - + + - - - Voronoi Main - - - - + + Voronoi Main - - - - - - - + + + + +
      - - +his/her PC. Upon the community request, more documentation on the +theoretical aspects of the implementation will be published. +The +authors would like to acknowledge the Steven Fortune's article "A Sweepline algorithm +for Voronoi diagrams", that covers fundamental ideas of the +current implementation. - - +
      - + + - +
      - -

      THE BOOST.POLYGON VORONOI LIBRARY
      -

      -
      -The Boost.Polygon Voronoi library provides functionality to construct the Voronoi diagram +

      +

      THE BOOST.POLYGON VORONOI LIBRARY

      +
      +The Voronoi extension of the Boost.Polygon library provides +functionality to construct a Voronoi +diagram of a set of points and linear segments in 2D space with the following set of limitations:
      • coordinates of the input points and endpoints of the -segments +input segments should be of the integer type;
      • input segments should not overlap except their endpoints.
      While the first restriction is permanent (it allows to give the exact warranties about the output precision and -algorithm execution), -the second one may be resolved using the Boost.Polygon functionality. +algorithm execution flow), +the second one may be resolved using the Boost.Polygon segment utils. The strong sides of the library and main benefits comparing to the other implementations are discussed in the following paragraphs.
      -

      Robustness and Efficiency

      -Let's explain a bit those terms. The efficiency is simply measured by -the time it takes the algorithm to execute. The robustness is a bit -more harder to explain. But those of you who had the experience with -the following situations would understand what it doesn't mean: application segfaults randomly, algorithm output contains -degeneracies or is completely invalid (e.g. a point is considered to be outside of the polygon, -while should be inside). In other words robust implementation doesn't -fail and produces expected output in 100% of cases, thus user can rely -on -it. Robustness is a weak place of the most non-commercial -implementations of any complex geometric algorithm. The main issues could be divided onto two main categories: memory management -issues, numeric stability issues. Our implementation avoids the -first type of issues using pure STL data structures, thus you won't find -any operator new in the code. The second category of problems is -resolved using multiprecision geometric -predicates. -Even for commercial implementations usage of such predicates usually -results in a huge performance slowdown. Here is another strong side of -the Boost.Polygon -Voronoi library: we avoid multiprecision computations in 95% of cases -using -extremely fast floating-point predicates. Yes, those are not always -exact, but we developed the relative -error arithmetic apparatus to identify them and switch to the -higher precision predicates when required.
      -

      Precision of the Output Structures
      -

      -One of the extremely important results of using two types of predicates -is that library efficiently computes relatively precise coordinates of -the output geometries. Here we will explain a bit what exactly -"relatively precise" means and how the received output may differ from -the theoretically correct one (here and after we assume that output -coordinate type is the IEEE-754 floating-point type).
      -
      -Voronoi implementation guaranties that the relative error of the -coordinates of the output -geometries is always not higher than 64 machine epsilons (6 -bits of mantissa), while in many cases it is slightly less. That also -means that using floating-point type with the larger mantissa will -produce more precise output. Let's consider -the following example: the output Voronoi -vertex has double (53-bit mantissa) x-coordinate equal to 1.0, then the -absolute error is at most 2^-53 * 2^6 = 2^-47 and the exact value of -x-coordinate lies in the range [1.0 - 2^-47, 1.0 + 2^-47]. For -x-coordinate equal to 2^31, the absolute error will be at most 2^-53 * -2^31 * 2^6 = 2^-16 and the exact value of x-coordinate lies in the -range -[2^31 - 2^-16, 2^31 + 2^16]. For the output Voronoi vertex with long -double -(64-bit mantissa) x-coordinate equal to 2^31, the absolute error will -be at most 2^-64 * 2 ^31 * 2^6 = 2^-27 and the exact value of -x-coordinate -lies in the range [2^31-2^-27, 2^31+2^-27]. If you'd like to become -master of the absolute and relative error try this article.
      -
      -During the finalization step the implementation unites Voronoi vertices whose both -coordinates are situated within the relative error range equal to 128 -machine epsilons and removes any Voronoi edges between them. That is -the only case that might cause differences between the algorithm output -topology and theoretically precise one.  Now let's see what is the practical -impact of this. Consider the following example: we are going to construct the -Voronoi diagram of our Solar System. The radius of our Solar System is -approximately 2^42 metres, and we are going to snap it to the integer -grid of [-2^42; 2^42] x [-2^42; 2^42].  Let's choose the long double -(64 bit mantissa) output coordinate type, then the maximum absolute error -for the output geometries within our Solar System will be on its boundaries -and equal to 2^-64 * 2^42 * 2^6 = 2^-18 metres. In the output we are going to -consider vertices with both coordinates that are within 2^-17 metres (8 -micrometres) distance to be equal. That distance is equal to -the size of a bacteria and is relative to the Solar System size.

      Fully Functional with Segments

      -There are not many implementations of the Voronoi diagram construction -algorithm that could -handle linear segment inputs, even considering the commercial libraries. +There are just a few implementations of the Voronoi diagram +construction +algorithm that can +handle input data sets that contain linear segment, even considering +the commercial +libraries. Support of the -segments allows to discretize any input geometry (circle, ellipse, -parabola). Of course as the result those might have floating-point -coordinates, but that is resolved using scaling and snapping to the -integer grid. This functionality is very handy as it allows to compute -the medial axis transform of the arbitrary set of input geometries. So -one may start -using it for the next generation pattern recognition or computer vision -project.
      -

      Basic and Advanced Usage Cases

      -The main library header voronoi.hpp -defines the following static functions to integrate the Voronoi library functionality with the Boost.Polygon interfaces:
      -
      - +segments allows to discretize any input geometry (sampled +floating-point coordinates can be scaled and snapped to the integer +grid): circle, ellipse, +parabola. This functionality allows to compute +the medial axis transform of the arbitrary set of input geometries, +with direct applications in the computer vision +projects. +

      Robustness and Efficiency

      +Robustness issues can be divided onto the two main categories: memory +management +issues and numeric stability issues. The implementation avoids the +first type of the issues using pure STL data structures, thus there is +no +presence of the new operator in the code. The second category of +the problems is +resolved using the multiprecision geometric +predicates. +Even for the commercial libraries, usage of such predicates +results in a vast performance slowdown. The Voronoi implementation +overcomes this by avoiding the multiprecision +computations in the 95% of the cases and +uses the efficient, floating-point based predicates. Such preciates +don't +produce the correct result always, however the library embeds the +relative +error arithmetic apparatus to identify such situations and switch +to the +higher precision predicates when appropriate. As the result, the +implementation has a solid performance comparing to the other known +libraries (more details in the benchmarks).
      +

      Precision of the Output Structures

      +The Voronoi implementation guaranties, that the relative error of the +coordinates of the output +geometries is at most 64 machine epsilons (6 +bits of mantissa, for the IEEE-754 floating-point type), while on +average it's slightly lower. This means, that the precision of the +output +geometries can be increased simply by using a floating-point type with +the larger mantissa. The practical point of this statements is +explained in the following table:
      +
      - - + + + + - - + + + + - - + + + + - - - - - - + + + + - - - - - - + + + +
      template <typename Point, typename VB>
      -size_t insert(const Point &point, VB *vb)
      -
      Inserts a point into the Voronoi builder data structure.
      -Point type should model the point concept.
      - -Returns index number of the inserted site.
      -
      Output Coordinate Type Output Coordinate Value Max Absolute Error Precise Value Range
      template <typename PointIterator, typename VB>
      -void insert(PointIterator first,
      -            PointIterator last,
      -            VB *vb)
      -
      Inserts an iterator range of points into the Voronoi builder data structure.
      -Corresponding point type should model the point concept.
      -
      double (53 bit mantissa) 1 2-53 * 26 += 2-471 ± 2-47
      template <typename Segment, typename VB>
      -size_t insert(const Segment &segment, VB *vb)
      -
      Inserts a segment into the Voronoi builder data structure.
      -Segment type should model the segment concept.
      - -Returns index number of the inserted site.
      -
      double (53 bit mantissa) 231 2-53 * 231 +* 26 = 2-16231 ± 2-16
      template <typename SegmentIterator, typename VB>
      -void insert(SegmentIterator first,
      -            SegmentIterator last,
      -            VB *vb)
      -
      Inserts an iterator range of segments into the Voronoi builder data structure.
      -Corresponding segment type should model the segment concept.
      -
      template <typename PointIterator, typename VD>
      -void construct_voronoi(PointIterator first,
                             -PointIterator last,
      -                       -VD *vd)
      -
      Constructs Voronoi diagram of a set of points.
      Corresponding point type should model the point concept.
      -
      long double (64 bit +mantissa)1 2-64 * 26 += 2-581 ± 2-58
      template <typename SegmentIterator, typename VD>
      -void construct_voronoi(SegmentIterator first,
      -                       -SegmentIterator last,
      -                       -VD *vd)
      -
      Constructs Voronoi diagram of a set of segments.
      Corresponding segment type should model the segment concept.
      -
      template <typename PointIterator,
      -          typename SegmentIterator,
      -          typename VD>
      void construct_voronoi(PointIterator p_first,
      -                       -PointIterator p_last,
                             -SegmentIterator s_first,
      -                       -SegmentIterator s_last,
                             -VD *vd)
      -
      Constructs Voronoi -diagram of a set of points and segments.
      Corresponding point type should model the point concept.
      -Corresponding segment type should model the segment concept.
      -
      long double (64 bit +mantissa) 2312-64 * 231 +* 26 = 2-27231 ± 2-27
      -
      This -means that it's possible to construct the Voronoi diagram with the -following two lines of code (if corresponding input types satisfy the Boost.Polygon concept model):
      +Detailed description of the absolute and relative errors evaluation can +be found in the article: "What +Every Computer Scientist Should Know About Floating-Point Arithmetic".
      +
      +During the finalization step the implementation unites the Voronoi +vertices +whose both +coordinates are situated within the relative error range equal to 128 +machine epsilons and removes any Voronoi edges between those. This is +the only case, that might cause differences between the algorithm +output +topology and theoretically precise one, and practically means the +following: for the Voronoi diagram of a set of solid bodies inside the +Solar System (radius 242 metres) and the long double (64 bit +mantissa) output coordinate type the maximum absolute error within the +Solar System rectangle will be equal to 2-64 * 242 +* 26 = 2-18 metres; as the result, vertices with +both coordinates that are within 2-18 metres (8 +micrometres or the size of a bacteria) will be considered +equal and united.
      +

      Simple Interface

      +The boost/polygon/voronoi.hpp +library header defines the following static functions to integrate the +Voronoi library +functionality with the Boost.Polygon interfaces:
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      template +<typename Point, typename VB>
      +size_t insert(const Point +&point, VB *vb)
      Inserts a point into the Voronoi builder data structure.
      +Point type should model the point concept.
      +Returns index of the inserted site.
      template +<typename PointIterator, typename VB>
      +void insert(PointIterator +first,
      +            +PointIterator last,
      +            VB +*vb)
      Inserts an iterator range of points into the Voronoi +builder data structure.
      +Corresponding point type should model the point concept.
      template +<typename Segment, typename VB>
      +size_t insert(const Segment +&segment, VB *vb)
      Inserts a segment into the Voronoi builder data +structure.
      +Segment type should model the segment concept.
      +Returns index of the inserted site.
      template +<typename SegmentIterator, typename VB>
      +void insert(SegmentIterator +first,
      +            +SegmentIterator last,
      +            VB +*vb)
      Inserts an iterator range of segments into the Voronoi +builder data structure.
      +Corresponding segment type should model the segment concept.
      template +<typename PointIterator, typename VD>
      +void construct_voronoi(PointIterator +first,
      +                       +PointIterator last,
      +                       +VD *vd)
      Constructs the Voronoi diagram of a set of points.
      +Corresponding point type should model the point concept.
      template +<typename SegmentIterator, typename VD>
      +void construct_voronoi(SegmentIterator +first,
      +                       +SegmentIterator last,
      +                       +VD *vd)
      Constructs the Voronoi diagram of a set of segments.
      +Corresponding segment type should model the segment concept.
      template +<typename PointIterator,
      +          typename +SegmentIterator,
      +          typename VD>
      +void construct_voronoi(PointIterator +p_first,
      +                       +PointIterator p_last,
      +                       +SegmentIterator s_first,
      +                       +SegmentIterator s_last,
      +                       +VD *vd)
      Constructs the Voronoi +diagram of a set of points and segments.
      +Corresponding point type should model the point concept.
      +Corresponding segment type should model the segment concept.
      +
      +The +following two lines of code construct the Voronoi diagram of a set of +points (as +long as the corresponding input geometry type satisfies the +Boost.Polygon concept model):

      voronoi_diagram<double> vd;
      - construct_voronoi(points.begin(), points.end(), &vd);
      -
      The library also provides the clear interfaces to - associate user data with the output geometries and efficiently traverse Voronoi graph. -More details on those are covered in the basic Voronoi tutorial. Advanced usage of the library with the configuration of the coordinate + construct_voronoi(points.begin(), +points.end(), &vd);
      +
      +The library provides the clear interfaces to associate the user data +with the +output geometries and efficiently traverse +the +Voronoi graph. +More details on those topics are covered in the basic Voronoi tutorial. Advanced +usage of the library with the configuration of the coordinate types is explained in the advanced Voronoi tutorial. -The library also allows users to implement their own Voronoi diagram / -Delaunay triangulation construction routines based on the Voronoi builder API.
      -

      No Third Party Dependencies
      -

      Yes, -the library doesn't depend on any 3rd party code. Even more than that -there is only one dependency on the Boost libraries: boost/cstdint.hpp. -All the required multiprecision types functionality is implemented as -part of the library and is not exposed to the user. Considering the -fact that Voronoi implementation consists of just 7 headers (3 public -and 4 private) it is easy to compile it within a minute after download. -On the other hand voronoi.hpp header provides integration routines with -the Boost.Polygon concepts and models with a drawback of additional -dependencies.

      Extensible for the User Provided Coordinate Types

      -Our implementation is coordinate type agnostic. That means that as soon -as user provided types satisfy the set of restrictions of the Voronoi builder coordinate type traits -and implement methods required by the library, no changes are required -neither to the algorithm, nor to the implementation of the predicates. So it's +The library allows users to implement their own Voronoi diagram / +Delaunay triangulation construction routines based on the Voronoi builder API.
      +

      No Third Party Dependencies

      +The Voronoi extension of the Boost.Polygon library doesn't depend on +any 3rd party code +and contains single dependency on the Boost libraries: +boost/cstdint.hpp. +All the required multiprecision types and related functionality are +encapsulated as +part of the implementation. The library is fast to compile (3 public +and 4 private heades), has strong cohesion between its components and +is clearly modularized from the rest of the Boost.Polygon library, with +the optional integration through the voronoi.hpp header.
      +

      Extensible for the User Provided Coordinate Types

      +The implementation is coordinate type agnostic. As long +as the user provided types satisfy the set of the requirements of the Voronoi builder coordinate type traits, +no additional +changes +are needed +neither to the algorithm, nor to the implementation of the predicates. +For example, it's possible to -construct Voronoi diagram for the 256-bit integer input coordinate type +construct the Voronoi diagram with the 256-bit integer input coordinate +type and 512-bit output floating-point type without making any changes to the -internal code.
      -

      Bright Future
      -

      +library.
      +

      Future Development

      Below one may find the list of the main directions for the future development of the library.
      -High-priority tasks that already have approximate implementation plan -are the following (some of those may be proposed as future GSoC projects):
      +The high-priority tasks that already have the approximate +implementation plan +are the following (some of those may be proposed as future GSoC +projects):
        -
      • Implementing Delaunay triangulation data structure.
        +
      • Implement the Delaunay triangulation data structure.
        Note: only data structure needs to be implemented that properly processes events provided by the Voronoi builder.
      • -
      • Implementing medial axis transform data structure.
        +
      • Implement the medial axis transform data structure.
        Note: in general case the Voronoi diagram has completely the same geometry as the medial axis (they are 100% equal), however for many applications user is not interested in the Voronoi edges inside the hole regions. The main point -of this data structure is to automatically filter Voronoi edges that +of this data structure is to automatically filter the Voronoi edges +that belong to those areas.
      • -
      • Voronoi -diagram data structure could be used to find K nearest neighbors of N +
      • The Voronoi +diagram data structure can be used to find the K nearest neighbors of +the N sites in O(N*K*log(K) + N*log(N)) time. The return value would be a -list of the k nearest neighbors for each site.
        -
      • -
      • Using the r-tree data structure built on top of the +list of the k nearest neighbors for each site.
      • +
      • Use the r-tree data structure built on top of the bounding rectangles around the Voronoi cells to answer the nearest -neighbor queries in log(N) time, where N is the number of the Voronoi cells.
        +neighbor queries in log(N) time, where N is the number of the Voronoi +cells.
        Note: there should be r-tree data structure available soon as part of the Boost libraries.
      • - -
      • Providing interface to retrieve the convex hull of a set of -points and segments from the Voronoi builder once the Voronoi diagram is -constructed in O(N) time.
      • -
      • Providing serialization utilities for the Voronoi diagram data structure.
        -
      • - - +
      • Expose O(N) interface to retrieve the convex hull of a set +of +points and segments from the Voronoi builder, once the Voronoi diagram +is +constructed.
      • +
      • Provide serialization utilities for the Voronoi diagram +data structure.
      High-priority tasks to be considered:
        -
      • Dropping the restriction on the non-intersecting input +
      • Drop the restriction on the non-intersecting input geometries.
      • -
      • Integration of the Voronoi diagram data structure with the BGL (Boost +
      • Integrate the Voronoi diagram data structure with the +BGL (Boost Graph Library).
      • -
      • Support of the other types of distance metrics.
      • +
      • Support the other types of distance metrics.
      • Construction of the constrained Delaunay triangulation.
      • Support of the circular input geometries.
      Based on the community suggestions priorities may be changed.
      -

      Theoretical Research
      -

      Voronoi +

      Theoretical Research

      +The Voronoi library was developed as part of the Google Summer of Code 2010. The -library was actively maintained for the last two years and involved +library was actively maintained for the last three years and involved +the strong mathematical research in the field of algorithms, data structures, relative error arithmetic and numerical robustness. Nowadays one can -often read a scientific article that contains non-practical theoretical +often read a scientific paper, that contains non-practical +theoretical results or implementation with benchmarks nobody else can reproduce. The opposite story is with -the Boost.Polygon Voronoi library. We provide pure implementation and +the Voronoi library, that contains complete +implementation of +the Voronoi diagram construction algorithm and benchmarks one may run on -his PC. In case community finds it useful we will incrementally -add more documentation on the theoretical side of our implementation. The -authors would like to acknowledge the Steven Fortune's article "A Sweepline algorithm -for Voronoi diagrams", that contains the fundamental ideas of the -current implementation.
      -
        +   - + - + @@ -414,6 +475,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.Copyright © Andrii Sydorchuk 2010-2013.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - - \ No newline at end of file + + diff --git a/doc/voronoi_predicates.htm b/doc/voronoi_predicates.htm deleted file mode 100644 index 467dca2..0000000 --- a/doc/voronoi_predicates.htm +++ /dev/null @@ -1,251 +0,0 @@ - - - - - - - - - - - - - Voronoi Predicates - - - - - - - - - - - - - - - - - - - - -
      - -
      - - - - -
      - - -

      - - -

      Voronoi Predicates
      -

      - -In mathematical theory predicate is an operator which returns true -or false (e.g. it may answer a question: "is it sunny today?").
      - -Voronoi predicates contain implementation of a set of the geometric -predicates used by the Voronoi builder. -Except of those they also provide -functors that allow to compute the coordinates of the centers of the -inscribed -circles (those correspond to the Voronoi vertices) within the given -relative error precision range (64 machine epsilons). This means that -the more mantissa bits -your floating point type has the better precision of the output -geometries you'll get. This -is a very handy functionality as it allows to improve output precision -simply providing 3rd party IEEE-754 like floating-point types.
      - - -

      Geometric Predicates

      - -The main issues with the implementation of any complex geometric -algorithm arise when dealing with the robustness of the geometric -predicates. -Usually this -is also the point where the commercial projects stand strong against -noncommercial implementations (it's not the case with our -implementation). -For the short example let's consider the following code snippet, that -could -be used to compute orientation of the three points:
      - -
      - - double -cross_product(double dx1, double dy1, double dx2, double dy2) {
      - -   -return dx1 * dy2 - dx2 * dy1;
      - - }
      -
      -int main() {
      -  int v = 1 << 30;  // 2 ^ 30
      -  double result =
      cross_product(v, v - 1, v + 1, -v);
      -  printf("%.3f", result);
      -  return 0;
      -}
      -
      -
      The -output of this simple program will be "0.000", while -the correct one is "1.000". In terms of the orientation test this means -that points are collinear instead of being CCW oriented. This is one of -the basic predicates used in any geometric algorithm and taking wrong -output from it may influence the further algorithm execution: -corrupting algorithm underlying structures or producing completely -invalid output. Voronoi uses -slightly more complex predicates. To insure that they are robust and -efficient the approach that combines two known techniques (lazy -arithmetic and multiple -precision computations) is used.
      - - -

      Lazy Arithmetic

      - -Lazy -arithmetic is based on the usage of IEEE-754 floating-point types to -quickly evaluate the result of the expression. While this approach has -a good speed -performance it doesn't produce reliable results all the time (as in the -example above). The way to solve the issue is apart from computing -result of the expression compute the relative error of it as well. This -will -give us the range of values the evaluated result belongs to and based -on that we can -come up with two decisions: 1) output the value; 2) recompute the -expression using multiprecision type. The way relative errors are -evaluated is explained in the Voronoi -Robust FPT section.
      - - -

      Multiple Precision Arithmetic

      - -In the vast majority of cases -the lazy arithmetic approach produces correct result thus further -processing is not required. In other cases the Voronoi library defined -or user -provided multiple precision types are used to produce correct result. -However even that doesn't solve all the cases. Multiprecision geometric -predicates could be divided onto two categories:
      - -
      - -1) mathematical transformation of the predicate exists that evaluates -the exact result:
      -
      -Predicate: A/B + C/D ?< 0;
      -After math. transform: (A*D + B*C) / (B * D) ?< 0;
      -
      -Predicate: sqrt(A) ?< 1.2;
      -After math. transform: A ?< 1.44;
      -
      -
      2) the correct result could be produced only by increasing -precision of the multiprecision type and with defined relative error -for the output type:
      - -
      - - Predicate: -sqrt(A) + sqrt(B) + sqrt(C) + sqrt(D) + sqrt(E) ?< 1.2;
      -Imagine that value of the expression to the left is very close to 1.2;
      -

      - - Predicate: -sin(x) ?< 0.57;
      -Relative error of sin function should be known;
      -
      -
      The Voronoi of points could be completely -implemented using predicates of the first type, however the Voronoi of -segments could not. -The predicate that doesn't fall into the first category is responsible -for comparison of the Voronoi circle events. However it appears that -properly used -this predicate can't corrupt algorithm internal structures and produces -output technically the same as produced in case this predicate fell in -the first category.  The main reasons for this are: 1) algorithm -operates with integer coordinate type of the input geometries; 2) -closely -situated Voronoi vertices are considered to be the same in the output -data structure (this won't influence main targets algorithm is used -for).
      -
        - - - - - - - - - - - -
      Copyright:Copyright © Andrii Sydorchuk 2010-2012.
      License:Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -http://www.boost.org/LICENSE_1_0.txt)
      -
      - - - \ No newline at end of file diff --git a/doc/voronoi_robust_fpt.htm b/doc/voronoi_robust_fpt.htm deleted file mode 100644 index 7f6ad0a..0000000 --- a/doc/voronoi_robust_fpt.htm +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - - - - - Voronoi Robust FPT - - - - - - - - - - - - -
      - -
      - - - - -
      - - -

      - -

      Voronoi Robust FPT

      -The Voronoi -robust floating-point types are the set of classes and tools that -allow to estimate relative error of the arithmetic expressions. It is -assumed that the other Boost libraries may find this unit functionality -extremely useful, as it can be used to implement robust and efficient -arithmetic predicates or functors that compute values within known -relative error.
      -

      Robust Fpt Type

      -The robust -fpt type (robust floating-point type) -- represents the IEEE-754 floating-point type wrapper that also -contains -information about the relative error of the underlying value. The -implementation overloads 5 standard operations: +, -, *, /, sqrt and -apart from the evaluating value of the expression also computes its -relative -error. Let's consider two values A and B; C - rounding error, re(X) -- relative error of the X expression, then following rules apply:
      -
      - re(A+B) -<= max(re(A), re(B)) + C, if A * B >= 0;
      - re(A-B) -<= (B * re(A) + A * re(B)) / |A - B| + C, if A * B < 0;
      - re(A*B) -<= re(A) + re(B) + C;
      - re(A/B) -<= re(A) + re(B) + C;
      - re(sqrt(A)) -<= re(A) * 0.5 + C;
      -
      -
      The constant C is equal to the rounding error, -which for the above set of arithmetic operations in the IEEE-754 -floating-point implementation should be equal to 1 machine epsilon.
      -

      Robust Difference Type

      -The robust -difference type - -represents expression wrapper that holds the positive and negative -partial -sums of the expression in a separate values in order to avoid -the cancellation errors before evaluating the final difference. -Following -arithmetic operators are overloaded for the robust difference type: +, --, *, / (division operator is not overloaded for the case were both -arguments have robust difference type).
      -Looking at the relative error formulas above one may notice a few facts:
      -1) all of the formulas evaluate upper bound of the relative error, the -actual value could be a lot smaller;
      -2) relative error estimate for the expression depends on the order -operations are evaluated;
      -3) relative error of  the difference of two positive numbers may -be -extremely large in case their values are close to each other (this is -also known as the cancellation error).
      -To explain this a bit, consider the following expression (~ - stands for -almost equal, << - many times larger than):
      -
      - A - B + -C, where A ~ B and C << B;
      -
      -Computing the relative error of this expression from left to right will -produce extremely large relative error:
      -
      - re(A-B+C) -= max(re(A-B), re(C)) = re(A-B) = (B * re(A) + A * re(B)) / 0 = INF;
      -
      -
      While doing this from right to left will keep the relative -error value small:
      -
      - re(A-B+C) -= re(C-B+A) = max(re(C-B), re(A)) = max(re(A), re(B));
      -
      -
      While both estimates are valid (they define upper bound of -the relative error), of course the second one is preferable.
      -Here is the place where robust difference type comes useful. Basically -it splits expression onto positive and negative partial sums and -evaluates the -difference only when the result is required. And did I mention that -positive and negative values might be of the robust fpt type, that's -why -the relative error is always known for the expression result.
      -

      Robust Sqrt Expression Structure

      -The robust square root expression structure allows to compute the -result of -the expression that contains square roots within defined relative -error. -As an example, consider the following expression:
      -
      - A * -sqrt(a) - B * sqrt(b), A * B > 0, a >= 0, b >= 0;
      -
      -Computing this expressions directly may apply huge cancellation error, -however it may be transformed to the next equivalent expression:
      -
      -(A * A * a - B * B * b) / (A * sqrt(a) + B * sqrt(b));

      -
      -The numerator and denominator of this expression could be computed -directly as those won't lead to the cancellation errors.
      -
      -In general case the robust sqrt expression structure allows to evaluate -the following set of expressions:
      -
      -sum(A[i] * sqrt(a[i]), i = 1 .. N), N <= 4;

      -
      -This appears to be enough for the Boost.Polygon Voronoi.
      -
        - - - - - - - - - - - -
      Copyright:Copyright © Andrii Sydorchuk 2010-2012
      License:Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -http://www.boost.org/LICENSE_1_0.txt)
      -
      - - \ No newline at end of file diff --git a/example/input_data/primary/primary_072.txt b/example/input_data/primary/primary_072.txt new file mode 100644 index 0000000..a43fcf3 --- /dev/null +++ b/example/input_data/primary/primary_072.txt @@ -0,0 +1,5 @@ +0 +3 +1403829871 74 1403829871 275 +1403829871 275 1403829741 275 +1403829741 275 1403829744 73 \ No newline at end of file diff --git a/example/output_data/primary/primary_072.png b/example/output_data/primary/primary_072.png new file mode 100644 index 0000000000000000000000000000000000000000..89a06d31aa1298917a740bb65d40cca60941426c GIT binary patch literal 4264 zcmeAS@N?(olHy`uVBq!ia0y~yV2S`?4mJh`hJ9%>?l3SguoOFahH!9jaMW<5bTBY5 za29w(7BevL9RXp+soH$f3=9HZo-U3d6?5L+wJo}HL$dAS`sF*A-yRg4X)%R)tJ#AS zo!gAK+_-F_10Q*8X4u*^lXpVn>Ff>H9N1aheP_Lr|HS%^wZKpGb(5{omr(H&zd3xr z=B#?Pt>I(sx>ftP%Qb}-^Bzj6%d%x)IB(PhZzT$7&wF@ z7#I?nxEU0D5*Qg;I7bzY2EoWk1&epf+R4cu4vA?tFl}UAEM>Oo_SwT%*^Z~gG+#L6 z`kFCer(AAMz1^Obx9;3`{bBJnV9hE0^3w;i3qJoaXJlmR{uj%3u29tC_|4)yd!zr| zsD2S0x_8woe)-jQe}d}s8VsiKJ0Gc+w)>wOVb85CG5Nr&tKN&11Vuvso-y>^z5D6y zd(QPCS6{O&-jH|y)w^5OTfg7PtFAZrYO;Z=mNkrjcBOu~_q0b=1%0y*Sk5~0@rZZJ z{;PN0zOOew%$y%@BlhRU^xfHS*B@T~yYT;Z{lksckp^wPdspAqJCx=bw`-<))1p=L zEyLahrrf>nxnk9?oi@jNUT<1eC)*c){kwI;*|1H<`LH}l?@BjmAZ>Nv|mg+&~&du$4_zHf@~)4 zDwRzZE-{YZS;TxEy}tMH+m`!En<~0?G(`$TTri$^)UJ?qv*LyYp99PB?g{V@;_*xIs1(_cMuZVE>j zgezswJR+*obfC#nIP$d8x&%WOu`_pnulg0Dl>P3AsLmI=v@mu@|y-t8GZ=bP2nEL{w+qfu^NGk+nkM z8@TQ*V^rIC+xnj0_v3Y1`42A$7qYH?$S0;V*E+IRAbf)s6ZbWTl&z}k5=vRb*0i3; za*jEu#i9xrtE(?bQ#{d2)vTExZlv%_+m`wa?Qph^TA%W3eZIhf( z_<>FqF`uOE<$so46*#ZF>0O8R10E)Bi@diJRo68bbLu=W$?nxDWVLBNz~r}m+X`t9R);$den9gng0utor)Ok=T=YB2qc45*HQ2~Vw4bN})uZhq82Qo&Wk#*0R z+LX|<)|-xq3aD&onEpGYJTS=g{0X6OP_1Q@mo*QhPLM-KAw3Von#iG}kgW$|33BQv ztp5(O;slGBL0_D*cMPMjK*WKHs&1V^Rv(uH#>cNzHysf*P;6wKe3SR}wud~uTlzp! zJ_(GMGejdFab-9pFkYT%wdsiHg^mME%S=O4I<*%lHnRHUzX3TQnTb0ic@2og&LVcf z53G)}k#);gi%s`zKifRwdeL!!>DKQ4HLrJZuPFxEKUXlqK|XKQtJ=Bpk&n1uOgO;w ztH=*zXfPA^i}RWwXZLaHEbwnv@{VDgD;(jl|C{pb`=O=Lq5pLYSxeq8`pUq-zIXkq z`>S8shknidu|g=^;rg9}OuxSGS`~No`;MyE(El0cdNF2{=XfG1_GfsCZvRSXPn zDjO1vc3)#=Fc3s)Wf<3z@RJ`VX!jx zH6z1}28g)_YVK^2V|ZY~#64sF>1)gkGUPY!)V5~ZGB5}WL|iyC8x)U1NbyKXYjMV% zyol|*=?n=zNO6}?w=RmGp#YQ&AMg6gz_479?1t#%-@D59ep(1 ziKG4d?&OrH?_9g;{;F4@p?mfGZ+r69c7JC%6tTyJBlg4hIg962b?x)9J9|7?rZyJrgm&WQ*wR# zHEjxx+wY^XHG-Yi~^Bq1~W0z$`c83>)OArdMU!dKKQylpNovwO!r;RVBvw3|L7MqIFjK3 vo7k;#3=fX8h#A;lhbFo~&~Lu+pJ7?=t=(4(H~nE?U|{fc^>bP0l+XkK)2Kkh literal 0 HcmV?d00001 diff --git a/include/boost/polygon/detail/boolean_op_45.hpp b/include/boost/polygon/detail/boolean_op_45.hpp index 061727b..b2130ce 100644 --- a/include/boost/polygon/detail/boolean_op_45.hpp +++ b/include/boost/polygon/detail/boolean_op_45.hpp @@ -370,6 +370,7 @@ namespace boost { namespace polygon{ template static bool applyLogic(Count2 count) { #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { //apply or @@ -383,7 +384,7 @@ namespace boost { namespace polygon{ } else return false; #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif } @@ -405,6 +406,7 @@ namespace boost { namespace polygon{ template static bool applyLogic(Count1 count) { #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { //apply or @@ -416,7 +418,7 @@ namespace boost { namespace polygon{ } else return false; #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif } diff --git a/include/boost/polygon/detail/polygon_45_set_view.hpp b/include/boost/polygon/detail/polygon_45_set_view.hpp index caf4c62..a0dc046 100644 --- a/include/boost/polygon/detail/polygon_45_set_view.hpp +++ b/include/boost/polygon/detail/polygon_45_set_view.hpp @@ -39,6 +39,7 @@ namespace boost { namespace polygon{ rinput_.set(polygon_45_set_traits::begin(rvalue_), polygon_45_set_traits::end(rvalue_)); #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) @@ -50,7 +51,7 @@ namespace boost { namespace polygon{ else output_ -= rinput_; #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif } }; @@ -62,6 +63,7 @@ namespace boost { namespace polygon{ output_.set(polygon_45_set_traits::begin(lvalue_), polygon_45_set_traits::end(lvalue_)); #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) @@ -73,7 +75,7 @@ namespace boost { namespace polygon{ else output_ -= rvalue_; #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif } }; @@ -153,6 +155,7 @@ namespace boost { namespace polygon{ rinput_.set(polygon_45_set_traits::begin(rvalue_), polygon_45_set_traits::end(rvalue_)); #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) @@ -164,7 +167,7 @@ namespace boost { namespace polygon{ else output_ -= rinput_; #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif polygon_45_set_mutable_traits::set(lvalue_, output_.begin(), output_.end()); return lvalue_; diff --git a/include/boost/polygon/detail/polygon_set_view.hpp b/include/boost/polygon/detail/polygon_set_view.hpp index 661884a..243d40c 100644 --- a/include/boost/polygon/detail/polygon_set_view.hpp +++ b/include/boost/polygon/detail/polygon_set_view.hpp @@ -13,7 +13,7 @@ namespace boost { namespace polygon{ template inline void polygon_set_data::clean() const { if(dirty_) { - polygon_45_set_data tmp; + //polygon_45_set_data tmp; //very important: //the 45 degree algorithm does not satisfy //the precondition of arbitrary polygon formation @@ -102,6 +102,7 @@ namespace boost { namespace polygon{ // if(linput_.downcast(l45) && rinput_.downcast(r45)) { // //the op codes are screwed up between 45 and arbitrary //#ifdef BOOST_POLYGON_MSVC +//#pragma warning (push) //#pragma warning (disable: 4127) //#endif // if(op_type < 2) @@ -111,7 +112,7 @@ namespace boost { namespace polygon{ // else // l45.template applyAdaptiveBoolean_<2>(o45, r45); //#ifdef BOOST_POLYGON_MSVC -//#pragma warning (default: 4127) +//#pragma warning (pop) //#endif // output_.insert(o45); // } else { diff --git a/include/boost/polygon/detail/scan_arbitrary.hpp b/include/boost/polygon/detail/scan_arbitrary.hpp index 735ed25..acf7f65 100644 --- a/include/boost/polygon/detail/scan_arbitrary.hpp +++ b/include/boost/polygon/detail/scan_arbitrary.hpp @@ -1038,7 +1038,8 @@ namespace boost { namespace polygon{ bool first_iteration = true; //we want to return from inside the loop when we hit end or new x #ifdef BOOST_POLYGON_MSVC -#pragma warning( disable: 4127 ) +#pragma warning (push) +#pragma warning (disable: 4127) #endif while(true) { if(begin == end || (!first_iteration && ((*begin).first.first.get(VERTICAL) != y || @@ -1146,7 +1147,7 @@ namespace boost { namespace polygon{ } } #ifdef BOOST_POLYGON_MSVC -#pragma warning( default: 4127 ) +#pragma warning (pop) #endif } @@ -2292,11 +2293,12 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 stdcout << polys[j] << "\n"; stdcout << polys90[j] << "\n"; #ifdef BOOST_POLYGON_ICC +#pragma warning (push) #pragma warning (disable:1572) #endif if(area(polys[j]) != area(polys90[j])) { #ifdef BOOST_POLYGON_ICC -#pragma warning (default:1572) +#pragma warning (pop) #endif stdcout << "merge failed with area mismatch\n"; failed = true; @@ -2539,6 +2541,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 if(edge.second < edge.first) elem.second *= -1; if(scanline_base::is_vertical(edge)) elem.second *= -1; #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op_type == 0) { //OR @@ -2569,7 +2572,7 @@ pts.push_back(Point(12344171, 6695983 )); pts.push_back(Point(12287208, 6672388 } } #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif if(right.size() == 1) { if((*(right.begin())) == 0) { diff --git a/include/boost/polygon/detail/voronoi_predicates.hpp b/include/boost/polygon/detail/voronoi_predicates.hpp index fbaa96b..dad76a6 100644 --- a/include/boost/polygon/detail/voronoi_predicates.hpp +++ b/include/boost/polygon/detail/voronoi_predicates.hpp @@ -35,7 +35,8 @@ class voronoi_predicates { enum { ULPS = 64, - ULPSx2 = 128 + ULPSx2 = 128, + ULPSx5 = 320 }; template @@ -160,21 +161,21 @@ class voronoi_predicates { bool operator()(const site_type& lhs, const circle_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.x()), to_fpt(rhs.lower_x()), ULPS); + ulp_cmp(to_fpt(lhs.x()), to_fpt(rhs.lower_x()), ULPSx5); if (xCmp != ulp_cmp_type::EQUAL) return xCmp == ulp_cmp_type::LESS; typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.y()), to_fpt(rhs.lower_y()), ULPS); + ulp_cmp(to_fpt(lhs.y()), to_fpt(rhs.lower_y()), ULPSx5); return yCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const site_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x()), ULPS); + ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x()), ULPSx5); if (xCmp != ulp_cmp_type::EQUAL) return xCmp == ulp_cmp_type::LESS; typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y()), ULPS); + ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y()), ULPSx5); return yCmp == ulp_cmp_type::LESS; } diff --git a/include/boost/polygon/gtl.hpp b/include/boost/polygon/gtl.hpp index 048d15d..1fc1a57 100644 --- a/include/boost/polygon/gtl.hpp +++ b/include/boost/polygon/gtl.hpp @@ -9,10 +9,12 @@ #define GTL_GTL_HPP #ifdef __ICC +#pragma warning (push) #pragma warning (disable:1125) #endif #ifdef WIN32 +#pragma warning (push) #pragma warning( disable: 4996 ) #pragma warning( disable: 4800 ) #endif @@ -21,7 +23,13 @@ #include "polygon.hpp" namespace gtl = boost::polygon; using namespace boost::polygon::operators; -#if __ICC -#pragma warning (default:1125) + +#ifdef WIN32 +#pragma warning (pop) #endif + +#ifdef __ICC +#pragma warning (pop) +#endif + #endif diff --git a/include/boost/polygon/polygon_45_set_data.hpp b/include/boost/polygon/polygon_45_set_data.hpp index cf03518..4438d74 100644 --- a/include/boost/polygon/polygon_45_set_data.hpp +++ b/include/boost/polygon/polygon_45_set_data.hpp @@ -1551,6 +1551,7 @@ namespace boost { namespace polygon{ l90sd.sort(); r90sd.sort(); #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { @@ -1567,7 +1568,7 @@ namespace boost { namespace polygon{ r90sd.begin(), r90sd.end(), boolean_op::BinaryCount()); } #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif result.data_.clear(); result.insert(output); @@ -1678,6 +1679,7 @@ namespace boost { namespace polygon{ } l90sd.sort(); #ifdef BOOST_POLYGON_MSVC +#pragma warning (push) #pragma warning (disable: 4127) #endif if(op == 0) { @@ -1688,7 +1690,7 @@ namespace boost { namespace polygon{ l90sd.self_xor(); } #ifdef BOOST_POLYGON_MSVC -#pragma warning (default: 4127) +#pragma warning (pop) #endif result.data_.clear(); result.insert(l90sd); diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index de4de80..b4d0e9d 100644 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -985,11 +985,12 @@ namespace boost { namespace polygon{ area_type x1 = (area_type)x(previous); area_type x2 = (area_type)x(*begin_range); #ifdef BOOST_POLYGON_ICC +#pragma warning (push) #pragma warning (disable:1572) #endif if(x1 != x2) { #ifdef BOOST_POLYGON_ICC -#pragma warning (default:1572) +#pragma warning (pop) #endif // do trapezoid area accumulation area += (x2 - x1) * (((area_type)y(*begin_range) - y_base) + diff --git a/include/boost/polygon/voronoi.hpp b/include/boost/polygon/voronoi.hpp index fb7de49..bca6add 100644 --- a/include/boost/polygon/voronoi.hpp +++ b/include/boost/polygon/voronoi.hpp @@ -17,10 +17,10 @@ #include "voronoi_builder.hpp" #include "voronoi_diagram.hpp" -// Public methods to compute Voronoi diagram. +// Public methods to compute Voronoi diagram of a set of points and segments. // Coordinates of the points and of the endpoints of the segments should belong // to the 32-bit signed integer range [-2^31, 2^31-1]. To use wider input -// coordinate range voronoi_builder configuration via coordinate type traits is +// coordinate range voronoi_builder configuration via coordinate type traits // is required. // Complexity - O(N*logN), memory usage - O(N), N - number of input objects. namespace boost { @@ -34,8 +34,7 @@ typename enable_if< >::type >::type, std::size_t ->::type -insert(const Point& point, VB* vb) { +>::type insert(const Point& point, VB* vb) { return vb->insert_point(x(point), y(point)); } @@ -49,8 +48,7 @@ typename enable_if< >::type >::type, void ->::type -insert(PointIterator first, const PointIterator last, VB* vb) { +>::type insert(const PointIterator first, const PointIterator last, VB* vb) { for (PointIterator it = first; it != last; ++it) { insert(*it, vb); } @@ -64,8 +62,7 @@ typename enable_if< >::type >::type, std::size_t ->::type -insert(const Segment& segment, VB* vb) { +>::type insert(const Segment& segment, VB* vb) { return vb->insert_segment( x(low(segment)), y(low(segment)), x(high(segment)), y(high(segment))); @@ -81,8 +78,9 @@ typename enable_if< >::type >::type, void ->::type -insert(SegmentIterator first, SegmentIterator last, VB* vb) { +>::type insert(const SegmentIterator first, + const SegmentIterator last, + VB* vb) { for (SegmentIterator it = first; it != last; ++it) { insert(*it, vb); } @@ -98,8 +96,9 @@ typename enable_if< >::type >::type, void ->::type -construct_voronoi(PointIterator first, PointIterator last, VD* vd) { +>::type construct_voronoi(const PointIterator first, + const PointIterator last, + VD* vd) { default_voronoi_builder builder; insert(first, last, &builder); builder.construct(vd); @@ -115,8 +114,9 @@ typename enable_if< >::type >::type, void ->::type -construct_voronoi(SegmentIterator first, SegmentIterator last, VD* vd) { +>::type construct_voronoi(const SegmentIterator first, + const SegmentIterator last, + VD* vd) { default_voronoi_builder builder; insert(first, last, &builder); builder.construct(vd); @@ -141,9 +141,11 @@ typename enable_if< >::type >::type, void ->::type -construct_voronoi(PointIterator p_first, PointIterator p_last, - SegmentIterator s_first, SegmentIterator s_last, VD* vd) { +>::type construct_voronoi(const PointIterator p_first, + const PointIterator p_last, + const SegmentIterator s_first, + const SegmentIterator s_last, + VD* vd) { default_voronoi_builder builder; insert(p_first, p_last, &builder); insert(s_first, s_last, &builder); diff --git a/include/boost/polygon/voronoi_diagram.hpp b/include/boost/polygon/voronoi_diagram.hpp index 0a56173..7df26ec 100644 --- a/include/boost/polygon/voronoi_diagram.hpp +++ b/include/boost/polygon/voronoi_diagram.hpp @@ -328,7 +328,7 @@ class voronoi_diagram { return vertices_.size(); } - void _reserve(int num_sites) { + void _reserve(std::size_t num_sites) { cells_.reserve(num_sites); vertices_.reserve(num_sites << 1); edges_.reserve((num_sites << 2) + (num_sites << 1)); diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index b108a1f..dcd8aef 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -3565,7 +3565,7 @@ int main() { } } - if (1) { + { using namespace boost::polygon; typedef point_data Point; typedef segment_data Dls; @@ -3604,7 +3604,7 @@ int main() { assert_s(dlss.size() == 11, "intersection2"); } - if (1) { + { using namespace boost::polygon; std::vector > > segs; segment_data sarray[2]; From 1ebb72d500378ecadebe952487f396cd7f11365f Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Tue, 16 Jul 2013 20:15:38 +0000 Subject: [PATCH 26/32] Polygon: merging fix of bug #8197 with release branch. [SVN r85055] --- include/boost/polygon/detail/polygon_45_touch.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/polygon/detail/polygon_45_touch.hpp b/include/boost/polygon/detail/polygon_45_touch.hpp index 5da606b..c584f52 100644 --- a/include/boost/polygon/detail/polygon_45_touch.hpp +++ b/include/boost/polygon/detail/polygon_45_touch.hpp @@ -64,7 +64,9 @@ namespace boost { namespace polygon{ //inline CountTouch& operator=(int count) { counts[0] = counts[1] = count; return *this; } inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } inline int& operator[](int index) { - std::vector >::iterator itr = lower_bound(counts.begin(), counts.end(), std::make_pair(index, int(0))); + std::vector >::iterator itr = + std::lower_bound(counts.begin(), counts.end(), + std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; } From 91e0dba10639c618601d8924f6967af8784c54ea Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Sun, 29 Sep 2013 18:44:35 +0000 Subject: [PATCH 27/32] Polygon: Merging trunk into the release branch. [SVN r86009] --- benchmark/Jamfile.v2 | 19 +- benchmark/voronoi_benchmark_points.cpp | 78 +- benchmark/voronoi_benchmark_segments.cpp | 97 ++- doc/gtl_polygon_90_set_concept.htm | 86 +- .../boost/polygon/detail/polygon_45_touch.hpp | 4 +- .../polygon/detail/polygon_formation.hpp | 791 ++++++++++++++---- .../polygon/detail/voronoi_predicates.hpp | 344 ++++---- .../polygon/detail/voronoi_structures.hpp | 45 +- include/boost/polygon/polygon_90_set_data.hpp | 28 + include/boost/polygon/voronoi_builder.hpp | 2 +- test/Jamfile.v2 | 5 + test/gtl_boost_unit_test.cpp | 248 +++++- test/voronoi_predicates_test.cpp | 171 ++-- test/voronoi_structures_test.cpp | 70 +- 14 files changed, 1421 insertions(+), 567 deletions(-) diff --git a/benchmark/Jamfile.v2 b/benchmark/Jamfile.v2 index 41b7bd0..53c19a3 100644 --- a/benchmark/Jamfile.v2 +++ b/benchmark/Jamfile.v2 @@ -5,21 +5,24 @@ import testing ; +# Path constants required by the benchmarks. +path-constant GMP_ROOT : /home/slevin/Workspace/Libraries/gmp ; +path-constant MPFR_ROOT : /home/slevin/Workspace/Libraries/mpfr ; +path-constant CGAL_ROOT : /home/slevin/Workspace/Libraries/cgal ; +path-constant SHULL_ROOT : /home/slevin/Workspace/Libraries/s_hull ; + project voronoi-benchmark : requirements $(CGAL_ROOT)/include - $(SHULL_ROOT) - msvc:$(CGAL_ROOT)/auxiliary/gmp/include - msvc:$(CGAL_ROOT)/lib/libCGAL-vc90-mt-4.0.lib - msvc:$(CGAL_ROOT)/lib/libCGAL_Core-vc90-mt-4.0.lib - msvc:$(CGAL_ROOT)/auxiliary/gmp/lib/libgmp-10.lib - msvc:$(CGAL_ROOT)/auxiliary/gmp/lib/libmpfr-4.lib - msvc:$(BOOST_ROOT)/libs/thread/build//boost_thread - msvc:$(BOOST_ROOT)/libs/test/build//boost_unit_test_framework + $(SHULL_ROOT)/include + gcc:$(GMP_ROOT)/lib/libgmp.so + gcc:$(MPFR_ROOT)/lib/libmpfr.so gcc:$(CGAL_ROOT)/lib/libCGAL.so gcc:$(CGAL_ROOT)/lib/libCGAL_Core.so gcc:$(SHULL_ROOT)/s_hull.so + gcc:$(BOOST_ROOT)/libs/timer/build//boost_timer + gcc:$(BOOST_ROOT)/libs/thread/build//boost_thread gcc:$(BOOST_ROOT)/libs/test/build//boost_unit_test_framework ; diff --git a/benchmark/voronoi_benchmark_points.cpp b/benchmark/voronoi_benchmark_points.cpp index 15e123f..75564a9 100644 --- a/benchmark/voronoi_benchmark_points.cpp +++ b/benchmark/voronoi_benchmark_points.cpp @@ -16,9 +16,11 @@ #include #include -#include +#include typedef boost::int32_t int32; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; // Include for the Boost.Polygon Voronoi library. #include @@ -26,18 +28,11 @@ typedef boost::polygon::default_voronoi_builder VB_BOOST; typedef boost::polygon::voronoi_diagram VD_BOOST; // Includes for the CGAL library. -#include -#include -#include -#include -#include -typedef CGAL::Quotient ENT; -typedef CGAL::Simple_cartesian CK; -typedef CGAL::Simple_cartesian EK; -typedef CGAL::Segment_Delaunay_graph_filtered_traits_2< - CK, CGAL::Field_with_sqrt_tag, EK, CGAL::Field_tag> Gt; -typedef CGAL::Segment_Delaunay_graph_2 SDT_CGAL; -typedef SDT_CGAL::Point_2 Point_CGAL; +#include +#include +typedef CGAL::Exact_predicates_inexact_constructions_kernel CGAL_KERNEL; +typedef CGAL::Delaunay_triangulation_2 DT_CGAL; +typedef CGAL_KERNEL::Point_2 POINT_CGAL; // Includes for the S-Hull library. #include @@ -48,7 +43,7 @@ const int NUM_POINTS[] = {10, 100, 1000, 10000, 100000, 1000000}; const int NUM_RUNS[] = {100000, 10000, 1000, 100, 10, 1}; std::ofstream bf("benchmark_points.txt", std::ios_base::out | std::ios_base::app); -boost::timer timer; +boost::timer::cpu_timer timer; void format_line(int num_points, int num_tests, double time_per_test) { bf << "| " << std::setw(16) << num_points << " "; @@ -57,50 +52,65 @@ void format_line(int num_points, int num_tests, double time_per_test) { bf << "|" << std::endl; } -void run_boost_test() { +double get_elapsed_secs() { + cpu_times elapsed_times(timer.elapsed()); + return 1E-9 * static_cast( + elapsed_times.system + elapsed_times.user); +} + +void run_boost_voronoi_test() { boost::mt19937 gen(RANDOM_SEED); - bf << "Boost.Polygon Voronoi of Points:\n"; + bf << "Boost.Polygon Voronoi Diagram of Points:\n"; for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { VB_BOOST vb; VD_BOOST vd; - for (int k = 0; k < NUM_POINTS[i]; ++k) - vb.insert_point(static_cast(gen()), static_cast(gen())); + for (int k = 0; k < NUM_POINTS[i]; ++k) { + int32 x = static_cast(gen()); + int32 y = static_cast(gen()); + vb.insert_point(x, y); + } vb.construct(&vd); } - double time_per_test = timer.elapsed() / NUM_RUNS[i]; + double time_per_test = get_elapsed_secs() / NUM_RUNS[i]; format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); } bf << "\n"; } -void run_cgal_test() { +void run_cgal_delaunay_test() { boost::mt19937 gen(RANDOM_SEED); - bf << "CGAL Triangulation of Points:\n"; + bf << "CGAL Delaunay Triangulation of Points:\n"; for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { - SDT_CGAL dt; + DT_CGAL dt; + std::vector points; for (int k = 0; k < NUM_POINTS[i]; ++k) { - dt.insert(Point_CGAL( - static_cast(gen()), static_cast(gen()))); + int32 x = static_cast(gen()); + int32 y = static_cast(gen()); + points.push_back(POINT_CGAL(x, y)); } + // CGAL's implementation sorts points along + // the Hilbert curve implicitly to improve + // spatial ordering of the input geometries. + dt.insert(points.begin(), points.end()); } - double time_per_test = timer.elapsed() / NUM_RUNS[i]; + double time_per_test = get_elapsed_secs() / NUM_RUNS[i]; format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); } bf << "\n"; } -void run_shull_test() { +void run_shull_delaunay_test() { boost::mt19937 gen(RANDOM_SEED); - bf << "S-Hull Triangulation of Points:\n"; + bf << "S-Hull Delaunay Triangulation of Points:\n"; // This value is required by S-Hull as it doesn't seem to support properly // coordinates with the absolute value higher than 100. float koef = 100.0 / (1 << 16) / (1 << 15); for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { // S-Hull doesn't deal properly with duplicates so we need // to eliminate them before running the algorithm. @@ -124,7 +134,7 @@ void run_shull_test() { } s_hull_del_ray2(pts, triads); } - double time_per_test = timer.elapsed() / NUM_RUNS[i]; + double time_per_test = get_elapsed_secs() / NUM_RUNS[i]; format_line(NUM_POINTS[i], NUM_RUNS[i], time_per_test); } bf << "\n"; @@ -133,9 +143,9 @@ void run_shull_test() { int main() { bf << std::setiosflags(std::ios::right | std::ios::fixed) << std::setprecision(6); - run_boost_test(); - run_cgal_test(); - run_shull_test(); + run_boost_voronoi_test(); + run_cgal_delaunay_test(); + run_shull_delaunay_test(); bf.close(); return 0; } diff --git a/benchmark/voronoi_benchmark_segments.cpp b/benchmark/voronoi_benchmark_segments.cpp index 7dd777c..7078020 100644 --- a/benchmark/voronoi_benchmark_segments.cpp +++ b/benchmark/voronoi_benchmark_segments.cpp @@ -16,26 +16,24 @@ #include #include -#include +#include typedef boost::int32_t int32; +using boost::timer::cpu_times; +using boost::timer::nanosecond_type; // Include for the Boost.Polygon Voronoi library. #include typedef boost::polygon::voronoi_diagram VD_BOOST; // Includes for the CGAL library. -#include -#include #include #include #include -typedef CGAL::Quotient ENT; -typedef CGAL::Simple_cartesian CK; -typedef CGAL::Simple_cartesian EK; -typedef CGAL::Segment_Delaunay_graph_filtered_traits_2< - CK, CGAL::Field_with_sqrt_tag, EK, CGAL::Field_tag> Gt; -typedef CGAL::Segment_Delaunay_graph_2 SDT_CGAL; + +typedef CGAL::Simple_cartesian K; +typedef CGAL::Segment_Delaunay_graph_filtered_traits_without_intersections_2 GT; +typedef CGAL::Segment_Delaunay_graph_2 SDT_CGAL; typedef SDT_CGAL::Point_2 Point_CGAL; typedef SDT_CGAL::Site_2 Site_CGAL; @@ -51,7 +49,7 @@ const int NUM_SEGMENTS[] = {10, 100, 1000, 10000, 100000, 1000000}; const int NUM_RUNS[] = {100000, 10000, 1000, 100, 10, 1}; std::ofstream bf("benchmark_segments.txt", std::ios_base::out | std::ios_base::app); -boost::timer timer; +boost::timer::cpu_timer timer; void format_line(int num_points, int num_tests, double time_per_test) { bf << "| " << std::setw(16) << num_points << " "; @@ -60,7 +58,13 @@ void format_line(int num_points, int num_tests, double time_per_test) { bf << "|" << std::endl; } -void clean_segment_set(std::vector &data) { +double get_elapsed_secs() { + cpu_times elapsed_times(timer.elapsed()); + return 1E-9 * static_cast( + elapsed_times.system + elapsed_times.user); +} + +void clean_segment_set(std::vector* data) { typedef int32 Unit; typedef boost::polygon::scanline_base::Point Point; typedef boost::polygon::scanline_base::half_edge half_edge; @@ -68,9 +72,9 @@ void clean_segment_set(std::vector &data) { std::vector > half_edges; std::vector > half_edges_out; segment_id id = 0; - half_edges.reserve(data.size()); - for (std::vector::iterator it = data.begin(); - it != data.end(); ++it) { + half_edges.reserve(data->size()); + for (std::vector::iterator it = data->begin(); + it != data->end(); ++it) { POINT_POLYGON l = it->low(); POINT_POLYGON h = it->high(); half_edges.push_back(std::make_pair(half_edge(l, h), id++)); @@ -85,19 +89,19 @@ void clean_segment_set(std::vector &data) { id = half_edges_out[i].second; POINT_POLYGON l = half_edges_out[i].first.first; POINT_POLYGON h = half_edges_out[i].first.second; - SEGMENT_POLYGON orig_seg = data[id]; + SEGMENT_POLYGON orig_seg = data->at(id); if (orig_seg.high() < orig_seg.low()) std::swap(l, h); result.push_back(SEGMENT_POLYGON(l, h)); } - std::swap(result, data); + std::swap(result, *data); } std::vector get_intersection_runtime() { std::vector running_times; boost::mt19937 gen(RANDOM_SEED); for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { SSD_POLYGON ssd; for (int k = 0; k < NUM_SEGMENTS[i]; ++k) { @@ -108,18 +112,18 @@ std::vector get_intersection_runtime() { ssd.push_back(SEGMENT_POLYGON( POINT_POLYGON(x1, y1), POINT_POLYGON(x1 + dx, y1 + dy))); } - clean_segment_set(ssd); + clean_segment_set(&ssd); } - running_times.push_back(timer.elapsed()); + running_times.push_back(get_elapsed_secs()); } return running_times; } -void run_voronoi_test(const std::vector &running_times) { +void run_boost_voronoi_test(const std::vector &running_times) { boost::mt19937 gen(RANDOM_SEED); bf << "Boost.Polygon Voronoi of Segments:\n"; for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { SSD_POLYGON ssd; VD_BOOST vd; @@ -129,22 +133,24 @@ void run_voronoi_test(const std::vector &running_times) { int32 dx = (gen() & 1023) + 1; int32 dy = (gen() & 1023) + 1; ssd.push_back(SEGMENT_POLYGON( - POINT_POLYGON(x1, y1), POINT_POLYGON(x1 + dx, y1 + dy))); + POINT_POLYGON(x1, y1), + POINT_POLYGON(x1 + dx, y1 + dy))); } - clean_segment_set(ssd); + clean_segment_set(&ssd); boost::polygon::construct_voronoi(ssd.begin(), ssd.end(), &vd); } - double time_per_test = (timer.elapsed() - running_times[i]) / NUM_RUNS[i]; + double time_per_test = + (get_elapsed_secs() - running_times[i]) / NUM_RUNS[i]; format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test); } bf << "\n"; } -void run_cgal_test(const std::vector &running_times) { +void run_cgal_delaunay_test(const std::vector &running_times) { boost::mt19937 gen(RANDOM_SEED); bf << "CGAL Triangulation of Segments:\n"; for (int i = 0; i < NUM_TESTS; ++i) { - timer.restart(); + timer.start(); for (int j = 0; j < NUM_RUNS[i]; ++j) { SSD_POLYGON ssd; for (int k = 0; k < NUM_SEGMENTS[i]; ++k) { @@ -152,18 +158,37 @@ void run_cgal_test(const std::vector &running_times) { int32 y1 = gen(); int32 dx = (gen() & 1023) + 1; int32 dy = (gen() & 1023) + 1; - ssd.push_back(SEGMENT_POLYGON(POINT_POLYGON(x1, y1), - POINT_POLYGON(x1 + dx, y1 + dy))); + ssd.push_back(SEGMENT_POLYGON( + POINT_POLYGON(x1, y1), + POINT_POLYGON(x1 + dx, y1 + dy))); } - clean_segment_set(ssd); - SDT_CGAL dt; + clean_segment_set(&ssd); + + typedef std::vector Points_container; + typedef std::vector::size_type Index_type; + typedef std::vector< std::pair > Constraints_container; + Points_container points; + Constraints_container constraints; + points.reserve(ssd.size() * 2); + constraints.reserve(ssd.size()); for (SSD_POLYGON::iterator it = ssd.begin(); it != ssd.end(); ++it) { - dt.insert(Site_CGAL::construct_site_2( - Point_CGAL(it->low().x(), it->low().y()), - Point_CGAL(it->high().x(), it->high().y()))); + points.push_back(Point_CGAL( + boost::polygon::x(it->low()), + boost::polygon::y(it->low()))); + points.push_back(Point_CGAL( + boost::polygon::x(it->high()), + boost::polygon::y(it->high()))); + constraints.push_back( + std::make_pair(points.size() - 2, points.size() - 1)); } + + SDT_CGAL sdg; + sdg.insert_segments( + points.begin(), points.end(), + constraints.begin(), constraints.end()); } - double time_per_test = (timer.elapsed() - running_times[i]) / NUM_RUNS[i]; + double time_per_test = + (get_elapsed_secs() - running_times[i]) / NUM_RUNS[i]; format_line(NUM_SEGMENTS[i], NUM_RUNS[i], time_per_test); } bf << "\n"; @@ -173,8 +198,8 @@ int main() { bf << std::setiosflags(std::ios::right | std::ios::fixed) << std::setprecision(6); std::vector running_times = get_intersection_runtime(); - run_voronoi_test(running_times); - run_cgal_test(running_times); + run_boost_voronoi_test(running_times); + run_cgal_delaunay_test(running_times); bf.close(); return 0; } diff --git a/doc/gtl_polygon_90_set_concept.htm b/doc/gtl_polygon_90_set_concept.htm index 127d5c4..a3829c3 100644 --- a/doc/gtl_polygon_90_set_concept.htm +++ b/doc/gtl_polygon_90_set_concept.htm @@ -1,28 +1,18 @@ - - - - Boost Polygon Library: Polygon 90 Set Concept - - - - - +-->Boost Polygon Library: Polygon 90 Set Concept + + + + + +
      - -
      - + +
        @@ -77,14 +67,9 @@ Tutorial
      - +
      +

      @@ -110,16 +95,13 @@ vectors of models of polygon_90_concept or polygon_90_with_holes_concept or rectangle_concept are automatically models of polygon_90_set_concept.

      Operators

      -

      The return type of some operators is the polygon_90_set_view operator template +

      The return type of some operators is the polygon_90_set_view operator template type.  This type is itself a model of the polygon_90_set concept, -but furthermore can be used as an argument to the polygon_90_set_data constructor and +but furthermore can be used as an argument to the polygon_90_set_data constructor and assignment operator.  The operator template exists to eliminate temp copies of intermediate results when Boolean operators are chained together.

      -

      Operators are declared inside the namespace boost::polygon::operators.

      +

      Operators are declared inside the namespace boost::polygon::operators.

      @@ -773,6 +755,22 @@ points is equal to the number of edges.  O( n log n) runtime complexity and O(n) memory wrt vertices + intersections. + + + + @@ -915,8 +913,7 @@ runtime complexity and O(n) memory wrt vertices + intersections. @@ -985,14 +982,10 @@ vertices + intersections. - - +
      template +<typename output_container>
      +void get(output_container& output, size_t k) const
      Expects a standard +container of geometry objects.  Will scan and eliminate +overlaps.  Converts polygon set geometry to objects of that type +and appends them to the container.  The resulting polygons will +have at most k vertices. For Manhattan data k should be at least 4 . +Polygons will be output with counterclockwise winding, hole polygons +will be output with clockwise winding.  The last vertex of an +output polygon is not the duplicate of the first, and the number of +points is equal to the number of edges.  O( n log n) runtime +complexity and O(n) memory wrt vertices + intersections.
      +
      template <typename output_container>
      void get_polygons(output_container& output) const
      polygon_90_set_data& - move(coordinate_type x_delta,
      -                          + move(coordinate_type x_delta,
                                coordinate_type y_delta)
      Add x_delta to x values and y_delta to y values of vertices stored within the polygon set.  Linear wrt. vertices.
        +   - + @@ -1000,10 +993,7 @@ vertices + intersections. @@ -1012,5 +1002,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Intel Corporation 2008-2010.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - + + \ No newline at end of file diff --git a/include/boost/polygon/detail/polygon_45_touch.hpp b/include/boost/polygon/detail/polygon_45_touch.hpp index c584f52..90717e1 100644 --- a/include/boost/polygon/detail/polygon_45_touch.hpp +++ b/include/boost/polygon/detail/polygon_45_touch.hpp @@ -65,8 +65,8 @@ namespace boost { namespace polygon{ inline CountTouch& operator=(const CountTouch& count) { counts = count.counts; return *this; } inline int& operator[](int index) { std::vector >::iterator itr = - std::lower_bound(counts.begin(), counts.end(), - std::make_pair(index, int(0))); + std::lower_bound(counts.begin(), counts.end(), + std::make_pair(index, int(0))); if(itr != counts.end() && itr->first == index) { return itr->second; } diff --git a/include/boost/polygon/detail/polygon_formation.hpp b/include/boost/polygon/detail/polygon_formation.hpp index a9490ce..be2f543 100644 --- a/include/boost/polygon/detail/polygon_formation.hpp +++ b/include/boost/polygon/detail/polygon_formation.hpp @@ -1,10 +1,12 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). */ +#include +#include #ifndef BOOST_POLYGON_POLYGON_FORMATION_HPP #define BOOST_POLYGON_POLYGON_FORMATION_HPP namespace boost { namespace polygon{ @@ -25,24 +27,24 @@ namespace polygon_formation { * TAIL End is represented by true because TAIL comes after head and 1 after 0 */ const End TAIL = true; - + /* * 2D turning direction, left and right sides (is a boolean value since it has two states.) */ typedef bool Side; - + /* * LEFT Side is 0 because we inuitively think left to right; left < right */ const Side LEFT = false; - + /* * RIGHT Side is 1 so that right > left */ const Side RIGHT = true; /* - * The PolyLine class is data storage and services for building and representing partial polygons. + * The PolyLine class is data storage and services for building and representing partial polygons. * As the polyline is added to it extends its storage to accomodate the data. * PolyLines can be joined head-to-head/head-to-tail when it is determined that two polylines are * part of the same polygon. @@ -59,14 +61,14 @@ namespace polygon_formation { class PolyLine { private: //data - + /* * ptdata_ a vector of coordiantes * if VERTICAL_HEAD, first coordiante is an X * else first coordinate is a Y */ std::vector ptdata_; - + /* * head and tail points to other polylines before and after this in a chain */ @@ -87,18 +89,18 @@ namespace polygon_formation { * default constructor (for preallocation) */ PolyLine(); - + /* * constructor that takes the orientation, coordiante and side to which there is solid */ PolyLine(orientation_2d orient, Unit coord, Side side); - + //copy constructor PolyLine(const PolyLine& pline); - + //destructor ~PolyLine(); - + //assignment operator PolyLine& operator=(const PolyLine& that); @@ -118,18 +120,18 @@ namespace polygon_formation { /* * returns true if first coordinate is an X value (first segment is vertical) */ - bool verticalHead() const; + bool verticalHead() const; /* * returns the orientation_2d fo the tail */ orientation_2d tailOrient() const; - + /* * returns true if last coordinate is an X value (last segment is vertical) */ bool verticalTail() const; - + /* * retrun true if PolyLine has odd number of coordiantes */ @@ -157,7 +159,7 @@ namespace polygon_formation { * retrun true if the tail of this polyline is connect to the head of a polyline */ bool tailToHead() const; - + /* * retrun the side on which there is solid for this polyline */ @@ -177,12 +179,12 @@ namespace polygon_formation { * adds a coordinate value to the end of the polyline changing the tail orientation */ PolyLine& pushCoordinate(Unit coord); - + /* * removes a coordinate value at the end of the polyline changing the tail orientation */ PolyLine& popCoordinate(); - + /* * extends the tail of the polyline to include the point, changing orientation if needed */ @@ -299,7 +301,7 @@ namespace polygon_formation { * that edge is supposed to be solid or space. Any incomplete polygon will have two active tails. Active tails * may be joined together to merge two incomplete polygons into a larger incomplete polygon. If two active tails * that are to be merged are the oppositve ends of the same incomplete polygon that indicates that the polygon - * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete + * has been closed and is complete. The active tail keeps a pointer to the other active tail of its incomplete * polygon so that it is easy to check this condition. These pointers are updated when active tails are joined. * The active tail also keeps a list of pointers to active tail objects that serve as handles to closed holes. In * this way a hole can be associated to another incomplete polygon, which will eventually be its enclosing shell, @@ -314,11 +316,25 @@ namespace polygon_formation { class ActiveTail { private: //data - PolyLine* tailp_; + PolyLine* tailp_; ActiveTail *otherTailp_; std::list holesList_; + //Sum of all the polylines which constitute the active tail (including holes)// + size_t polyLineSize_; public: + inline size_t getPolyLineSize(){ + return polyLineSize_; + } + + inline void setPolyLineSize(int delta){ + polyLineSize_ = delta; + } + + inline void addPolyLineSize(int delta){ + polyLineSize_ += delta; + } + /* * iterator over coordinates of the figure */ @@ -331,7 +347,7 @@ namespace polygon_formation { End startEnd_; public: inline iterator() : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() {} - inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : + inline iterator(const ActiveTail* at, bool isHole, orientation_2d orient) : pLine_(), pLineEnd_(), index_(), indexEnd_(), startEnd_() { //if it is a hole and orientation is vertical or it is not a hole and orientation is horizontal //we want to use this active tail, otherwise we want to use the other active tail @@ -343,7 +359,10 @@ namespace polygon_formation { //now we have the right winding direction //if it is horizontal we need to skip the first element pLine_ = at->getTail(); - index_ = at->getTail()->numSegments() - 1; + + if(at->getTail()->numSegments() > 0) + index_ = at->getTail()->numSegments() - 1; + if((at->getOrient() == HORIZONTAL) ^ (orient == HORIZONTAL)) { pLineEnd_ = at->getTail(); indexEnd_ = pLineEnd_->numSegments() - 1; @@ -358,10 +377,27 @@ namespace polygon_formation { } else { --index_; } } else { pLineEnd_ = at->getOtherActiveTail()->getTail(); + if(pLineEnd_->numSegments() > 0) indexEnd_ = pLineEnd_->numSegments() - 1; } at->getTail()->joinTailToTail(*(at->getOtherActiveTail()->getTail())); } + + inline size_t size(void){ + size_t count = 0; + End dir = startEnd_; + PolyLine const * currLine = pLine_; + size_t ops = 0; + while(currLine != pLineEnd_){ + ops++; + count += currLine->numSegments(); + currLine = currLine->next(dir == HEAD ? TAIL : HEAD); + dir = currLine->endConnectivity(dir == HEAD ? TAIL : HEAD); + } + count += pLineEnd_->numSegments(); + return count; //no. of vertices + } + //use bitwise copy and assign provided by the compiler inline iterator& operator++() { if(pLine_ == pLineEnd_ && index_ == indexEnd_) { @@ -560,7 +596,7 @@ namespace polygon_formation { /* deallocate an activetail object */ template void destroyActiveTail(ActiveTail* aTail); - + template class PolyLineHoleData { private: @@ -576,7 +612,9 @@ namespace polygon_formation { inline compact_iterator_type end_compact() const { return p_->end(); } inline iterator_type begin() const { return iterator_type(begin_compact(), end_compact()); } inline iterator_type end() const { return iterator_type(end_compact(), end_compact()); } - inline std::size_t size() const { return 0; } + inline std::size_t size() const { + return p_->getPolyLineSize(); + } inline ActiveTail* yield() { return p_; } template inline PolyLineHoleData& set(iT inputBegin, iT inputEnd) { @@ -586,7 +624,7 @@ namespace polygon_formation { inline PolyLineHoleData& set_compact(iT inputBegin, iT inputEnd) { return *this; } - + }; template @@ -646,7 +684,7 @@ namespace polygon_formation { inline PolyLinePolygonWithHolesData& set_compact(iT inputBegin, iT inputEnd) { return *this; } - + // initialize a polygon from x,y values, it is assumed that the first is an x // and that the input is a well behaved polygon template @@ -679,18 +717,83 @@ namespace polygon_formation { std::vector outputPolygons_; bool fractureHoles_; public: - typedef typename std::vector::iterator iterator; + typedef typename std::vector::iterator iterator; inline ScanLineToPolygonItrs() : tailMap_(), outputPolygons_(), fractureHoles_(false) {} /* construct a scanline with the proper offsets, protocol and options */ inline ScanLineToPolygonItrs(bool fractureHoles) : tailMap_(), outputPolygons_(), fractureHoles_(fractureHoles) {} - + ~ScanLineToPolygonItrs() { clearOutput_(); } - + /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ - void processEdges(iterator& beginOutput, iterator& endOutput, - Unit currentX, std::vector >& leftEdges, - std::vector >& rightEdges); + void processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, + std::vector >& rightEdges, + size_t vertexThreshold=(std::numeric_limits::max)() ); + + /********************************************************************** + *methods implementing new polygon formation code + * + **********************************************************************/ + void updatePartialSimplePolygonsWithRightEdges(Unit currentX, + const std::vector >& leftEdges, size_t threshold); + void updatePartialSimplePolygonsWithLeftEdges(Unit currentX, + const std::vector >& leftEdges, size_t threshold); + + void closePartialSimplePolygon(Unit, ActiveTail*, ActiveTail*); + + void maintainPartialSimplePolygonInvariant(iterator& ,iterator& ,Unit, + const std::vector >&, + const std::vector >&, + size_t vertexThreshold=(std::numeric_limits::max)()); + + void insertNewLeftEdgeIntoTailMap(Unit, Unit, Unit, + typename std::map*>::iterator &); + /**********************************************************************/ + + inline size_t getTailMapSize(){ + typename std::map* >::const_iterator itr; + size_t tsize = 0; + for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ + tsize += (itr->second)->getPolyLineSize(); + } + return tsize; + } + /*print the active tails in this map:*/ + inline void print(){ + typename std::map* >::const_iterator itr; + printf("=========TailMap[%lu]=========\n", tailMap_.size()); + for(itr=tailMap_.begin(); itr!=tailMap_.end(); ++itr){ + std::cout<< "[" << itr->first << "] : " << std::endl; + //print active tail// + ActiveTail const *t = (itr->second); + PolyLine const *pBegin = t->getTail(); + PolyLine const *pEnd = t->getOtherActiveTail()->getTail(); + std::string sorient = pBegin->solidToRight() ? "RIGHT" : "LEFT"; + std::cout<< " ActiveTail.tailp_ (solid= " << sorient ; + End dir = TAIL; + while(pBegin!=pEnd){ + std::cout << pBegin << "={ "; + for(size_t i=0; inumSegments(); i++){ + point_data u = pBegin->getPoint(i); + std::cout << "(" << u.x() << "," << u.y() << ") "; + } + std::cout << "} "; + pBegin = pBegin->next(dir == HEAD ? TAIL : HEAD); + dir = pBegin->endConnectivity(dir == HEAD ? TAIL : HEAD); + } + if(pEnd){ + std::cout << pEnd << "={ "; + for(size_t i=0; inumSegments(); i++){ + point_data u = pEnd->getPoint(i); + std::cout << "(" << u.x() << "," << u.y() << ") "; + } + std::cout << "} "; + } + std::cout << " end= " << pEnd << std::endl; + } + } + private: void clearOutput_(); }; @@ -706,9 +809,9 @@ namespace polygon_formation { // inline ScanLineToPolygons() : scanline_() {} // /* construct a scanline with the proper offsets, protocol and options */ // inline ScanLineToPolygons(bool fractureHoles) : scanline_(fractureHoles) {} - + // /* process all vertical edges, left and right, at a unique x coordinate, edges must be sorted low to high */ -// inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, +// inline void processEdges(std::vector& outBufferTmp, Unit currentX, std::vector >& leftEdges, // std::vector >& rightEdges) { // typename ScanLineToPolygonItrs::iterator itr, endItr; // scanline_.processEdges(itr, endItr, currentX, leftEdges, rightEdges); @@ -754,12 +857,12 @@ namespace polygon_formation { //constructor template - inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : + inline PolyLine::PolyLine(orientation_2d orient, Unit coord, Side side) : ptdata_(1, coord), headp_(0), tailp_(0), state_(orient.to_int() + - (side << 3)) {} + (side << 3)){} //copy constructor template @@ -796,7 +899,7 @@ namespace polygon_formation { //valid PolyLine template - inline bool PolyLine::isValid() const { + inline bool PolyLine::isValid() const { return state_ > -1; } //first coordinate is an X value @@ -818,7 +921,7 @@ namespace polygon_formation { inline bool PolyLine::verticalTail() const { return to_bool(verticalHead() ^ oddLength()); } - + template inline orientation_2d PolyLine::tailOrient() const { return (verticalTail() ? VERTICAL : HORIZONTAL); @@ -850,16 +953,16 @@ namespace polygon_formation { inline bool PolyLine::tailToHead() const { return to_bool(!tailToTail()); } - + template inline bool PolyLine::tailToTail() const { return to_bool(state_ & TAIL_TO_TAIL); } template - inline Side PolyLine::solidSide() const { + inline Side PolyLine::solidSide() const { return solidToRight(); } - + template inline bool PolyLine::solidToRight() const { return to_bool(state_ & SOLID_TO_RIGHT) != 0; @@ -884,12 +987,14 @@ namespace polygon_formation { template inline PolyLine& PolyLine::pushPoint(const point_data& point) { - point_data endPt = getEndPoint(); - //vertical is true, horizontal is false - if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { - //we were pushing a colinear segment - return popCoordinate(); - } + if(numSegments()){ + point_data endPt = getEndPoint(); + //vertical is true, horizontal is false + if((tailOrient().to_int() ? point.get(VERTICAL) == endPt.get(VERTICAL) : point.get(HORIZONTAL) == endPt.get(HORIZONTAL))) { + //we were pushing a colinear segment + return popCoordinate(); + } + } return pushCoordinate(tailOrient().to_int() ? point.get(VERTICAL) : point.get(HORIZONTAL)); } @@ -1007,28 +1112,31 @@ namespace polygon_formation { } template - inline ActiveTail::ActiveTail() : tailp_(0), otherTailp_(0), holesList_() {} + inline ActiveTail::ActiveTail() : tailp_(0), otherTailp_(0), holesList_(), + polyLineSize_(0) {} template - inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : - tailp_(0), otherTailp_(0), holesList_() { + inline ActiveTail::ActiveTail(orientation_2d orient, Unit coord, Side solidToRight, ActiveTail* otherTailp) : + tailp_(0), otherTailp_(0), holesList_(), polyLineSize_(0) { tailp_ = createPolyLine(orient, coord, solidToRight); otherTailp_ = otherTailp; + polyLineSize_ = tailp_->numSegments(); } template - inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : - tailp_(active), otherTailp_(otherTailp), holesList_() {} + inline ActiveTail::ActiveTail(PolyLine* active, ActiveTail* otherTailp) : + tailp_(active), otherTailp_(otherTailp), holesList_(), + polyLineSize_(0) {} //copy constructor template - inline ActiveTail::ActiveTail(const ActiveTail& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_() {} + inline ActiveTail::ActiveTail(const ActiveTail& that) : tailp_(that.tailp_), otherTailp_(that.otherTailp_), holesList_(), polyLineSize_(that.polyLineSize_) {} //destructor template - inline ActiveTail::~ActiveTail() { + inline ActiveTail::~ActiveTail() { //clear them in case the memory is read later - tailp_ = 0; otherTailp_ = 0; + tailp_ = 0; otherTailp_ = 0; } template @@ -1036,6 +1144,7 @@ namespace polygon_formation { //self assignment is safe in this case tailp_ = that.tailp_; otherTailp_ = that.otherTailp_; + polyLineSize_ = that.polyLineSize_; return *this; } @@ -1050,45 +1159,50 @@ namespace polygon_formation { } template - inline bool ActiveTail::operator<=(const ActiveTail& b) const { + inline bool ActiveTail::operator<=(const ActiveTail& b) const { return !(*this > b); } - + template - inline bool ActiveTail::operator>(const ActiveTail& b) const { + inline bool ActiveTail::operator>(const ActiveTail& b) const { return b < (*this); } - + template - inline bool ActiveTail::operator>=(const ActiveTail& b) const { + inline bool ActiveTail::operator>=(const ActiveTail& b) const { return !(*this < b); } template - inline PolyLine* ActiveTail::getTail() const { + inline PolyLine* ActiveTail::getTail() const { return tailp_; } template - inline PolyLine* ActiveTail::getOtherTail() const { + inline PolyLine* ActiveTail::getOtherTail() const { return otherTailp_->tailp_; } template - inline ActiveTail* ActiveTail::getOtherActiveTail() const { + inline ActiveTail* ActiveTail::getOtherActiveTail() const { return otherTailp_; } template inline bool ActiveTail::isOtherTail(const ActiveTail& b) { // assert( (tailp_ == b.getOtherTail() && getOtherTail() == b.tailp_) || - // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) + // (tailp_ != b.getOtherTail() && getOtherTail() != b.tailp_)) // ("ActiveTail: Active tails out of sync"); return otherTailp_ == &b; } template inline ActiveTail& ActiveTail::updateTail(PolyLine* newTail) { + //subtract the old size and add new size// + int delta = newTail->numSegments() - tailp_->numSegments(); + addPolyLineSize(delta); + otherTailp_->addPolyLineSize(delta); tailp_ = newTail; return *this; } template inline ActiveTail* ActiveTail::addHole(ActiveTail* hole, bool fractureHoles) { + if(!fractureHoles){ holesList_.push_back(hole); copyHoles(*hole); @@ -1100,7 +1214,7 @@ namespace polygon_formation { if(other->getOrient() == VERTICAL) { //assert that hole.getOrient() == HORIZONTAL //this case should never happen - h = hole; + h = hole; v = other; } else { //assert that hole.getOrient() == VERTICAL @@ -1128,30 +1242,34 @@ namespace polygon_formation { } template - inline bool ActiveTail::solidToRight() const { + inline bool ActiveTail::solidToRight() const { return getTail()->solidToRight(); } template - inline Unit ActiveTail::getCoord() const { + inline Unit ActiveTail::getCoord() const { return getTail()->getEndCoord(); } + + template + inline Unit ActiveTail::getCoordinate() const { + return getCoord(); } template - inline Unit ActiveTail::getCoordinate() const { - return getCoord(); } - - template - inline orientation_2d ActiveTail::getOrient() const { + inline orientation_2d ActiveTail::getOrient() const { return getTail()->tailOrient(); } template - inline void ActiveTail::pushCoordinate(Unit coord) { + inline void ActiveTail::pushCoordinate(Unit coord) { //appropriately handle any co-linear polyline segments by calling push point internally point_data p; p.set(HORIZONTAL, coord); p.set(VERTICAL, coord); //if we are vertical assign the last coordinate (an X) to p.x, else to p.y p.set(getOrient().get_perpendicular(), getCoordinate()); + int oldSegments = tailp_->numSegments(); tailp_->pushPoint(p); + int delta = tailp_->numSegments() - oldSegments; + addPolyLineSize(delta); + otherTailp_->addPolyLineSize(delta); } @@ -1241,16 +1359,16 @@ namespace polygon_formation { if((getOrient() == HORIZONTAL) ^ !isHole) { //our first coordinate is a y value, so we need to rotate it to the end typename std::vector::iterator tmpItr = outVec.begin(); - tmpItr += size; + tmpItr += size; outVec.erase(++tmpItr); //erase the 2nd element } End startEnd = tailp_->endConnectivity(HEAD); if(isHole) startEnd = otherTailp_->tailp_->endConnectivity(HEAD); while(nextPolyLinep) { bool nextStartEnd = nextPolyLinep->endConnectivity(!startEnd); - nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); + nextPolyLinep = nextPolyLinep->writeOut(outVec, startEnd); startEnd = nextStartEnd; - } + } if((getOrient() == HORIZONTAL) ^ !isHole) { //we want to push the y value onto the end since we ought to have ended with an x outVec.push_back(firsty); //should never be executed because we want first value to be an x @@ -1284,7 +1402,7 @@ namespace polygon_formation { //solid indicates if it was joined by a solit or a space template - inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ @@ -1324,6 +1442,11 @@ namespace polygon_formation { at1->getTail()->joinTailToTail(*(at2->getTail())); *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); + + int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); + (at1->getOtherActiveTail())->setPolyLineSize(accumulate); + (at2->getOtherActiveTail())->setPolyLineSize(accumulate); + at1->getOtherActiveTail()->copyHoles(*at1); at1->getOtherActiveTail()->copyHoles(*at2); destroyActiveTail(at1); @@ -1334,7 +1457,7 @@ namespace polygon_formation { //solid indicates if it was joined by a solit or a space template template - inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, + inline ActiveTail* ActiveTail::joinChains(ActiveTail* at1, ActiveTail* at2, bool solid, std::vector& outBufferTmp) { //checks to see if we closed a figure if(at1->isOtherTail(*at2)){ @@ -1348,7 +1471,7 @@ namespace polygon_formation { //because otherwise it would have to have another vertex to the right of this one //and would not be closed at this point return at1; - } else { + } else { //assert pG != 0 //the figure that was closed is a shell outBufferTmp.push_back(at1); @@ -1360,6 +1483,11 @@ namespace polygon_formation { at1->getTail()->joinTailToTail(*(at2->getTail())); *(at1->getOtherActiveTail()) = ActiveTail(at1->getOtherTail(), at2->getOtherActiveTail()); *(at2->getOtherActiveTail()) = ActiveTail(at2->getOtherTail(), at1->getOtherActiveTail()); + + int accumulate = at2->getPolyLineSize() + at1->getPolyLineSize(); + (at1->getOtherActiveTail())->setPolyLineSize(accumulate); + (at2->getOtherActiveTail())->setPolyLineSize(accumulate); + at1->getOtherActiveTail()->copyHoles(*at1); at1->getOtherActiveTail()->copyHoles(*at2); destroyActiveTail(at1); @@ -1367,8 +1495,8 @@ namespace polygon_formation { return 0; } - template inline typename std::map::iterator findAtNext(std::map& theMap, - typename std::map::iterator pos, const TKey& key) + template inline typename std::map::iterator findAtNext(std::map& theMap, + typename std::map::iterator pos, const TKey& key) { if(pos == theMap.end()) return theMap.find(key); //if they match the mapItr is pointing to the correct position @@ -1377,22 +1505,22 @@ namespace polygon_formation { } if(pos->first > key) { return theMap.end(); - } + } //else they are equal and no need to do anything to the iterator return pos; } // createActiveTailsAsPair is called in these two end cases of geometry // 1. lower left concave corner + // ###| // ###| - // ###| - // ###|### + // ###|### // ###|### // 2. lower left convex corner - // |### - // |### - // | - // | + // |### + // |### + // | + // | // In case 1 there may be a hole propigated up from the bottom. If the fracture option is enabled // the two active tails that form the filament fracture line edges can become the new active tail pair // by pushing x and y onto them. Otherwise the hole simply needs to be associated to one of the new active tails @@ -1408,7 +1536,11 @@ namespace polygon_formation { (*at2) = ActiveTail(HORIZONTAL, y, !solid, at1); //provide a function through activeTail class to provide this at1->getTail()->joinHeadToHead(*(at2->getTail())); - if(phole) + + at1->addPolyLineSize(1); + at2->addPolyLineSize(1); + + if(phole) at1->addHole(phole, fractureHoles); //assert fractureHoles == false return std::pair*, ActiveTail*>(at1, at2); } @@ -1425,118 +1557,486 @@ namespace polygon_formation { at1->pushCoordinate(x); //assert at2 is vertical at2->pushCoordinate(y); + return std::pair*, ActiveTail*>(at1, at2); } + /* + * | + * | + * = + * |######## + * |######## (add a new ActiveTail in the tailMap_). + * |######## + * |######## + * |######## + * = + * | + * | + * + * NOTE: Call this only if you are sure that the $ledege$ is not in the tailMap_ + */ + template + inline void ScanLineToPolygonItrs:: + insertNewLeftEdgeIntoTailMap(Unit currentX, Unit yBegin, Unit yEnd, + typename std::map *>::iterator &hint){ + ActiveTail *currentTail = NULL; + std::pair*, ActiveTail*> tailPair = + createActiveTailsAsPair(currentX, yBegin, true, currentTail, + fractureHoles_); + currentTail = tailPair.first; + if(!tailMap_.empty()){ + ++hint; + } + hint = tailMap_.insert(hint, std::make_pair(yBegin, tailPair.second)); + currentTail->pushCoordinate(yEnd); ++hint; + hint = tailMap_.insert(hint, std::make_pair(yEnd, currentTail)); + } + + template + inline void ScanLineToPolygonItrs:: + closePartialSimplePolygon(Unit currentX, ActiveTail*pfig, + ActiveTail*ppfig){ + pfig->pushCoordinate(currentX); + ActiveTail::joinChains(pfig, ppfig, false, outputPolygons_); + } + /* + * If the invariant is maintained correctly then left edges can do the + * following. + * + * =### + * ####### + * ####### + * ####### + * ####### + * =### + * |### (input left edge) + * |### + * =### + * ####### + * ####### + * =### + */ + template + inline void ScanLineToPolygonItrs:: + updatePartialSimplePolygonsWithLeftEdges(Unit currentX, + const std::vector > &leftEdges, size_t vertexThreshold){ + typename std::map* >::iterator succ, succ1; + typename std::map* >::iterator pred, pred1, hint; + Unit begin, end; + ActiveTail *pfig, *ppfig; + std::pair*, ActiveTail*> tailPair; + size_t pfig_size = 0; + + hint = tailMap_.begin(); + for(size_t i=0; i < leftEdges.size(); i++){ + begin = leftEdges[i].get(LOW); end = leftEdges[i].get(HIGH); + succ = findAtNext(tailMap_, hint, begin); + pred = findAtNext(tailMap_, hint, end); + + if(succ != tailMap_.end() && pred != tailMap_.end()){ //CASE-1// + //join the corresponding active tails// + pfig = succ->second; ppfig = pred->second; + pfig_size = pfig->getPolyLineSize() + ppfig->getPolyLineSize(); + + if(pfig_size >= vertexThreshold){ + size_t bsize = pfig->getPolyLineSize(); + size_t usize = ppfig->getPolyLineSize(); + + if(usize+2 < vertexThreshold){ + //cut-off the lower piece (succ1, succ) join (succ1, pred)// + succ1 = succ; --succ1; + assert((succ1 != tailMap_.end()) && + ((succ->second)->getOtherActiveTail() == succ1->second)); + closePartialSimplePolygon(currentX, succ1->second, succ->second); + tailPair = createActiveTailsAsPair(currentX, succ1->first, + true, NULL, fractureHoles_); + + //just update the succ1 with new ActiveTail*// + succ1->second = tailPair.second; + ActiveTail::joinChains(tailPair.first, pred->second, true, + outputPolygons_); + }else if(bsize+2 < vertexThreshold){ + //cut-off the upper piece () join ()// + pred1 = pred; ++pred1; + assert(pred1 != tailMap_.end() && + ((pred1->second)->getOtherActiveTail() == pred->second)); + closePartialSimplePolygon(currentX, pred->second, pred1->second); + + //just update the pred1 with ActiveTail* = pfig// + pred1->second = pfig; + pfig->pushCoordinate(currentX); + pfig->pushCoordinate(pred1->first); + }else{ + //cut both and create an left edge between (pred->first, succ1)// + succ1 = succ; --succ1; + pred1 = pred; ++pred1; + assert(pred1 != tailMap_.end() && succ1 != tailMap_.end()); + assert((pred1->second)->getOtherActiveTail() == pred->second); + assert((succ1->second)->getOtherActiveTail() == succ->second); + + closePartialSimplePolygon(currentX, succ1->second, succ->second); + closePartialSimplePolygon(currentX, pred->second, pred1->second); + + tailPair = createActiveTailsAsPair(currentX, succ1->first, + true, NULL, fractureHoles_); + succ1->second = tailPair.second; + pred1->second = tailPair.first; + (tailPair.first)->pushCoordinate(pred1->first); + } + }else{ + //just join them with closing// + pfig->pushCoordinate(currentX); + ActiveTail::joinChains(pfig, ppfig, true, outputPolygons_); + } + hint = pred; ++hint; + tailMap_.erase(succ); tailMap_.erase(pred); + }else if(succ == tailMap_.end() && pred != tailMap_.end()){ //CASE-2// + //succ is missing in the map, first insert it into the map// + tailPair = createActiveTailsAsPair(currentX, begin, true, NULL, + fractureHoles_); + hint = pred; ++hint; + hint = tailMap_.insert(hint, std::make_pair(begin, tailPair.second)); + + pfig = pred->second; + pfig_size = pfig->getPolyLineSize() + 2; + if(pfig_size >= vertexThreshold){ + //cut-off piece from [pred, pred1] , add [begin, pred1]// + pred1 = pred; ++pred1; + assert((pred1 != tailMap_.end()) && + ((pred1->second)->getOtherActiveTail() == pred->second)); + closePartialSimplePolygon(currentX, pred->second, pred1->second); + + //update: we need left edge between (begin, pred1->first)// + pred1->second = tailPair.first; + (tailPair.first)->pushCoordinate(pred1->first); + }else{ + //just join// + ActiveTail::joinChains(tailPair.first, pfig, + true, outputPolygons_); + } + tailMap_.erase(pred); + }else if(succ != tailMap_.end() && pred == tailMap_.end()){ //CASE-3// + //pred is missing in the map, first insert it into the map// + hint = succ; ++hint; + hint = tailMap_.insert(hint, std::make_pair(end, (ActiveTail *) NULL)); + pfig = succ->second; + pfig_size = pfig->getPolyLineSize() + 2; + if(pfig_size >= vertexThreshold){ + //this figure needs cutting here// + succ1 = succ; --succ1; + assert((succ1 != tailMap_.end()) && + (succ1->second == pfig->getOtherActiveTail())); + ppfig = succ1->second; + closePartialSimplePolygon(currentX, ppfig, pfig); + + //update: we need a left edge between (succ1->first, end)// + tailPair = createActiveTailsAsPair(currentX, succ1->first, + true, NULL, fractureHoles_); + succ1->second = tailPair.second; + hint->second = tailPair.first; + (tailPair.first)->pushCoordinate(end); + }else{ + //no cutting needed// + hint->second = pfig; + pfig->pushCoordinate(currentX); + pfig->pushCoordinate(end); + } + tailMap_.erase(succ); + }else{ + //insert both pred and succ// + insertNewLeftEdgeIntoTailMap(currentX, begin, end, hint); + } + } + } + + template + inline void ScanLineToPolygonItrs:: + updatePartialSimplePolygonsWithRightEdges(Unit currentX, + const std::vector > &rightEdges, size_t vertexThreshold) + { + + typename std::map* >::iterator succ, pred, hint; + std::pair*, ActiveTail*> tailPair; + Unit begin, end; + size_t i = 0; + //If rightEdges is non-empty Then tailMap_ is non-empty // + assert(rightEdges.empty() || !tailMap_.empty() ); + + while( i < rightEdges.size() ){ + //find the interval in the tailMap which contains this interval// + pred = tailMap_.lower_bound(rightEdges[i].get(HIGH)); + assert(pred != tailMap_.end()); + succ = pred; --succ; + assert(pred != succ); + end = pred->first; begin = succ->first; + + //we now have a [begin, end] // + bool found_solid_opening = false; + bool erase_succ = true, erase_pred = true; + Unit solid_opening_begin = 0; + Unit solid_opening_end = 0; + size_t j = i+1; + ActiveTail *pfig = succ->second; + ActiveTail *ppfig = pred->second; + size_t partial_fig_size = pfig->getPolyLineSize(); + //Invariant:// + assert(succ->second && (pfig)->getOtherActiveTail() == ppfig); + + hint = succ; + Unit key = rightEdges[i].get(LOW); + if(begin != key){ + found_solid_opening = true; + solid_opening_begin = begin; solid_opening_end = key; + } + + while(j < rightEdges.size() && rightEdges[j].get(HIGH) <= end){ + if(rightEdges[j-1].get(HIGH) != rightEdges[j].get(LOW)){ + if(!found_solid_opening){ + found_solid_opening = true; + solid_opening_begin = rightEdges[j-1].get(HIGH); + solid_opening_end = rightEdges[j].get(LOW); + }else{ + ++hint; + insertNewLeftEdgeIntoTailMap(currentX, + rightEdges[j-1].get(HIGH), rightEdges[j].get(LOW), hint); + } + } + j++; + } + + //trailing edge// + if(end != rightEdges[j-1].get(HIGH)){ + if(!found_solid_opening){ + found_solid_opening = true; + solid_opening_begin = rightEdges[j-1].get(HIGH); solid_opening_end = end; + }else{ + // a solid opening has been found already, we need to insert a new left + // between [rightEdges[j-1].get(HIGH), end] + Unit lbegin = rightEdges[j-1].get(HIGH); + tailPair = createActiveTailsAsPair(currentX, lbegin, true, NULL, + fractureHoles_); + hint = tailMap_.insert(pred, std::make_pair(lbegin, tailPair.second)); + pred->second = tailPair.first; + (tailPair.first)->pushCoordinate(end); + erase_pred = false; + } + } + + size_t vertex_delta = ((begin != solid_opening_begin) && + (end != solid_opening_end)) ? 4 : 2; + + if(!found_solid_opening){ + //just close the figure, TODO: call closePartialPolygon// + pfig->pushCoordinate(currentX); + ActiveTail::joinChains(pfig, ppfig, false, outputPolygons_); + hint = pred; ++hint; + }else if(partial_fig_size+vertex_delta >= vertexThreshold){ + //close the figure and add a pseudo left-edge// + closePartialSimplePolygon(currentX, pfig, ppfig); + assert(begin != solid_opening_begin || end != solid_opening_end); + + if(begin != solid_opening_begin && end != solid_opening_end){ + insertNewLeftEdgeIntoTailMap(currentX, solid_opening_begin, + solid_opening_end, hint); + }else if(begin == solid_opening_begin){ + //we just need to update the succ in the tailMap_// + tailPair = createActiveTailsAsPair(currentX, solid_opening_begin, + true, NULL, fractureHoles_); + succ->second = tailPair.second; + hint = succ; ++hint; + hint = tailMap_.insert(pred, std::make_pair(solid_opening_end, + tailPair.first)); + (tailPair.first)->pushCoordinate(solid_opening_end); + erase_succ = false; + }else{ + //we just need to update the pred in the tailMap_// + tailPair = createActiveTailsAsPair(currentX, solid_opening_begin, + true, NULL, fractureHoles_); + hint = tailMap_.insert(pred, std::make_pair(solid_opening_begin, + tailPair.second)); + pred->second = tailPair.first; + (tailPair.first)->pushCoordinate(solid_opening_end); + erase_pred = false; + } + }else{ + //continue the figure (by adding at-most two new vertices)// + if(begin != solid_opening_begin){ + pfig->pushCoordinate(currentX); + pfig->pushCoordinate(solid_opening_begin); + //insert solid_opening_begin// + hint = succ; ++hint; + hint = tailMap_.insert(hint, std::make_pair(solid_opening_begin, pfig)); + }else{ + erase_succ = false; + } + + if(end != solid_opening_end){ + std::pair*, ActiveTail*> tailPair = + createActiveTailsAsPair(currentX, solid_opening_end, false, + NULL, fractureHoles_); + hint = pred; ++hint; + hint = tailMap_.insert(hint, std::make_pair(solid_opening_end, + tailPair.second)); + ActiveTail::joinChains(tailPair.first, ppfig, false, + outputPolygons_); + }else{ + erase_pred = false; + } + } + + //Remove the pred and succ if necessary// + if(erase_succ){ + tailMap_.erase(succ); + } + if(erase_pred){ + tailMap_.erase(pred); + } + i = j; + } + } + + // Maintains the following invariant: + // a. All the partial polygons formed at any state can be closed + // by a single edge. + template + inline void ScanLineToPolygonItrs:: + maintainPartialSimplePolygonInvariant(iterator& beginOutput, + iterator& endOutput, Unit currentX, const std::vector >& l, + const std::vector >& r, size_t vertexThreshold) { + + clearOutput_(); + if(!l.empty()){ + updatePartialSimplePolygonsWithLeftEdges(currentX, l, vertexThreshold); + } + + if(!r.empty()){ + updatePartialSimplePolygonsWithRightEdges(currentX, r, vertexThreshold); + } + beginOutput = outputPolygons_.begin(); + endOutput = outputPolygons_.end(); + + } + //Process edges connects vertical input edges (right or left edges of figures) to horizontal edges stored as member //data of the scanline object. It also creates now horizontal edges as needed to construct figures from edge data. // - //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique + //There are only 12 geometric end cases where the scanline intersects a horizontal edge and even fewer unique //actions to take: // 1. Solid on both sides of the vertical partition after the current position and space on both sides before - // ###|### - // ###|### - // | - // | + // ###|### + // ###|### + // | + // | // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 2. Solid on both sides of the vertical partition before the current position and space on both sides after - // | - // | - // ###|### - // ###|### + // | + // | + // ###|### + // ###|### // This case does not need to be handled because there is no vertical edge at the current x coordinate. // // 3. Solid on the left of the vertical partition after the current position and space elsewhere - // ###| - // ###| - // | - // | + // ###| + // ###| + // | + // | // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 4. Solid on the left of the vertical partion before the current position and space elsewhere - // | - // | - // ###| + // | + // | + // ###| // ###| // The horizontal edge from the left is found and joined to the currently active vertical edge. // // 5. Solid to the right above and below and solid to the left above current position. - // ###|### - // ###|### - // |### - // |### + // ###|### + // ###|### + // |### + // |### // The horizontal edge from the left is found and joined to the currently active vertical edge, // potentially closing a hole. // // 6. Solid on the left of the vertical partion before the current position and solid to the right above and below // |### - // |### - // ###|### + // |### + // ###|### // ###|### // The horizontal edge from the left is found and turns upward because of the vertical right edge to become // the currently active vertical edge. // // 7. Solid on the right of the vertical partition after the current position and space elsewhere - // |### - // |### - // | - // | + // |### + // |### + // | + // | // Create two new ActiveTails, one is added to the horizontal edges and the other becomes the vertical currentTail // // 8. Solid on the right of the vertical partion before the current position and space elsewhere - // | - // | - // |### + // | + // | + // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data // // 9. Solid to the right above and solid to the left above and below current position. - // ###|### - // ###|### - // ###| + // ###|### + // ###|### + // ###| // ###| // The currentTail vertical edge turns right and is added to the horizontal edges data // // 10. Solid on the left of the vertical partion above and below the current position and solid to the right below + // ###| // ###| - // ###| - // ###|### + // ###|### // ###|### // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 11. Solid to the right above and solid to the left below current position. + // |### // |### - // |### - // ###| + // ###| // ###| // The currentTail vertical edge joins the horizontal edge from the left (may close a polygon) // Create two new ActiveTails, one is added to the horizontal edges data and the other becomes the vertical currentTail // // 12. Solid on the left of the vertical partion above the current position and solid to the right below + // ###| // ###| - // ###| - // |### + // |### // |### // The currentTail vertical edge turns right and is added to the horizontal edges data. // The horizontal edge from the left turns upward and becomes the currentTail vertical edge // template inline void ScanLineToPolygonItrs:: - processEdges(iterator& beginOutput, iterator& endOutput, - Unit currentX, std::vector >& leftEdges, - std::vector >& rightEdges) { + processEdges(iterator& beginOutput, iterator& endOutput, + Unit currentX, std::vector >& leftEdges, + std::vector >& rightEdges, + size_t vertexThreshold) { clearOutput_(); - typename std::map*>::iterator nextMapItr = tailMap_.begin(); + typename std::map*>::iterator nextMapItr; //foreach edge unsigned int leftIndex = 0; unsigned int rightIndex = 0; bool bottomAlreadyProcessed = false; ActiveTail* currentTail = 0; const Unit UnitMax = (std::numeric_limits::max)(); + + if(vertexThreshold < (std::numeric_limits::max)()){ + maintainPartialSimplePolygonInvariant(beginOutput, endOutput, currentX, + leftEdges, rightEdges, vertexThreshold); + return; + } + + nextMapItr = tailMap_.begin(); while(leftIndex < leftEdges.size() || rightIndex < rightEdges.size()) { - interval_data edges[2] = {interval_data (UnitMax, UnitMax), interval_data (UnitMax, UnitMax)}; + interval_data edges[2] = {interval_data (UnitMax, UnitMax), + interval_data (UnitMax, UnitMax)}; bool haveNextEdge = true; if(leftIndex < leftEdges.size()) edges[0] = leftEdges[leftIndex]; @@ -1551,7 +2051,7 @@ namespace polygon_formation { interval_data & nextEdge = edges[!trailingEdge]; //process this edge if(!bottomAlreadyProcessed) { - //assert currentTail = 0 + //assert currentTail = 0 //process the bottom end of this edge typename std::map*>::iterator thisMapItr = findAtNext(tailMap_, nextMapItr, edge.get(LOW)); @@ -1578,7 +2078,7 @@ namespace polygon_formation { //we need to create one and another one to be the current vertical tail //if this is a trailing edge then there is space to the right of the vertical edge //so pass the inverse of trailingEdge to indicate solid to the right - std::pair*, ActiveTail*> tailPair = + std::pair*, ActiveTail*> tailPair = createActiveTailsAsPair(currentX, edge.get(LOW), !trailingEdge, currentTail, fractureHoles_); currentTail = tailPair.first; tailMap_.insert(nextMapItr, std::pair*>(edge.get(LOW), tailPair.second)); @@ -1606,7 +2106,7 @@ namespace polygon_formation { //two new tails are created, the vertical becomes current tail, the horizontal becomes thisMapItr tail //pass true becuase they are created at the lower left corner of some solid //pass null because there is no hole pointer possible - std::pair*, ActiveTail*> tailPair = + std::pair*, ActiveTail*> tailPair = createActiveTailsAsPair(currentX, edge.get(HIGH), true, 0, fractureHoles_); currentTail = tailPair.first; thisMapItr->second = tailPair.second; @@ -1640,7 +2140,7 @@ namespace polygon_formation { currentTail = ActiveTail::joinChains(currentTail, tail, !trailingEdge, outputPolygons_); nextMapItr = thisMapItr; //set nextMapItr to the next position after this one ++nextMapItr; - if(currentTail) { + if(currentTail) { //figure is not closed// Unit nextItrY = UnitMax; if(nextMapItr != tailMap_.end()) { nextItrY = nextMapItr->first; @@ -1662,7 +2162,7 @@ namespace polygon_formation { //set current tail to null currentTail = 0; } - } + } //delete thisMapItr from the map tailMap_.erase(thisMapItr); } else { @@ -1675,7 +2175,7 @@ namespace polygon_formation { //leave nextMapItr unchanged, it is still next } } - + //increment index leftIndex += !trailingEdge; rightIndex += trailingEdge; @@ -1718,8 +2218,10 @@ namespace polygon_formation { //public API to access polygon formation algorithm template - unsigned int get_polygons(output_container& container, iterator_type begin, iterator_type end, - orientation_2d orient, bool fracture_holes, concept_type ) { + unsigned int get_polygons(output_container& container, + iterator_type begin, iterator_type end, orientation_2d orient, + bool fracture_holes, concept_type, + size_t sliceThreshold = (std::numeric_limits::max)() ) { typedef typename output_container::value_type polygon_type; typedef typename std::iterator_traits::value_type::first_type coordinate_type; polygon_type poly; @@ -1738,7 +2240,8 @@ namespace polygon_formation { if(pos != prevPos) { if(orient == VERTICAL) { typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; - scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, + leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); @@ -1746,7 +2249,8 @@ namespace polygon_formation { } } else { typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; - scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, + leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); @@ -1783,7 +2287,7 @@ namespace polygon_formation { } if(orient == VERTICAL) { typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; - scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + scanlineToPolygonItrsV.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); @@ -1791,7 +2295,8 @@ namespace polygon_formation { } } else { typename polygon_formation::ScanLineToPolygonItrs::iterator itrPoly, itrPolyEnd; - scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges); + scanlineToPolygonItrsH.processEdges(itrPoly, itrPolyEnd, prevPos, leftEdges, rightEdges, sliceThreshold); + for( ; itrPoly != itrPolyEnd; ++ itrPoly) { ++countPolygons; assign(poly, *itrPoly); diff --git a/include/boost/polygon/detail/voronoi_predicates.hpp b/include/boost/polygon/detail/voronoi_predicates.hpp index dad76a6..11dd915 100644 --- a/include/boost/polygon/detail/voronoi_predicates.hpp +++ b/include/boost/polygon/detail/voronoi_predicates.hpp @@ -161,21 +161,21 @@ class voronoi_predicates { bool operator()(const site_type& lhs, const circle_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.x()), to_fpt(rhs.lower_x()), ULPSx5); + ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPSx5); if (xCmp != ulp_cmp_type::EQUAL) return xCmp == ulp_cmp_type::LESS; typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.y()), to_fpt(rhs.lower_y()), ULPSx5); + ulp_cmp(to_fpt(lhs.y0()), to_fpt(rhs.lower_y()), ULPSx5); return yCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const site_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x()), ULPSx5); + ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPSx5); if (xCmp != ulp_cmp_type::EQUAL) return xCmp == ulp_cmp_type::LESS; typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y()), ULPSx5); + ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y0()), ULPSx5); return yCmp == ulp_cmp_type::LESS; } @@ -198,24 +198,25 @@ class voronoi_predicates { class distance_predicate { public: typedef Site site_type; + typedef typename site_type::point_type point_type; // Returns true if a horizontal line going through a new site intersects // right arc at first, else returns false. If horizontal line goes // through intersection point of the given two arcs returns false also. bool operator()(const site_type& left_site, const site_type& right_site, - const site_type& new_site) const { + const point_type& new_point) const { if (!left_site.is_segment()) { if (!right_site.is_segment()) { - return pp(left_site, right_site, new_site); + return pp(left_site, right_site, new_point); } else { - return ps(left_site, right_site, new_site, false); + return ps(left_site, right_site, new_point, false); } } else { if (!right_site.is_segment()) { - return ps(right_site, left_site, new_site, true); + return ps(right_site, left_site, new_point, true); } else { - return ss(left_site, right_site, new_site); + return ss(left_site, right_site, new_point); } } } @@ -229,18 +230,15 @@ class voronoi_predicates { MORE = 1 }; - typedef typename Site::point_type point_type; - // Robust predicate, avoids using high-precision libraries. // Returns true if a horizontal line going through the new point site // intersects right arc at first, else returns false. If horizontal line // goes through intersection point of the given two arcs returns false. bool pp(const site_type& left_site, const site_type& right_site, - const site_type& new_site) const { + const point_type& new_point) const { const point_type& left_point = left_site.point0(); const point_type& right_point = right_site.point0(); - const point_type& new_point = new_site.point0(); if (left_point.x() > right_point.x()) { if (new_point.y() <= left_point.y()) return false; @@ -261,16 +259,15 @@ class voronoi_predicates { } bool ps(const site_type& left_site, const site_type& right_site, - const site_type& new_site, bool reverse_order) const { + const point_type& new_point, bool reverse_order) const { kPredicateResult fast_res = fast_ps( - left_site, right_site, new_site, reverse_order); - if (fast_res != UNDEFINED) - return (fast_res == LESS); + left_site, right_site, new_point, reverse_order); + if (fast_res != UNDEFINED) { + return fast_res == LESS; + } - fpt_type dist1 = find_distance_to_point_arc( - left_site, new_site.point0()); - fpt_type dist2 = find_distance_to_segment_arc( - right_site, new_site.point0()); + fpt_type dist1 = find_distance_to_point_arc(left_site, new_point); + fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); // The undefined ulp range is equal to 3EPS + 7EPS <= 10ULP. return reverse_order ^ (dist1 < dist2); @@ -278,19 +275,15 @@ class voronoi_predicates { bool ss(const site_type& left_site, const site_type& right_site, - const site_type& new_site) const { + const point_type& new_point) const { // Handle temporary segment sites. - if (left_site.point0() == right_site.point0() && - left_site.point1() == right_site.point1()) { - return ot::eval(left_site.point0(), - left_site.point1(), - new_site.point0()) == ot::LEFT; + if (left_site.sorted_index() == right_site.sorted_index()) { + return ot::eval( + left_site.point0(), left_site.point1(), new_point) == ot::LEFT; } - fpt_type dist1 = find_distance_to_segment_arc( - left_site, new_site.point0()); - fpt_type dist2 = find_distance_to_segment_arc( - right_site, new_site.point0()); + fpt_type dist1 = find_distance_to_segment_arc(left_site, new_point); + fpt_type dist2 = find_distance_to_segment_arc(right_site, new_point); // The undefined ulp range is equal to 7EPS + 7EPS <= 14ULP. return dist1 < dist2; @@ -309,8 +302,8 @@ class voronoi_predicates { if (is_vertical(site)) { return (to_fpt(site.x()) - to_fpt(point.x())) * to_fpt(0.5); } else { - const point_type& segment0 = site.point0(true); - const point_type& segment1 = site.point1(true); + const point_type& segment0 = site.point0(); + const point_type& segment1 = site.point1(); fpt_type a1 = to_fpt(segment1.x()) - to_fpt(segment0.x()); fpt_type b1 = to_fpt(segment1.y()) - to_fpt(segment0.y()); fpt_type k = get_sqrt(a1 * a1 + b1 * b1); @@ -335,11 +328,10 @@ class voronoi_predicates { kPredicateResult fast_ps( const site_type& left_site, const site_type& right_site, - const site_type& new_site, bool reverse_order) const { + const point_type& new_point, bool reverse_order) const { const point_type& site_point = left_site.point0(); - const point_type& segment_start = right_site.point0(true); - const point_type& segment_end = right_site.point1(true); - const point_type& new_point = new_site.point0(); + const point_type& segment_start = right_site.point0(); + const point_type& segment_end = right_site.point1(); if (ot::eval(segment_start, segment_end, new_point) != ot::RIGHT) return (!right_site.is_inverse()) ? LESS : MORE; @@ -394,7 +386,9 @@ class voronoi_predicates { public: typedef Node node_type; typedef typename Node::site_type site_type; - typedef typename site_type::coordinate_type coordinate_type; + typedef typename site_type::point_type point_type; + typedef typename point_type::coordinate_type coordinate_type; + typedef point_comparison_predicate point_comparison_type; typedef distance_predicate distance_predicate_type; // Compares nodes in the balanced binary search tree. Nodes are @@ -408,13 +402,17 @@ class voronoi_predicates { // Get x coordinate of the rightmost site from both nodes. const site_type& site1 = get_comparison_site(node1); const site_type& site2 = get_comparison_site(node2); + const point_type& point1 = get_comparison_point(site1); + const point_type& point2 = get_comparison_point(site2); - if (site1.x() < site2.x()) { + if (point1.x() < point2.x()) { // The second node contains a new site. - return predicate_(node1.left_site(), node1.right_site(), site2); - } else if (site1.x() > site2.x()) { + return distance_predicate_( + node1.left_site(), node1.right_site(), point2); + } else if (point1.x() > point2.x()) { // The first node contains a new site. - return !predicate_(node2.left_site(), node2.right_site(), site1); + return !distance_predicate_( + node2.left_site(), node2.right_site(), point1); } else { // This checks were evaluated experimentally. if (site1.sorted_index() == site2.sorted_index()) { @@ -443,25 +441,31 @@ class voronoi_predicates { return node.right_site(); } + const point_type& get_comparison_point(const site_type& site) const { + return point_comparison_(site.point0(), site.point1()) ? + site.point0() : site.point1(); + } + // Get comparison pair: y coordinate and direction of the newer site. std::pair get_comparison_y( const node_type& node, bool is_new_node = true) const { if (node.left_site().sorted_index() == node.right_site().sorted_index()) { - return std::make_pair(node.left_site().y(), 0); + return std::make_pair(node.left_site().y0(), 0); } if (node.left_site().sorted_index() > node.right_site().sorted_index()) { if (!is_new_node && node.left_site().is_segment() && is_vertical(node.left_site())) { - return std::make_pair(node.left_site().y1(), 1); + return std::make_pair(node.left_site().y0(), 1); } - return std::make_pair(node.left_site().y(), 1); + return std::make_pair(node.left_site().y1(), 1); } - return std::make_pair(node.right_site().y(), -1); + return std::make_pair(node.right_site().y0(), -1); } - distance_predicate_type predicate_; + point_comparison_type point_comparison_; + distance_predicate_type distance_predicate_; }; template @@ -473,8 +477,9 @@ class voronoi_predicates { bool ppp(const site_type& site1, const site_type& site2, const site_type& site3) const { - return ot::eval(site1.point0(), site2.point0(), site3.point0()) == - ot::RIGHT; + return ot::eval(site1.point0(), + site2.point0(), + site3.point0()) == ot::RIGHT; } bool pps(const site_type& site1, @@ -482,10 +487,10 @@ class voronoi_predicates { const site_type& site3, int segment_index) const { if (segment_index != 2) { - typename ot::Orientation orient1 = ot::eval(site1.point0(), - site2.point0(), site3.point0(true)); - typename ot::Orientation orient2 = ot::eval(site1.point0(), - site2.point0(), site3.point1(true)); + typename ot::Orientation orient1 = ot::eval( + site1.point0(), site2.point0(), site3.point0()); + typename ot::Orientation orient2 = ot::eval( + site1.point0(), site2.point0(), site3.point1()); if (segment_index == 1 && site1.x0() >= site2.x0()) { if (orient1 != ot::RIGHT) return false; @@ -496,9 +501,8 @@ class voronoi_predicates { return false; } } else { - if (site3.point0(true) == site1.point0() && - site3.point1(true) == site2.point0()) - return false; + return (site3.point0() != site1.point0()) || + (site3.point1() != site2.point0()); } return true; } @@ -507,17 +511,16 @@ class voronoi_predicates { const site_type& site2, const site_type& site3, int point_index) const { - if (site2.point0() == site3.point0() && - site2.point1() == site3.point1()) { + if (site2.sorted_index() == site3.sorted_index()) { return false; } if (point_index == 2) { if (!site2.is_inverse() && site3.is_inverse()) return false; if (site2.is_inverse() == site3.is_inverse() && - ot::eval(site2.point0(true), + ot::eval(site2.point0(), site1.point0(), - site3.point1(true)) != ot::RIGHT) + site3.point1()) != ot::RIGHT) return false; } return true; @@ -526,11 +529,8 @@ class voronoi_predicates { bool sss(const site_type& site1, const site_type& site2, const site_type& site3) const { - if (site1.point0() == site2.point0() && site1.point1() == site2.point1()) - return false; - if (site2.point0() == site3.point0() && site2.point1() == site3.point1()) - return false; - return true; + return (site1.sorted_index() != site2.sorted_index()) && + (site2.sorted_index() != site3.sorted_index()); } }; @@ -620,10 +620,10 @@ class voronoi_predicates { bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type cA[4], cB[4]; - big_int_type line_a = static_cast(site3.point1(true).y()) - - static_cast(site3.point0(true).y()); - big_int_type line_b = static_cast(site3.point0(true).x()) - - static_cast(site3.point1(true).x()); + big_int_type line_a = static_cast(site3.y1()) - + static_cast(site3.y0()); + big_int_type line_b = static_cast(site3.x0()) - + static_cast(site3.x1()); big_int_type segm_len = line_a * line_a + line_b * line_b; big_int_type vec_x = static_cast(site2.y()) - static_cast(site1.y()); @@ -636,15 +636,15 @@ class voronoi_predicates { big_int_type teta = line_a * vec_x + line_b * vec_y; big_int_type denom = vec_x * line_b - vec_y * line_a; - big_int_type dif0 = static_cast(site3.point1().y()) - + big_int_type dif0 = static_cast(site3.y1()) - static_cast(site1.y()); big_int_type dif1 = static_cast(site1.x()) - - static_cast(site3.point1().x()); + static_cast(site3.x1()); big_int_type A = line_a * dif1 - line_b * dif0; - dif0 = static_cast(site3.point1().y()) - + dif0 = static_cast(site3.y1()) - static_cast(site2.y()); dif1 = static_cast(site2.x()) - - static_cast(site3.point1().x()); + static_cast(site3.x1()); big_int_type B = line_a * dif1 - line_b * dif0; big_int_type sum_AB = A + B; @@ -716,10 +716,10 @@ class voronoi_predicates { bool recompute_c_y = true, bool recompute_lower_x = true) { big_int_type a[2], b[2], c[2], cA[4], cB[4]; - const point_type& segm_start1 = site2.point1(true); - const point_type& segm_end1 = site2.point0(true); - const point_type& segm_start2 = site3.point0(true); - const point_type& segm_end2 = site3.point1(true); + const point_type& segm_start1 = site2.point1(); + const point_type& segm_end1 = site2.point0(); + const point_type& segm_start2 = site3.point0(); + const point_type& segm_end2 = site3.point1(); a[0] = static_cast(segm_end1.x()) - static_cast(segm_start1.x()); b[0] = static_cast(segm_end1.y()) - @@ -850,32 +850,32 @@ class voronoi_predicates { big_int_type a[3], b[3], c[3], cA[4], cB[4]; // cA - corresponds to the cross product. // cB - corresponds to the squared length. - a[0] = static_cast(site1.x1(true)) - - static_cast(site1.x0(true)); - a[1] = static_cast(site2.x1(true)) - - static_cast(site2.x0(true)); - a[2] = static_cast(site3.x1(true)) - - static_cast(site3.x0(true)); + a[0] = static_cast(site1.x1()) - + static_cast(site1.x0()); + a[1] = static_cast(site2.x1()) - + static_cast(site2.x0()); + a[2] = static_cast(site3.x1()) - + static_cast(site3.x0()); - b[0] = static_cast(site1.y1(true)) - - static_cast(site1.y0(true)); - b[1] = static_cast(site2.y1(true)) - - static_cast(site2.y0(true)); - b[2] = static_cast(site3.y1(true)) - - static_cast(site3.y0(true)); + b[0] = static_cast(site1.y1()) - + static_cast(site1.y0()); + b[1] = static_cast(site2.y1()) - + static_cast(site2.y0()); + b[2] = static_cast(site3.y1()) - + static_cast(site3.y0()); - c[0] = static_cast(site1.x0(true)) * - static_cast(site1.y1(true)) - - static_cast(site1.y0(true)) * - static_cast(site1.x1(true)); - c[1] = static_cast(site2.x0(true)) * - static_cast(site2.y1(true)) - - static_cast(site2.y0(true)) * - static_cast(site2.x1(true)); - c[2] = static_cast(site3.x0(true)) * - static_cast(site3.y1(true)) - - static_cast(site3.y0(true)) * - static_cast(site3.x1(true)); + c[0] = static_cast(site1.x0()) * + static_cast(site1.y1()) - + static_cast(site1.y0()) * + static_cast(site1.x1()); + c[1] = static_cast(site2.x0()) * + static_cast(site2.y1()) - + static_cast(site2.y0()) * + static_cast(site2.x1()); + c[2] = static_cast(site3.x0()) * + static_cast(site3.y1()) - + static_cast(site3.y0()) * + static_cast(site3.x1()); for (int i = 0; i < 3; ++i) cB[i] = a[i] * a[i] + b[i] * b[i]; @@ -1060,48 +1060,46 @@ class voronoi_predicates { const site_type& site3, int segment_index, circle_type& c_event) { - fpt_type line_a = to_fpt(site3.point1(true).y()) - - to_fpt(site3.point0(true).y()); - fpt_type line_b = to_fpt(site3.point0(true).x()) - - to_fpt(site3.point1(true).x()); + fpt_type line_a = to_fpt(site3.y1()) - to_fpt(site3.y0()); + fpt_type line_b = to_fpt(site3.x0()) - to_fpt(site3.x1()); fpt_type vec_x = to_fpt(site2.y()) - to_fpt(site1.y()); fpt_type vec_y = to_fpt(site1.x()) - to_fpt(site2.x()); robust_fpt_type teta(robust_cross_product( - static_cast(site3.point1(true).y()) - - static_cast(site3.point0(true).y()), - static_cast(site3.point0(true).x()) - - static_cast(site3.point1(true).x()), + static_cast(site3.y1()) - + static_cast(site3.y0()), + static_cast(site3.x0()) - + static_cast(site3.x1()), static_cast(site2.x()) - static_cast(site1.x()), static_cast(site2.y()) - static_cast(site1.y())), to_fpt(1.0)); robust_fpt_type A(robust_cross_product( - static_cast(site3.point1(true).y()) - - static_cast(site3.point0(true).y()), - static_cast(site3.point0(true).x()) - - static_cast(site3.point1(true).x()), - static_cast(site3.point1().y()) - + static_cast(site3.y0()) - + static_cast(site3.y1()), + static_cast(site3.x0()) - + static_cast(site3.x1()), + static_cast(site3.y1()) - static_cast(site1.y()), - static_cast(site1.x()) - - static_cast(site3.point1().x())), to_fpt(1.0)); + static_cast(site3.x1()) - + static_cast(site1.x())), to_fpt(1.0)); robust_fpt_type B(robust_cross_product( - static_cast(site3.point1(true).y()) - - static_cast(site3.point0(true).y()), - static_cast(site3.point0(true).x()) - - static_cast(site3.point1(true).x()), - static_cast(site3.point1().y()) - + static_cast(site3.y0()) - + static_cast(site3.y1()), + static_cast(site3.x0()) - + static_cast(site3.x1()), + static_cast(site3.y1()) - static_cast(site2.y()), - static_cast(site2.x()) - - static_cast(site3.point1().x())), to_fpt(1.0)); + static_cast(site3.x1()) - + static_cast(site2.x())), to_fpt(1.0)); robust_fpt_type denom(robust_cross_product( - static_cast(site2.y()) - - static_cast(site1.y()), + static_cast(site1.y()) - + static_cast(site2.y()), static_cast(site1.x()) - static_cast(site2.x()), - static_cast(site3.point1(true).y()) - - static_cast(site3.point0(true).y()), - static_cast(site3.point0(true).x()) - - static_cast(site3.point1(true).x())), to_fpt(1.0)); + static_cast(site3.y1()) - + static_cast(site3.y0()), + static_cast(site3.x1()) - + static_cast(site3.x0())), to_fpt(1.0)); robust_fpt_type inv_segm_len(to_fpt(1.0) / get_sqrt(line_a * line_a + line_b * line_b), to_fpt(3.0)); robust_dif_type t; @@ -1118,11 +1116,11 @@ class voronoi_predicates { t += teta * (A + B) / (robust_fpt_type(to_fpt(2.0)) * denom * denom); } robust_dif_type c_x, c_y; - c_x += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.x()) + - to_fpt(site2.x()))); + c_x += robust_fpt_type(to_fpt(0.5) * + (to_fpt(site1.x()) + to_fpt(site2.x()))); c_x += robust_fpt_type(vec_x) * t; - c_y += robust_fpt_type(to_fpt(0.5) * (to_fpt(site1.y()) + - to_fpt(site2.y()))); + c_y += robust_fpt_type(to_fpt(0.5) * + (to_fpt(site1.y()) + to_fpt(site2.y()))); c_y += robust_fpt_type(vec_y) * t; robust_dif_type r, lower_x(c_x); r -= robust_fpt_type(line_a) * robust_fpt_type(site3.x0()); @@ -1149,10 +1147,10 @@ class voronoi_predicates { const site_type& site3, int point_index, circle_type& c_event) { - const point_type& segm_start1 = site2.point1(true); - const point_type& segm_end1 = site2.point0(true); - const point_type& segm_start2 = site3.point0(true); - const point_type& segm_end2 = site3.point1(true); + const point_type& segm_start1 = site2.point1(); + const point_type& segm_end1 = site2.point0(); + const point_type& segm_start2 = site3.point0(); + const point_type& segm_end2 = site3.point1(); fpt_type a1 = to_fpt(segm_end1.x()) - to_fpt(segm_start1.x()); fpt_type b1 = to_fpt(segm_end1.y()) - to_fpt(segm_start1.y()); fpt_type a2 = to_fpt(segm_end2.x()) - to_fpt(segm_start2.x()); @@ -1343,54 +1341,54 @@ class voronoi_predicates { const site_type& site2, const site_type& site3, circle_type& c_event) { - robust_fpt_type a1(to_fpt(site1.x1(true)) - to_fpt(site1.x0(true))); - robust_fpt_type b1(to_fpt(site1.y1(true)) - to_fpt(site1.y0(true))); + robust_fpt_type a1(to_fpt(site1.x1()) - to_fpt(site1.x0())); + robust_fpt_type b1(to_fpt(site1.y1()) - to_fpt(site1.y0())); robust_fpt_type c1(robust_cross_product( - site1.x0(true), site1.y0(true), - site1.x1(true), site1.y1(true)), to_fpt(1.0)); + site1.x0(), site1.y0(), + site1.x1(), site1.y1()), to_fpt(1.0)); - robust_fpt_type a2(to_fpt(site2.x1(true)) - to_fpt(site2.x0(true))); - robust_fpt_type b2(to_fpt(site2.y1(true)) - to_fpt(site2.y0(true))); + robust_fpt_type a2(to_fpt(site2.x1()) - to_fpt(site2.x0())); + robust_fpt_type b2(to_fpt(site2.y1()) - to_fpt(site2.y0())); robust_fpt_type c2(robust_cross_product( - site2.x0(true), site2.y0(true), - site2.x1(true), site2.y1(true)), to_fpt(1.0)); + site2.x0(), site2.y0(), + site2.x1(), site2.y1()), to_fpt(1.0)); - robust_fpt_type a3(to_fpt(site3.x1(true)) - to_fpt(site3.x0(true))); - robust_fpt_type b3(to_fpt(site3.y1(true)) - to_fpt(site3.y0(true))); + robust_fpt_type a3(to_fpt(site3.x1()) - to_fpt(site3.x0())); + robust_fpt_type b3(to_fpt(site3.y1()) - to_fpt(site3.y0())); robust_fpt_type c3(robust_cross_product( - site3.x0(true), site3.y0(true), - site3.x1(true), site3.y1(true)), to_fpt(1.0)); + site3.x0(), site3.y0(), + site3.x1(), site3.y1()), to_fpt(1.0)); robust_fpt_type len1 = (a1 * a1 + b1 * b1).sqrt(); robust_fpt_type len2 = (a2 * a2 + b2 * b2).sqrt(); robust_fpt_type len3 = (a3 * a3 + b3 * b3).sqrt(); robust_fpt_type cross_12(robust_cross_product( - static_cast(site1.x1(true)) - - static_cast(site1.x0(true)), - static_cast(site1.y1(true)) - - static_cast(site1.y0(true)), - static_cast(site2.x1(true)) - - static_cast(site2.x0(true)), - static_cast(site2.y1(true)) - - static_cast(site2.y0(true))), to_fpt(1.0)); + static_cast(site1.x1()) - + static_cast(site1.x0()), + static_cast(site1.y1()) - + static_cast(site1.y0()), + static_cast(site2.x1()) - + static_cast(site2.x0()), + static_cast(site2.y1()) - + static_cast(site2.y0())), to_fpt(1.0)); robust_fpt_type cross_23(robust_cross_product( - static_cast(site2.x1(true)) - - static_cast(site2.x0(true)), - static_cast(site2.y1(true)) - - static_cast(site2.y0(true)), - static_cast(site3.x1(true)) - - static_cast(site3.x0(true)), - static_cast(site3.y1(true)) - - static_cast(site3.y0(true))), to_fpt(1.0)); + static_cast(site2.x1()) - + static_cast(site2.x0()), + static_cast(site2.y1()) - + static_cast(site2.y0()), + static_cast(site3.x1()) - + static_cast(site3.x0()), + static_cast(site3.y1()) - + static_cast(site3.y0())), to_fpt(1.0)); robust_fpt_type cross_31(robust_cross_product( - static_cast(site3.x1(true)) - - static_cast(site3.x0(true)), - static_cast(site3.y1(true)) - - static_cast(site3.y0(true)), - static_cast(site1.x1(true)) - - static_cast(site1.x0(true)), - static_cast(site1.y1(true)) - - static_cast(site1.y0(true))), to_fpt(1.0)); + static_cast(site3.x1()) - + static_cast(site3.x0()), + static_cast(site3.y1()) - + static_cast(site3.y0()), + static_cast(site1.x1()) - + static_cast(site1.x0()), + static_cast(site1.y1()) - + static_cast(site1.y0())), to_fpt(1.0)); // denom = cross_12 * len3 + cross_23 * len1 + cross_31 * len2. robust_dif_type denom; diff --git a/include/boost/polygon/detail/voronoi_structures.hpp b/include/boost/polygon/detail/voronoi_structures.hpp index 532eb7e..f37a454 100644 --- a/include/boost/polygon/detail/voronoi_structures.hpp +++ b/include/boost/polygon/detail/voronoi_structures.hpp @@ -130,48 +130,36 @@ class site_event { (this->point1_ != that.point1_); } - coordinate_type x(bool oriented = false) const { - return x0(oriented); + coordinate_type x() const { + return point0_.x(); } - coordinate_type y(bool oriented = false) const { - return y0(oriented); + coordinate_type y() const { + return point0_.y(); } - coordinate_type x0(bool oriented = false) const { - if (!oriented) - return point0_.x(); - return is_inverse() ? point1_.x() : point0_.x(); + coordinate_type x0() const { + return point0_.x(); } - coordinate_type y0(bool oriented = false) const { - if (!oriented) - return point0_.y(); - return is_inverse() ? point1_.y() : point0_.y(); + coordinate_type y0() const { + return point0_.y(); } - coordinate_type x1(bool oriented = false) const { - if (!oriented) - return point1_.x(); - return is_inverse() ? point0_.x() : point1_.x(); + coordinate_type x1() const { + return point1_.x(); } - coordinate_type y1(bool oriented = false) const { - if (!oriented) - return point1_.y(); - return is_inverse() ? point0_.y() : point1_.y(); + coordinate_type y1() const { + return point1_.y(); } - const point_type& point0(bool oriented = false) const { - if (!oriented) - return point0_; - return is_inverse() ? point1_ : point0_; + const point_type& point0() const { + return point0_; } - const point_type& point1(bool oriented = false) const { - if (!oriented) - return point1_; - return is_inverse() ? point0_ : point1_; + const point_type& point1() const { + return point1_; } std::size_t sorted_index() const { @@ -197,6 +185,7 @@ class site_event { } site_event& inverse() { + std::swap(point0_, point1_); flags_ ^= IS_INVERSE; return *this; } diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp index abd85b4..305aa3e 100644 --- a/include/boost/polygon/polygon_90_set_data.hpp +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -163,6 +163,12 @@ namespace boost { namespace polygon{ get_dispatch(output, typename geometry_concept::type()); } + template + inline void get(output_container& output, size_t vthreshold) const { + get_dispatch(output, typename geometry_concept::type(), vthreshold); + } + + template inline void get_polygons(output_container& output) const { get_dispatch(output, polygon_90_concept()); @@ -829,10 +835,25 @@ namespace boost { namespace polygon{ void get_dispatch(output_container& output, polygon_90_concept tag) const { get_fracture(output, true, tag); } + + template + void get_dispatch(output_container& output, polygon_90_concept tag, + size_t vthreshold) const { + get_fracture(output, true, tag, vthreshold); + } + template void get_dispatch(output_container& output, polygon_90_with_holes_concept tag) const { get_fracture(output, false, tag); } + + template + void get_dispatch(output_container& output, polygon_90_with_holes_concept tag, + size_t vthreshold) const { + get_fracture(output, false, tag, vthreshold); + } + + template void get_dispatch(output_container& output, polygon_45_concept tag) const { get_fracture(output, true, tag); @@ -854,6 +875,13 @@ namespace boost { namespace polygon{ clean(); ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag); } + + template + void get_fracture(output_container& container, bool fracture_holes, concept_type tag, + size_t vthreshold) const { + clean(); + ::boost::polygon::get_polygons(container, data_.begin(), data_.end(), orient_, fracture_holes, tag, vthreshold); + } }; template diff --git a/include/boost/polygon/voronoi_builder.hpp b/include/boost/polygon/voronoi_builder.hpp index 918b86a..48a06a3 100644 --- a/include/boost/polygon/voronoi_builder.hpp +++ b/include/boost/polygon/voronoi_builder.hpp @@ -388,7 +388,7 @@ class voronoi_builder { site_event_type site1 = it_first->first.left_site(); if (!site1.is_segment() && site3.is_segment() && - site3.point1(true) == site1.point0()) { + site3.point1() == site1.point0()) { site3.inverse(); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3b010c5..4f1962f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,6 +24,11 @@ test-suite polygon-unit [ run gtl_boost_unit_test.cpp ] ; +test-suite skeleton-unit + : + [ run skeleton_predicates_test.cpp ] + ; + test-suite voronoi-unit : [ run voronoi_builder_test.cpp ] diff --git a/test/gtl_boost_unit_test.cpp b/test/gtl_boost_unit_test.cpp index dcd8aef..1ade242 100644 --- a/test/gtl_boost_unit_test.cpp +++ b/test/gtl_boost_unit_test.cpp @@ -6,7 +6,7 @@ http://www.boost.org/LICENSE_1_0.txt). */ #include -//#define BOOST_POLYGON_NO_DEPS +#define BOOST_POLYGON_NO_DEPS #include namespace gtl = boost::polygon; @@ -2221,6 +2221,239 @@ bool test_extents2() { return gtl::equivalence(rect, rect2); } +/*************New Polygon Formation Tests********************/ +/* + * + * Test Input: + * +--------------------+ + * | +-------+ | + * | | | | + * | | | | + * +-----+ | | | + * | | | | + * | | | | + * +-----+ | | | + * | | | | + * | | | | + * | +-------+ | + * +--------+ | + * | | + * | | + * +--------+ | + * | | + * | | + * +--------+ | + * | | + * | | + * +--------+ | + * | | + * | | + * +--------------------+ + * + * Test Plan: + * a. call 'get(out, param)' , param >=4 + * b. check if each polygon in the container is <= param + * c. check the area of all the pieces sum up to original piece + */ +typedef int intDC; +typedef boost::polygon::polygon_90_with_holes_data GTLPolygon; +typedef boost::polygon::polygon_90_set_data GTLPolygonSet; +typedef boost::polygon::polygon_90_concept GTLPolygonConcept; +typedef boost::polygon::point_data GTLPoint; +inline void PrintPolygon(const GTLPolygon&); +inline GTLPolygon CreateGTLPolygon(const int*, size_t); +int test_new_polygon_formation(int argc, char** argv){ + // // + // Sub-Test-1: do a Boolean and call the new get // + // // + int coordinates[] = {0,0, 10,0, 10,10, 0,10}; + int coordinates1[] = {9,1, 20,1, 20,10, 9,10}; + std::vector pts; + size_t count = sizeof(coordinates)/(2*sizeof(intDC)); + size_t count1 = sizeof(coordinates1)/(2*sizeof(intDC)); + GTLPolygon poly, poly1; + GTLPolygonSet polySet; + + poly = CreateGTLPolygon(coordinates, count); + poly1 = CreateGTLPolygon(coordinates1, count1); + + polySet.insert(poly); + polySet.insert(poly1); + + std::vector result; + polySet.get(result, 100); + + if(result.size() > 1){ + std::cerr << "FAILED: expecting only one polygon because the" + " threshold is 100" << std::endl; + return 1; + } + + if(result[0].size() != 6){ + std::cerr << "FAILED: expecting only 6 vertices" << std::endl; + return 1; + } + + if(area(result[0]) != 190){ + std::cerr <<"FAILED: expecting only 6 vertices" << std::endl; + return 1; + } + + //expect no more than 1 polygon + std::cout << "Found " << result.size() << "polygons after union" + << std::endl; + for(size_t i=0; i 6){ + std::cerr << "FAILED: expecting size to be less than 6" << std::endl; + return 1; + } + } + + std::cout << "platinum_area = " << platinum_area << " , gold_area=" + << gold_area << std::endl; + if( platinum_area != gold_area){ + std::cerr << "FAILED: Area mismatch" << std::endl; + return 1; + } + std::cout << "[SUB-TEST-1] PASSED\n"; + + result.clear(); + polySet.get(result, 4); + platinum_area = 0; + std::cout << "Found " << result.size() << " slices" << std::endl; + for(size_t i=0; i 4){ + std::cerr << "FAILED: expecting size to be < 4" << std::endl; + return 1; + } + } + + std::cout << "platinum_area=" << platinum_area << ", gold_area=" + << gold_area << std::endl; + + if( platinum_area != gold_area){ + std::cerr << "FAILED: Area mismatch" << std::endl; + return 1; + } + + std::cout << "[SUB-TEST-1] PASSED" << std::endl; + return 0; +} + +/* + * INPUT: + * +--------+ + * | | + * | | + * | +---+ + * | | + * | +---+ + * | | + * +--------+ + * X + * + * TEST PLAN: as the sweepline moves and reaches + * X the number of vertices in the solid jumps by 4 + * instead of 2. So make sure we don't get a 6 vertex + * polygon when the threshold is 4 and 6. + */ +int test_new_polygon_formation_marginal_threshold(int argc, char**){ + std::vector pts; + GTLPolygon polygon; + GTLPolygonSet pset; + std::vector result; + intDC coords[] = {0,0, 15,0, 15,10, 10,10, 10,15, 5,15, 5,10, 0,10}; + size_t count = sizeof(coords)/(2*sizeof(intDC)); + + polygon = CreateGTLPolygon(coords, count); + pset.insert(polygon); + + for(size_t i=0; i<1; i++){ + pset.get(result, i ? 4 : 6); + double gold_area = 175, plat_area = 0; + for(size_t i=0; i (i ? 4 : 6) ){ + size_t expected = i ? 4 : 6; + std::cerr << "FAILED: Expecting no more than " << + expected << " vertices" << std::endl; + return 1; + } + PrintPolygon(result[i]); + plat_area += area(result[i]); + } + + if(plat_area != gold_area){ + std::cerr << "FAILED area mismatch gold=" << gold_area << + " plat=" << plat_area << std::endl; + return 1; + } + } + std::cout << "Test Passed" << std::endl; + return 0; +} + +inline void PrintPolygon(const GTLPolygon& p){ + //get an iterator of the point_data + boost::polygon::point_data pt; + boost::polygon::polygon_90_data::iterator_type itr; + + size_t vertex_id = 0; + for(itr = p.begin(); itr != p.end(); ++itr){ + pt = *itr; + std::cout << "Vertex-" << ++vertex_id << "(" << pt.x() << + "," << pt.y() << ")" << std::endl; + } +} + +// size: is the number of vertices // +inline GTLPolygon CreateGTLPolygon(const int *coords, size_t size){ + GTLPolygon r; + std::vector pts; + + for(size_t i=0; i BOOST_CHECK_EQUAL(event_comparison(A, B), R1); \ BOOST_CHECK_EQUAL(event_comparison(B, A), R2) -#define CHECK_DISTANCE_PREDICATE(S1, S2, S3, RES) \ - BOOST_CHECK_EQUAL(distance_predicate(S1, S2, S3), RES) +#define CHECK_DISTANCE_PREDICATE(S1, S2, P3, RES) \ + BOOST_CHECK_EQUAL(distance_predicate(S1, S2, P3), RES) #define CHECK_NODE_COMPARISON(node, nodes, res, sz) \ for (int i = 0; i < sz; ++i) { \ @@ -140,102 +140,119 @@ BOOST_AUTO_TEST_CASE(event_comparison_test5) { BOOST_AUTO_TEST_CASE(distance_predicate_test1) { site_type site1(-5, 0); + site1.sorted_index(1); site_type site2(-8, 9); + site2.sorted_index(0); site_type site3(-2, 1); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 5), false); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 5), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 4), false); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 4), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 6), true); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 6), true); + site3.sorted_index(2); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 6), true); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, 6), true); } BOOST_AUTO_TEST_CASE(distance_predicate_test2) { site_type site1(-4, 0, -4, 20); + site1.sorted_index(0); site_type site2(-2, 10); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 11), false); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 9), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 11), true); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 9), true); + site2.sorted_index(1); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 11), false); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 9), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 11), true); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 9), true); } BOOST_AUTO_TEST_CASE(disntace_predicate_test3) { site_type site1(-5, 5, 2, -2); + site1.sorted_index(0); site1.inverse(); site_type site2(-2, 4); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -1), false); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -1), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 1), false); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 1), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 4), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 4), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 5), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 5), false); + site2.sorted_index(1); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, -1), false); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, -1), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 4), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 5), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 5), false); } BOOST_AUTO_TEST_CASE(distance_predicate_test4) { site_type site1(-5, 5, 2, -2); + site1.sorted_index(0); site_type site2(-2, -4); + site2.sorted_index(2); site_type site3(-4, 1); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, 1), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, 1), true); - CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, 1), true); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, 1), true); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -2), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -2), false); - CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -2), true); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -2), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -8), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -8), false); - CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -8), true); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -8), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(0, -9), true); - CHECK_DISTANCE_PREDICATE(site2, site1, site_type(0, -9), false); - CHECK_DISTANCE_PREDICATE(site1, site3, site_type(0, -9), true); - CHECK_DISTANCE_PREDICATE(site3, site1, site_type(0, -9), false); + site3.sorted_index(1); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site1, site3, point_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, 1), true); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, -2), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site1, site3, point_type(0, -2), true); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, -8), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site1, site3, point_type(0, -8), true); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(0, -9), true); + CHECK_DISTANCE_PREDICATE(site2, site1, point_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site1, site3, point_type(0, -9), true); + CHECK_DISTANCE_PREDICATE(site3, site1, point_type(0, -9), false); } BOOST_AUTO_TEST_CASE(disntace_predicate_test5) { site_type site1(-5, 5, 2, -2); + site1.sorted_index(0); site_type site2 = site1; site2.inverse(); site_type site3(-2, 4); + site3.sorted_index(3); site_type site4(-2, -4); + site4.sorted_index(2); site_type site5(-4, 1); - CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 1), false); - CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 4), false); - CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 5), false); - CHECK_DISTANCE_PREDICATE(site3, site2, site_type(0, 7), true); - CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -2), false); - CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -2), false); - CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -8), false); - CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -8), false); - CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -9), false); - CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -9), false); - CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -18), false); - CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -18), false); - CHECK_DISTANCE_PREDICATE(site4, site1, site_type(0, -1), true); - CHECK_DISTANCE_PREDICATE(site5, site1, site_type(0, -1), true); + site5.sorted_index(1); + CHECK_DISTANCE_PREDICATE(site3, site2, point_type(0, 1), false); + CHECK_DISTANCE_PREDICATE(site3, site2, point_type(0, 4), false); + CHECK_DISTANCE_PREDICATE(site3, site2, point_type(0, 5), false); + CHECK_DISTANCE_PREDICATE(site3, site2, point_type(0, 7), true); + CHECK_DISTANCE_PREDICATE(site4, site1, point_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site5, site1, point_type(0, -2), false); + CHECK_DISTANCE_PREDICATE(site4, site1, point_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site5, site1, point_type(0, -8), false); + CHECK_DISTANCE_PREDICATE(site4, site1, point_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site5, site1, point_type(0, -9), false); + CHECK_DISTANCE_PREDICATE(site4, site1, point_type(0, -18), false); + CHECK_DISTANCE_PREDICATE(site5, site1, point_type(0, -18), false); + CHECK_DISTANCE_PREDICATE(site4, site1, point_type(0, -1), true); + CHECK_DISTANCE_PREDICATE(site5, site1, point_type(0, -1), true); } BOOST_AUTO_TEST_CASE(distance_predicate_test6) { site_type site1(-5, 0, 2, 7); site_type site2 = site1; site2.inverse(); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(2, 7), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(1, 5), false); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(-1, 5), true); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(2, 7), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(1, 5), false); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(-1, 5), true); } BOOST_AUTO_TEST_CASE(distance_predicate_test7) { site_type site1(-5, 5, 2, -2); + site1.sorted_index(1); site1.inverse(); site_type site2(-5, 5, 0, 6); + site2.sorted_index(0); site_type site3(-2, 4, 0, 4); - site_type site4(0, 2); - site_type site5(0, 5); - site_type site6(0, 6); - site_type site7(0, 8); + site3.sorted_index(2); + point_type site4(0, 2); + point_type site5(0, 5); + point_type site6(0, 6); + point_type site7(0, 8); CHECK_DISTANCE_PREDICATE(site1, site2, site4, false); CHECK_DISTANCE_PREDICATE(site1, site2, site5, true); CHECK_DISTANCE_PREDICATE(site1, site2, site6, true); @@ -251,11 +268,13 @@ BOOST_AUTO_TEST_CASE(distance_predicate_test7) { CHECK_DISTANCE_PREDICATE(site3, site1, site7, true); } -BOOST_AUTO_TEST_CASE(distatnce_predicate_test8) { +BOOST_AUTO_TEST_CASE(distance_predicate_test8) { site_type site1(-5, 3, -2, 2); + site1.sorted_index(0); site1.inverse(); site_type site2(-5, 5, -2, 2); - CHECK_DISTANCE_PREDICATE(site1, site2, site_type(-4, 2), false); + site2.sorted_index(1); + CHECK_DISTANCE_PREDICATE(site1, site2, point_type(-4, 2), false); } BOOST_AUTO_TEST_CASE(node_comparison_test1) { @@ -377,8 +396,11 @@ BOOST_AUTO_TEST_CASE(node_comparison_test8) { BOOST_AUTO_TEST_CASE(circle_formation_predicate_test1) { site_type site1(0, 0); + site1.sorted_index(1); site_type site2(-8, 0); + site2.sorted_index(0); site_type site3(0, 6); + site3.sorted_index(2); CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, -4.0, 3.0, 1.0); } @@ -386,78 +408,109 @@ BOOST_AUTO_TEST_CASE(circle_formation_predicate_test2) { int min_int = (std::numeric_limits::min)(); int max_int = (std::numeric_limits::max)(); site_type site1(min_int, min_int); + site1.sorted_index(0); site_type site2(min_int, max_int); + site2.sorted_index(1); site_type site3(max_int-1, max_int-1); + site3.sorted_index(2); site_type site4(max_int, max_int); + site4.sorted_index(3); CHECK_CIRCLE_EXISTENCE(site1, site2, site4, true); CHECK_CIRCLE_EXISTENCE(site1, site3, site4, false); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test3) { site_type site1(-4, 0); + site1.sorted_index(0); site_type site2(0, 4); + site2.sorted_index(4); site_type site3(site1.point0(), site2.point0()); + site3.sorted_index(1); CHECK_CIRCLE_EXISTENCE(site1, site3, site2, false); site_type site4(-2, 0); + site4.sorted_index(2); site_type site5(0, 2); + site5.sorted_index(3); CHECK_CIRCLE_EXISTENCE(site3, site4, site5, false); CHECK_CIRCLE_EXISTENCE(site4, site5, site3, false); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test4) { site_type site1(-4, 0, -4, 20); + site1.sorted_index(0); site_type site2(-2, 10); + site2.sorted_index(1); site_type site3(4, 10); + site3.sorted_index(2); CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 1.0, 6.0, 6.0); CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 14.0, 6.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test5) { site_type site1(1, 0, 7, 0); + site1.sorted_index(2); site1.inverse(); site_type site2(-2, 4, 10, 4); + site2.sorted_index(0); site_type site3(6, 2); + site3.sorted_index(3); site_type site4(1, 0); + site4.sorted_index(1); CHECK_CIRCLE_FORMATION_PREDICATE(site3, site1, site2, 4.0, 2.0, 6.0); CHECK_CIRCLE_FORMATION_PREDICATE(site4, site2, site1, 1.0, 2.0, 3.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test6) { site_type site1(-1, 2, 8, -10); + site1.sorted_index(1); site1.inverse(); site_type site2(-1, 0, 8, 12); + site2.sorted_index(0); site_type site3(1, 1); + site3.sorted_index(2); CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 6.0, 1.0, 11.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test7) { site_type site1(1, 0, 6, 0); + site1.sorted_index(2); site1.inverse(); site_type site2(-6, 4, 0, 12); + site2.sorted_index(0); site_type site3(1, 0); + site3.sorted_index(1); CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 5.0, 6.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test8) { site_type site1(1, 0, 5, 0); + site1.sorted_index(2); site1.inverse(); site_type site2(0, 12, 8, 6); + site2.sorted_index(0); site_type site3(1, 0); + site3.sorted_index(1); CHECK_CIRCLE_FORMATION_PREDICATE(site3, site2, site1, 1.0, 5.0, 6.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test9) { site_type site1(0, 0, 4, 0); + site1.sorted_index(1); site_type site2(0, 0, 0, 4); + site2.sorted_index(0); site_type site3(0, 4, 4, 4); + site3.sorted_index(2); site1.inverse(); CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 2.0, 2.0, 4.0); } BOOST_AUTO_TEST_CASE(circle_formation_predicate_test10) { site_type site1(1, 0, 41, 30); + site1.sorted_index(1); site_type site2(-39, 30, 1, 60); + site2.sorted_index(0); site_type site3(1, 60, 41, 30); + site3.sorted_index(2); site1.inverse(); CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 1.0, 30.0, 25.0); } diff --git a/test/voronoi_structures_test.cpp b/test/voronoi_structures_test.cpp index 5fe35db..052a3d4 100644 --- a/test/voronoi_structures_test.cpp +++ b/test/voronoi_structures_test.cpp @@ -27,12 +27,12 @@ typedef beach_line_node_data node_data_type; BOOST_AUTO_TEST_CASE(point_2d_test1) { point_type p(1, 2); - BOOST_CHECK_EQUAL(p.x(), 1); - BOOST_CHECK_EQUAL(p.y(), 2); + BOOST_CHECK_EQUAL(1, p.x()); + BOOST_CHECK_EQUAL(2, p.y()); p.x(3); - BOOST_CHECK_EQUAL(p.x(), 3); + BOOST_CHECK_EQUAL(3, p.x()); p.y(4); - BOOST_CHECK_EQUAL(p.y(), 4); + BOOST_CHECK_EQUAL(4, p.y()); } BOOST_AUTO_TEST_CASE(site_event_test1) { @@ -40,14 +40,16 @@ BOOST_AUTO_TEST_CASE(site_event_test1) { s.sorted_index(1); s.initial_index(2); s.source_category(SOURCE_CATEGORY_SEGMENT_START_POINT); - BOOST_CHECK(s.x0() == 1 && s.x1() == 1); - BOOST_CHECK(s.y0() == 2 && s.y1() == 2); + BOOST_CHECK_EQUAL(1, s.x0()); + BOOST_CHECK_EQUAL(1, s.x1()); + BOOST_CHECK_EQUAL(2, s.y0()); + BOOST_CHECK_EQUAL(2, s.y1()); BOOST_CHECK(s.is_point()); BOOST_CHECK(!s.is_segment()); BOOST_CHECK(!s.is_inverse()); - BOOST_CHECK(s.sorted_index() == 1); - BOOST_CHECK(s.initial_index() == 2); - BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_SEGMENT_START_POINT); + BOOST_CHECK_EQUAL(1, s.sorted_index()); + BOOST_CHECK_EQUAL(2, s.initial_index()); + BOOST_CHECK_EQUAL(SOURCE_CATEGORY_SEGMENT_START_POINT, s.source_category()); } BOOST_AUTO_TEST_CASE(site_event_test2) { @@ -55,38 +57,38 @@ BOOST_AUTO_TEST_CASE(site_event_test2) { s.sorted_index(1); s.initial_index(2); s.source_category(SOURCE_CATEGORY_INITIAL_SEGMENT); - BOOST_CHECK(s.x0(true) == 1 && s.x0() == 1); - BOOST_CHECK(s.y0(true) == 2 && s.y0() == 2); - BOOST_CHECK(s.x1(true) == 3 && s.x1() == 3); - BOOST_CHECK(s.y1(true) == 4 && s.y1() == 4); + BOOST_CHECK_EQUAL(1, s.x0()); + BOOST_CHECK_EQUAL(2, s.y0()); + BOOST_CHECK_EQUAL(3, s.x1()); + BOOST_CHECK_EQUAL(4, s.y1()); BOOST_CHECK(!s.is_point()); BOOST_CHECK(s.is_segment()); BOOST_CHECK(!s.is_inverse()); - BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_INITIAL_SEGMENT); + BOOST_CHECK_EQUAL(SOURCE_CATEGORY_INITIAL_SEGMENT, s.source_category()); s.inverse(); - BOOST_CHECK(s.x1(true) == 1 && s.x0() == 1); - BOOST_CHECK(s.y1(true) == 2 && s.y0() == 2); - BOOST_CHECK(s.x0(true) == 3 && s.x1() == 3); - BOOST_CHECK(s.y0(true) == 4 && s.y1() == 4); + BOOST_CHECK_EQUAL(3, s.x0()); + BOOST_CHECK_EQUAL(4, s.y0()); + BOOST_CHECK_EQUAL(1, s.x1()); + BOOST_CHECK_EQUAL(2, s.y1()); BOOST_CHECK(s.is_inverse()); - BOOST_CHECK(s.source_category() == SOURCE_CATEGORY_INITIAL_SEGMENT); + BOOST_CHECK_EQUAL(SOURCE_CATEGORY_INITIAL_SEGMENT, s.source_category()); } BOOST_AUTO_TEST_CASE(circle_event_test) { circle_type c(0, 1, 2); - BOOST_CHECK_EQUAL(c.x(), 0); - BOOST_CHECK_EQUAL(c.y(), 1); - BOOST_CHECK_EQUAL(c.lower_x(), 2); - BOOST_CHECK_EQUAL(c.lower_y(), 1); + BOOST_CHECK_EQUAL(0, c.x()); + BOOST_CHECK_EQUAL(1, c.y()); + BOOST_CHECK_EQUAL(2, c.lower_x()); + BOOST_CHECK_EQUAL(1, c.lower_y()); BOOST_CHECK(c.is_active()); c.x(3); c.y(4); c.lower_x(5); - BOOST_CHECK_EQUAL(c.x(), 3); - BOOST_CHECK_EQUAL(c.y(), 4); - BOOST_CHECK_EQUAL(c.lower_x(), 5); - BOOST_CHECK_EQUAL(c.lower_y(), 4); + BOOST_CHECK_EQUAL(3, c.x()); + BOOST_CHECK_EQUAL(4, c.y()); + BOOST_CHECK_EQUAL(5, c.lower_x()); + BOOST_CHECK_EQUAL(4, c.lower_y()); c.deactivate(); BOOST_CHECK(!c.is_active()); } @@ -101,20 +103,20 @@ BOOST_AUTO_TEST_CASE(ordered_queue_test) { *vi[i] <<= 1; BOOST_CHECK(!q.empty()); for (int i = 0; i < 20; ++i, q.pop()) - BOOST_CHECK_EQUAL(q.top(), i << 1); + BOOST_CHECK_EQUAL(i << 1, q.top()); BOOST_CHECK(q.empty()); } BOOST_AUTO_TEST_CASE(beach_line_node_key_test) { node_key_type key(1); - BOOST_CHECK_EQUAL(key.left_site(), 1); - BOOST_CHECK_EQUAL(key.right_site(), 1); + BOOST_CHECK_EQUAL(1, key.left_site()); + BOOST_CHECK_EQUAL(1, key.right_site()); key.left_site(2); - BOOST_CHECK_EQUAL(key.left_site(), 2); - BOOST_CHECK_EQUAL(key.right_site(), 1); + BOOST_CHECK_EQUAL(2, key.left_site()); + BOOST_CHECK_EQUAL(1, key.right_site()); key.right_site(3); - BOOST_CHECK_EQUAL(key.left_site(), 2); - BOOST_CHECK_EQUAL(key.right_site(), 3); + BOOST_CHECK_EQUAL(2, key.left_site()); + BOOST_CHECK_EQUAL(3, key.right_site()); } BOOST_AUTO_TEST_CASE(beach_line_node_data_test) { From d1768dbda786b890d206dde7f8d82b234472104e Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 1 Oct 2013 03:58:37 +0000 Subject: [PATCH 28/32] Comment out reference to missing test file that was preventing release testing from progressing. [SVN r86094] --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4f1962f..7fdb6b9 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -26,7 +26,7 @@ test-suite polygon-unit test-suite skeleton-unit : - [ run skeleton_predicates_test.cpp ] + # [ run skeleton_predicates_test.cpp ] ; test-suite voronoi-unit From a62754183dfa3a2a613291e14e974e16c55cb893 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Wed, 9 Oct 2013 19:55:41 +0000 Subject: [PATCH 29/32] Polygon: Merging updates to the benchmark. [SVN r86220] --- .../benchmark_results/benchmark_points.txt | 60 -- .../benchmark_results/benchmark_segments.txt | 44 -- .../plots/benchmark_points.png | Bin 0 -> 10492 bytes .../plots/benchmark_points_10.png | Bin 15729 -> 0 bytes .../plots/benchmark_points_100.png | Bin 16377 -> 0 bytes .../plots/benchmark_points_1000.png | Bin 16148 -> 0 bytes .../plots/benchmark_points_10000.png | Bin 16407 -> 0 bytes .../plots/benchmark_points_100000.png | Bin 16169 -> 0 bytes .../plots/benchmark_points_1000000.png | Bin 16201 -> 0 bytes .../plots/benchmark_points_all.png | Bin 22818 -> 0 bytes .../plots/benchmark_points_memory.png | Bin 24251 -> 0 bytes .../plots/benchmark_segments.png | Bin 0 -> 10402 bytes .../plots/benchmark_segments_10.png | Bin 13036 -> 0 bytes .../plots/benchmark_segments_100.png | Bin 13089 -> 0 bytes .../plots/benchmark_segments_1000.png | Bin 13067 -> 0 bytes .../plots/benchmark_segments_10000.png | Bin 13387 -> 0 bytes .../plots/benchmark_segments_100000.png | Bin 13245 -> 0 bytes .../plots/benchmark_segments_1000000.png | Bin 13223 -> 0 bytes .../plots/benchmark_segments_all.png | Bin 19244 -> 0 bytes .../plots/benchmark_segments_memory.png | Bin 24333 -> 0 bytes doc/voronoi_benchmark.htm | 617 +++++++----------- doc/voronoi_builder.htm | 129 ++-- doc/voronoi_main.htm | 115 ++-- test/Jamfile.v2 | 5 - 24 files changed, 324 insertions(+), 646 deletions(-) delete mode 100644 benchmark/benchmark_results/benchmark_points.txt delete mode 100644 benchmark/benchmark_results/benchmark_segments.txt create mode 100644 benchmark/benchmark_results/plots/benchmark_points.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_10.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_100.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_1000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_10000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_100000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_1000000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_all.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_points_memory.png create mode 100644 benchmark/benchmark_results/plots/benchmark_segments.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_10.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_100.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_1000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_10000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_100000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_1000000.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_all.png delete mode 100644 benchmark/benchmark_results/plots/benchmark_segments_memory.png diff --git a/benchmark/benchmark_results/benchmark_points.txt b/benchmark/benchmark_results/benchmark_points.txt deleted file mode 100644 index eb4ec61..0000000 --- a/benchmark/benchmark_results/benchmark_points.txt +++ /dev/null @@ -1,60 +0,0 @@ -System: CPU i5-7600 2.8 GHz, 4Gb RAM. -OS: Windows 7 Professional 32 bit. -Compiler: MSVC-9.0. - -Boost.Polygon Voronoi of Points: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000027 | -| 100 | 10000 | 0.000392 | -| 1000 | 1000 | 0.004541 | -| 10000 | 100 | 0.047540 | -| 100000 | 10 | 0.530200 | -| 1000000 | 1 | 5.882000 | - -CGAL Triangulation of Points: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000116 | -| 100 | 10000 | 0.002649 | -| 1000 | 1000 | 0.039140 | -| 10000 | 100 | 0.684090 | -| 100000 | 10 | 16.904600 | -| 1000000 | 1 | 566.056000 | - -S-Hull Triangulation of Points: -| 10 | 100000 | 0.000043 | -| 100 | 10000 | 0.000521 | -| 1000 | 1000 | 0.007125 | -| 10000 | 100 | 0.091640 | -| 100000 | 10 | 1.218000 | -| 1000000 | 1 | 15.394000 | - -System: CPU i5-7600 2.8 GHz, 4Gb RAM. -OS: Ubuntu 11.10 64 bit. -Compiler: gcc 4.6.1. - -Boost.Polygon Voronoi of Points: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000013 | -| 100 | 10000 | 0.000192 | -| 1000 | 1000 | 0.002130 | -| 10000 | 100 | 0.022900 | -| 100000 | 10 | 0.274000 | -| 1000000 | 1 | 3.290000 | - -CGAL Triangulation of Points: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000052 | -| 100 | 10000 | 0.001150 | -| 1000 | 1000 | 0.016680 | -| 10000 | 100 | 0.297900 | -| 100000 | 10 | 8.047000 | -| 1000000 | 1 | 315.740000 | - -S-Hull Triangulation of Points: -| 10 | 100000 | 0.000012 | -| 100 | 10000 | 0.000139 | -| 1000 | 1000 | 0.002010 | -| 10000 | 100 | 0.028300 | -| 100000 | 10 | 0.432000 | -| 1000000 | 1 | 6.350000 | - diff --git a/benchmark/benchmark_results/benchmark_segments.txt b/benchmark/benchmark_results/benchmark_segments.txt deleted file mode 100644 index da27ac1..0000000 --- a/benchmark/benchmark_results/benchmark_segments.txt +++ /dev/null @@ -1,44 +0,0 @@ -System: CPU i5-7600 2.8 GHz, 4Gb RAM. -OS: Windows 7 Professional 32 bit. -Compiler: MSVC-9.0. - -Boost.Polygon Voronoi of Segments: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000290 | -| 100 | 10000 | 0.003655 | -| 1000 | 1000 | 0.038158 | -| 10000 | 100 | 0.389470 | -| 100000 | 10 | 4.031300 | -| 1000000 | 1 | 40.912000 | - -CGAL Triangulation of Segments: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.001047 | -| 100 | 10000 | 0.014812 | -| 1000 | 1000 | 0.177315 | -| 10000 | 100 | 2.561340 | -| 100000 | 10 | 49.314600 | -| 1000000 | 1 | 1640.830000 | - -System: CPU i5-7600 2.8 GHz, 4Gb RAM. -OS: Ubuntu 11.10 64 bit. -Compiler: gcc 4.6.1. - -Boost.Polygon Voronoi of Segments: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000165 | -| 100 | 10000 | 0.002006 | -| 1000 | 1000 | 0.020440 | -| 10000 | 100 | 0.209700 | -| 100000 | 10 | 2.228000 | -| 1000000 | 1 | 22.250000 | - -CGAL Triangulation of Segments: -| Number of points | Number of tests | Time per one test | -| 10 | 100000 | 0.000483 | -| 100 | 10000 | 0.007006 | -| 1000 | 1000 | 0.084000 | -| 10000 | 100 | 1.191900 | -| 100000 | 10 | 23.538000 | -| 1000000 | 1 | 856.650000 | - diff --git a/benchmark/benchmark_results/plots/benchmark_points.png b/benchmark/benchmark_results/plots/benchmark_points.png new file mode 100644 index 0000000000000000000000000000000000000000..c3825054d42a58ab5a61e3ac45eec72f21b6dbd3 GIT binary patch literal 10492 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 diff --git a/benchmark/benchmark_results/plots/benchmark_points_100.png b/benchmark/benchmark_results/plots/benchmark_points_100.png deleted file mode 100644 index b876cbaecd40dd1c153aa708bd132873fc41dc7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16377 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

      FBNOl9xx-1NG;;~8jlLd#<&$! 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 gkPksc^*lrj3=9lxN#5=*4F5rJ!QSPQ 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 diff --git a/benchmark/benchmark_results/plots/benchmark_points_1000000.png b/benchmark/benchmark_results/plots/benchmark_points_1000000.png deleted file mode 100644 index 470962695be86ef2aaa950d855b7abdeb36fc427..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16201 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 diff --git a/benchmark/benchmark_results/plots/benchmark_points_all.png b/benchmark/benchmark_results/plots/benchmark_points_all.png deleted file mode 100644 index 68f89ca1571e09918b8af03fe01b273ea1d29f06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22818 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%0AlP2}s|NHUk>gspz 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�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 diff --git a/benchmark/benchmark_results/plots/benchmark_segments.png b/benchmark/benchmark_results/plots/benchmark_segments.png new file mode 100644 index 0000000000000000000000000000000000000000..0bbc03625125def98127de72341d9d189c7b2c76 GIT binary patch literal 10402 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 B`)2?E diff --git a/benchmark/benchmark_results/plots/benchmark_segments_1000.png b/benchmark/benchmark_results/plots/benchmark_segments_1000.png deleted file mode 100644 index 01b61638439f62ca3550c14fc300a1e12c0d0ba7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13067 zcmeAS@N?(olHy`uVBq!ia0y~yVEn?sz^KE)#K6F?>*lrj3=9lxN#5=*4F5rJ!QSPQ z85k58JY5_^D(1YsTOA{E^}qdx?>aggnqpX7#2a0C1VRpQv)wZe+#{^Qy0CR-t-URwAN~08(qa{G4m>uYOs&OUka#I;-O z>)YGkZ>G;bd*Va__v%%v;wqnt%FD}diwX;y7NJx3_v`ieiifQF`s@Gx{+@q-U+sYg z#?Q~r?k<0SZ*TSYV|}u}&lsQo@#BY1>@E{~`}n=Pug6vEs;H#g*pT?@-nDDj*jQM0 z?A{%}yR5gPrWORY_GxHoWnEhnIZJhW-d!yX4Gw<(`u~5wH#aqH+O+A^>C-#KSKYq& z>Z)_qy)Q1Zb~P18Is}E)d^9vP0?cPjnDF7*?EI?AO5Mm!PuB1Mm-RJfrTLW8Pd`6D zFKVD;+kgoK39(9q4{y&ZjWwpK+?PH+mV?fHJM`b|F1+ILNlucn``DJt3&p%b?` z&3AJwlWl9k^XAvr*Kf98cXxOBeA{X>!K+uUoS9|ny)q>4-X2S1FL?n z*r=zcH`_d4PhWq3{r@@_7Z)d|L$~wy%ZiCD3(>ln_3`7!bLY<8-Bp^rdSh$)xj8TI z@82JzSO0u&`J=~=|Ni~kFJoEs>q};%gMgIOue0X&Yd#!gKi((%`_=08S9V+1{`z8k z-p088UrpK8g$ospj5cl9@ZtCS{qhD04BwM|JUkSXs;jG&iV6w>R)%nLa^B(I8WsHg zm7?u+tHAR2_iA6S-7doA>fmtT;$rukR&OfLojFtU`K)>U@3-46i=V9sS=ByYyYzQq zVWIv1KcAaexfd;7?A|YT_fqKY>hJINRDPC{mS$#R>XWftR4JnSw(0lP`x_FO1$XY+ zRrmF3xcRRkv8%Dr*I&PG-McF*gQd;$QldY9{P^?BW&f*Z<*Z6pY~1+qxO}~gNrphQqNU}} z!2a;Rd{?$PosH8J>6%uxu5^)>mR84$wcGD;@$;`=v*ypY+xeXxw&y=TKVSdxsJOgM zg@CB&)G1R^a&!MqC>9kGI<)Qmix(a)yUX9p878?TBrKRZ_3FRBzh}p7&Az^FWymU4 zZm~UoKAjE?4c%S#Hb~ypdv``o&XbC-%*@Q4CvM%U`t;V z{#|8ntA9rja(6!k@2e z?(eHLot@hJ{=!1%S3<2$3j;KwY>z!W+%6ngSZFACcTeSH-G^~2uFl#O&i}GqHFzY*)b_Rui`1sMX@>5De!h@%$r^nZPJZk^%$798CUxkck?pv3}Zu$Aj{B6+c zc20kto;yDmtXlQzKqGT!XQ$TGtTQtVT}(1BEt#qvE@xMBl1?$}}RO>g?2KY!%wek8uRv2kzJ*GV2K_v`=f z^;&9G^rU0=?%iwG>IxR>Us>|*s&m!4r$3+1S6^gX{Y^qz8Wc`Biq-SV-`$CfirSTb z-)>{XoA>YM&z*br>5{qj^>*6Yr>|cR*PEW6k`fXUVp4r|Uj4tyw!}q?7khhoMeXW{ z+7Vx?^y=>J^0>Hr2b2h&D7x&vqndjZPwl@0v+uPTJ=K9Vy%e}W}W=Bv^(7np%bLY&F zQR?dKEG#Vi`EK|7J9qDb!g`z9_e00uRQAi++Wr6YdDW^_D^{#%WM<#g8oRsf?(T9> zVZQ&@tJN15yVw8ydOa#XjsKv*nSXzOr=Oqq_x1YyZZ0k?EG#C~SKqvOvuN?+sa~lu zF?06sw-;R5{!sT}-Pg_+p!&r_C2C8?#iQNgv&%XkZ#*E}aZtIQabCgypXcl6%$=Km zch}a+&uJSYY91ZojQ!5>g<)AL!@QFH|Ns5|_4W1IwQJS==17Q%Eqnd0q3*y5S%!vo zgXf?+ICuWE%#4f+e-7I-Fzj96Ue0J~ZM}K>u5FID5AWTxXV0QVO?z`C865OAM7nnE zveMVrk1bzPTK?{iriMm>y!Iuw{;!Rzwr<@Tp;I?UjDf*wa*SSnMn=ZhvPpbO3Mn*@B^iJa=zgYPWw@pw`r_TerSi{%5{L zVbbkwxnIA2&ENCU&Bev#@}y(Oj?FYqfA;K|nTg4oxV^vb>?~$wWd#-Db~QhCmA=09 za)ZD-28P_L7cM+__pa{!J=>*0GiS~60{NI*T+gQZ+ZqoQP$F6pxHu;_cdOUBxV>4K znJ4SSy?lMoet3BJ{9Nnue}8^{dn;`hz{-%JtgO6v&6+jQ+w*eo@2kDFCDWzk*_oM% zhubVIElc0u1Bo2(lg*C0w7>rU=JfM=(c9kq`uaL{ciGzo`x2l0%XoKEq`gRM{giwA ze=j(yzoL3lCl70_jxW<(UG}dTkD0X@9J(D8W*8>BrKF^!rmC9${I+qKs!*qjsp;3_ z^7TDEJvD#7USIA%|DNDprycf9Ezzd=^Ym7%%D+_h=repN zUbQl6zj#oY_WVCiTe(w>I$ah8t^D=%_4k|U^93h*sNC9B`ug?y{c-W}`%7L1xx2e7 zUDC2FdUAqYzD7ZW>uA!)K3QuX9-c#o4zcmcSY%yUu{L`9w%dhUf1b9w!8?B*d%Lbh z`R9PVsq3mQ&TC;iBcE8iyIkxZwH&^#~uB+0-#zx2EUsg-D zwzgVYTJEaUdJ_Ef(A%g-*HzkLTs>94FW(&j(z)x(GxlZn4+Y-EgkI77VW_xxyUA%`x4%x0C-zg%5)R$9MMwrwiB_<~i*sK6X4) zlIQM2P4&qqudSJ*Y?AT!uzIW0&sWi}V`E}WxU;je?$v(3yJLq%qr-!D@8m>9pFVsT z7#zI0=I5vQ`oEzoL%zMaS^V?UQ%6U~oWIKMeJrf3scC7ucJCGrOio@rb7rLbohN=^ z3nyCZ^K&(9Zfk4H<9$BOZ^zZFv!7pvgnU^RwnIN=N5H~>IaZ~o&YsoP)O>lYS6WU^ zE`R@DGeKGVx;vLI8(Ujf|Nr;*RY8Am?_872pq!jHudc4PepFzhc*oM2kEx;U*s)_f zcI>!wC+6EvgMa`2xu{G(4Jz~Y?6LXA=WTAjz2ELv$J+Sl=<1i3mUfHl_sQGKJ^ZKg z@aYzwdm9;Uy}Glr_}#mAQU3paz1@EQ*SEK~-|YSD-Y+L>U$mmXnj?{+&g+ z{G34%I|Fa>v7XM3juk6cUXY}8$=+voG#m~d`}(@7Dl0+Hr9s<1`P=^$5fuD*-u}Ocn3$NTsHL^Fx{69k#&?6F=RMN{ zPaIEXdf=xZ@aJd$*W>C{TcS2^+4Sz}#@H=f+w<@5%elF!p@E?-@z?kF`%_PgDgAo0 z`TR8fc)Q9^DGLKK($mF-g`HhCZrpf!x_)@Rgp7=gwDjxu@AW62tor)usF+^Nj)I$; zQs0(lRA{M$Kf0k5TfXpb?UQ87>w6dP<6wKhdF9K>3H~}ZqMJ5@3sQ$9kpjnCob1d3kzX)QQ|t zkm%>fC%86d=cK*WU%ub32el}Jf-aq#YaN}XZf;)w>dMN?%l+fG=gA5#U9!YyrqR<@ z@wkq@zPx4I&gDlRSv!H@z|21PcZ`gTudlD)U-I(OzS`fQwrF3psHo`DrAvSQ`nAe? z&)&W3V|G4z^(rbjI5<4q-6ec|+}DpEKYj**?3J?V>Ccmo_X%G7^Ye3Yaq-+abNFPf zQc_Yx1O)|!gf8u^{{BCB_Vmj}C(0{Maj-O5m%p21RqAzJHZ#`O*LQo~-CKKp3LEMM z$HwXka6BpcxvTVb-klwW2?rWdPfyESD<&qkE_U~{#2JRk$5K*KmMmK)CMueHXUD|c zgST)0J}zI+!^I`U)ymb{)UhsRr%~#uDNmj}*|Nn%Uw{3K84}Ua(Nn#)W?oiPR#q<4 zc6N4F3euWtG_z-~@>E@OQ`5DpR$byN_wi?bVb9FmoOrnHE-uc$zi;i%s)vVKCrp@d;DCdYmzS4N_tDSK z&xdcnygq(^zx_W8W#z+{FK=G7XweD~IC1gf#vMCmtW8Kw-I{xQoBsYkM!LFhZ>G-= z&9C_Q=;-%*)%hnTC<=A9=z9A4u3fn@(4Oy6{g1D2Z~VVs@BVJ*&YhN)mO`CJE?*A* zTza->Wk}V-L#%CyZ{ECVFn&hdiAQ(#EdH|0*z+s=;^InwMt7#>ClN2D|YSr zbz@`lv}x1W*x25LUS4zNfjL_P-?GOm+cqX2e|K~9^CO+Y+TrVbyuCkv{HVC-U^Dyj zrAsr{`pvidduFC_Vq#)uW~T3LL9SMpFVE-KS5<<*T-)kv*RF+aZfb957rc4bd}mvgzWV$7`_iDy)YPR;3psdrOiWGp*8bi$apJ`# zo|CJ-y;*th&dHORpPrn|*_0hxcjmtt!-ZAqNpd^0udgdDEw!_=3tu0nx@iBuU#E{B zchA0h>5`F_R@UolYvXG^x?W!wn`$&OOnKhCdF*^LFRrh@-@wTH?cLqiZ{M!{xvFZ# zilCKB%F5s0-IW#*QJH?a(?daE#_ZYBQc|a$eq!YotNCOr-lZ7ccIr*$`SWJwJynK8_ zgojJi)Z2gJSs5%YecWOh@_G@T)d3ktvc&E#vox7^P zzx(|B{OlPsTH4#czr9`l`Po@+F`XM5liPP`=I6gZJzc-sMQNf(NL<`H(RXKeReVhH z@!>gaQ2XnPq*>05gU#&5#>UszL^``@hpmyYD0uLH<=N9SS=tnpR)%C{WqG-zrKPE= zs=gARJ?;Lk(%0Yb*Kgmv+1T7%UCG(`@QoW0+S;qt=KD{WIrCv!3VxpQ>|IObJ8ll*oy?R2PCXi}2W zZ^5JX|Nj{0+}LpCN=R{W@wclxcIZr>BR7snKbn zK&Oj~icseb>nSE1CmU!@eRXcG_1)d&^%WqO`X5<4;aB7Q%SJ9P$BrEn>QvFwJ9qKo z#Z#wN?b>B!X<7N_$H%Cr=K1&bl)aS_jEs!zJessLC^8^GKwdsSBg3NTiHDL^-Jc3q zS5OGB^GaR0abw1`X=xc5FP=P65$cqYk=dff?9hH_3s3kX;jiETS+V}%oqH9{>=i<` zX~!P1&o-{>yYsUmfT5wFp5=riq_F>x11dUskwNi}Jfr?$*_V6= zf;r01{jhxA$8N&(LHN*Is{gu7Ze5F#hewlx2Qh9W1_qNO|ES#%T2;w!DM)ivhTc!*}UdL%(_R1 zUA}%;$2;HZDp)p9;9Y-0oA2KT>w2r-b8&0GmpHLx*E_#x1D>0lQ~y2VUA*hm46mvM zum3T;n9#Vfbz-Ex+kw?D!%SO#D+g$b#;$YUUtsDM7ryTGKAUwpvE>X8JQdy~-M;(U zcQ<4H2mMEa?_ySloH}$l--EkORf$nvEsdc;q%>7^`n79Q|EWrfAO7$iMO*LZpAaiK0b_!JK4+l|*AuUjW9nowM0Z^RwE8N-X zw1XL9I;a%^HnoVI!M3U3IhQib8koRCK8SUPpw^w)$!w!qR9swKRHP!*xqSKZT^si8 zvqP#sUVM9dJ2NxWMP;hj-#>p`lqNn~wRP*)R&H^LwvC%NOIww!xVG);)vL$*WH)cw zVq##x!Nc=r!D0unR}WlvP@DYp`E&m{79S6_atE!va_Q0}U2`L&Stgm6Zf;J$844bM z?tJm$;$l8NJ~ubFS*zRH+Ac5iRbEv5{G8{~pyJ}roPM*v>(jh2YrLe31+C$J7 zNWsHH4<0-?apJ_QS6SOqK0Z3CsHmvF_sgZPudm{aw+{KX=RT_xANo^HBNu^Jme{JsUR`K0P(ny6nva z50$G|uP$A>)TQL_uhRPZ|G~@sHs-haR#sQX?<_ic_3GAT%a*NM*VnNwZtttdj~_n= zf$Nv<&7C{9U)I{q<@59N=g*!kEh@4qc`;$)#6TAp7Y`2)Q0HDd`3c_#lL=l+mn~c7 zl9HAd78La9!>QKRR-w)%H?Kx-&-?rD_xrN4vS-hpMMck?IrHocL+6D7b8ISubi`KQ zm%cT<&;6aIrsltY|K7YTC@kE#ZJVE`r=(ShMs!kM-o54i@=9IZ-Q67>6Hcb^^75YD zcDQYKjGj1GtJl&=pcdJqw{PdpnezuUJf))2(%!BgwI$=>q1IWt5>iq^6N6SxIho?L z@WQ!seYU5UEn5~E8XC1bK|&{D!-vYm$cTtL`|Ia-WMyaT>gdSLOW@}$ude%#qRz4Dn2G{e*5M1b$w+JIDGl?<$L$`ftqM5PF%bg7<=&4sjS=Ea^>XY-n7eQ ziR;J7SQagrIdkT(NlTV3yLRQuj-5L*-#R`2|9L~g!AlFdPhY$C?cLqoT2ogoS#spq zF}I~bCsQ`1CA+Il)|`4uFLswnY-;-qp2I7aXPBIPTBH=TGNk<7or|*+Gu*A_O_Q`J zc#yyU?=s7qMj00rwyBtyT)BC3=G(;GT*F1Rm(9z}Fw{NVhtk>7a+t>fA2>^i$CnhTE$L;xXuloI5`}(>s zFD^cP`gC>p`hVYU=g)rU)Q~CJu)Ja8#*HpYo!#BVB_&%nZCbT%ou8kdoPC`QsL#1) z(V|CBPEKxS;}z;Y`v1@8{%0IP#anmm_;G7%wo6KC>e0Fjt9IrlCnrZm&04r{;pEAa zJyc#TV7^$m}jo5;LwbZfr>W{Oqi%s_L_6&jJGj+uGXZ*L?B}2?@!}TZmD&hhINEUH|y;81 z$%Nzfy6#*bN`(9}k|oL}96uBBM^HFi0$Pw?eIlIC(4a1UXs$M_j6ZbOh+%=dz`K}- zd6Eou!LN2PgT{13-QGb&74I-QfU1H+TX-N9jKof8olpR+3NAzSCq6-|0(?&6sGC^W zoPti3-sNU^A)w{9;x)L63-?NPZ~j#i`<;owswGI}VyXBo$wPBjv(0|FZ2O`Tu-Z~H z$6fE7tetlhhhBf|JJICa1IK0SteF_zt_ge+c>OVN?Ds`;74Pf}lAIB?Q~p)djzddc zi7QQAx0{*aZPUv4W?PSCHhW!gy>6SC&hg!SfystF&xL}O<8!|}kkWizdRLaA!iH&b zn_iq(VtMTM#m)+Mq@ zp68WLxSe`hqO;vpNsi$b-({niyVJFs`=83~F7$V0O0p{085U>%HzP02b?&-;35G8c zhvu%Hv3lvusb7y6%-wM1)YR2N`7eKUFgo-nMzyV0{`tM*<(}_{yvyaL+?oE}PRT5{MMwmI)8zV`DWAH#(((3pZQGs7?Dhvy`hr80oqfQLbegdfz( zo5l!kp383MJ5`*V`+l3i2lv}LJD^5r;yx?uIPG{;_%;=D>aA)W1KLy8cb24lZ zJT%u>_Kq$y!v!~v@^c^DeITvZmk;iVF0qD4gA&!h7kdtP`TEKlrFcX{+*lL2Iq%Mn zgSCejEm|~Xipbh!VQZs~{a+TwfRa_*ifD zvaIDb)vLZSFEGVo{{FCCzUa=X6)QA!bzX{c%fD>K42j_2;B78?)0Zz>CM7Lx9xM&^r`3#UE7z?P<6tS;S#x(+sd?TV34??K zn^I423FGGGzP>K@w85DfhRH@oMnS>B-CbQ~d3SDX*@`x*V7C7JTHH*)6buqWt#o+(o#V|K~GOlGc&XMwcle?Q&aQu)?Irw z(>UG9$!XuuXR|+i_;7Nvy8le0r8iTqr+^0{%=r2Hw`?(4JN;O%ba+_Uww#-r3LhU^ zIeBi!rOTI>2E8=DUlSY{IB~{|8#iuLJUrC;d|vgspRz9!{Mrikk~Lgd)>Az+zc1u=Ssax zKHhhCbNcyCVfCryn|WXqH;3w~dWW$BBFQ z_AOY@kZE+PucPC~)9LYt4j=A(aXWwiT+8BT4-dD`ojdpMpFci6K5qSTwLd>SJ>1Uk zKi6vOQP~#>=jL{-*t2Jkd%qmd;V*A)ZeFv-=dSG9PkOPtI9QlKvyMhH*Srk7dGqGF zb?aW8H4Trx#mewPU-pc0`P*At*R4Bu{P^=%S691yxgKBt^T&^jwNX(~ZmzDmcXxg5 z*5CKy*4EWNYS~*OOBbvT(Nb4mZe9LPAP_VRsX6u3+UV_ik(*ME_sP15NJ{Q3e}8Ym zf(3Pdf2F3T3I@8lwN0NM9v64-`~7-(F|ldWr;E$V-c4a|Iv3Z`;h{BklRW2)nKSS1 zF89AXH|_NMdwXwRxR8*Vy7cR+pp`m$dSwL#39B>LLc`PQdEKiknq?7tGcGFG+wV6{ zKey-CtJUw`y<4|#olvJsaq0JWcb}i1Z*FMF$PZ@+Zu($Q{l@1>U%o!j2r+Ny0}V4$RwbZ(C2&6_v#^73-F>c#GA zX=^(-%XGDSzue}uv$G5mnWF6~KRv1Z{4Dc(ocs5k(Gd|-rcW0R%*|cf+S>YS>$0b% zrKQvLV!1dtGJa*n#m(#P?yibndv#hFBg3!mowdKqZf{F57wJCw_SSs$=|86bp1bGx z-}AG2wwO*hnezPne0~m&9R&}Yrca-~bZM%ybMwZH8^dT=wnTcXxOB^_tLH<(Ctc-EUN9 zZV5BhF8`Lu>&Mc_2V5}o7eKcx#qxgnX~(d%f@pr_rYpCZARz#op-A5FT8fl z<7(l?yd;N*+rFyXEHQK9xy`uXt%2@m4jzeFy1%M}-p;EoU#}&9=WRzUM+XbfU8P-D z1=li9Y@E1r#q4PF>j}l}fxF&uJFtT$%DUb(o9pWYYd)3T&dqb(+A-F(D)pWJwRif~ zeYcLhc)%ClaIT@?`Ky0-uPo|*KVg+%{mN7PQ*Ulmn|7}3-sjT0g5ZIaRbNi|v7J1p zpBi3PCT}oZkOL&~t-av+tAlgBJ<8?h56#tPU%ii9S&fg;_Bs6LM{PWY^+}fIbXGfuLHWv%XKQHyBdinbL zcAhwM=FPpm)vvnOh34hueg1*%1TSYtJkhY zMMSKKzpACLr)OqjQuFia^x)v&;^N{^t*PDJ-riGPl`cAmS$~#z`0~n1s;=h@X(y}h;7YpIcr&YNp%qhIA38ykyq z9lf)&c=6)JH{-YS%UB2q30->AC&9+eFFtMU+P8OimxpSFdU|&D_V#)$opdtA_p~Ti ztA~n`(nOCX0UAq!GSkx1Vq)fmXzi`~x+?5x`+B=${eleYbEV#8W@i5V{r$R*r>}3S zH=m4!fQ-x;zYR;4FR!kw?3J_q_2_8#9qH|xHr?8mJG;HzJt}I}HSfpAdbPE+qqpVU z+)?=W&D*zEpT2zgGHB(O+4=icu2|vWYb^(*SgZrsq*+p8+% z851*S>(;GPr-u6ap8fgx`Rr-d78W7l;m403zrU{*v=VUNzI~I`d}mn{E?T;D>GbK- zL5?l@-_Lu&Y_65AalwNF_v?Q97H>+uu)s0LGb3Zg=FP=5H8qKeiD6-35fKs2&d%@e z?R9o`wlsT(=&|43ReHI~R7pw6#^%pue|yzM`TPHV`}6a&qod=wbLZ;n>eSTK7Q6TR zd3kARYtObS&GLTBZJ>YH{Z&mlsF_%t{69A@&#vyzk7ZAp8WX;}xaccA)2_Da@~O4! zm`Yao$?p99>sQ>al9fAl%;@0a=GNBMuC1-rkKcD@nuZ7$c+94&>lbuU=C|t+eZ9v2 z{~Cs_4Ds{xD}Q%KanYAAC7{W&=qGAWbhtTDHcUqkuw(&}v<==}53QEe$lM@w9 z&B*w1QhmOQtLxNh)3{igT)V~A#_zW?GMcpZ{i|11KR-SF@#DvxJ26VLY^%3b*(}w2 zb9?*xwQJX2>$`L3j+eK$xPF|@RIhd($xYeU*Bv-;prfP1viMm_dirX2|JYq6oV>hq zO|!%LCkqoHs_?S@*ZH$n==K zuKTYLLy14O$;NKi_cCN0OHR{~vp*nO*9z}D?`c`hRnv+zqAKui&yqu_te`~%t(lT> zK|+OlZ;CmrSGcqD5V*I0Xs&jPwf)0QO#X^@b{^Woqi;B48Y5UWs1ipV0zT|rah`3T z(~ja+5e7&la`T+`jy2$lf@SXC*hd#MC%gmK5dzSf#E>Vi^O@qZ;{8253oa|%*_qU{ zMzV4zXw9up>XN^vaSVSN3Z8rAS)SVQX97snGc)D7#v$`CW_!guJ6COv&j|Xey|`w< z>pq9wJKt}ZBf%W|ooRuy!kwL2CNGQ6f3+9;na?G)y5z2SMNUuR+P~JNX8JF8$ur2Z zKK#cab;dn}$3rMo#%ND{Yv9R}yRsSFqLLauF|T&}W}CcR{CXcli9*Zo#eq^0cizjb zd>zNYu!ZS+BP0G!I9h-GLh|3%ELT_8>aWZU3?`u=AraBh+bchBYv0}5>pOcpD?>y3 z=55>R=FCXVyT9*l-(E(B26e_~7>k^ddj1DIb93KziE6j;NE(&AxbWe_hdFcRn3)8H zhi|X`{%%{TL-FlbuU-i%yOq>&M?ER}d1YnrRIk+CTdu9Tb?erH2M_x0aerVtBx~{W zK{NlWSFgUkzhD3J)6=8f;{QLNx6jR3vTj}8`FXZcty)vPR)*MJ+O}-jvWpil_HX{a zZR>)kCnhSNxBWiHK_O%MwW!pzv}cbVO`0*|#zkwUI)@$3ucf4=&(F2qUiY_3TwGj9 z%BJGOj>5+sFV4&~Ubt}K<>mhWUoM~Dv0}@Xk|Q00-QxOuyu7g+lU$QQ;PIZy&rHnB z$NOZZ<>mLMo}M<_JfDr7J^#**ja#;qJUKBjfB)aIjEomcy{BJEzBJdm9JJ!uWy*{h z7S-S0Y)n3WZl-a2hspN6_5c6vsr-E7*V=E6wIXM?1w=(zmA$#K)O-4`pFh_|Y*ezf ztvxkGQ&`<^PtjAZ-B*`-Pk(l9u65<7C-wh--{)#|`n=`M?d|Vd#p4u|&R&bUwfox2 zjBTlFo%42i78HCazh8U(-F5K_&iDzuYrTDZ-dtYZKXc~Hw8YxlzwPpM6(1fr3JXuZ za3R3n-hN@gjQR8bKb;<5RZ+3$@3-6af4@!-(b~FU!;i1m<2zSu+ji~xb#p_*j~5m? zyM#nV&6+-ad+Fly3KXzBi_jh;Sy?Yn5a!SWEoybM^w(Z(At6IK| zNAgfu-ZoaHQ)kZn`SG~lJm-c%>8mS~CQZ6=Fdwbtr zT6+5T`~CALOfabWlJT|8Jnv3HLBWMrmEP6=-)_He;_rHST05`wveFY#vjqa@+tsd% z-+%8LH>baF&z*(6LPA1qJd&4IhwDpA&*l_Xn`2el)iGzz9B_a3`0?lG?f;jQm-~Bo zMC>lh_4DhyR?RGU^X5%nDU%gTkAWtr-@Ws5nKo@&|K;{D{v-G9)g9>&bXr(&VS(df zw_YP-1k_U{>93)AW~wd^Xor<|BCBG1Vl%#7QNuR`0SM{Q~tI$Ha7aG6&Dm( zRDOE$@$vELI*~$RVrGelSk9h$)vhEdExkJ3AS*k&x3@P`OZ51@t+(34qBm^Vknle- zCFRJ!Xbq7~(pn;2b$@^TeQy6hb64o~b+Pg`6&JSbS-LlSE|;~n_1bCY=h?2lI^~*L zVq#*^&N~+_TsUxG!PRD_11Dso)J3?C_sQ8I)E<|rv`h8!cDLSai}|(S+NFE)Nmo_`USAiR?EdlU)vK+ot*@s0`1rIqCC0|e z9$&V_&-L=O*>an%skwy2#JqX)=8s1^gTHQzb-|{zvr@^)kEh2~Wqx>Y@b>on_jh-1 z@9aGJ>gwwImCxti+?>Au=d;=0zJ2rEzN_l%s}@dSCMKr3e?On^EPgH}A;H4R%F4o0 z^W~y@l{^<*&$X`aVrUO3KY0 zynt2Nt%rk)>r&OJdmkPizFG3j>2-)n?#`Er*||FVdQ&MBb@0CD)-tpET3 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_10000.png b/benchmark/benchmark_results/plots/benchmark_segments_10000.png deleted file mode 100644 index 4f0e840cba6f65ad5e2aa695fff7e576431c86ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13387 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 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_100000.png b/benchmark/benchmark_results/plots/benchmark_segments_100000.png deleted file mode 100644 index 126bd9f07920fafd853c3592e8ed0ec418a41bdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13245 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 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_1000000.png b/benchmark/benchmark_results/plots/benchmark_segments_1000000.png deleted file mode 100644 index a484504809a55132bfbdf29f33255d3cbce83e6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13223 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 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_all.png b/benchmark/benchmark_results/plots/benchmark_segments_all.png deleted file mode 100644 index a2c77a130226b2926bcd6b2e914627c5cc49d302..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19244 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 diff --git a/benchmark/benchmark_results/plots/benchmark_segments_memory.png b/benchmark/benchmark_results/plots/benchmark_segments_memory.png deleted file mode 100644 index fe25346368b331835a90448c2bfdba9e4d76950d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24333 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 - - + + + + - - Voronoi Benchmark - - - + Voronoi Benchmark +
      - - +
      - - +
      - + +
        @@ -72,124 +65,172 @@ Tutorial
      - +

      +

      Voronoi Benchmark

      -There are not many known Voronoi libraries that are capable to satisfy -the -following set of conditions:
      -
        -
      • could handle input data sets of points and segments
        -
      • -
      • give exact warranties about the algorithm robustness and -output topology
        -
      • -
      • compute coordinates of the output geometries within the -fixed relative precision
        -
      • -
      -Below is the list of libraries included in this benchmark sorted by the -number of conditions each of them satisfies:
      -
        -
      • Boost.Polygon Voronoi - satisfies all the conditions above, -implements sweep-line algorithm.
        -
      • -
      • CGAL - satisfies the first two conditions, implements -incremental algorithm. CGAL is a well-known -library in the computational geometry area, especially for its -robustness.
        -
      • -
      • S-Hull -- doesn't satisfy any of the above conditions. S-Hull is a non-robust -implementation of the sweep-hull algorithm used to construct Delaunay -triangulation of a set of points.
        -
      • -
      -At the moment this benchmark includes only two robust implementations: -Boost.Polygon Voronoi and CGAL. Thus we are considering comparison of -those two to be of the most interest.
      -
      -Other libraries (OpenVoronoi, - Triangle) -would be added to this benchmark -incrementally (we are open for suggestions).
      -

      Important
      -

      -While results of this benchmark show complete dominance of -the Boost.Polygon Voronoi over the CGAL Delaunay Graph implementation, -we would like to make it clear -that both libraries use different approach to construct Voronoi -diagram. Thus there are problems where the CGAL's incremental approach -would -be still more vital than the sweep-line algorithm (e.g. input sites are -inserted as a live stream -data).
      -

      Voronoi Benchmark Details
      -

      +

      Benchmark Details

      +From the topological perspective Delaunay triangulation is a dual +data structure to the Voronoi diagram, thus libraries that provide +Delaunay triangulation construction routines were also included into +the benchmark. However, from the computation perspective Voronoi +diagram contains more information as it embeds information regarding +the coordinates of the centers of the inscribed circles tangent to the +three or more input geometries.
      + + The benchmark consists of the two parts:
      - -Below we list important benchmark details that should be considered -while reviewing its results:
      -
        -
      • We ensure that input data sets are the same for all -libraries by initializing random generator with the same seed
      • -
      • We ensure that input data sets that consist of segments -don't contain intersections using Boost.Polygon functionality
      • -
      • S-Hull's implementation doesn't process duplicate points -properly, thus those are eliminated before the algorithm execution -explicitly (Boost.Polygon Voronoi and CGAL do that  implicitly)
        -
      • -
      • There is no Voronoi diagram data structure in CGAL/S-Hull. -That's why we use the segment Delaunay graph which is topologically -dual to the Voronoi diagram
      • -
      • CGAL's and S-Hull's output Delaunay triangulation doesn't -contain information -about coordinates of the Voronoi vertices. We didn't include time to -compute Voronoi vertices and memory -storage required for those in this benchmark.
        -
      • -
      • Both Boost.Polygon Voronoi and CGAL process each input -segment -as 3 input objects (segment itself and its endpoints), thus the running -time and memory usage for Voronoi of segments would be at -least 3 times -slower than for Voronoi of points
      • -
      -The benchmark was executed on the following two system configurations:
      -
      -Hardware: Intel i5-7600 2.8 GHz, 4GiB RAM.
      -OS: Windows 7 Professional 32-bit.
      -Libraries: Boost 1.48.0, CGAL-4.0.
      -
      -Hardware: Intel i5-7600 2.8 GHz, 4GiB RAM.
      -OS: Ubuntu 11.10 64-bit.
      -Libraries: Boost 1.48.0, CGAL-4.0, GMP 5.0.4, MPFR 3.1.0 + cumulative -patch.
      -

      Voronoi Benchmark Results

      -

      Random Points Benchmark

      - +
        +
      1. construction of the Voronoi diagram / Delaunay triangulation of a set of +random points uniformly distributed over 32-bit integer grid (voronoi_benchmark_points.cpp)
      2. construction of the Voronoi diagram / Delaunay triangulation of a set of +random non-intersecting +segments uniformly distributed over 32-bit integer grid (voronoi_benchmark_segments.cpp).
      3. +
      + + + +

      Libraries

      +
      - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Test specification
      +
      Library
      Average construction + Boost.Polygon
      +
      CGAL
      +
      SHull
      +
      Official page
      +
      www.boost.org/libs/polygon‎
      +
      http://www.cgal.org
      +
      http://www.s-hull.org
      +
      Algorithm
      +
      sweep-line
      +
      incremental
      +
      sweep-hull
      +
      Supported input geometries
      +
      points and segments
      +
      points and segments
      +
      points
      +
      Output data structure
      +
      Voronoi diagram
      +
      Delaunay triangulation
      +
      Delaunay triangulation
      +
      Complexity
      +
      O(N log N)
      +
      O(N log N)O(N log N)
      Memory usage
      +
      O(N)
      +
      O(N)
      +
      O(N)
      +
      Robustness policies
      +
      lazy arithmetic, exact predicates, topology analysis
      +
      lazy arithmetic, exact predicates, topology analysis
      +
      non-robust
      +
      Output coordinates precision
      +
      128 machine epsilon
      +
      no output coordinates
      +
      no output coordinates
      +
      External dependencies
      +
      No
      +
      Boost, GMP, MPFR
      +
      No
      +
      +
      + +The other known libraries (OpenVoronoi, + Triangle, Vroni) will be considered for the inclusion into the benchmark in the future.
      +
        +
          + + + + + + + +
        + + +
          + + +
        + +
      +

      System Configuration
      +

      + + +Hardware: Intel i5-7600 2.8 GHz, 16GiB RAM.
      +OS: Ubuntu 13.04 64-bit.
      +Compiler: GCC 4.7.3.
      +Libraries and dependencies: Boost 1.54.0, CGAL-4.3-beta1, GMP 5.1.4, MPFR 3.1.2, S-Hull.
      +

      Benchmark Results

      +

      Random Points Benchmark

      Benchmark Points Chart
      + + + + + + @@ -200,15 +241,9 @@ of Points
      - - - + + + @@ -219,40 +254,20 @@ Linux-64
      Linux-64
      - - - - - - - - - - + - - - - - - @@ -260,17 +275,14 @@ Linux-64
      - - - - - - @@ -278,17 +290,14 @@ Linux-64
      - - - - - - @@ -296,17 +305,14 @@ Linux-64
      - - - - - - @@ -314,71 +320,27 @@ Linux-64
      - - - - - -
      Test specification
      +
      Average construction time (in secs)
      Number of Runs
      Boost -Win-32
      -
      CGAL -Win-32
      -
      S-Hull -Win-32
      -
      Boost Linux-64
      10
      -
      100000
      -
      0.000027
      -
      0.000116
      -
      0.000043
      -
      0.000013
      -
      0.000052
      -
      0.000012
      -
      100
      10000
      0.000392
      + + + +
      0.000206
      0.002649
      +
       0.000073
      0.000521
      -
      0.000192
      -
       0.001150
      -
      0.000139
      +
      0.000243
      1000
      0.004541
      + + + +
      0.002250
      0.039140
      +
      0.000753
      0.007125
      -
      0.002130
      -
      0.016680
      -
      0.002010
      +
      0.002184
      100
      0.047540
      + + + +
      0.024100
      0.684090
      +
      0.007917
      0.091640
      -
      0.022900
      -
      0.297900
      -
      0.028300
      +
      0.030552
      10
      0.530200
      + + + +
      0.292000
       16.904600
      +
      0.084336
      1.218000
      -
      0.274000
      -
      8.047000
      -
      0.432000
      +
      0.451913
      1
      5.882000
      + + + +
      3.470000
      566.056000
      +
      0.902300
      15.394000
      -
      3.290000
      -
      315.740000
      -
      6.350000
      +
      6.603814

      - +

      Random Segments Benchmark

      Benchmark Segment Chart
      + +
      - - - - - - - - - - - - - - - - -

      +
      Test specification

      -
      -

      Random Segments Benchmark

      - - - - - @@ -388,12 +350,8 @@ of Segments
      - - + + @@ -401,32 +359,17 @@ Linux-64
      Linux-64
      - - - - - - - - + - - - - @@ -434,13 +377,11 @@ Linux-64
      - - - - @@ -448,13 +389,11 @@ Linux-64
      - - - - @@ -462,13 +401,11 @@ Linux-64
      - - - - @@ -476,99 +413,22 @@ Linux-64
      - - - -
      Test specification
      -
      Average construction + Average construction time (in secs)
      Number of Runs
      Boost -Win-32
      -
      CGAL -Win-32
      -
      Boost Linux-64
      10
      -
      100000
      -
      0.000290
      -
      0.001047
      -
      0.000165
      -
      0.000483
      -
      100
      10000
      0.003655
      + + +
      0.002284
      0.014812
      -
      0.002006
      -
      0.007006
      +
      0.002985
      1000
      0.038158
      + + +
      0.023240
      0.177315
      -
      0.020440
      -
      0.084000
      +
      0.032180
      100
      0.389470
      + + +
       0.237700
      2.561340
      -
       0.209700
      -
      1.191900
      +
      0.337400
      10
      4.031300
      + + +
      2.488000
      49.314600
      -
      2.228000
      -
      23.538000
      +
      3.633000
      1
      40.912000
      + + +
      25.00000
      1640.830000
      -
      22.250000
      -
      856.650000
      +
      39.090000
      -
      - - - - - - - - - - - - - - - - - - - -

      -

      -
      - -

      Voronoi Benchmark Summary

      -The main conclusions for the benchmark results above are following:
      -
        -
      • There is no input size range were CGAL would outperform -Boost.Polygon Voronoi. Even considering the fact that we didn't include -time it would take CGAL to compute coordinates of the Voronoi vertices.
      • -
      • The more interesting fact is that robust implementation of -the Boost.Polygon Voronoi is faster than non-robust of -S-Hull (except small input sets of around 100 points on Linux-64).
        -
      • -
      • Logarithmic execution time shows that Boost.Polygon Voronoi -and S-Hull -have clear N*log(N) complexity, while this doesn't seem to be true for -CGAL (at least for large input data sets).
        -
      • -
      • Boost.Polygon Voronoi computes coordinates of the output -Voronoi vertices within 64 machine epsilon precision. There are no such -warranties for the CGAL library.
        -
      • -
      • Boost.Polygon Voronoi of points is 4 times faster for small -input data sets (10 points) and this factor grows up to 100 for large -input data sets (1000000 points).
      • -
      • Boost.Polygon Voronoi of segments is 3 times faster for -small input data sets (10 segments) and this factor grows up to 40 for -large input data sets (1000000 segments).
      • -
      • Boost.Polygon -Voronoi is capable to construct Voronoi of 10000 points or 1000 -segments in 0.02 seconds. This allows to produce real time frame rate -for those quantities.
      • -
      -
        +   - + @@ -576,10 +436,7 @@ for those quantities. @@ -588,5 +445,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Andrii Sydorchuk 2010-2012.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - + + \ No newline at end of file diff --git a/doc/voronoi_builder.htm b/doc/voronoi_builder.htm index be80846..042703e 100644 --- a/doc/voronoi_builder.htm +++ b/doc/voronoi_builder.htm @@ -1,22 +1,15 @@ - - + + + + - - Voronoi Builder - - - + Voronoi Builder +
      - -
      - + +
        @@ -70,20 +63,14 @@ Tutorial
      - +

      +

      Voronoi Builder

      The Voronoi builder is the event generator structure, that implements the sweepline algorithm, -scanning 2D space and spawning the two types of events: site +scanning 2D space and spawning the two types of events: site events and circle events. Each event is reported to the output data structure builder. The structure shares Voronoi name, as the events generated by it @@ -112,35 +99,28 @@ following include set doesn't depend on any external headers the Boost.Polygon library:

      #include -<voronoi_builder.hpp>
      +<voronoi_builder.hpp>
      #include <voronoi_diagram.hpp>

      Declaration

      Header: boost/polygon/voronoi_builder.hpp

      - template -<typename T,
      + template +<typename T,
                -typename CTT = detail::voronoi_ctype_traits<T>,
      +typename CTT = detail::voronoi_ctype_traits<T>,
                -typename VP = detail::voronoi_predicates<CTT> >
      +typename VP = detail::voronoi_predicates<CTT> >
      class voronoi_builder;

      T
      - specifies the coordinate type of the input geometries (points and segments).
      - CTT + CTT - defines the input/output coordinate type traits used by the Voronoi predicates (VP).
      - VP + VP - the predicate kernel, that contains robust and efficient predicates and functors.
      The Voronoi builder data structure is ready to use from the box with @@ -152,25 +132,19 @@ efficient predicates as long as types defined by the coordinate type traits satisfy the requirements explained at the end of this page. In case those -requirements are not satisfied, +requirements are not satisfied, the proper predicate kernel -implementation is required.
      +implementation is required.

      Member Functions

      - +
      - + - - +output data structure to process them.
      +Complexity: O(N * log N), where N is the total number of input points and segments.
      +

      The library provides the default coordinate type traits specialization for the 32-bit signed integer type:

      - +

      template <typename T>
      struct voronoi_ctype_traits;

      @@ -244,33 +217,28 @@ Voronoi builder predicate kernel user should define the following set of traits (the assumption is made that input geometries have X-bit signed integer coordinate type):

      -

      voronoi_builder()voronoi_builder() Default constructor.
      size_t insert_point(const int_type& x,
      +
      size_t insert_point(const int_type& x,
                          const int_type& y)
      Inserts a point object with @@ -178,9 +152,7 @@ the specified coordinates into the Voronoi builder.
      Returns index of the inserted point.
      size_t insert_segment(const int_type& + size_t insert_segment(const int_type& x1,
                            const int_type& y1,
      @@ -201,7 +173,9 @@ void construct(OUTPUT* output) algorithm over the set of inserted geometries and generates site and circle events to the OUTPUT data structure. It's the responsibility of the -output data structure to process them.
      void @@ -216,8 +190,7 @@ zero.
      +
      - - - - - - - - - -
      int_type + int_type At least X-bit signed integer type.
      int_x2_type + int_x2_type At least 2X-bit signed integer type.
      uint_x2_type + uint_x2_type At least 2X-bit unsigned integer type.
      big_int_type + big_int_type At least 8X-bit signed integer type if input dataset contains only points.
      @@ -278,40 +246,35 @@ At least 64X-bit signed integer type if input dataset contains segments.
      fpt_type + fpt_type IEEE-754 floating point type, with mantissa at least (X+16) bits and exponent able to handle 32X-bit unsigned integer type.
      efpt_type + efpt_type IEEE-754 floating point type, with mantissa at least (X+16) bits and exponent able to handle 64X-bit unsigned integer type.
      ulp_cmp_type + ulp_cmp_type Ulp comparison structure, that checks if two fpt_type values are within the given ulp range (relative error range).
      to_fpt_converter_type + to_fpt_converter_type Type converter structure, that converts any of the integer types above plus efpt_type to the fpt_type using operator().
      to_efpt_converter_type + to_efpt_converter_type Type converter structure, that converts any of the integer types above to the efpt_type using @@ -346,12 +309,9 @@ tutorial.
        + - + @@ -359,10 +319,7 @@ tutorial. @@ -371,5 +328,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Andrii Sydorchuk 2010-2013.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - + + \ No newline at end of file diff --git a/doc/voronoi_main.htm b/doc/voronoi_main.htm index 2fc913b..c98134a 100644 --- a/doc/voronoi_main.htm +++ b/doc/voronoi_main.htm @@ -1,26 +1,21 @@ - - + + + + + - - Voronoi Main + Voronoi Main + - - - - + +
      - - -
      - + +
        @@ -74,17 +69,11 @@ Tutorial
      - +

      +

      THE BOOST.POLYGON VORONOI LIBRARY

      -
      +
      The Voronoi extension of the Boost.Polygon library provides functionality to construct a Voronoi diagram @@ -101,12 +90,11 @@ except their endpoints. While the first restriction is permanent (it allows to give the exact warranties about the output precision and algorithm execution flow), -the second one may be resolved using the Boost.Polygon segment utils. +the second one may be resolved using the Boost.Polygon segment utils. The strong sides of the library and main benefits comparing to the other implementations are -discussed in the following paragraphs.
      -

      Fully Functional with Segments

      +discussed in the following paragraphs.
      +

      Fully Functional with Segments

      There are just a few implementations of the Voronoi diagram construction algorithm that can @@ -154,8 +142,7 @@ output geometries can be increased simply by using a floating-point type with the larger mantissa. The practical point of this statements is explained in the following table:
      - +
      @@ -196,10 +183,8 @@ mantissa)
      Output Coordinate Type
      Detailed description of the absolute and relative errors evaluation can -be found in the article: "What -Every Computer Scientist Should Know About Floating-Point Arithmetic".
      +be found in the article: "What +Every Computer Scientist Should Know About Floating-Point Arithmetic".

      During the finalization step the implementation unites the Voronoi vertices @@ -218,14 +203,12 @@ both coordinates that are within 2-18 metres (8 micrometres or the size of a bacteria) will be considered equal and united.

      Simple Interface

      -The boost/polygon/voronoi.hpp +The boost/polygon/voronoi.hpp library header defines the following static functions to integrate the Voronoi library functionality with the Boost.Polygon interfaces:

      - +
      +Corresponding point type should model the point concept.
      +Complexity: O(N * log N), memory usage: O(N), where N is the total number of input points.
      + +Corresponding segment type should model the segment concept.
      +Complexity: O(N * log N), memory usage: O(N), where N is the total number of input segments.
      + SegmentIterator,
                typename VD>
      void construct_voronoi(PointIterator -p_first,
      -                       +p_first,
                             PointIterator p_last,
                             SegmentIterator s_first,
      @@ -315,7 +299,9 @@ VD *vd) +Corresponding segment type should model the segment concept.
      +Complexity: O(N* log N), memory usage: O(N), where N is the total number of input points and segments.
      +
      template @@ -276,25 +259,27 @@ Corresponding segment type should model the segment concept. template <typename PointIterator, typename VD>
      void construct_voronoi(PointIterator -first,
      -                       +first,
                             PointIterator last,
                             VD *vd)
      Constructs the Voronoi diagram of a set of points.
      -Corresponding point type should model the point concept.
      template <typename SegmentIterator, typename VD>
      void construct_voronoi(SegmentIterator -first,
      -                       +first,
                             SegmentIterator last,
                             VD *vd)
      Constructs the Voronoi diagram of a set of segments.
      -Corresponding segment type should model the segment concept.
      template @@ -303,8 +288,7 @@ Corresponding segment type should model the segment concept. Constructs the Voronoi diagram of a set of points and segments.
      Corresponding point type should model the point concept.
      -Corresponding segment type should model the segment concept.
      @@ -336,14 +322,12 @@ with the output geometries and efficiently traverse the Voronoi graph. -More details on those topics are covered in the basic Voronoi tutorial. Advanced +More details on those topics are covered in the basic Voronoi tutorial. Advanced usage of the library with the configuration of the coordinate types is explained in the advanced Voronoi tutorial. The library allows users to implement their own Voronoi diagram / -Delaunay triangulation construction routines based on the Voronoi builder API.
      +Delaunay triangulation construction routines based on the Voronoi builder API.

      No Third Party Dependencies

      The Voronoi extension of the Boost.Polygon library doesn't depend on any 3rd party code @@ -354,12 +338,10 @@ encapsulated as part of the implementation. The library is fast to compile (3 public and 4 private heades), has strong cohesion between its components and is clearly modularized from the rest of the Boost.Polygon library, with -the optional integration through the voronoi.hpp header.
      +the optional integration through the voronoi.hpp header.

      Extensible for the User Provided Coordinate Types

      The implementation is coordinate type agnostic. As long -as the user provided types satisfy the set of the requirements of the Voronoi builder coordinate type traits, +as the user provided types satisfy the set of the requirements of the Voronoi builder coordinate type traits, no additional changes are needed @@ -441,21 +423,15 @@ benchmarks one may run on his/her PC. Upon the community request, more documentation on the theoretical aspects of the implementation will be published. The -authors would like to acknowledge the Steven Fortune's article "A Sweepline algorithm +authors would like to acknowledge the Steven Fortune's article "A Sweepline algorithm for Voronoi diagrams", that covers fundamental ideas of the current implementation.
        + - + @@ -463,10 +439,7 @@ current implementation. @@ -475,5 +448,5 @@ http://www.boost.org/LICENSE_1_0.txt)
      Copyright: Copyright © Andrii Sydorchuk 2010-2013.
      License: Distributed under the Boost Software -License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      - - + + \ No newline at end of file diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7fdb6b9..3b010c5 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -24,11 +24,6 @@ test-suite polygon-unit [ run gtl_boost_unit_test.cpp ] ; -test-suite skeleton-unit - : - # [ run skeleton_predicates_test.cpp ] - ; - test-suite voronoi-unit : [ run voronoi_builder_test.cpp ] From 80367374fa8f09810efd20850519a39252270ccd Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Wed, 9 Oct 2013 22:17:20 +0000 Subject: [PATCH 30/32] Polygon: fixing (site, circle) and (circle, circle) comparison. [SVN r86223] --- .../polygon/detail/voronoi_predicates.hpp | 49 ++++++++++-------- test/polygon_segment_test.cpp | 7 ++- test/voronoi_predicates_test.cpp | 50 ++++++++++++++++++- 3 files changed, 81 insertions(+), 25 deletions(-) diff --git a/include/boost/polygon/detail/voronoi_predicates.hpp b/include/boost/polygon/detail/voronoi_predicates.hpp index 11dd915..f5b87ba 100644 --- a/include/boost/polygon/detail/voronoi_predicates.hpp +++ b/include/boost/polygon/detail/voronoi_predicates.hpp @@ -35,8 +35,7 @@ class voronoi_predicates { enum { ULPS = 64, - ULPSx2 = 128, - ULPSx5 = 320 + ULPSx2 = 128 }; template @@ -161,32 +160,21 @@ class voronoi_predicates { bool operator()(const site_type& lhs, const circle_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPSx5); - if (xCmp != ulp_cmp_type::EQUAL) - return xCmp == ulp_cmp_type::LESS; - typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.y0()), to_fpt(rhs.lower_y()), ULPSx5); - return yCmp == ulp_cmp_type::LESS; + ulp_cmp(to_fpt(lhs.x0()), to_fpt(rhs.lower_x()), ULPS); + return xCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const site_type& rhs) const { typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPSx5); - if (xCmp != ulp_cmp_type::EQUAL) - return xCmp == ulp_cmp_type::LESS; - typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.y0()), ULPSx5); - return yCmp == ulp_cmp_type::LESS; + ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.x0()), ULPS); + return xCmp == ulp_cmp_type::LESS; } bool operator()(const circle_type& lhs, const circle_type& rhs) const { - typename ulp_cmp_type::Result xCmp = - ulp_cmp(to_fpt(lhs.lower_x()), to_fpt(rhs.lower_x()), ULPSx2); - if (xCmp != ulp_cmp_type::EQUAL) - return xCmp == ulp_cmp_type::LESS; - typename ulp_cmp_type::Result yCmp = - ulp_cmp(to_fpt(lhs.lower_y()), to_fpt(rhs.lower_y()), ULPSx2); - return yCmp == ulp_cmp_type::LESS; + if (lhs.lower_x() != rhs.lower_x()) { + return lhs.lower_x() < rhs.lower_x(); + } + return lhs.y() < rhs.y(); } private: @@ -1510,10 +1498,29 @@ class voronoi_predicates { } } } + if (lies_outside_vertical_segment(circle, site1) || + lies_outside_vertical_segment(circle, site2) || + lies_outside_vertical_segment(circle, site3)) { + return false; + } return true; } private: + bool lies_outside_vertical_segment( + const circle_type& c, const site_type& s) { + if (!s.is_segment() || !is_vertical(s)) { + return false; + } + fpt_type y0 = to_fpt(s.is_inverse() ? s.y1() : s.y0()); + fpt_type y1 = to_fpt(s.is_inverse() ? s.y0() : s.y1()); + return ulp_cmp(c.y(), y0, ULPS) == ulp_cmp_type::LESS || + ulp_cmp(c.y(), y1, ULPS) == ulp_cmp_type::MORE; + } + + private: + to_fpt_converter to_fpt; + ulp_cmp_type ulp_cmp; circle_existence_predicate_type circle_existence_predicate_; circle_formation_functor_type circle_formation_functor_; }; diff --git a/test/polygon_segment_test.cpp b/test/polygon_segment_test.cpp index 5e3d620..9744916 100644 --- a/test/polygon_segment_test.cpp +++ b/test/polygon_segment_test.cpp @@ -70,8 +70,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(segment_traits_test, T, test_types) { template struct Segment { - point_data p0; - point_data p1; + typedef T coordinate_type; + typedef point_data point_type; + point_type p0; + point_type p1; }; namespace boost { @@ -93,6 +95,7 @@ namespace polygon { template struct segment_mutable_traits< Segment > { + typedef T coordinate_type; typedef point_data point_type; static void set( diff --git a/test/voronoi_predicates_test.cpp b/test/voronoi_predicates_test.cpp index a8c50b7..3ea51e9 100644 --- a/test/voronoi_predicates_test.cpp +++ b/test/voronoi_predicates_test.cpp @@ -132,9 +132,9 @@ BOOST_AUTO_TEST_CASE(event_comparison_test4) { BOOST_AUTO_TEST_CASE(event_comparison_test5) { circle_type circle(1, 2, 3); CHECK_EVENT_COMPARISON(circle, site_type(0, 100), false, true); - CHECK_EVENT_COMPARISON(circle, site_type(3, 0), false, true); + CHECK_EVENT_COMPARISON(circle, site_type(3, 0), false, false); CHECK_EVENT_COMPARISON(circle, site_type(3, 2), false, false); - CHECK_EVENT_COMPARISON(circle, site_type(3, 3), true, false); + CHECK_EVENT_COMPARISON(circle, site_type(3, 3), false, false); CHECK_EVENT_COMPARISON(circle, site_type(4, 2), true, false); } @@ -514,3 +514,49 @@ BOOST_AUTO_TEST_CASE(circle_formation_predicate_test10) { site1.inverse(); CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, 1.0, 30.0, 25.0); } + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test11) { + site_type site1(0, 0, 0, 10); + site1.sorted_index(2); + site1.inverse(); + site_type site2(-8, 10); + site2.sorted_index(0); + site_type site3(-7, 14, -1, 14); + site3.sorted_index(1); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, -4.0, 10.0, 0.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test12) { + site_type site1(0, 0, 0, 10); + site1.sorted_index(2); + site1.inverse(); + site_type site2(-8, 10); + site2.sorted_index(0); + site_type site3(-7, 15, -1, 15); + site3.sorted_index(1); + CHECK_CIRCLE_EXISTENCE(site1, site2, site3, false); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test13) { + site_type site1(0, 0, 0, 10); + site1.sorted_index(2); + site1.inverse(); + site_type site2(-7, -4, -1, -4); + site2.sorted_index(1); + site2.inverse(); + site_type site3(-8, 0); + site3.sorted_index(0); + CHECK_CIRCLE_FORMATION_PREDICATE(site1, site2, site3, -4.0, 0.0, 0.0); +} + +BOOST_AUTO_TEST_CASE(circle_formation_predicate_test14) { + site_type site1(0, 0, 0, 10); + site1.sorted_index(2); + site1.inverse(); + site_type site2(-7, -5, -1, -5); + site2.sorted_index(1); + site2.inverse(); + site_type site3(-8, 0); + site3.sorted_index(0); + CHECK_CIRCLE_EXISTENCE(site1, site2, site3, false); +} From 473be38ebf13ce2ed6b85e6fa368f0b4e2020db1 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Tue, 19 Nov 2013 23:54:15 +0000 Subject: [PATCH 31/32] Polygon: fix issue #9386 [SVN r86776] --- include/boost/polygon/polygon_traits.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/boost/polygon/polygon_traits.hpp b/include/boost/polygon/polygon_traits.hpp index b4d0e9d..6055bc7 100644 --- a/include/boost/polygon/polygon_traits.hpp +++ b/include/boost/polygon/polygon_traits.hpp @@ -1418,18 +1418,6 @@ namespace boost { namespace polygon{ } */ - template - typename enable_if< - typename gtl_and< typename is_mutable_point_concept::type>::type, - typename is_polygon_with_holes_type::type>::type, - bool>::type - center(T1& center_point, const T2& polygon) { - typedef typename polygon_traits::coordinate_type coordinate_type; - rectangle_data bbox; - extents(bbox, polygon); - return center(center_point, bbox); - } - template typename enable_if< typename gtl_and< typename is_mutable_rectangle_concept::type>::type, @@ -1451,6 +1439,18 @@ namespace boost { namespace polygon{ return true; } + template + typename enable_if< + typename gtl_and< typename is_mutable_point_concept::type>::type, + typename is_polygon_with_holes_type::type>::type, + bool>::type + center(T1& center_point, const T2& polygon) { + typedef typename polygon_traits::coordinate_type coordinate_type; + rectangle_data bbox; + extents(bbox, polygon); + return center(center_point, bbox); + } + template template polygon_90_data& polygon_90_data::operator=(const T2& rvalue) { From f6811bfe14d84c916a12670d1103bc9210116758 Mon Sep 17 00:00:00 2001 From: Andrii Sydorchuk Date: Tue, 11 Mar 2014 20:29:42 +0100 Subject: [PATCH 32/32] Polygon: Removing explicit modificator from point_data copy constructor. --- include/boost/polygon/point_data.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/polygon/point_data.hpp b/include/boost/polygon/point_data.hpp index e37f82f..23c23ed 100644 --- a/include/boost/polygon/point_data.hpp +++ b/include/boost/polygon/point_data.hpp @@ -46,7 +46,7 @@ class point_data { } template - explicit point_data(const PointType& that) { + point_data(const PointType& that) { *this = that; }

    13. 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 Yy>F@Qv+e&gFfcH9y85}Sb4q9e0F`HULI3~& literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_064.png b/example/output_data/primary/primary_064.png new file mode 100644 index 0000000000000000000000000000000000000000..c393c425eaadb2f3b4d8539a6216c0ce7617aef7 GIT binary patch literal 12733 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 literal 0 HcmV?d00001 diff --git a/example/output_data/primary/primary_065.png b/example/output_data/primary/primary_065.png new file mode 100644 index 0000000000000000000000000000000000000000..81b2b77176df63a93230b06f4851ebd56570d642 GIT binary patch literal 38011 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 z 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 LC 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 y&+)w?l3SguoOFahH!9jaMW<5bTBY5 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

    DQ* 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 &s*L61|;JJrE0AhC)tc2?dWZ~Y?# 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