diff --git a/Intersections_3/test/Intersections_3/intersection_test_helper.h b/Intersections_3/test/Intersections_3/intersection_test_helper.h new file mode 100644 index 00000000000..857a82313e2 --- /dev/null +++ b/Intersections_3/test/Intersections_3/intersection_test_helper.h @@ -0,0 +1,445 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "create_bbox_mesh.h" + +#include +#include +#include + +const double epsilon = 0.001; + +struct randomint +{ + randomint() ; + int get() const { return sequence[cur]; } + int next() { cur = (cur+1)%11; return get();} + +private: + int sequence[11]; + int cur; +}; + +inline randomint::randomint() +{ + cur = 0; + sequence[0] = 19; + sequence[1] = 5; + sequence[2] = 17; + sequence[3] = 13; + sequence[4] = 29; + sequence[5] = 2; + sequence[6] = 23; + sequence[7] = 31; + sequence[8] = 3; + sequence[9] = 37; + sequence[10] = 11; +} + +randomint ri; + +inline double to_nt(int d) +{ + return double(d); +} + +template +struct Intersection_3_tester +{ + typedef CGAL::Bbox_3 Bbox; + + typedef CGAL::Iso_cuboid_3 Cub; + typedef CGAL::Line_3 L; + typedef CGAL::Point_3 P; + typedef CGAL::Plane_3 Pl; + typedef CGAL::Ray_3 R; + typedef CGAL::Segment_3 S; + typedef CGAL::Sphere_3 Sph; + typedef CGAL::Tetrahedron_3 Tet; + typedef CGAL::Triangle_3 Tr; + + typedef std::vector

