cgal/Packages/Arrangement/include/CGAL/Arr_conic_traits_2.h

1283 lines
37 KiB
C++

// Copyright (c) 1999 Tel-Aviv University (Israel).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $Source$
// $Revision$ $Date$
// $Name$
//
// Author(s) : Ron Wein <wein@post.tau.ac.il>
#ifndef CGAL_ARR_CONIC_TRAITS_2_H
#define CGAL_ARR_CONIC_TRAITS_2_H
#include <CGAL/basic.h>
#include <CGAL/tags.h>
#include <CGAL/Arrangement_2/Conic_arc_2.h>
#include <list>
CGAL_BEGIN_NAMESPACE
// ----------------------------------------------------------------------------
// Arrangement traits for conic arcs.
//
template <class Kernel_>
class Arr_conic_traits_2
{
public:
typedef Kernel_ Kernel;
typedef typename Kernel::FT NT;
// Categories:
//#define HAS_LEFT_NOT
#if !defined(HAS_LEFT_NOT)
typedef Tag_true Has_left_category;
#else
typedef Tag_false Has_left_category;
#endif
// The difference between Curve_2 and X_monotone_curve_2 is semantical only,
// NOT syntactical.
typedef Conic_arc_2<Kernel> Curve_2;
typedef Curve_2 X_monotone_curve_2;
// Using typename to please compiler (e.g., CC with IRIX64 on mips)
typedef typename Curve_2::Kernel R;
typedef typename Curve_2::Point_2 Point_2;
typedef typename Curve_2::Circle_2 Circle_2;
typedef typename Curve_2::Segment_2 Segment_2;
// For backward compatibility:
typedef Curve_2 Curve;
typedef X_monotone_curve_2 X_curve;
typedef Point_2 Point;
typedef Circle_2 Circle;
typedef Segment_2 Segment;
#ifdef CGAL_CONIC_ARC_USE_CACHING
private:
typedef typename Curve_2::Intersections Intersections;
mutable std::list<Intersections> inter_list; // For caching intersections.
#endif
public:
// Constructor.
Arr_conic_traits_2()
{}
////////// Planar Map methods: //////////
// Compare the co-ordinates of two given points.
Comparison_result compare_x(const Point_2& p0, const Point_2& p1) const
{
return (p0.compare_x(p1));
}
Comparison_result compare_xy(const Point_2& p0, const Point_2& p1) const
{
Comparison_result x_res = p0.compare_x(p1);
if (x_res != EQUAL)
return (x_res);
return (p0.compare_y(p1));
}
// Check whether the given curve is a vertical segment.
bool curve_is_vertical(const X_monotone_curve_2& curve) const
{
return (curve.is_vertical_segment());
}
// Check whether the x co-ordinate of the given point is contained in the
// x-range of the given x-monotone curve.
bool point_in_x_range(const X_monotone_curve_2& curve,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(curve));
if (curve.is_vertical_segment())
{
// Check if the vertical segment's x co-ordinate is the same as p's.
return (compare_x (curve.source(), p) == EQUAL);
}
else
{
// Since the curve is x-monotone, if the point x co-ordinate is to the
// left (or to the right of both curve's source and target points), then
// the point is obviously not in the curve's x range.
Comparison_result res1 = compare_x(p, curve.source());
Comparison_result res2 = compare_x(p, curve.target());
return ((res1 == EQUAL) || (res2 == EQUAL) || (res1 != res2));
}
}
// Decide wether curve1 is above, below or equal to curve2 at the
// x co-ordinate of the given point.
Comparison_result curves_compare_y_at_x (const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
CGAL_precondition(point_in_x_range(curve1, p));
CGAL_precondition(point_in_x_range(curve2, p));
if (curve1.contains_point(p) && curve2.contains_point(p))
return (EQUAL);
// Get the points on curve1 with the same x co-ordinate as p.
int n1;
Point_2 ps1[2];
if (curve1.is_vertical_segment())
{
// In case curve1 is a vertical segment, both the source and target
// of the curve has the same x co-ordinate as p.
// Make sure that ps1[0] has a smaller y value than ps1[1].
n1 = 2;
if (_compare_y (curve1.source(), curve1.target()) == SMALLER)
{
ps1[0] = curve1.source();
ps1[1] = curve1.target();
}
else
{
ps1[0] = curve1.target();
ps1[1] = curve1.source();
}
}
else if (compare_x(p, curve1.source()) == EQUAL)
{
ps1[0] = curve1.source();
n1 = 1;
}
else if (compare_x(p, curve1.target()) == EQUAL)
{
ps1[0] = curve1.target();
n1 = 1;
}
else
{
// Find all points on curve1 with the same x co-ordinate as p.
n1 = curve1.get_points_at_x (p, ps1);
CGAL_assertion(n1 == 1);
}
// Get the points on curve2 with the same x co-ordinate as p.
int n2;
Point_2 ps2[2];
if (curve2.is_vertical_segment())
{
// In case curve2 is a vertical segment, both the source and target
// of the curve has the same x co-ordinate as p.
// Make sure that ps2[0] has a smaller y value than ps2[1].
n2 = 2;
if (_compare_y (curve2.source(), curve2.target()) == SMALLER)
{
ps2[0] = curve2.source();
ps2[1] = curve2.target();
}
else
{
ps2[0] = curve2.target();
ps2[1] = curve2.source();
}
}
else if (compare_x(p, curve2.source()) == EQUAL)
{
ps2[0] = curve2.source();
n2 = 1;
}
else if (compare_x(p, curve2.target()) == EQUAL)
{
ps2[0] = curve2.target();
n2 = 1;
}
else
{
// Find all points on curve2 with the same x co-ordinate as p.
n2 = curve2.get_points_at_x (p, ps2);
CGAL_assertion(n2 == 1);
}
// Deal with vertical segments:
if (n1 == 2)
{
// Check if the vertical segment curve1 contains ps2[0] or ps2[1].
if (_compare_y (ps1[0], ps2[0]) != LARGER &&
_compare_y (ps1[1], ps2[0]) != SMALLER)
{
return (EQUAL);
}
if (n2 == 2)
{
if (_compare_y (ps1[0], ps2[1]) != LARGER &&
_compare_y (ps1[1], ps2[1]) != SMALLER)
{
return (EQUAL);
}
}
}
else if (n2 == 2)
{
// Check if the vertical segment curve2 contains ps1[0].
if (_compare_y (ps2[0], ps1[0]) != LARGER &&
_compare_y (ps2[1], ps1[0]) != SMALLER)
{
return (EQUAL);
}
}
// None of the curves is a vertical segments and both have exactly
// one point with the given x co-ordinate:
// Compare the y co-ordinates of these two points.
return (_compare_y (ps1[0], ps2[0]));
/* DEBUG:
Comparison_result res = _compare_y (ps1[0], ps2[0]);
if (curve1.conic() != curve2.conic())
std::cout << "curves_compare_y_at_x() : " << std::endl
<< "C1 : " << curve1 << std::endl
<< "C2 : " << curve2 << std::endl
<< "p = (" << CGAL::to_double(p.x()) << ","
<< CGAL::to_double(p.y()) << ")" << std::endl
<< "ps1[0] = (" << CGAL::to_double(ps1[0].x()) << ","
<< CGAL::to_double(ps1[0].y()) << ")" << std::endl
<< "ps2[0] = (" << CGAL::to_double(ps2[0].x()) << ","
<< CGAL::to_double(ps2[0].y()) << ")" << std::endl
<< "res = " << (res == EQUAL ?
"EQUAL" : res == SMALLER ?
"SMALLER" : "LARGER") << std::endl
<< std::endl;
return (res);
*/
}
// Decide wether curve1 is above, below or equal to curve2 immediately to
// the left of the x co-ordinate of the given point.
Comparison_result
curves_compare_y_at_x_left(const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
// The two curve must not be vertical segments.
CGAL_precondition(! curve1.is_vertical_segment());
CGAL_precondition(! curve2.is_vertical_segment());
// Check that both curves are defined to the left of p.
CGAL_precondition((compare_x(curve1.source(), p) == SMALLER) ||
(compare_x(curve1.target(), p) == SMALLER));
CGAL_precondition((compare_x(curve2.source(), p) == SMALLER) ||
(compare_x(curve2.target(), p) == SMALLER));
// Get the points on curve1 with the same x co-ordinate as p.
int n1;
Point_2 ps1[2];
if (curve1.contains_point(p))
{
ps1[0] = p;
n1 = 1;
}
else
{
n1 = curve1.get_points_at_x (p, ps1);
}
// Make sure that there is exactly one point.
CGAL_assertion(n1 == 1);
// Get the points on curve2 with the same x co-ordinate as p.
int n2;
Point_2 ps2[2];
if (curve2.contains_point(p))
{
ps2[0] = p;
n2 = 1;
}
else
{
n2 = curve2.get_points_at_x (p, ps2);
}
// Make sure that there is exactly one point.
CGAL_assertion(n2 == 1);
// Tje two curves must intersect at x(p).
CGAL_precondition (_compare_y (ps1[0], ps2[0]) == EQUAL);
// If the curves are the same, they are equal to the left of p:
if (curve_equal(curve1,curve2))
return (EQUAL);
// The two curves intersect at ps1[0] = ps2[0] - proceed from here.
return (_curve_compare_at_intersection_left (curve1, curve2, ps1[0]));
}
// Decide wether curve1 is above, below or equal to curve2 immediately to
// the right of the x co-ordinate of the given point.
Comparison_result
curves_compare_y_at_x_right(const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
// The two curve must not be vertical segments.
CGAL_precondition(! curve1.is_vertical_segment());
CGAL_precondition(! curve2.is_vertical_segment());
// Check that both curves are defined to the right of p.
CGAL_precondition((compare_x(curve1.source(), p) == LARGER) ||
(compare_x(curve1.target(), p) == LARGER));
CGAL_precondition((compare_x(curve2.source(), p) == LARGER) ||
(compare_x(curve2.target(), p) == LARGER));
// Get the points on curve1 with the same x co-ordinate as p.
int n1;
Point_2 ps1[2];
if (curve1.contains_point(p))
{
ps1[0] = p;
n1 = 1;
}
else
{
n1 = curve1.get_points_at_x (p, ps1);
}
// Make sure we have a single point.
CGAL_assertion(n1 == 1);
// Get the points on curve2 with the same x co-ordinate as p.
int n2;
Point_2 ps2[2];
if (curve2.contains_point(p))
{
ps2[0] = p;
n2 = 1;
}
else
{
n2 = curve2.get_points_at_x (p, ps2);
}
// Make sure we have a single point.
CGAL_assertion(n2 == 1);
// The two curves must intersect at p(x).
CGAL_precondition (_compare_y (ps1[0], ps2[0]) == EQUAL);
// If the two curves are the same, they are equal to the right of p:
if (curve_equal(curve1,curve2))
return (EQUAL);
// The two curves intersect at ps1[0] = ps2[0] - proceed from here:
return (_curve_compare_at_intersection_right (curve1, curve2, ps1[0]));
/* DEBUG:
Comparison_result res = _curve_compare_at_intersection_right (curve1,
curve2,
ps1[0]);
if (curve1.conic() != curve2.conic())
std::cout << "curves_compare_y_at_x_right() : " << std::endl
<< "C1 : " << curve1 << std::endl
<< "C2 : " << curve2 << std::endl
<< "p = (" << CGAL::to_double(p.x()) << ","
<< CGAL::to_double(p.y()) << std::endl
<< "ps1[0] = (" << CGAL::to_double(ps1[0].x()) << ","
<< CGAL::to_double(ps1[0].y()) << std::endl
<< "res = " << (res == EQUAL ?
"EQUAL" : res == SMALLER ?
"SMALLER" : "LARGER") << std::endl
<< std::endl;
return (res);
*/
}
// Check whether the given point is above, under or on the given curve.
Comparison_result curve_compare_y_at_x(const Point_2& p,
const X_monotone_curve_2& curve) const
{
CGAL_precondition(is_x_monotone(curve));
CGAL_precondition(point_in_x_range(curve,p));
// A special treatment for vertical segments:
if (curve.is_vertical_segment())
{
// In case p has the same x c-ordinate of the vertical segment, compare
// it to the segment endpoints to determine its position.
Comparison_result res1 = _compare_y (p, curve.source());
Comparison_result res2 = _compare_y (p, curve.target());
if (res1 == res2)
return (res1);
else
return (EQUAL);
}
// Check whether the point is exactly on the curve.
if (curve.contains_point(p))
return (EQUAL);
// Get the points on the arc with the same x co-ordinate as p.
int n;
Point_2 ps[2];
if (compare_x(p, curve.source()) == EQUAL)
{
ps[0] = curve.source();
n = 1;
}
else if (compare_x(p, curve.target()) == EQUAL)
{
ps[0] = curve.target();
n = 1;
}
else
{
n = curve.get_points_at_x (p, ps);
}
// Make sure there is exactly one point.
CGAL_assertion(n == 1);
// Compare p with the a point of the curve with the same x co-ordinate.
return (_compare_y(p, ps[0]));
}
// Cehck whether the two points are identical.
bool point_equal (const Point_2& p1, const Point_2& p2) const
{
return (p1.equals(p2));
}
// Check whether the two curves are identical.
bool curve_equal (const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
// Check whether all arc features are the same.
if (curve1.conic().orientation() == curve2.conic().orientation())
{
// Same orientation:
return (curve1.has_same_base_conic(curve2) &&
curve1.source().equals(curve2.source()) &&
curve1.target().equals(curve2.target()));
}
else
{
// Check the flip case:
return (curve1.has_same_base_conic(curve2) &&
curve1.source().equals(curve2.target()) &&
curve1.target().equals(curve2.source()));
}
}
// Get the source and target vertex of the curve.
Point_2 curve_source(const X_monotone_curve_2& curve) const
{
return (curve.source());
}
Point_2 curve_target(const X_monotone_curve_2& curve) const
{
return (curve.target());
}
// Return a point to the left or to the right of p.
Point_2 point_to_left (const Point_2& p) const
{
NT x = CGAL::to_double(p.x()) - 1;
return (Point_2(x , p.y(),
Point_2::User_defined));
}
Point_2 point_to_right (const Point_2& p) const
{
NT x = CGAL::to_double(p.x()) + 1;
return (Point_2(x , p.y(),
Point_2::User_defined));
}
#if defined(HAS_LEFT_NOT)
// Reflect a point in y.
Point_2 point_reflect_in_y (const Point_2& p) const
{
return (p.reflect_in_y());
}
// Reflect a curve in y.
X_monotone_curve_2 curve_reflect_in_y (const X_monotone_curve_2& curve) const
{
return (curve.reflect_in_y());
}
// Reflect a point in x and y.
Point_2 point_reflect_in_x_and_y (const Point_2& p) const
{
return (p.reflect_in_x_and_y());
}
// Reflect a curve in x and y.
X_monotone_curve_2
curve_reflect_in_x_and_y (const X_monotone_curve_2& curve) const
{
return (curve.reflect_in_x_and_y());
}
#endif
////////// Arrangement methods: //////////
// Change the orientation of the curve (swap the source and the target).
X_monotone_curve_2 curve_opposite (const X_monotone_curve_2& curve) const
{
// Flip the arc.
return (curve.flip());
}
// Check whether the curve is x-monotone.
bool is_x_monotone (const Curve_2& curve) const
{
return (curve.is_x_monotone());
}
/*! Cut the given curve into x-monotone subcurves and inserts them to the
* given output iterator.
* \param cv the input curve
* \param o the output iterator
* \return the past-the-end iterator
*/
template<class OutputIterator>
OutputIterator curve_make_x_monotone (const Curve_2& curve,
OutputIterator o) const
{
// Find the points of vertical tangency and act accordingly.
int n;
Point_2 ps[2];
n = curve.vertical_tangency_points (ps);
if (n == 0)
{
// In case the given curve is already x-monotone:
*o++ = curve;
return (o);
}
// Split the conic arc into x-monotone sub-curves.
if (curve.is_full_conic())
{
// Make sure we have two vertical tangency points.
CGAL_assertion(n == 2);
// In case the curve is a full conic, split it to two x-monotone curves,
// one going from ps[0] to ps[1], and the other from ps[1] to ps[0].
*o++ = X_monotone_curve_2 (curve, ps[0], ps[1], false);
*o++ = X_monotone_curve_2 (curve, ps[1], ps[0], false);
}
else
{
X_monotone_curve_2 sub_curve1;
X_monotone_curve_2 sub_curve2;
X_monotone_curve_2 sub_curve3;
if (n == 1)
{
// Split the arc into two x-monotone sub-curves: one going from the
// arc source to ps[0], and the other from ps[0] to the target.
_curve_split (curve,
sub_curve1, sub_curve2,
ps[0]);
*o++ = sub_curve1;
*o++ = sub_curve2;
}
else if (n == 2)
{
// Split the arc into three x-monotone sub-curves: one going from the
// arc source to ps[0], one from ps[0] to ps[1], and the last one
// from ps[1] to the target.
// Notice that ps[0] and ps[1] might switch places.
X_monotone_curve_2 temp;
_curve_split (curve,
sub_curve1, sub_curve2,
ps[0]);
if (sub_curve2.contains_point(ps[1]))
{
temp = sub_curve2;
_curve_split (temp,
sub_curve2, sub_curve3,
ps[1]);
}
else if (sub_curve1.contains_point(ps[1]))
{
// Actually we switch between ps[0] and ps[1].
temp = sub_curve1;
sub_curve3 = sub_curve2;
_curve_split (temp,
sub_curve1, sub_curve2,
ps[1]);
}
else
{
// We should never reach here:
CGAL_assertion(false);
}
*o++ = sub_curve1;
*o++ = sub_curve2;
*o++ = sub_curve3;
}
else
{
// We should never reach here:
CGAL_assertion(false);
}
}
return (o);
}
// Split the given curve into two sub-curves at the given point.
void curve_split (const X_monotone_curve_2& curve,
X_monotone_curve_2& sub_curve1,
X_monotone_curve_2& sub_curve2,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(curve));
// Make sure the point is on the curve and is not an end-point.
CGAL_precondition(curve.contains_point(p));
CGAL_precondition(! p.equals(curve.source()));
CGAL_precondition(! p.equals(curve.target()));
// Split the curve.
_curve_split (curve,
sub_curve1, sub_curve2,
p);
return;
}
// Find the nearest intersection point between the two given curves to the
// right of the given point.
// In case of an overlap, p1 and p2 are the source and destination of the
// overlapping curve. Otherwise p1=p2 is the calculated intersection point.
bool nearest_intersection_to_right (const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p,
Point_2& p1,
Point_2& p2) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
// Deal with overlapping curves:
int n_ovlps;
X_monotone_curve_2 ovlp_arcs[2];
n_ovlps = curve1.overlaps (curve2, ovlp_arcs);
CGAL_assertion (n_ovlps < 2);
if (n_ovlps == 1)
{
Point_2 ovlp_source = ovlp_arcs[0].source();
Point_2 ovlp_target = ovlp_arcs[0].target();
if (ovlp_source.compare_lex_xy(p) == LARGER &&
ovlp_target.compare_lex_xy(p) == LARGER)
{
// The entire overlapping arc is to the right of p:
p1 = ovlp_source;
p2 = ovlp_target;
return (true);
}
else if (ovlp_source.compare_lex_xy(p) != LARGER &&
ovlp_target.compare_lex_xy(p) == LARGER)
{
// The source is to the left of p, and the traget is to its right.
p1 = p;
p2 = ovlp_target;
return (true);
}
else if (ovlp_source.compare_lex_xy(p) == LARGER &&
ovlp_target.compare_lex_xy(p) != LARGER)
{
// The source is to the right of p, and the traget is to its left.
p1 = ovlp_source;
p2 = p;
return (true);
}
else
{
// The entire overlapping arc is to the left of p:
return (false);
}
}
// In case there are no overlaps and the base conics are the same,
// there cannot be any intersection points, unless the two x-monotone
// curves share an end point.
if (curve1.has_same_base_conic(curve2))
{
const Point_2 *nearest_end_P = NULL;
if ((curve1.source().equals(curve2.source()) ||
curve1.source().equals(curve2.target())) &&
curve1.source().compare_lex_xy(p) == LARGER)
{
nearest_end_P = &(curve1.source());
}
if ((curve1.target().equals(curve2.source()) ||
curve1.target().equals(curve2.target())) &&
curve1.target().compare_lex_xy(p) == LARGER)
{
if (nearest_end_P == NULL ||
nearest_end_P->compare_lex_xy (curve1.target()) == LARGER)
{
nearest_end_P = &(curve1.target());
}
}
if (nearest_end_P != NULL)
{
// A common end point was found:
p1 = p2 = *nearest_end_P;
return (true);
}
else
{
// No intersection:
return (false);
}
}
// Find the intersection points and choose the one nearest to p.
int n;
Point_2 ps[4];
const Point_2 *nearest_inter_P = NULL;
#ifdef CGAL_CONIC_ARC_USE_CACHING
n = curve1.intersections_with (curve2, ps, &inter_list);
#else
n = curve1.intersections_with (curve2, ps);
#endif
/* DEBUG:
std::cout << "nearest_intersection_to_right() : " << std::endl
<< "C1 : " << curve1 << std::endl
<< "C2 : " << curve2 << std::endl
<< "p = (" << CGAL::to_double(p.x()) << ","
<< CGAL::to_double(p.y()) <<") [n = " << n << "]"
<< std::endl;
*/
for (int i = 0; i < n; i++)
{
// Check if the current point is to the right of p.
if (ps[i].compare_lex_xy(p) == LARGER)
{
// Compare with the nearest point so far.
if (nearest_inter_P == NULL ||
nearest_inter_P->compare_lex_xy (ps[i]) == LARGER)
{
nearest_inter_P = &(ps[i]);
}
}
}
if (nearest_inter_P != NULL)
{
// Return the nearest intersection point.
p1 = p2 = *nearest_inter_P;
/* DEBUG:
std::cout << "p1 = p2 = (" << CGAL::to_double(p1.x()) << ","
<< CGAL::to_double(p1.y()) << std::endl << std::endl;
*/
return (true);
}
// No intersection found.
/* DEBUG:
std::cout << "No intersection found!" << std::endl << std::endl;
*/
return (false);
}
// Find the nearest intersection point between the two given curves to the
// left of the given point.
// In case of an overlap, p1 and p2 are the source and destination of the
// overlapping curve. Otherwise p1=p2 is the calculated intersection point.
bool nearest_intersection_to_left (const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p,
Point_2& p1,
Point_2& p2) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
// Deal with overlapping curves:
int n_ovlps;
X_monotone_curve_2 ovlp_arcs[2];
n_ovlps = curve1.overlaps (curve2, ovlp_arcs);
CGAL_assertion (n_ovlps < 2);
if (n_ovlps == 1)
{
Point_2 ovlp_source = ovlp_arcs[0].source();
Point_2 ovlp_target = ovlp_arcs[0].target();
if (ovlp_source.compare_lex_xy(p) == SMALLER &&
ovlp_target.compare_lex_xy(p) == SMALLER)
{
// The entire overlapping arc is to the left of p:
p1 = ovlp_source;
p2 = ovlp_target;
return (true);
}
else if (ovlp_source.compare_lex_xy(p) != SMALLER &&
ovlp_target.compare_lex_xy(p) == SMALLER)
{
// The source is to the right of p, and the traget is to its left.
p1 = p;
p2 = ovlp_target;
return (true);
}
else if (ovlp_source.compare_lex_xy(p) == SMALLER &&
ovlp_target.compare_lex_xy(p) != SMALLER)
{
// The source is to the left of p, and the traget is to its right.
p1 = ovlp_source;
p2 = p;
return (true);
}
else
{
// The entire overlapping arc is to the right of p:
return (false);
}
}
// In case there are no overlaps and the base conics are the same,
// there cannot be any intersection points, unless the two x-monotone
// curves share an end point.
if (curve1.has_same_base_conic(curve2))
{
const Point_2 *nearest_end_P = NULL;
if ((curve1.source().equals(curve2.source()) ||
curve1.source().equals(curve2.target())) &&
curve1.source().compare_lex_xy(p) == SMALLER)
{
nearest_end_P = &(curve1.source());
}
if ((curve1.target().equals(curve2.source()) ||
curve1.target().equals(curve2.target())) &&
curve1.target().compare_lex_xy(p) == SMALLER)
{
if (nearest_end_P == NULL ||
nearest_end_P->compare_lex_xy (curve1.target()) == SMALLER)
{
nearest_end_P = &(curve1.target());
}
}
if (nearest_end_P != NULL)
{
// A common end point was found:
p1 = p2 = *nearest_end_P;
return (true);
}
else
{
// No intersection:
return (false);
}
}
// Find the intersection points and choose the one nearest to p.
int n;
Point_2 ps[4];
const Point_2 *nearest_inter_P = NULL;
#ifdef CGAL_CONIC_ARC_USE_CACHING
n = curve1.intersections_with (curve2, ps, &inter_list);
#else
n = curve1.intersections_with (curve2, ps);
#endif
for (int i = 0; i < n; i++)
{
// Check if the current point is to the right of p.
if (ps[i].compare_lex_xy(p) == SMALLER)
{
// Compare with the nearest point so far.
if (nearest_inter_P == NULL ||
nearest_inter_P->compare_lex_xy (ps[i]) == SMALLER)
{
nearest_inter_P = &(ps[i]);
}
}
}
if (nearest_inter_P != NULL)
{
// Return the nearest intersection point.
p1 = p2 = *nearest_inter_P;
return (true);
}
// No intersection found.
return (false);
}
// Check whether two curves overlap.
bool curves_overlap (const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2) const
{
CGAL_precondition(is_x_monotone(curve1));
CGAL_precondition(is_x_monotone(curve2));
X_monotone_curve_2 ovlp_arcs[2];
return (curve1.overlaps (curve2, ovlp_arcs) > 0);
}
private:
////////// Private auxiliary methods: //////////
// Compare two points by their y coordinate:
Comparison_result _compare_y(const Point_2& p0, const Point_2& p1) const
{
return (p0.compare_y(p1));
}
// Split the given curve into two sub-curves at the given point.
// Since this is a private function, there are no preconditions.
void _curve_split (const X_monotone_curve_2& curve,
X_monotone_curve_2& sub_curve1,
X_monotone_curve_2& sub_curve2,
const Point_2& p) const
{
CGAL_precondition(! p.equals(curve.source()));
CGAL_precondition(! p.equals(curve.target()));
// Split the curve to source->p and p->target.
sub_curve1 = X_monotone_curve_2 (curve, curve.source(), p, false);
sub_curve2 = X_monotone_curve_2 (curve, p, curve.target(), false);
CGAL_assertion(sub_curve1.is_x_monotone());
CGAL_assertion(sub_curve2.is_x_monotone());
return;
}
// Decide wether curve1 is above, below or equal to curve2 immediately to
// the left of p_int, which is assumed to be an intersection of both curves.
// Furthermore, the two curves are assumed to be defined to p_int's left.
Comparison_result _curve_compare_at_intersection_left
(const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p_int) const
{
// In case one arc is facing upwards and another facing downwards, it is
// very clear that the one facing upward is above the one facing downwards.
if (curve1.has_same_base_conic(curve2))
{
Comparison_result fac1 = curve1.facing();
Comparison_result fac2 = curve2.facing();
if (fac1 == LARGER && fac2 == SMALLER)
return (LARGER);
else if (fac1 == SMALLER && fac2 == LARGER)
return (SMALLER);
}
// Otherwise, the two curves do intersect at p_int = ps1[0] = ps2[0]:
// make a decision based on their partial derivatives.
//const Point_2& p_int = ps1[0];
const NT _zero = 0;
NT slope1_numer, slope1_denom;
NT slope2_numer, slope2_denom;
curve1.derive_by_x_at (p_int, 1, slope1_numer, slope1_denom);
curve2.derive_by_x_at (p_int, 1, slope2_numer, slope2_denom);
/*const*/ bool is_vertical_slope1 = (slope1_denom == _zero);
/*const*/ bool is_vertical_slope2 = (slope2_denom == _zero);
// RWRW - CHECK THIS !!!
if (! is_vertical_slope1 &&
p_int.is_approximate() &&
eps_compare<APNT>(TO_APNT(slope1_denom), 0) == EQUAL)
{
is_vertical_slope1 = true;
}
if (! is_vertical_slope2 &&
p_int.is_approximate() &&
eps_compare<APNT>(TO_APNT(slope2_denom), 0) == EQUAL)
{
is_vertical_slope2 = true;
}
// TO HERE ...
if (!is_vertical_slope1 && !is_vertical_slope2)
{
// The two curves have derivatives at p_int: use it to determine which
// one is above the other (the one with a smaller slope in above).
// RWRW - CHECK THIS !!!
Comparison_result slope_res =
(!p_int.is_approximate()) ?
CGAL::compare(slope2_numer*slope1_denom, slope1_numer*slope2_denom) :
eps_compare<APNT>(TO_APNT(slope2_numer*slope1_denom),
TO_APNT(slope1_numer*slope2_denom));
if (slope_res != EQUAL)
return (slope_res);
// Use the second order derivative.
curve1.derive_by_x_at (p_int, 2, slope1_numer, slope1_denom);
curve2.derive_by_x_at (p_int, 2, slope2_numer, slope2_denom);
slope_res = CGAL::compare (slope2_numer*slope1_denom,
slope1_numer*slope2_denom);
//CGAL_assertion(slope_res != EQUAL);
return ((slope_res == LARGER) ? SMALLER : LARGER);
}
else if (!is_vertical_slope2)
{
// The first curve has a vertical slope at p_int: check whether it is
// facing upwards or downwards and decide accordingly.
Comparison_result fac1 = curve1.facing();
CGAL_assertion(fac1 != EQUAL);
return (fac1);
}
else if (!is_vertical_slope1)
{
// The second curve has a vertical slope at p_int: check whether it is
// facing upwards or downwards and decide accordingly.
Comparison_result fac2 = curve2.facing();
CGAL_assertion(fac2 != EQUAL);
return ((fac2 == LARGER) ? SMALLER : LARGER);
}
else
{
// The two curves have vertical slopes at p_int:
// First check whether one is facing up and one down. In this case the
// comparison result is trivial.
Comparison_result fac1 = curve1.facing();
Comparison_result fac2 = curve2.facing();
if (fac1 == LARGER && fac2 == SMALLER)
return (LARGER);
else if (fac1 == SMALLER && fac2 == LARGER)
return (SMALLER);
// Compute the second order derivative by y and act according to it.
curve1.derive_by_y_at (p_int, 2, slope1_numer, slope1_denom);
curve2.derive_by_y_at (p_int, 2, slope2_numer, slope2_denom);
Comparison_result slope_res = CGAL::compare(slope2_numer*slope1_denom,
slope1_numer*slope2_denom);
CGAL_assertion(slope_res != EQUAL);
if (fac1 == LARGER && fac2 == LARGER)
{
// Both are facing up.
return ((slope_res == LARGER) ? SMALLER : LARGER);
}
else
{
// Both are facing down.
return (slope_res);
}
}
// We should never reach here:
CGAL_assertion(false);
return (EQUAL);
}
// Decide wether curve1 is above, below or equal to curve2 immediately to
// the right of p_int, which is assumed to be an intersection of both curves.
// Furthermore, the two curves are assumed to be defined to p_int's right.
Comparison_result _curve_compare_at_intersection_right
(const X_monotone_curve_2& curve1,
const X_monotone_curve_2& curve2,
const Point_2& p_int) const
{
// In case one arc is facing upwards and another facing downwards, it is
// very clear that the one facing upward is above the one facing downwards.
if (curve1.has_same_base_conic(curve2))
{
Comparison_result fac1 = curve1.facing();
Comparison_result fac2 = curve2.facing();
if (fac1 == LARGER && fac2 == SMALLER)
return (LARGER);
else if (fac1 == SMALLER && fac2 == LARGER)
return (SMALLER);
}
// Otherwise, the two curves do intersect at p_int = ps1[0] = ps2[0]:
// make a decision based on their partial derivatives.
//const Point_2& p_int = ps1[0];
const NT _zero = 0;
NT slope1_numer, slope1_denom;
NT slope2_numer, slope2_denom;
curve1.derive_by_x_at (p_int, 1, slope1_numer, slope1_denom);
curve2.derive_by_x_at (p_int, 1, slope2_numer, slope2_denom);
/*const*/ bool is_vertical_slope1 = (slope1_denom == _zero);
/*const*/ bool is_vertical_slope2 = (slope2_denom == _zero);
// RWRW - CHECK THIS !!!
if (! is_vertical_slope1 &&
p_int.is_approximate() &&
eps_compare<APNT>(TO_APNT(slope1_denom), 0) == EQUAL)
{
is_vertical_slope1 = true;
}
if (! is_vertical_slope2 &&
p_int.is_approximate() &&
eps_compare<APNT>(TO_APNT(slope2_denom), 0) == EQUAL)
{
is_vertical_slope2 = true;
}
// TO HERE ...
if (!is_vertical_slope1 && !is_vertical_slope2)
{
// The two curves have derivatives at p_int: use it to determine which
// one is above the other (the one with a larger slope is below).
// RWRW - CHECK THIS !!!
Comparison_result slope_res =
(! p_int.is_approximate()) ?
CGAL::compare (slope1_numer*slope2_denom, slope2_numer*slope1_denom) :
eps_compare<APNT> (TO_APNT(slope1_numer*slope2_denom),
TO_APNT(slope2_numer*slope1_denom));
if (slope_res != EQUAL)
return (slope_res);
// Use the second order derivative.
curve1.derive_by_x_at (p_int, 2, slope1_numer, slope1_denom);
curve2.derive_by_x_at (p_int, 2, slope2_numer, slope2_denom);
slope_res = CGAL::compare (slope1_numer*slope2_denom,
slope2_numer*slope1_denom);
//CGAL_assertion(slope_res != EQUAL);
return (slope_res);
}
else if (!is_vertical_slope2)
{
// The first curve has a vertical slope at p_int: check whether it is
// facing upwards or downwards and decide accordingly.
Comparison_result fac1 = curve1.facing();
CGAL_assertion(fac1 != EQUAL);
return (fac1);
}
else if (!is_vertical_slope1)
{
// The second curve has a vertical slope at p_int: check whether it is
// facing upwards or downwards and decide accordingly.
Comparison_result fac2 = curve2.facing();
CGAL_assertion(fac2 != EQUAL);
return ((fac2 == LARGER) ? SMALLER : LARGER);
}
else
{
// The two curves have vertical slopes at p_int:
// First check whether one is facing up and one down. In this case the
// comparison result is trivial.
Comparison_result fac1 = curve1.facing();
Comparison_result fac2 = curve2.facing();
if (fac1 == LARGER && fac2 == SMALLER)
return (LARGER);
else if (fac1 == SMALLER && fac2 == LARGER)
return (SMALLER);
// Compute the second order derivative by y and act according to it.
curve1.derive_by_y_at (p_int, 2, slope1_numer, slope1_denom);
curve2.derive_by_y_at (p_int, 2, slope2_numer, slope2_denom);
Comparison_result slope_res = CGAL::compare (slope1_numer*slope2_denom,
slope2_numer*slope1_denom);
CGAL_assertion(slope_res != EQUAL);
if (fac1 == LARGER && fac2 == LARGER)
{
// Both are facing up.
return ((slope_res == LARGER) ? SMALLER : LARGER);
}
else
{
// Both are facing down.
return (slope_res);
}
}
// We should never reach here:
CGAL_assertion(false);
return (EQUAL);
}
};
CGAL_END_NAMESPACE
#endif