mirror of https://github.com/CGAL/cgal
Rewrote test_minkowski_sum
This commit is contained in:
parent
427fd6e2db
commit
722ea5c9da
|
|
@ -1,52 +1,22 @@
|
|||
#ifndef CGAL_READ_POLYGON_TEST_H
|
||||
#define CGAL_READ_POLYGON_TEST_H
|
||||
#ifndef CGAL_READ_POLYGON_H
|
||||
#define CGAL_READ_POLYGON_H
|
||||
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
/*!
|
||||
* 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 <class Kernel>
|
||||
bool read_polygon (const char *filename, CGAL::Polygon_2<Kernel>& pgn)
|
||||
void read_polygon (const char *filename, CGAL::Polygon_2<Kernel>& pgn)
|
||||
{
|
||||
std::ifstream ifile(filename);
|
||||
ifile >> pgn;
|
||||
std::ifstream file(filename);
|
||||
|
||||
// Make sure the polygon is simple.
|
||||
if (! pgn.is_simple())
|
||||
if (!file)
|
||||
{
|
||||
std::cerr << "Error - the polygon is not simple." << std::endl;
|
||||
return false;
|
||||
std::cerr << "Failed to open " << filename << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Kernel>
|
||||
bool read_polygon_with_holes (const char *filename, CGAL::Polygon_with_holes_2<Kernel>& pgn)
|
||||
{
|
||||
std::ifstream ifile(filename);
|
||||
ifile >> pgn;
|
||||
// TODO: what can go wrong?
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Kernel>
|
||||
bool write_polygon_with_holes (const char *filename, CGAL::Polygon_with_holes_2<Kernel>& pgn)
|
||||
{
|
||||
std::cout << filename << std::endl;
|
||||
std::ofstream ofile(filename);
|
||||
if (ofile.is_open()) {
|
||||
ofile << pgn;
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
return true;
|
||||
file >> pgn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
compare ./data/rooms_part1.dat ./data/rooms_part2.dat
|
||||
compare ./data/comb_part1.dat ./data/comb_part2.dat
|
||||
compare ./data/knife_part1.dat ./data/knife_part2.dat
|
||||
compare ./data/mchain_part1.dat ./data/mchain_part2.dat
|
||||
compare ./data/random_part1.dat ./data/random_part2.dat
|
||||
compare ./data/wheels_part1.dat ./data/wheels_part2.dat
|
||||
compare ./data/r35975_part1.dat ./data/r35975_part2.dat
|
||||
compare ./data/r38305_part1.dat ./data/r38305_part2.dat
|
||||
compare ./data/D.dat ./data/E.dat
|
||||
compare ./data/F.dat ./data/G.dat
|
||||
compare ./data/F.dat ./data/E.dat
|
||||
compare ./data/F.dat ./data/D.dat
|
||||
compare ./data/F.dat ./data/A.dat
|
||||
compare ./data/A.dat ./data/G.dat
|
||||
compare ./data/B.dat ./data/G.dat
|
||||
verify ./data/dangling_edge_part1.dat ./data/dangling_edge_part2.dat ./data/dangling_edge_result.dat
|
||||
verify ./data/isolated_vertex_part1.dat ./data/isolated_vertex_part2.dat ./data/isolated_vertex_result.dat
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
#include <CGAL/basic.h>
|
||||
|
||||
#ifdef CGAL_USE_GMP
|
||||
// GMP is installed. Use the GMP rational number-type.
|
||||
#include <CGAL/Gmpq.h>
|
||||
typedef CGAL::Gmpq Rational;
|
||||
#else
|
||||
// GMP is not installed. Use CGAL's exact rational number-type.
|
||||
#include <CGAL/MP_Float.h>
|
||||
#include <CGAL/Quotient.h>
|
||||
typedef CGAL::Quotient<CGAL::MP_Float> Rational;
|
||||
#endif
|
||||
|
||||
#include <CGAL/Cartesian.h>
|
||||
#include <CGAL/minkowski_sum_2.h>
|
||||
#include <CGAL/Small_side_angle_bisector_decomposition_2.h>
|
||||
#include <CGAL/Polygon_convex_decomposition_2.h>
|
||||
#include <CGAL/Boolean_set_operations_2.h>
|
||||
#include <CGAL/Timer.h>
|
||||
#include "read_polygon.h"
|
||||
#include <cstring>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
typedef Kernel::Segment_2 Segment_2;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef CGAL::Polygon_with_holes_2<Kernel> Polygon_with_holes_2;
|
||||
|
||||
/*! Check if two polygons with holes are the same. */
|
||||
bool are_equal (const Polygon_with_holes_2& ph1,
|
||||
const Polygon_with_holes_2& ph2)
|
||||
{
|
||||
std::list<Polygon_with_holes_2> 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. Because of the structure of the *.cmd file
|
||||
// (which is concatenated to the command line) we need to get all the
|
||||
// inputs in one command line. This is the reason we read triplets/quadruplets of
|
||||
// arguments. Each triplet/quadruplet is one input for the program.
|
||||
if (argc < 3)
|
||||
{
|
||||
std::cerr << "Usage: " << argv[0] << ". The input are triplets/quadruplets of:"
|
||||
<< "<compare|verify> <polygon#1> <polygon#2> [polygon#3]"
|
||||
<< std::endl;
|
||||
return (1);
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
while (i < argc)
|
||||
{
|
||||
bool verify = strcmp(argv[i], "verify") == 0;
|
||||
|
||||
// Read the polygons from the input files.
|
||||
Polygon_2 pgn1, pgn2;
|
||||
Polygon_with_holes_2 result;
|
||||
CGAL::Timer timer;
|
||||
|
||||
if (! read_polygon (argv[i+1], pgn1))
|
||||
{
|
||||
std::cerr << "Failed to read: <" << argv[i+1] << ">." << std::endl;
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (! read_polygon (argv[i+2], pgn2))
|
||||
{
|
||||
std::cerr << "Failed to read: <" << argv[i+2] << ">." << std::endl;
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (verify)
|
||||
{
|
||||
if (! read_polygon_with_holes (argv[i+3], result))
|
||||
{
|
||||
std::cerr << "Failed to read: <" << argv[i+3] << ">." << std::endl;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Testing " << argv[i+1] << " and " << argv[i+2] << std::endl;
|
||||
|
||||
Polygon_with_holes_2 sum_conv_new;
|
||||
|
||||
std::cout << "Using the reduced convolution method ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_conv_new = minkowski_sum_by_reduced_convolution_2 (pgn1, pgn2);
|
||||
timer.stop();
|
||||
std::cout << "Done (" << timer.time() << " s)" << std::endl;
|
||||
|
||||
if (verify)
|
||||
{
|
||||
if (are_equal (result, sum_conv_new))
|
||||
{
|
||||
std::cout << "OK." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = sum_conv_new;
|
||||
}
|
||||
|
||||
Polygon_with_holes_2 sum_conv;
|
||||
std::cout << "Using the convolution method ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_conv = minkowski_sum_by_full_convolution_2 (pgn1, pgn2);
|
||||
timer.stop();
|
||||
if (are_equal (result, sum_conv))
|
||||
{
|
||||
std::cout << "OK (" << timer.time() << " s)" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Define auxiliary polygon-decomposition objects.
|
||||
CGAL::Small_side_angle_bisector_decomposition_2<Kernel> ssab_decomp;
|
||||
CGAL::Optimal_convex_decomposition_2<Kernel> opt_decomp;
|
||||
CGAL::Hertel_Mehlhorn_convex_decomposition_2<Kernel> hm_approx_decomp;
|
||||
CGAL::Greene_convex_decomposition_2<Kernel> greene_decomp;
|
||||
Polygon_with_holes_2 sum_decomp;
|
||||
|
||||
std::cout << "Using the small-side angle-bisector decomposition ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_decomp = minkowski_sum_2 (pgn1, pgn2, ssab_decomp);
|
||||
timer.stop();
|
||||
if (are_equal (result, sum_decomp))
|
||||
{
|
||||
std::cout << "OK (" << timer.time() << " s)" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Using the optimal convex decomposition ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_decomp = minkowski_sum_2 (pgn1, pgn2, opt_decomp);
|
||||
timer.stop();
|
||||
if (are_equal (result, sum_decomp))
|
||||
{
|
||||
std::cout << "OK (" << timer.time() << " s)" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Using the Hertel--Mehlhorn decomposition ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_decomp = minkowski_sum_2 (pgn1, pgn2, hm_approx_decomp);
|
||||
timer.stop();
|
||||
if (are_equal (result, sum_decomp))
|
||||
{
|
||||
std::cout << "OK (" << timer.time() << " s)" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Using the Greene decomposition ... ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
sum_decomp = minkowski_sum_2 (pgn1, pgn2, greene_decomp);
|
||||
timer.stop();
|
||||
if (are_equal (result, sum_decomp))
|
||||
{
|
||||
std::cout << "OK (" << timer.time() << " s)" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ERROR (different result)." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
write_polygon_with_holes((std::string("./results/") + basename(argv[i+1]) + "-and-" + basename(argv[i+2]) + ".dat").c_str(), sum_conv_new);
|
||||
|
||||
if (verify)
|
||||
{
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
i += 3;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rfsohg
|
||||
data/comb_part1.dat data/comb_part2.dat
|
||||
data/knife_part1.dat data/knife_part2.dat
|
||||
data/mchain_part1.dat data/mchain_part2.dat
|
||||
data/random_part1.dat data/random_part2.dat
|
||||
data/wheels_part1.dat data/wheels_part2.dat
|
||||
data/r35975_part1.dat data/r35975_part2.dat
|
||||
data/r38305_part1.dat data/r38305_part2.dat
|
||||
data/D.dat data/E.dat
|
||||
data/F.dat data/G.dat
|
||||
data/F.dat data/E.dat
|
||||
data/F.dat data/D.dat
|
||||
data/F.dat data/A.dat
|
||||
data/A.dat data/G.dat
|
||||
data/B.dat data/G.dat
|
||||
data/dangling_edge_part1.dat data/dangling_edge_part2.dat
|
||||
data/isolated_vertex_part1.dat data/isolated_vertex_part2.dat
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
#include <CGAL/basic.h>
|
||||
|
||||
#ifdef CGAL_USE_GMP
|
||||
// GMP is installed. Use the GMP rational number-type.
|
||||
#include <CGAL/Gmpq.h>
|
||||
typedef CGAL::Gmpq Rational;
|
||||
#else
|
||||
// GMP is not installed. Use CGAL's exact rational number-type.
|
||||
#include <CGAL/MP_Float.h>
|
||||
#include <CGAL/Quotient.h>
|
||||
typedef CGAL::Quotient<CGAL::MP_Float> Rational;
|
||||
#endif
|
||||
|
||||
#include <CGAL/minkowski_sum_2.h>
|
||||
#include <CGAL/Small_side_angle_bisector_decomposition_2.h>
|
||||
#include <CGAL/Polygon_convex_decomposition_2.h>
|
||||
#include <CGAL/Boolean_set_operations_2.h>
|
||||
#include <CGAL/Timer.h>
|
||||
|
||||
#include "read_polygon.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef CGAL::Polygon_with_holes_2<Kernel> Polygon_with_holes_2;
|
||||
|
||||
bool are_equal(const Polygon_with_holes_2& ph1,
|
||||
const Polygon_with_holes_2& ph2)
|
||||
{
|
||||
std::list<Polygon_with_holes_2> sym_diff;
|
||||
CGAL::symmetric_difference (ph1, ph2, std::back_inserter(sym_diff));
|
||||
return sym_diff.empty();
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REDUCED_CONVOLUTION,
|
||||
FULL_CONVOLUTION,
|
||||
SSAB_DECOMP,
|
||||
OPT_DECOMP,
|
||||
HM_DECOMP,
|
||||
GREENE_DECOMP
|
||||
} Strategy;
|
||||
|
||||
static const char *strategy_names[] =
|
||||
{
|
||||
"reduced convolution",
|
||||
"full convolution",
|
||||
"small-side angle-bisector decomposition",
|
||||
"optimal convex decomposition",
|
||||
"Hertel-Mehlhorn decomposition",
|
||||
"Greene decomosition"
|
||||
};
|
||||
|
||||
Polygon_with_holes_2 compute_minkowski_sum_2(Polygon_2 &p, Polygon_2 &q, Strategy strategy)
|
||||
{
|
||||
switch (strategy)
|
||||
{
|
||||
case REDUCED_CONVOLUTION:
|
||||
{
|
||||
return minkowski_sum_by_reduced_convolution_2 (p, q);
|
||||
break;
|
||||
}
|
||||
case FULL_CONVOLUTION:
|
||||
{
|
||||
return minkowski_sum_by_full_convolution_2 (p, q);
|
||||
break;
|
||||
}
|
||||
case SSAB_DECOMP:
|
||||
{
|
||||
CGAL::Small_side_angle_bisector_decomposition_2<Kernel> decomp;
|
||||
return minkowski_sum_2(p, q, decomp);
|
||||
break;
|
||||
}
|
||||
case OPT_DECOMP:
|
||||
{
|
||||
CGAL::Optimal_convex_decomposition_2<Kernel> decomp;
|
||||
return minkowski_sum_2(p, q, decomp);
|
||||
break;
|
||||
}
|
||||
case HM_DECOMP:
|
||||
{
|
||||
CGAL::Hertel_Mehlhorn_convex_decomposition_2<Kernel> decomp;
|
||||
return minkowski_sum_2(p, q, decomp);
|
||||
break;
|
||||
}
|
||||
case GREENE_DECOMP:
|
||||
{
|
||||
CGAL::Greene_convex_decomposition_2<Kernel> decomp;
|
||||
return minkowski_sum_2(p, q, decomp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cerr << "Usage: " << argv[0] << " [method flag] [polygon files]..." << std::endl;
|
||||
std::cerr << "For the method flag, use a subset of the letters 'rfsohg'." << std::endl;
|
||||
std::cerr << "The program will compute the Minkowski sum of the first and second polygon, of the third and fourth, and so on." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Polygon_2 p, q;
|
||||
CGAL::Timer timer;
|
||||
|
||||
std::list<Strategy> strategies;
|
||||
for (int i = 0; i < strlen(argv[1]); i++)
|
||||
{
|
||||
switch (argv[1][i]) {
|
||||
case 'r':
|
||||
strategies.push_back(REDUCED_CONVOLUTION);
|
||||
break;
|
||||
case 'f':
|
||||
strategies.push_back(FULL_CONVOLUTION);
|
||||
break;
|
||||
case 's':
|
||||
strategies.push_back(SSAB_DECOMP);
|
||||
break;
|
||||
case 'o':
|
||||
strategies.push_back(OPT_DECOMP);
|
||||
break;
|
||||
case 'h':
|
||||
strategies.push_back(HM_DECOMP);
|
||||
break;
|
||||
case 'g':
|
||||
strategies.push_back(GREENE_DECOMP);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown flag '" << argv[1][i] << "'" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 2;
|
||||
while (i+1 < argc)
|
||||
{
|
||||
std::cout << "Testing " << argv[i] << " + " << argv[i+1] << std::endl;
|
||||
read_polygon (argv[i], p);
|
||||
read_polygon (argv[i+1], q);
|
||||
|
||||
bool compare = false;
|
||||
Polygon_with_holes_2 reference;
|
||||
|
||||
for (std::list<Strategy>::iterator it = strategies.begin(); it != strategies.end(); it++)
|
||||
{
|
||||
std::cout << "Using " << strategy_names[*it] << ": ";
|
||||
timer.reset();
|
||||
timer.start();
|
||||
Polygon_with_holes_2 result = compute_minkowski_sum_2(p, q, *it);
|
||||
timer.stop();
|
||||
std::cout << timer.time() << " s " << std::flush;
|
||||
|
||||
if (compare)
|
||||
{
|
||||
if (are_equal(reference, result))
|
||||
{
|
||||
std::cout << "(OK)";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "(ERROR: different result)";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compare = true;
|
||||
reference = result;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue