#include <iostream>
#include <vector>
#include <math>

using namespace std;

class Duz 
{
public:
	Duz()
		{}
	Duz( int X0, int Y0, int X1, int Y1, int Boja )
		: x0(X0), y0(Y0), x1(X1), y1(Y1), boja(Boja)
		{}

	int x0, y0, x1, y1;
	int boja;
};

ostream& operator<< ( ostream& ostr, const Duz& d )
{
	ostr << "{ " 
		 << d.x0 << ", "
		 << d.y0 << ", "
		 << d.x1 << ", "
		 << d.y1 << ", "
		 << d.boja << " }";
	return ostr;
}

class Lik
{
public:
	virtual ~Lik()
		{}
	virtual int PrevodjenjePlus( vector<Duz>& duzi, double eps ) = 0;	
	int Prevodjenje( vector<Duz>& duzi, double eps )
		{
		duzi.clear();
		return PrevodjenjePlus( duzi, eps );
		}
	virtual Lik* Kopija() const = 0;
};

class JednobojanLik : public Lik
{
public:
	JednobojanLik( int boja )
		: Lik(),
		  _boja(boja)
		{}
protected:
	int _boja;
};

class Pravougaonik : public JednobojanLik
{
public:
	Pravougaonik( int x0, int y0, int a, int b, int boja )
		: JednobojanLik(boja),
		  _x0(x0), _y0(y0), _a(a), _b(b)
		{}
		
	int PrevodjenjePlus( vector<Duz>& duzi, double )
		{
		// u narednim redovima se koristi ekvivalent 
		// sledeceg para naredbi
		//Duz d( _x0, _y0, _x0+_a, _y0, boja );
		//duzi.push_back( d );
		duzi.push_back( Duz( _x0, _y0, _x0+_a, _y0, _boja ));
		duzi.push_back( Duz( _x0+_a, _y0, _x0+_a, _y0+_b, _boja ));
		duzi.push_back( Duz( _x0+_a, _y0+_b, _x0, _y0+_b, _boja ));
		duzi.push_back( Duz( _x0, _y0+_b, _x0, _y0, _boja ));
		return 4;
		}

	Lik* Kopija() const
		{ return new Pravougaonik( *this ); }
	
private:
	int _x0, _y0, _a, _b;
};

class Kvadrat : public Pravougaonik
{
public:
	Kvadrat( int x0, int y0, int a, int boja )
		: Pravougaonik( x0, y0, a, a, boja )
		{}
	Lik* Kopija() const
		{ return new Kvadrat( *this ); }
};

class Krug : public JednobojanLik
{
public:
	Krug( int xc, int yc, int r, int boja )
		: JednobojanLik(boja),
		  _xc(xc), _yc(yc), _r(r)
		{}

	int PrevodjenjePlus( vector<Duz>& duzi, double eps )
		{
		int n = eps < _r ? ceil( M_PI/acos(1-eps/_r)) : 4;
		if( n<4 ) n=4;
		double alpha = M_PI * 2 / n;
		Duz d;
		d.x0 = _xc + _r;
		d.y0 = _yc;
		d.boja = _boja;
		for( int i=1; i<=n; i++ ){
			d.x1 = floor( _xc + _r * cos( alpha * i ) + 0.5 );
			d.y1 = floor( _yc + _r * sin( alpha * i ) + 0.5 );
			duzi.push_back( d );
			d.x0 = d.x1;
			d.y0 = d.y1;
			}
		return n;
		}

	Lik* Kopija() const
		{ return new Krug( *this ); }
		
private:
	int _xc, _yc, _r;
};

class SlozeniLik : public Lik
{
public:
	SlozeniLik()
		{}
	SlozeniLik(const SlozeniLik& l)
		{ init(l); }
	~SlozeniLik()
		{ deinit(); }
	SlozeniLik& operator = (const SlozeniLik& l)
		{
		if( this != &l ){
			deinit();
			init(l);
			}
		return *this;
		}
	Lik* Kopija() const
		{ return new SlozeniLik( *this ); }
		
	void Dodaj( Lik* l )
		{ _likovi.push_back( l ); }

	int PrevodjenjePlus( vector<Duz>& duzi, double eps )
		{
		int n = 0;
		for( unsigned i=0; i<_likovi.size(); i++ )
			n += _likovi[i]->PrevodjenjePlus( duzi, eps );
		return n;
		}
	
private:
	void init( const SlozeniLik& l )
		{
		for( unsigned i=0; i<l._likovi.size(); i++ )
			_likovi.push_back( l._likovi[i]->Kopija() );		
		}
		
	void deinit()
		{
		for( unsigned i=0; i<_likovi.size(); i++ )
			delete _likovi[i];
		_likovi.clear();
		}

	vector<Lik*> _likovi;
};

main()
{
	vector<Duz> duzi;
	
	SlozeniLik s;
	s.Dodaj( new Pravougaonik( 0,0,10,5,1));
	s.Dodaj( new Kvadrat( 20, 10, 40, 7 ));
	s.Dodaj( new Krug( 0, 0, 20, 3 ));
	s.PrevodjenjePlus( duzi, 2.5 );
	
	cout << "Duzi:" << endl;
	for( unsigned i=0; i<duzi.size(); i++ )
		cout << duzi[i] << endl;
		
	return 0;
}




