hyper_segment_2.h

来自「CGAL is a collaborative effort of severa」· C头文件 代码 · 共 731 行 · 第 1/2 页

H
731
字号
   * Compare the slopes of two hyper-segments at their intersection point.   * \param seg The other segment.   * \param q A placeholder for the x-coordinate of the intersection point.   * \return SMALLER if the slope of (*this) is less than seg's at q;   *         LARGER if it is larger at q;   *         EQUAL if the two slopes are equal (in case of an overlap).   * \pre Both (*this) and seg are equal at q.x()   */  Comparison_result compare_slopes (const Self& seg,				    const Point_2& q) const  {    // The underlying hyperbola is:    //   y = sqrt(A*x^2 + B*x + C)    //    // If we derive, we obtain:    //                 2A*x + B            2A*x + B    //   y' = ------------------------- = ----------    //         2*sqrt(A*x^2 + B*x + C)        y    //    NT                y2 = _A*q.x()*q.x() + _B*q.x() + _C;    Comparison_result res = _compare (y2, 0);    CGAL_precondition(_compare (y2,				seg._A*q.x()*q.x() + seg._B*q.x() + seg._C) 		      == EQUAL);    CGAL_assertion(res != SMALLER);        if (res == LARGER)    {      // The y-coordinate of the intersection point is greater than 0.      // It is therefore sufficient to compare the numerators of the       // expressions of the two derivatives:      res = _compare (2*_A*q.x() + _B,		      2*seg._A*q.x() + seg._B);      if (res != EQUAL)	return (res);      // Compare the second derivatives, where:      //      //          2A*y^2 - (2A*x + B)^2      //   y'' = -----------------------      //                2*y^3      //      return (_compare (2*_A*y2 - (2*_A*q.x() + _B)*(2*_A*q.x() + _B),			2*seg._A*y2 - (2*seg._A*q.x() + seg._B)*			(2*seg._A*q.x() + seg._B)));    }    else // (res == EQUAL), that is the y-coordinate is 0.    {      // Compare the second derivative by x, which in our case equals:      return (_compare (2*_A*q.x() + _B,			2*seg._A*q.x() + seg._B));    }  }  /*!   * Intersect the two hyper-segments.   * \param seg The second hyper-segment.   * \param p1 The output intersection point (if one exists).   * \param p2 The second intersection point (in case of an overlap).   * \return The number of intersection points computed:   *         0 - No intersection.   *         1 - A simple intersection returned as p1.   *         2 - An overlapping segment, whose end-points are p1 and p2.   */  int intersect (const Self& seg,		 Point_2& p1, Point_2& p2) const  {    // First check the case of overlapping hyper-segments.    if (_has_same_base_hyperbola(seg))    {      bool bs = point_is_in_x_range (seg._source);       bool bt = point_is_in_x_range (seg._target);             if (bs && bt)      {	// (*this) contains the second segment:	if (_compare (seg._source.x(), seg._target.x()) == SMALLER)	{	  p1 = seg._source;	  p2 = seg._target;	}	else	{	  p2 = seg._source;	  p1 = seg._target;	}	return (2);      }      else if (bs || bt)      {	// Only one of the end-points is contained in (*this):	const Point_2& p_in  = bs ? seg._source : seg._target;	const Point_2& p_out = bs ? seg._target : seg._source;	bool to_right = (_compare(_source.x(), _target.x()) == SMALLER);	Comparison_result res = _compare (p_out.x(), _source.x());	if (_compare (p_in.x(), _source.x()) == EQUAL)	{	  // The two hyper-segments share just a common end-point.	  if ((to_right && res == SMALLER) ||	      (!to_right && res == LARGER))	  {	    p1 = p_in;	    return (1);	  }	}	else if (_compare (p_in.x(), _target.x()) == EQUAL)	{	  // The two hyper-segments share just a common end-point.	  if ((to_right && res == LARGER) ||	      (!to_right && res == SMALLER))	  {	    p1 = p_in;	    return (1);	  }	}	if (res == SMALLER)	{	  p1 = to_right ? _source : _target;	  p2 = p_in;	}	else	{	  p1 = p_in;	  p2 = to_right ? _target : _source;	}	return (2);      }      else      {	// Check if seg contains (*this).	bs = seg.point_is_in_x_range (_source); 	bt = seg.point_is_in_x_range (_target); 	if (bs && bt)	{	  if (_compare (_source.x(), _target.x()) == SMALLER)	  {	    p1 = _source;	    p2 = _target;	  }	  else	  {	    p2 = _source;	    p1 = _target;	  }	  return (2); 	}      }      // The two segments are disjoint:      return (0);    }    // The equations of the two underlying hyperbola are given by:    //   H1: y = A1*x^2 + B1*x + C1    //   H2: y = A2*x^2 + B2*x + C2    //    // So the following must hold for the x-coordinates of the intersection    // points:    //   (A1 - A2)*x^2 + (B1 - B2)*x + (C1 - C2) = 0    //    NT     xs[2];    bool   bs[2];    int    n_xs;    int    i;    n_xs = _solve_quadratic_equation (_A - seg._A,				      _B - seg._B,				      _C - seg._C,				      xs[0], xs[1]);    // Check the legality of each of the x-coordinates.    bs[0] = false;    bs[1] = false;    for (i = 0; i < n_xs; i++)    {      bs[i] = true;      Comparison_result res1 = _compare(xs[i], _source.x());      Comparison_result res2 = _compare(xs[i], _target.x());      if (res1 != EQUAL && res2 != EQUAL && res1 == res2)	bs[i] = false;      else      {	res1 = _compare(xs[i], seg._source.x());	res2 = _compare(xs[i], seg._target.x());      	if (res1 != EQUAL && res2 != EQUAL && res1 == res2)	  bs[i] = false;      }    }    // Make sure we return one point at most.    if (!bs[0] && !bs[1])      return (0);    CGAL_assertion (!(bs[0] && bs[1]));    if (bs[0])      _get_point_at_x (xs[0], p1);    else      _get_point_at_x (xs[1], p1);    return (1);  }  /*!   * Split a hyper-segment at a given point.   * \param p The split point.   * \param seg1 The first resulting hyper-segment.   * \param seg2 The second resulting hyper-segment.   * \pre p lies in the interior of the curve (and is not and end-point).   */  void split (const Point_2& p,	      Self& seg1, Self& seg2) const  {    CGAL_precondition(point_position(p) == EQUAL);    CGAL_precondition(_compare(_source.x(), p.x()) != EQUAL);    CGAL_precondition(_compare(_target.x(), p.x()) != EQUAL);    seg1 = (*this);    seg1._target = p;    seg2 = (*this);    seg2._source = p;    return;  }  /*   * Trim the hyper-segment at the given x-coodinates.   * \param p1 A placeholder for the x-coordinates of the new source.   * \param p2 A placeholder for the x-coordinates of the new target.   * \return The trimmed hyper-segment.   * \pre p1 and p2 are both in the x-range of the hyper-segment.   */  Self trim (const Point_2& p1,	     const Point_2& p2) const  {    CGAL_precondition(point_is_in_x_range(p1));    CGAL_precondition(point_is_in_x_range(p2));    Self     trimmed (*this);    _get_point_at_x (p1.x(), trimmed._source);    _get_point_at_x (p2.x(), trimmed._target);    return (trimmed);  }protected:  /*!   * Compare two values.   */  inline Comparison_result _compare (const NT& val1, const NT& val2) const  {    return (CGAL_NTS compare(val1, val2));  }  /*!   * Check whether the underlying hyperbola contains a point with the given   * x-coordinate and compute it if it does.   * \param x The x-coordinate.   * \param p The output point.   * \return (true) if the underlying hyperbola contains a point with the    *         given x-coordinate.   */  bool _get_point_at_x (const NT& x,                        Point_2& p) const  {    // Try to compute the y-coordinate.    NT              val = _A*x*x + _B*x + _C;    static const NT _zero = 0;    if (_compare(val, _zero) == SMALLER)      return (false);    p = Point_2(x, CGAL::sqrt(val));    return (true);  }  /*!   * Check whether the two hyper-segments lie on the same hyperbola.   * \param seg The compared hyper-segment.   * \return (true) if the two hyper-segments lie on the same hyperbola.   */  bool _has_same_base_hyperbola (const Self& seg) const  {    return ((_compare (_A, seg._A) == EQUAL) &&	    (_compare (_B, seg._B) == EQUAL) &&	    (_compare (_C, seg._C) == EQUAL));  }  /*!   * Solve the equation a*x^2 + b*x + c = 0.   * \return The number of solutions found.   */  int _solve_quadratic_equation (const NT& a, const NT& b, const NT& c,				 NT& x1, NT& x2) const  {    static const NT _zero = 0;    static const NT _two = 2;    static const NT _four = 4;    if (_compare (a, _zero) == EQUAL)    {      // If this is a linear equation:      if (_compare (b, _zero) == EQUAL)	return (0);      x1 = -c / b;      return (1);    }    // Act according to the sign of (b^2 - 4ac):    const NT          disc = b*b - _four*a*c;    Comparison_result res = _compare (disc, _zero);    if (res == SMALLER)    {      return (0);    }    else if (res == EQUAL)    {      x1 = (-b) / (_two*a);      return (1);    }        const NT          sqrt_disc = CGAL::sqrt (disc);        x1 = (sqrt_disc - b) / (_two*a);    x2 = -(sqrt_disc + b) / (_two*a);    return (2);  }};#ifndef NO_OSTREAM_INSERT_CONIC_ARC_2template <class Kernel>std::ostream& operator<< (std::ostream& os, 			  const Hyper_segment_2<Kernel>& seg){  os << "{ y^2 = " << CGAL::to_double(seg.A()) << "*x^2 + "     << CGAL::to_double(seg.B()) << "*x + "      << CGAL::to_double(seg.C()) << " } : "     << "(" << CGAL::to_double(seg.source().x()) << ","      << CGAL::to_double(seg.source().y()) << ") -> "     << "(" << CGAL::to_double(seg.target().x()) << ","      << CGAL::to_double(seg.target().y()) << ")";  return (os);}#endif // NO_OSTREAM_INSERT_CONIC_ARC_2CGAL_END_NAMESPACE#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?