diff --git a/.gitattributes b/.gitattributes index 110da0d986e..067ea97a2a4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1219,6 +1219,8 @@ Minkowski_sum_2/test/Minkowski_sum_2/data/mchain_part1.dat -text Minkowski_sum_2/test/Minkowski_sum_2/data/mchain_part2.dat -text Minkowski_sum_2/test/Minkowski_sum_2/data/random_part1.dat -text Minkowski_sum_2/test/Minkowski_sum_2/data/random_part2.dat -text +Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part1.dat -text +Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part2.dat -text Minkowski_sum_2/test/Minkowski_sum_2/data/wheels_part1.dat -text Minkowski_sum_2/test/Minkowski_sum_2/data/wheels_part2.dat -text Modifier/doc_tex/Modifier/idraw/modifier.eps -text svneol=unset#application/postscript diff --git a/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Exact_offset_base_2.h b/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Exact_offset_base_2.h index b4a3ff8478b..4f513f4b1df 100644 --- a/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Exact_offset_base_2.h +++ b/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Exact_offset_base_2.h @@ -115,6 +115,9 @@ protected: // Traverse the polygon vertices and edges and construct the arcs that // constitute the single convolution cycle. + Alg_kernel alg_ker; + typename Alg_kernel::Equal_2 f_equal = alg_ker.equal_2_object(); + Nt_traits nt_traits; const Rational sqr_r = CGAL::square (r); const Algebraic alg_r = nt_traits.convert (r); @@ -127,7 +130,6 @@ protected: Alg_point_2 first_op; // The first offset point. Algebraic a, b, c; - unsigned int curve_index = 0; Traits_2 traits; std::list xobjs; @@ -187,28 +189,31 @@ protected: } else { - // Connect op2 (from the previous iteration) and op1 with a circular - // arc, whose supporting circle is (x1, x2) with radius r. - arc = Curve_2 (Rat_circle_2 (*curr, sqr_r), - CGAL::COUNTERCLOCKWISE, - op2, op1); - - // Subdivide the arc into x-monotone subarcs and append them to the - // convolution cycle. - xobjs.clear(); - f_make_x_monotone (arc, std::back_inserter(xobjs)); - - for (xobj_it = xobjs.begin(); xobj_it != xobjs.end(); ++xobj_it) + if (! f_equal (op2, op1)) { - assign_success = CGAL::assign (xarc, *xobj_it); - CGAL_assertion (assign_success); + // Connect op2 (from the previous iteration) and op1 with a circular + // arc, whose supporting circle is (x1, x2) with radius r. + arc = Curve_2 (Rat_circle_2 (*curr, sqr_r), + CGAL::COUNTERCLOCKWISE, + op2, op1); + + // Subdivide the arc into x-monotone subarcs and append them to the + // convolution cycle. + xobjs.clear(); + f_make_x_monotone (arc, std::back_inserter(xobjs)); + + for (xobj_it = xobjs.begin(); xobj_it != xobjs.end(); ++xobj_it) + { + assign_success = CGAL::assign (xarc, *xobj_it); + CGAL_assertion (assign_success); - *oi = Labeled_curve_2 (xarc, - X_curve_label (xarc.is_directed_right(), - cycle_id, - curve_index)); - ++oi; - curve_index++; + *oi = Labeled_curve_2 (xarc, + X_curve_label (xarc.is_directed_right(), + cycle_id, + curve_index)); + ++oi; + curve_index++; + } } } @@ -240,35 +245,38 @@ protected: } while (curr != first); - // Close the convolution cycle by creating the final circular arc, - // centered at the first vertex. - arc = Curve_2 (Rat_circle_2 (*first, sqr_r), - CGAL::COUNTERCLOCKWISE, - op2, first_op); - - // Subdivide the arc into x-monotone subarcs and append them to the - // convolution cycle. - bool is_last; - - xobjs.clear(); - f_make_x_monotone (arc, std::back_inserter(xobjs)); - - xobj_it = xobjs.begin(); - while (xobj_it != xobjs.end()) + if (! f_equal (op2, first_op)) { - assign_success = CGAL::assign (xarc, *xobj_it); - CGAL_assertion (assign_success); + // Close the convolution cycle by creating the final circular arc, + // centered at the first vertex. + arc = Curve_2 (Rat_circle_2 (*first, sqr_r), + CGAL::COUNTERCLOCKWISE, + op2, first_op); - ++xobj_it; - is_last = (xobj_it == xobjs.end()); - - *oi = Labeled_curve_2 (xarc, - X_curve_label (xarc.is_directed_right(), - cycle_id, - curve_index, - is_last)); - ++oi; - curve_index++; + // Subdivide the arc into x-monotone subarcs and append them to the + // convolution cycle. + bool is_last; + + xobjs.clear(); + f_make_x_monotone (arc, std::back_inserter(xobjs)); + + xobj_it = xobjs.begin(); + while (xobj_it != xobjs.end()) + { + assign_success = CGAL::assign (xarc, *xobj_it); + CGAL_assertion (assign_success); + + ++xobj_it; + is_last = (xobj_it == xobjs.end()); + + *oi = Labeled_curve_2 (xarc, + X_curve_label (xarc.is_directed_right(), + cycle_id, + curve_index, + is_last)); + ++oi; + curve_index++; + } } return (oi); diff --git a/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Union_of_segment_cycles_2.h b/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Union_of_segment_cycles_2.h index 93a1269102f..b7276fa6b70 100644 --- a/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Union_of_segment_cycles_2.h +++ b/Minkowski_sum_2/include/CGAL/Minkowski_sum_2/Union_of_segment_cycles_2.h @@ -95,10 +95,9 @@ public: do { out_bound.push_back (circ->source()->point()); - ++circ; + --circ; } while (circ != first); - ++hole_it; // Locate the holes in the union: Go over all arrangement faces. @@ -116,10 +115,10 @@ public: do { pgn_hole.push_back (circ->source()->point()); - ++circ; + --circ; } while (circ != first); - + // Insert it to the containers of holes in the Minkowski sum. *holes = pgn_hole; ++holes; diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test b/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test new file mode 100755 index 00000000000..c8ed7f2b381 --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/cgal_test @@ -0,0 +1,141 @@ +#! /bin/bash + +# This is a script for the CGAL test suite. Such a script must obey +# the following rules: +# +# - the name of the script is cgal_test +# - for every target two one line messages are written to the file 'error.txt' +# the first one indicates if the compilation was successful +# the second one indicates if the execution was successful +# if one of the two was not successful, the line should start with 'ERROR:' +# - running the script should not require any user interaction +# - the script should clean up object files and executables + +ERRORFILE=error.txt + +#---------------------------------------------------------------------# +# compile_and_run +#---------------------------------------------------------------------# + +compile_test() +{ + local name=$1; + + echo "Compiling $name ... " + if eval 'make CGAL_MAKEFILE=$CGAL_MAKEFILE $name'; then + echo " succesful compilation of $name" >> $ERRORFILE; + res=1; + else + echo " ERROR: compilation of $name" >> $ERRORFILE; + res=0; + fi +} + +run_test_Minkowski_sum() +{ + local datafile=$1; + local flags=$2; + + basedata=`basename "$datafile"` + OUTPUTFILE=ProgramOutput.$basedata.test_Minkowski_sum.$PLATFORM + first_file="$datafile"_part1.dat + second_file="$datafile"_part2.dat + + rm -f $OUTPUTFILE + COMMAND="./test_Minkowski_sum" + echo "Executing $COMMAND $first_file $second_file $flags ... " + echo + if eval $COMMAND $first_file $second_file $flags > $OUTPUTFILE 2>&1 ; then + echo " succesful execution of test_Minkowski_sum $datafile" >> $ERRORFILE + else + echo " ERROR: execution of test_Minkowski_sum $datafile" >> $ERRORFILE + fi +} + +clean_tests() +{ + eval "make CGAL_MAKEFILE=$CGAL_MAKEFILE clean > /dev/null 2>&1 " +} + +#---------------------------------------------------------------------# +# Minkowski sum test +#---------------------------------------------------------------------# +Minkowski_sum_tests() +{ + compile_test test_Minkowski_sum + + if [ ${res} -eq 0 ] ; then + echo " ERROR: not executed test_Minkowski_sum" >> $ERRORFILE + else + run_test_Minkowski_sum data/rooms -sohg + run_test_Minkowski_sum data/comb -sohg + run_test_Minkowski_sum data/fork -soh + run_test_Minkowski_sum data/knife -so + run_test_Minkowski_sum data/mchain -sh + run_test_Minkowski_sum data/random -sg + run_test_Minkowski_sum data/wheels -hg + fi + clean_tests +} + +#---------------------------------------------------------------------# +# Offset tests +#---------------------------------------------------------------------# +run_offset_test() +{ + local program=$1; + local datafile=$2; + local radius=$3; + local flags=$4; + + basedata=`basename "$datafile"` + OUTPUTFILE=ProgramOutput.$basedata.$program.$PLATFORM + + rm -f $OUTPUTFILE + COMMAND="./$program" + echo "Executing $COMMAND $datafile $radius $flags ... " + echo + if eval $COMMAND $datafile $radius $flags > $OUTPUTFILE 2>&1 ; then + echo " succesful execution of $program $datafile" >> $ERRORFILE + else + echo " ERROR: execution of $program $datafile" >> $ERRORFILE + fi +} + +offset_tests() +{ + compile_test test_exact_offset + + if [ ${res} -eq 0 ] ; then + echo " ERROR: not executed test_exact_offset" >> $ERRORFILE + else + run_offset_test test_exact_offset data/random_part1.dat 5/1 -sohg + run_offset_test test_exact_offset data/comb_part1.dat 1/1 -sohg + run_offset_test test_exact_offset data/wheels_part1.dat 100000/1 -sohg + fi + + compile_test test_approx_offset + + if [ ${res} -eq 0 ] ; then + echo " ERROR: not executed test_approx_offset" >> $ERRORFILE + else + run_offset_test test_approx_offset data/rooms_part1.dat 3/1 -sohg + run_offset_test test_approx_offset data/wheels_part1.dat 100000/1 -sohg + fi + + clean_tests +} + +#---------------------------------------------------------------------# +# remove the previous error file +#---------------------------------------------------------------------# + +rm -f $ERRORFILE +touch $ERRORFILE + +#---------------------------------------------------------------------# +# compile and run the tests +#---------------------------------------------------------------------# + +Minkowski_sum_tests +offset_tests \ No newline at end of file diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part1.dat b/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part1.dat new file mode 100644 index 00000000000..d0e45aaf936 --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part1.dat @@ -0,0 +1,27 @@ +26 +0/1 8/1 +0/1 0/1 +17/1 0/1 +17/1 18/1 +0/1 18/1 +0/1 9/1 +6/1 9/1 +6/1 10/1 +1/1 10/1 +1/1 17/1 +8/1 17/1 +8/1 14/1 +9/1 14/1 +9/1 17/1 +16/1 17/1 +16/1 10/1 +9/1 10/1 +8/1 9/1 +16/1 9/1 +16/1 1/1 +9/1 1/1 +9/1 8/1 +8/1 8/1 +8/1 1/1 +1/1 1/1 +1/1 8/1 diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part2.dat b/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part2.dat new file mode 100644 index 00000000000..ec815992c58 --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/data/rooms_part2.dat @@ -0,0 +1,9 @@ +8 +0/1 -3/1 +1/1 -1/1 +3/1 0/1 +1/1 1/1 +0/1 3/1 +-1/1 1/1 +-3/1 0/1 +-1/1 -1/1 diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/read_polygon.h b/Minkowski_sum_2/test/Minkowski_sum_2/read_polygon.h new file mode 100644 index 00000000000..6a1e31d5a94 --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/read_polygon.h @@ -0,0 +1,56 @@ +#ifndef CGAL_READ_POLYGON_TEST_H +#define CGAL_READ_POLYGON_TEST_H + +#include +#include +#include + +/*! + * Read a polygon from an input file. + * \param filename The name of the input file. + * \param pgn Output: The polygon. + * \return Whether the polygon was successfuly read. + */ +template +bool read_polygon (const char *filename, CGAL::Polygon_2& pgn) +{ + // Open the input file. + std::ifstream ifile (filename); + + if (! ifile.is_open()) + { + std::cerr << "Failed to open <" << filename << ">." << std::endl; + return (false); + } + + // Read the polygon. + int n_vertices; + typename Kernel::FT x, y; + std::list vertices; + int k; + + // Read the number of polygon vertices. + ifile >> n_vertices; + + // Read the vertices. + for (k = 0; k < n_vertices; k++) + { + ifile >> x >> y; + + vertices.push_back (typename Kernel::Point_2 (x, y)); + } + ifile.close(); + + pgn = CGAL::Polygon_2 (vertices.begin(), vertices.end()); + + // Make sure the polygon is simple. + if (! pgn.is_simple()) + { + std::cerr << "Error - the polygon is not simple." << std::endl; + return (false); + } + + return (true); +} + +#endif diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/test_Minkowski_sum.cpp b/Minkowski_sum_2/test/Minkowski_sum_2/test_Minkowski_sum.cpp index 003db48b52a..9acaa4c8fac 100644 --- a/Minkowski_sum_2/test/Minkowski_sum_2/test_Minkowski_sum.cpp +++ b/Minkowski_sum_2/test/Minkowski_sum_2/test_Minkowski_sum.cpp @@ -16,10 +16,9 @@ #include #include #include +#include "read_polygon.h" #include -#include -#include typedef CGAL::Cartesian Kernel; typedef Kernel::Point_2 Point_2; @@ -27,53 +26,6 @@ typedef Kernel::Segment_2 Segment_2; typedef CGAL::Polygon_2 Polygon_2; typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; -/*! - * Read a polygons from an input file. - * \param filename The name of the input file. - * \param pgn Output: The polygon. - * \return Whether the polygon was successfuly read. - */ -bool read_polygon (const char *filename, Polygon_2& pgn) -{ - // Open the input file. - std::ifstream ifile (filename); - - if (! ifile.is_open()) - { - std::cerr << "Failed to open <" << filename << ">." << std::endl; - return (false); - } - - // Read the polygon. - int n_vertices; - Rational x, y; - std::list vertices; - int k; - - // Read the number of polygon vertices. - ifile >> n_vertices; - - // Read the vertices. - for (k = 0; k < n_vertices; k++) - { - ifile >> x >> y; - - vertices.push_back (Point_2 (x, y)); - } - ifile.close(); - - pgn = Polygon_2 (vertices.begin(), vertices.end()); - - // Make sure the polygon is simple. - if (! pgn.is_simple()) - { - std::cerr << "Error - the polygon is not simple." << std::endl; - return (false); - } - - return (true); -} - /*! Check if two polygons with holes are the same. */ bool are_equal (const Polygon_with_holes_2& ph1, const Polygon_with_holes_2& ph2) @@ -87,13 +39,13 @@ bool are_equal (const Polygon_with_holes_2& ph1, } /*! The main program. */ -int main (int argc, char **argv ) +int main (int argc, char **argv) { // Read the input file. if (argc < 3) { std::cerr << "Usage: " << argv[0] - << " ." + << " [decomposition flags]" << std::endl; return (1); } @@ -113,6 +65,20 @@ int main (int argc, char **argv ) return (1); } + // Read the decomposition flags. + bool use_ssab = true; + bool use_opt = true; + bool use_hm = true; + bool use_greene = true; + + if (argc > 3) + { + use_ssab = (strchr (argv[3], 's') != NULL); + use_opt = (strchr (argv[3], 'o') != NULL); + use_hm = (strchr (argv[3], 'h') != NULL); + use_greene = (strchr (argv[3], 'g') != NULL); + } + // Compute the Minkowski sum using the convolution method. Polygon_with_holes_2 sum_conv; @@ -127,48 +93,60 @@ int main (int argc, char **argv ) CGAL::Greene_convex_decomposition_2 greene_decomp; Polygon_with_holes_2 sum_decomp; - std::cout << "Using the small-side angle-bisector decomposition ... "; - sum_decomp = minkowski_sum_2 (pgn1, pgn2, ssab_decomp); - if (are_equal (sum_conv, sum_decomp)) + if (use_ssab) { - std::cout << "OK." << std::endl; - } - else - { - std::cout << "ERROR (different result)." << std::endl; + std::cout << "Using the small-side angle-bisector decomposition ... "; + sum_decomp = minkowski_sum_2 (pgn1, pgn2, ssab_decomp); + if (are_equal (sum_conv, sum_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } } - std::cout << "Using the optimal convex decomposition ... "; - sum_decomp = minkowski_sum_2 (pgn1, pgn2, opt_decomp); - if (are_equal (sum_conv, sum_decomp)) + if (use_opt) { - std::cout << "OK." << std::endl; - } - else - { - std::cout << "ERROR (different result)." << std::endl; + std::cout << "Using the optimal convex decomposition ... "; + sum_decomp = minkowski_sum_2 (pgn1, pgn2, opt_decomp); + if (are_equal (sum_conv, sum_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } } - std::cout << "Using the Hertel--Mehlhorn decomposition ... "; - sum_decomp = minkowski_sum_2 (pgn1, pgn2, hm_approx_decomp); - if (are_equal (sum_conv, sum_decomp)) + if (use_hm) { - std::cout << "OK." << std::endl; - } - else - { - std::cout << "ERROR (different result)." << std::endl; + std::cout << "Using the Hertel--Mehlhorn decomposition ... "; + sum_decomp = minkowski_sum_2 (pgn1, pgn2, hm_approx_decomp); + if (are_equal (sum_conv, sum_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } } - std::cout << "Using the Greene decomposition ... "; - sum_decomp = minkowski_sum_2 (pgn1, pgn2, greene_decomp); - if (are_equal (sum_conv, sum_decomp)) + if (use_greene) { - std::cout << "OK." << std::endl; - } - else - { - std::cout << "ERROR (different result)." << std::endl; + std::cout << "Using the Greene decomposition ... "; + sum_decomp = minkowski_sum_2 (pgn1, pgn2, greene_decomp); + if (are_equal (sum_conv, sum_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } } return (0); diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/test_approx_offset.cpp b/Minkowski_sum_2/test/Minkowski_sum_2/test_approx_offset.cpp new file mode 100644 index 00000000000..35f38df30ff --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/test_approx_offset.cpp @@ -0,0 +1,159 @@ +#ifdef CGAL_USE_GMP + // GMP is installed. Use the GMP rational number-type. + #include + typedef CGAL::Gmpq Rational; +#else + // GMP is not installed. Use CGAL's exact rational number-type. + #include + #include + typedef CGAL::Quotient Rational; +#endif + +#include +#include +#include +#include +#include +#include +#include "read_polygon.h" +#include + +typedef CGAL::Cartesian Kernel; + +typedef Kernel::Point_2 Point_2; +typedef CGAL::Polygon_2 Polygon_2; + +typedef CGAL::Gps_circle_segment_traits_2 Gps_traits_2; +typedef Gps_traits_2::Polygon_2 Offset_polygon_2; +typedef Gps_traits_2::Polygon_with_holes_2 Offset_polygon_with_holes_2; + +/*! Check if two polygons with holes are the same. */ +bool are_equal (const Offset_polygon_with_holes_2& ph1, + const Offset_polygon_with_holes_2& ph2) +{ + std::list sym_diff; + + CGAL::symmetric_difference (ph1, ph2, + std::back_inserter(sym_diff)); + + return (sym_diff.empty()); +} + +/*! The main program. */ +int main (int argc, char **argv) +{ + // Read the input file. + if (argc < 3) + { + std::cerr << "Usage: ." << std::endl; + return (1); + } + + // Read the polygon from the input file. + Polygon_2 pgn; + + if (! read_polygon (argv[1], pgn)) + { + std::cerr << "Failed to read: <" << argv[1] << ">." << std::endl; + return (1); + } + + // Read the offset radius. + int numer, denom; + + if (sscanf (argv[2], "%d/%d", &numer, &denom) != 2) + { + std::cerr << "Invalid radius: " << argv[2] << std::endl; + return (1); + } + + Rational r = Rational (numer, denom); + const double eps = 0.0001; + + // Read the decomposition flags. + bool use_ssab = true; + bool use_opt = true; + bool use_hm = true; + bool use_greene = true; + + if (argc > 3) + { + use_ssab = (strchr (argv[3], 's') != NULL); + use_opt = (strchr (argv[3], 'o') != NULL); + use_hm = (strchr (argv[3], 'h') != NULL); + use_greene = (strchr (argv[3], 'g') != NULL); + } + + // Compute the Minkowski sum using the convolution method. + Offset_polygon_with_holes_2 offset_conv; + + std::cout << "Using the convolution method ... "; + offset_conv = approximated_offset_2 (pgn, r, eps); + std::cout << "Done." << std::endl; + + // Define auxiliary polygon-decomposition objects. + CGAL::Small_side_angle_bisector_decomposition_2 ssab_decomp; + CGAL::Optimal_convex_decomposition_2 opt_decomp; + CGAL::Hertel_Mehlhorn_convex_decomposition_2 hm_approx_decomp; + CGAL::Greene_convex_decomposition_2 greene_decomp; + Offset_polygon_with_holes_2 offset_decomp; + + if (use_ssab) + { + std::cout << "Using the small-side angle-bisector decomposition ... "; + offset_decomp = approximated_offset_2 (pgn, r, eps, ssab_decomp); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_opt) + { + std::cout << "Using the optimal convex decomposition ... "; + offset_decomp = approximated_offset_2 (pgn, r, eps, opt_decomp); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_hm) + { + std::cout << "Using the Hertel--Mehlhorn decomposition ... "; + offset_decomp = approximated_offset_2 (pgn, r, eps, hm_approx_decomp); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_greene) + { + std::cout << "Using the Greene decomposition ... "; + offset_decomp = approximated_offset_2 (pgn, r, eps, greene_decomp); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + return (0); +} + diff --git a/Minkowski_sum_2/test/Minkowski_sum_2/test_exact_offset.cpp b/Minkowski_sum_2/test/Minkowski_sum_2/test_exact_offset.cpp new file mode 100644 index 00000000000..d2844ed68ea --- /dev/null +++ b/Minkowski_sum_2/test/Minkowski_sum_2/test_exact_offset.cpp @@ -0,0 +1,172 @@ +#include + +#ifndef CGAL_USE_CORE + +#include + +int main () +{ + std::cout << "Sorry, this test needs CORE ..." << std::endl; + return (0); +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include "read_polygon.h" +#include + +typedef CGAL::CORE_algebraic_number_traits Nt_traits; +typedef Nt_traits::Rational Rational; +typedef Nt_traits::Algebraic Algebraic; +typedef CGAL::Cartesian Rat_kernel; +typedef CGAL::Cartesian Alg_kernel; +typedef CGAL::Arr_conic_traits_2 Conic_traits_2; + +typedef Rat_kernel::Point_2 Point_2; +typedef CGAL::Polygon_2 Polygon_2; + +typedef CGAL::Gps_traits_2 Gps_traits_2; +typedef Gps_traits_2::Polygon_2 Offset_polygon_2; +typedef Gps_traits_2::Polygon_with_holes_2 Offset_polygon_with_holes_2; + +/*! Check if two polygons with holes are the same. */ +bool are_equal (const Offset_polygon_with_holes_2& ph1, + const Offset_polygon_with_holes_2& ph2) +{ + std::list sym_diff; + + CGAL::symmetric_difference (ph1, ph2, + std::back_inserter(sym_diff)); + + return (sym_diff.empty()); +} + +/*! The main program. */ +int main (int argc, char **argv) +{ + // Read the input file. + if (argc < 3) + { + std::cerr << "Usage: ." << std::endl; + return (1); + } + + // Read the polygon from the input file. + Polygon_2 pgn; + + if (! read_polygon (argv[1], pgn)) + { + std::cerr << "Failed to read: <" << argv[1] << ">." << std::endl; + return (1); + } + + // Read the offset radius. + int numer, denom; + + if (sscanf (argv[2], "%d/%d", &numer, &denom) != 2) + { + std::cerr << "Invalid radius: " << argv[2] << std::endl; + return (1); + } + + Rational r = Rational (numer, denom); + + // Read the decomposition flags. + bool use_ssab = true; + bool use_opt = true; + bool use_hm = true; + bool use_greene = true; + + if (argc > 3) + { + use_ssab = (strchr (argv[3], 's') != NULL); + use_opt = (strchr (argv[3], 'o') != NULL); + use_hm = (strchr (argv[3], 'h') != NULL); + use_greene = (strchr (argv[3], 'g') != NULL); + } + + // Compute the Minkowski sum using the convolution method. + Conic_traits_2 traits; + + Offset_polygon_with_holes_2 offset_conv; + + std::cout << "Using the convolution method ... "; + offset_conv = offset_polygon_2 (pgn, r, traits); + std::cout << "Done." << std::endl; + + // Define auxiliary polygon-decomposition objects. + CGAL::Small_side_angle_bisector_decomposition_2 ssab_decomp; + CGAL::Optimal_convex_decomposition_2 opt_decomp; + CGAL::Hertel_Mehlhorn_convex_decomposition_2 hm_approx_decomp; + CGAL::Greene_convex_decomposition_2 greene_decomp; + Offset_polygon_with_holes_2 offset_decomp; + + if (use_ssab) + { + std::cout << "Using the small-side angle-bisector decomposition ... "; + offset_decomp = offset_polygon_2 (pgn, r, ssab_decomp, traits); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_opt) + { + std::cout << "Using the optimal convex decomposition ... "; + offset_decomp = offset_polygon_2 (pgn, r, opt_decomp, traits); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_hm) + { + std::cout << "Using the Hertel--Mehlhorn decomposition ... "; + offset_decomp = offset_polygon_2 (pgn, r, hm_approx_decomp, traits); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + if (use_greene) + { + std::cout << "Using the Greene decomposition ... "; + offset_decomp = offset_polygon_2 (pgn, r, greene_decomp, traits); + if (are_equal (offset_conv, offset_decomp)) + { + std::cout << "OK." << std::endl; + } + else + { + std::cout << "ERROR (different result)." << std::endl; + } + } + + return (0); +} + +#endif