Pol; + +protected: + CGAL::Random& r; + + bool has_exact_p; + bool has_exact_c; + + double m = 0, M = 100; + + bool verbose = true; + +public: + Intersection_3_tester(CGAL::Random& r, + const bool has_exact_p = false, + const bool has_exact_c = false) + : r(r), has_exact_p(has_exact_p), has_exact_c(has_exact_c) + { } + +public: + Pl pl(int a, int b, int c, int d) + { + int w = ri.next(); + return Pl(to_nt(a*w), to_nt(b*w), to_nt(c*w), to_nt(d*w)); + } + + P p(int x, int y, int z) + { + int w = ri.next(); + return P(to_nt(x*w), to_nt(y*w), to_nt(z*w), to_nt(w)); + } + + P random_point() + { + return p(r.get_int(m, M), r.get_int(m, M), r.get_int(m, M)); + } + +public: + template + bool approx_equal_nt(const Type &t1, const Type &t2) + { + if(t1 == t2) + return true; + + if(has_exact_c) + { + std::cerr << " Comparison failed between : " << t1 << " and " << t2 << "\n"; + return false; + } + + if(CGAL::abs(t1 - t2) / (CGAL::max)(CGAL::abs(t1), CGAL::abs(t2)) < epsilon) + return true; + + std::cerr << " Approximate comparison failed between : " << t1 << " and " << t2 << "\n"; + + return false; + } + + // we need approx equal to check approx kernels, but maybe we should only test with exact kernels + // (approx kernels were useful before, when the text output was checked by diff ?) + // idea : test containment with intervals ? or use some "epsilon double"? + // I need to convert the text output to exact rationals in the source... + // Well, for now the current scheme works. + template + bool approx_equal(const Type& t1, const Type& t2) + { + if(t1 != t2) + { + if(verbose) + std::cerr << "Failed comparison of " << typeid(Type).name() << ": " << t1 << " is NOT " << t2 << std::endl; + + return false; + } + + return true; + } + +// bool approx_equal(const P& p, const P& q) +// { +// return approx_equal_nt(p.x(), q.x()) && +// approx_equal_nt(p.y(), q.y()) && +// approx_equal_nt(p.z(), q.z()); +// } + + bool approx_equal(const S& p, const S& q) + { + std::cout << "compare segments " << p << " & " << q << std::endl; + + // allow opposite orientation + return (approx_equal(p.source(), q.source()) && approx_equal(p.target(), q.target())) || + (approx_equal(p.source(), q.target()) && approx_equal(p.target(), q.source())); + } + + bool approx_equal(const Pol& p, const Pol& q) + { + if(p.size() != q.size()) + return false; + + for(typename Pol::const_iterator itp = p.begin(), itq = q.begin(); itp != p.end(); ++itp, ++itq) + if(!approx_equal(*itp, *itq)) + return false; + + return true; + } + +public: + template + void check_do_intersect(const O1& o1, const O2& o2) + { + if(verbose) + { + std::cout << "\nExpecting intersection between " << typeid(O1).name() << " = " << o1 + << "\nand " << typeid(O2).name() << " = " << o2 << std::endl; + } + + const bool res12 = CGAL::do_intersect(o1, o2); + const bool res21 = CGAL::do_intersect(o2, o1); + + if(has_exact_p) + { + assert(res12); + assert(res21); + } + else + { + CGAL_warning(res12); + CGAL_warning(res21); + } + } + + template + void check_intersection(const O1& o1, const O2& o2) + { + check_do_intersect(o1, o2); + + std::cout << "1 --------------" << std::endl; + const auto res12 = CGAL::intersection(o1, o2); + std::cout << "2 --------------" << std::endl; + const auto res21 = CGAL::intersection(o2, o1); + + Res tmp; + if(has_exact_p) + { + assert(CGAL::assign(tmp, res12)); + assert(CGAL::assign(tmp, res21)); + } + else + { + CGAL_warning(CGAL::assign(tmp, res12)); + CGAL_warning(CGAL::assign(tmp, res21)); + } + } + + template + void check_intersection(const O1& o1, const O2& o2, + const Res& result, + bool do_opposite = true) + { + if(verbose) + { + std::cout << "\nCheck intersection between " << typeid(O1).name() << " = " << o1 + << "\nand " << typeid(O2).name() << " = " << o2 << std::endl; + std::cout << "Expecting result " << typeid(Res).name() << " = " << result << std::endl; + } + + const bool res12 = CGAL::do_intersect(o1, o2); + if(has_exact_p) + assert(res12); + else + CGAL_warning(res12); + + const auto ires12 = CGAL::intersection(o1, o2); + + Res tmp; + if(has_exact_p) + { + assert(CGAL::assign(tmp, ires12)); + assert(approx_equal(tmp, result)); + } + else + { + if(CGAL::assign(tmp, ires12)) + assert(approx_equal(tmp, result)); + else + CGAL_warning_msg(false, "Expected an intersection, but it was not found!"); + } + + if(do_opposite) + check_intersection(o2, o1, result, false); + } + + template + void check_intersection(const O1& o1, const O2& o2, + const O3& o3, const O4& o4) + { + if(verbose) + { + std::cout << "\nCheck intersection between " << typeid(O1).name() << " = " << o1 + << "\nand " << typeid(O2).name() << " = " << o2 << std::endl; + std::cout << "Expecting result to be the same as intersection between " << typeid(O3).name() << " = " << o3 + << "\nand " << typeid(O4).name() << " = " << o4 << std::endl; + } + + const bool res12 = CGAL::do_intersect(o1, o2); + const bool res34 = CGAL::do_intersect(o3, o4); + + if(has_exact_p) + assert(res12 == res34); + else + CGAL_warning(res12 == res34); + + if(res12 && res34) + { + const auto ires12 = CGAL::intersection(o1, o2); + const auto ires34 = CGAL::intersection(o3, o4); + + Res tmp12, tmp34; + if(has_exact_c) + { + assert(CGAL::assign(tmp12, ires12)); + assert(CGAL::assign(tmp34, ires34)); + assert(tmp12 == tmp34); + } + else + { + if(CGAL::assign(tmp12, ires12) && CGAL::assign(tmp34, ires34)) + { + CGAL_warning(tmp12 == tmp34); + } + } + } + } + + template + struct Variant_visitor + { + Variant_visitor(const OV& other_variant) + : ov(other_variant), equal(false) + { + assert(ov); + } + + template + bool compare_to_other_variant(const T& t) const + { + if(ov->type() == typeid(T)) + { + auto* r = boost::get(&*ov); // ov is an optional + assert(r); + return (t == *r); + } + + return false; + } + + template + void operator()(const T& value) const + { + if(equal) + return; + + if(compare_to_other_variant(value)) + equal = true; + } + + const OV& ov; + mutable bool equal; + }; + + template + void check_intersection(const O1& o1, const O2& o2, + const O3& o3, const O4& o4) + { + if(verbose) + { + std::cout << "\nCheck intersection between " << typeid(O1).name() << " = " << o1 + << "\nand " << typeid(O2).name() << " = " << o2 << std::endl; + std::cout << "Expecting result to be the same as intersection between " << typeid(O3).name() << " = " << o3 + << "\nand " << typeid(O4).name() << " = " << o4 << std::endl; + } + + const bool res12 = CGAL::do_intersect(o1, o2); + const bool res34 = CGAL::do_intersect(o3, o4); + + if(has_exact_p) + assert(res12 == res34); + else + CGAL_warning(res12 == res34); + + if(res12 && res34) + { + const auto ires12 = CGAL::intersection(o1, o2); + const auto ires34 = CGAL::intersection(o3, o4); + + if(has_exact_c) + { + assert(ires12 && ires34); + + Variant_visitor vis(ires12); + boost::apply_visitor(vis, *ires34); + assert(vis.equal); + } + } + } + +public: + template + void check_do_not_intersect(const O1& o1, const O2& o2) + { + const bool res12 = CGAL::do_intersect(o1, o2); + const bool res21 = CGAL::do_intersect(o2, o1); + + if(has_exact_p) + { + assert(!res12); + assert(!res21); + } + else + { + CGAL_warning(!res12); + CGAL_warning(!res21); + } + } + + template + void check_do_not_intersect(const O1& o1, const O2& o2, const O3& o3) + { + auto res123 = CGAL::do_intersect(o1, o2, o3); + auto res132 = CGAL::do_intersect(o1, o3, o2); + auto res213 = CGAL::do_intersect(o2, o1, o3); + auto res231 = CGAL::do_intersect(o2, o3, o1); + auto res312 = CGAL::do_intersect(o3, o1, o2); + auto res321 = CGAL::do_intersect(o3, o2, o1); + if(has_exact_p) + assert(!res123 && !res132 && !res213 && !res231 && !res312 && !res321); + else + CGAL_warning(!res123 && !res132 && !res213 && !res231 && !res312 && !res321); + } + + template + void check_no_intersection(const O1& o1, const O2& o2) + { + check_do_not_intersect(o1, o2); + + auto res12 = CGAL::intersection(o1, o2); + auto res21 = CGAL::intersection(o2, o1); + if(has_exact_p) + { + assert(!res12); + assert(!res21); + } + else + { + CGAL_warning(!res12); + CGAL_warning(!res21); + } + } + + template + void check_no_intersection(const O1& o1, const O2& o2, const O3& o3) + { + check_do_not_intersect(o1, o2, o3); + + auto res123 = CGAL::intersection(o1, o2, o3); + auto res132 = CGAL::intersection(o1, o3, o2); + auto res213 = CGAL::intersection(o2, o1, o3); + auto res231 = CGAL::intersection(o2, o3, o1); + auto res312 = CGAL::intersection(o3, o1, o2); + auto res321 = CGAL::intersection(o3, o2, o1); + if(has_exact_p) + assert(!res123 && !res132 && !res213 && !res231 && !res312 && !res321); + else + CGAL_warning(!res123 && !res132 && !res213 && !res231 && !res312 && !res321); + } +};