/* $NoKeywords: $ */
/*
//
// Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//				
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
//
////////////////////////////////////////////////////////////////
*/

#if !defined(ON_CIRCLE_INC_)
#define ON_CIRCLE_INC_

class ON_NurbsCurve;

/*
Description:
	ON_Circle is a circle in 3d.  The cirle is represented by a radius and an 
	orthonormal frame	of the plane containing the circle, with origin at the center.

	An Is_Valid() circle has positive radius and an Is_ Valid() plane defining the frame.
	
	The circle is parameterized by radians from 0 to 2 Pi given by 
     t -> center + cos(t)*radius*xaxis + sin(t)*radius*yaxis	
	where center, xaxis and yaxis define the orthonormal frame of the circle's plane.  
*/
class ON_CLASS ON_Circle
{
public:

  ON_Plane plane = ON_Plane::World_xy;
  double   radius = 1.0;

  ON_Circle() = default;
  ~ON_Circle() = default;
  ON_Circle(const ON_Circle&) = default;
  ON_Circle& operator=(const ON_Circle&) = default;

  static const ON_Circle UnitCircle; // unit circle in the xy plane

  // Creates a circle in the plane with center at
  // plane.origin.
  ON_Circle(
    const ON_Plane& plane,
    double radius
    );

  // Creates a circle parallel to the world XY plane
  // with given center and radius
  ON_Circle(
    const ON_3dPoint& center,
    double radius
    );

  // Creates a circle parallel to the plane
  // with given center and radius.
  ON_Circle(
    const ON_Plane& plane,
    const ON_3dPoint& center,
    double radius
    );

  // Create a circle through three 2d points.
  // The start/end of the circle is at point P.
  ON_Circle( // circle through 3 2d points
    const ON_2dPoint& P,
    const ON_2dPoint& Q,
    const ON_2dPoint& R
    );

  // Create a circle through three 3d points.
  // The start/end of the circle is at point P.
  ON_Circle(
    const ON_3dPoint& P,
    const ON_3dPoint& Q,
    const ON_3dPoint& R
    );

  // Creates a circle in the plane with center at
  // plane.origin.
  bool Create(
    const ON_Plane& plane,
    double radius
    );

  // Creates a circle parallel to the world XY plane
  // with given center and radius
  bool Create(
    const ON_3dPoint& center,
    double radius
    );

  // Creates a circle parallel to the plane
  // with given centr and radius.
  bool Create(
    const ON_Plane& plane,
    const ON_3dPoint& center,
    double radius
    );

  // Create a circle through three 2d points.
  // The start/end of the circle is at point P.
  bool Create( // circle through 3 2d points
    const ON_2dPoint& P,
    const ON_2dPoint& Q,
    const ON_2dPoint& R
    );

  // Create a circle through three 3d points.
  // The start/end of the circle is at point P.
  bool Create(
    const ON_3dPoint& P,
    const ON_3dPoint& Q,
    const ON_3dPoint& R
    );

  // Create a circle from two 2d points and a 
  // tangent at the first point.
  // The start/end of the circle is at point P.
  bool Create(
    const ON_2dPoint& P,
    const ON_2dVector& tangent_at_P,
    const ON_2dPoint& Q
    );

  // Create a circle from two 3d points and a 
  // tangent at the first point.
  // The start/end of the circle is at point P.
  bool Create(
    const ON_3dPoint& P,
    const ON_3dVector& tangent_at_P,
    const ON_3dPoint& Q
    );

	//	A Valid circle has m_radius>0 and m_plane.IsValid().
  bool IsValid() const;

  //bool UpdatePoints();  // sets m_point[] to have valid points

  bool IsInPlane( const ON_Plane&, double = ON_ZERO_TOLERANCE ) const;

  double Radius() const;
  double Diameter() const;
  double Circumference() const;
  const ON_3dPoint& Center() const;
  const ON_3dVector& Normal() const;
  const ON_Plane& Plane() const; // plane containing circle

  ON_BoundingBox BoundingBox() const;

  /*
	Description:
    Get tight bounding box.
	Parameters:
		tight_bbox - [in/out] tight bounding box
		bGrowBox -[in]	(default=false)			
      If true and the input tight_bbox is valid, then returned
      tight_bbox is the union of the input tight_bbox and the 
      arc's tight bounding box.
		xform -[in] (default=nullptr)
      If not nullptr, the tight bounding box of the transformed
      arc is calculated.  The arc is not modified.
	Returns:
    True if a valid tight_bbox is returned.
  */
	bool GetTightBoundingBox( 
			ON_BoundingBox& tight_bbox, 
      bool bGrowBox = false,
			const ON_Xform* xform = nullptr
      ) const;

  bool Transform( const ON_Xform& );

