/*	File: CirclArc.cpp
 *
 *	Design and Implementation Description:
 *		Aggregation ("has-a" relation) seems appropriate for structuring the
 *		relation between CircleArc and Circle.
 *		It is implemented by membership of a reference circle.
 *		A drawback of this solution is that we have two reference points which
 *		have to be kept consistent (checked by additional invariants).
 *	History:
 *		Date:		 Author:	 Change:
 *		97-05-26	 KHU		 Creation.
 * Remark:
 *		For efficiency reasons, we could apply derivation from Circle instead
 *		of membership. This is called a "mix-in" or "implementation inheritance"
 *		and does not reflect an "is-a" relation.
 *		A drawback of this solution is that CircleArc is indirectly derived
 *		from ClosedFigure, but the element function Area doesn't make sense.
 */

#include "CirclArc.h"

#include <assert.h>
#include <graphics.h>
#include <math.h>							// For M_PI.

	void CircleArc::Draw ()
	{
		static const Float factor = 180 / M_PI;
		arc
			(refCircle.Centre ().x,
			 refCircle.Centre ().y,
			 angleFrom * factor,
			 angleTo * factor,
			 refCircle.Radius ());
	}; // Draw

	Float CircleArc::Extent () const
	{
		Float angle = angleFrom - angleTo;
		if (angle < 0.0)
		{
			angle = 2 * M_PI - angle;
		};
		Float result = angle * refCircle.Radius ();
		assert(result >= 0.0);
		return result;
	}; // Extent

	void CircleArc::Move (const CoordinatePair & delta)
	{
		FigureState s = state;
		if (s == shown)
		{
			Hide ();
		};
		refCircle.Move (delta);
		refPoint.x += delta.x;
		refPoint.y += delta.y;
		if (s == shown)
		{
			Show ();
		};
		CheckInvariant ();
		assert(s == state);
	}; // Move

	void CircleArc::MoveTo (const CoordinatePair & newRefPoint)
	{
		FigureState s = state;
		if (s == shown)
		{
			Hide ();
		};
		refCircle.MoveTo (newRefPoint);
		refPoint = newRefPoint;
		if (s == shown)
		{
			Show ();
		};
		CheckInvariant ();
		assert(s == state);
	}; // MoveTo

	CircleArc::CircleArc
		(const Circle & refCircle, Float angleFrom, Float angleTo)
	:	refCircle (refCircle.Centre (), refCircle.Radius ())
	{
		assert(0.0 <= angleFrom);
		assert(angleFrom <= 2 * M_PI);
		assert(0.0 <= angleTo);
		assert(angleTo <= 2 * M_PI);
		refPoint        = refCircle.RefPoint ();
		this->angleFrom = angleFrom;
		this->angleTo   = angleTo;
		CheckInvariant ();
	}; // CircleArc

	void CircleArc::CheckInvariant ()
	{
		Figure::CheckInvariant ();
		assert(refPoint.x == refCircle.RefPoint ().x);
		assert(refPoint.y == refCircle.RefPoint ().y);
		assert(0.0 <= angleFrom);
		assert(angleFrom <= 2 * M_PI);
		assert(0.0 <= angleTo);
		assert(angleTo <= 2 * M_PI);
	}; // CheckInvariant

// End of CircleArc.

