Задача триангуляции невыпуклого многоугольника (C++)

triangle_2.jpg

Алгоритм триангуляции, примененный при написании данной программы, описан в заметках Задача триангуляции многоугольника и Определение направления обхода многоугольника.
Реализация на С++.

Программа

//...
class Triangulation
{
public:
	Triangulation(){;};
	Triangulation( SList &listPoints ){ lp = listPoints; };
 
	void triangulation(vector <Polygon_> &vn);
	static bool isInTriangle( POINT &point, POINT &t1, POINT &t2, POINT &t3 );
 
	//векторное произведение
	static int vp( POINT &a, POINT &b, POINT &c)
	{ return (a.x*b.y - a.x*c.y - b.x*a.y + b.x*c.y + c.x*a.y - c.x*b.y ); }
 
	//скалярное произведение
	static int scp( POINT &a, POINT &b, POINT &c )
	{ return( (c.x - b.x)*(a.x - b.x) + (c.y - b.y)*(a.y - b.y) ); }
 
	//добавление в список
	void appendtoTail(T &t){ lp.appendtoTail(t); }
 
	//удаление списка
	void clear(){ lp.clear(); }
 
	//количество точек многоугольника
	int size(){ return lp.size; }
 
private:
	SList lp;
	int direction;
 
	void determineDirection();
};
 
//функция определяет принадлежность точки point треугольнику t1_t2_t3
bool Triangulation::isInTriangle( POINT &point, POINT &t1, POINT &t2, POINT &t3 )
{
	int a, b, c;
	a = vp( point, t1, t2 );
	b = vp( point, t2, t3 );
	c = vp( point, t3, t1 );
	//Если все три двойки векторов однонаправленные, то point внутри треугольника
	return ( a < 0 && b < 0 && c < 0 || a > 0 && b > 0 && c > 0 );	
}
 
//функция определяет направление обхода многоугольника
void Triangulation::determineDirection()
{
	int maxx = lp.head->p.x;
	Node *np, *mp = lp.tail;
	POINT p1, p2, p3, px;
 
	//находим точку с максимальным значением по Х
	for( np = lp.head; np != lp.tail; np = np->next )
		if( maxx < (np->next->p.x ))
		{
			maxx = np->next->p.x;
			mp = np;
		}
	p1 = mp->p;
	p2 = mp->next->p;
	p3 = mp->next->next->p;
	//с помощью векторного произведения определяем 
	//направление тройки векторов
	if( vp( p1, p2, p3 ) > 0 )	direction = 1; // по часовой стрелке
	else direction = -1;//против часовой стрелки
}
 
//функция триангуляции
//vector < Polygon_ > &vn - массив с фигурами
//vn[0] - будет содержать (после вызова этой функции) массив вершин исходного многоугольника
//vn[1] ... vn[vn.size()-1] - массив вершин треугольников
void Triangulation::triangulation( vector < Polygon_ > &vn )
{
	int i, t;
	bool newTriangle;
	//первые 3 вершины
	Node *pn1 = lp.head, *pn2 = lp.head->next, *pn3 = lp.head->next->next, *it1;
 
	Polygon_ pol;
	pol.p = new POINT[lp.size];
	pol.size = lp.size;
	//определяем направление обхода многоугольника
	determineDirection();
 
	//заносим в vector массив вершин многоугольника
	for( i = 0, pn1 = lp.head; i < lp.size; pn1 = pn1->next, i++ )
		pol.p[i] = pn1->p;
	vn.push_back(pol);
 
	//пока не останется 3 точки
	while( lp.size != 3 )
	{
		//если вектора образуют правую тройку
		if( vp( pn2->p, pn1->p, pn3->p ) * direction < 0 )
		{
			newTriangle = true;
 
			//проверка не попала ли вершина в отсекаемый треугольник
			for( it1 = pn3->next; it1 != pn1; it1 = it1->next )
				if( isInTriangle(it1->p, pn1->p, pn2->p, pn3->p) )
				{
					newTriangle = false; //вершина попала в отсекаемый треугольник
					pn1 = pn1->next; //переходим к следующей вершине
					break;
				}
			if( newTriangle == true )//вершина не попала в отсекаемый треугольник
			{
				//заносим в vector новый треугольник
				pol.p = new POINT[3];
				pol.size = 3;
				pol.p[0] = pn1->p;	
				pol.p[1] = pn2->p;	
				pol.p[2] = pn3->p;
				vn.push_back(pol);
				//удаляем вершину из списка
				lp.delete_(pn2->key);
			}
			//сдвигаем 2ю и 3ю вершины
			pn2 = pn3;	pn3 = pn3->next;
		}
		else //вектора не образуют правую тройку,  сдвигаем 3 вершины
		{
			pn1 = pn2;	pn2 = pn3;	pn3 = pn3->next;
		}
	}
	//заносим в vector оставшийся треугольник
	pol.p = new POINT[3];
	pol.size = 3;
	pol.p[0] = lp.head->p; 
	pol.p[1] = lp.head->next->p; 
	pol.p[2] = lp.head->next->next->p;
	vn.push_back(pol);
}
//...

ВложениеРазмер
Триангуляция многоугольника45.85 кб