  // Circles use trigonometric parameterization
  // t -> center + cos(t)*radius*xaxis + sin(t)*radius*yaxis
  ON_3dPoint PointAt( 
    double // evaluation parameter
    ) const;
  ON_3dVector DerivativeAt( 
    int,   // derivative (>=0)
    double // evaluation parameter
    ) const;

  ON_3dVector TangentAt(double) const;

  // returns parameters of point on circle that is closest to given point
  bool ClosestPointTo( 
         const ON_3dPoint& point, 
         double* t
         ) const;

  // returns point on circle that is closest to given point
  ON_3dPoint ClosestPointTo( 
         const ON_3dPoint& point
         ) const;

  // evaluate circle's implicit equation in plane
  double EquationAt( const ON_2dPoint& plane_point ) const;

  ON_2dVector GradientAt( const ON_2dPoint& plane_point ) const;

  // rotate circle about its center
  bool Rotate(
        double sin_angle,
        double cos_angle,
        const ON_3dVector& axis_of_rotation
        );

  bool Rotate(
        double angle_in_radians,
        const ON_3dVector&  axis_of_rotation
        );

  // rotate circle about a point and axis
  bool Rotate(
        double sin_angle,
        double cos_angle,
        const ON_3dVector& axis_of_rotation,
        const ON_3dPoint& center_of_rotation
        );

  bool Rotate(
        double angle_in_radians,
        const ON_3dVector&  axis_of_rotation,
        const ON_3dPoint& center_of_rotation
        );

  bool Translate(
        const ON_3dVector& delta
        );

  bool Reverse();

  // Description:
  //   Get a four span rational degree 2 NURBS circle representation
  //   of the circle.
  // Returns:
  //   2 for success, 0 for failure
  // Remarks:
  //   Note that the parameterization of NURBS curve
  //   does not match  circle's transcendental paramaterization.  
  //   Use ON_Circle::GetRadianFromNurbFormParameter() and
  //   ON_Circle::GetParameterFromRadian() to convert between 
  //   the NURBS curve parameter and the transcendental parameter.
  int GetNurbForm(
        ON_NurbsCurve& nurbs_curve
        ) const; 

  /*
  Description:
    Convert a NURBS curve circle parameter to a circle radians parameter.
  Parameters:
    nurbs_parameter - [in]
    circle_radians_parameter - [out]
  Example:

          ON_Circle circle = ...;
          double nurbs_t = 1.2345; // some number in interval (0,2.0*ON_PI).
          double circle_t;
          circle.GetRadianFromNurbFormParameter( nurbs_t, &circle_t );

          ON_NurbsCurve nurbs_curve;
          circle.GetNurbsForm( nurbs_curve );
          circle_pt = circle.PointAt(circle_t);
          nurbs_pt = nurbs_curve.PointAt(nurbs_t);
          // circle_pt and nurbs_pt will be the same

  Remarks:
    The NURBS curve parameter is with respect to the NURBS curve
    created by ON_Circle::GetNurbForm.  At nurbs parameter values of 
    0.0, 0.5*ON_PI, ON_PI, 1.5*ON_PI, and 2.0*ON_PI, the nurbs
    parameter and radian parameter are the same.  At all other
    values the nurbs and radian parameter values are different.
  See Also:
    ON_Circle::GetNurbFormParameterFromRadian
  */
  bool GetRadianFromNurbFormParameter(
        double nurbs_parameter,
        double* circle_radians_parameter
        ) const;

  /*
  Description:
    Convert a circle radians parameter to a NURBS curve circle parameter.
  Parameters:
    circle_radians_parameter - [in] 0.0 to 2.0*ON_PI
    nurbs_parameter - [out]
  Example:

          ON_Circle circle = ...;
          double circle_t = 1.2345; // some number in interval (0,2.0*ON_PI).
          double nurbs_t;
          circle.GetNurbFormParameterFromRadian( circle_t, &nurbs_t );

          ON_NurbsCurve nurbs_curve;
          circle.GetNurbsForm( nurbs_curve );
          circle_pt = circle.PointAt(circle_t);
          nurbs_pt = nurbs_curve.PointAt(nurbs_t);
          // circle_pt and nurbs_pt will be the same

  Remarks:
    The NURBS curve parameter is with respect to the NURBS curve
    created by ON_Circle::GetNurbForm.  At radian values of 
    0.0, 0.5*ON_PI, ON_PI, 1.5*ON_PI, and 2.0*ON_PI, the nurbs
    parameter and radian parameter are the same.  At all other
    values the nurbs and radian parameter values are different.
  See Also:
    ON_Circle::GetNurbFormParameterFromRadian
  */
  bool GetNurbFormParameterFromRadian(
        double circle_radians_parameter,
        double* nurbs_parameter
        ) const;

};


#endif

