void CL_EarClipTriangulator_Impl::create_lists(bool create_ear_list)
{
	int vert_size = vertices.size();

	for( int i=0; i < vert_size; ++i )
	{
		LinkedVertice *v = vertices[i];

		if( i == 0 )
			v->previous = vertices.back();
		else
			v->previous = vertices[i-1];

		if( i == (vert_size-1) )
			v->next = vertices.front();
		else
			v->next = vertices[i+1];
	}
 
	unsigned int hole_size = hole.size();

	for( unsigned int j = 0; j < hole.size(); ++j )
	{
		if( j == 0 )
			hole[j]->previous = hole.back();
		else
			hole[j]->previous = hole[j-1];
 
		if( j == (hole_size-1) )
			hole[j]->next = hole.front();
		else
			hole[j]->next = hole[j+1];
	}

	if( create_ear_list )
	{
//		cl_write_console_line("Ear list:");

		for( std::vector<LinkedVertice*>::iterator it = vertices.begin(); it != vertices.end(); ++it )
		{
			if( is_ear(*(*it)) )
			{
				ear_list.push_back((*it));
				(*it)->is_ear = true;

//				cl_write_console_line(cl_format("    (%1,%2)", (*it)->x, (*it)->y ) );
			}

		}
	}
}
CL_EarClipResult CL_EarClipTriangulator_Impl::triangulate()
{
	create_lists(true);

	int num_triangles = vertices.size()-2;
	int tri_count = 0;
	
	CL_EarClipResult result(num_triangles);
	
	while( tri_count < num_triangles )
	{
		if( ear_list.empty() ) // something went wrong, but lets not crash anyway. 
			break;

		LinkedVertice *v = ear_list.back();
		ear_list.pop_back();
 
		CL_EarClipTriangulator_Triangle tri;

		tri.x1 = v->x;
		tri.y1 = v->y;

		tri.x2 = v->previous->x;
		tri.y2 = v->previous->y;

		tri.x3 = v->next->x;
		tri.y3 = v->next->y;

		result.get_triangles().push_back(tri);

		v->next->previous = v->previous;
		v->previous->next = v->next;

		if( is_ear(*v->next) )
		{
			if( v->next->is_ear == false ) // not marked as an ear yet. Mark it, and add to the list.
			{
				v->next->is_ear = true;
				ear_list.push_back(v->next);
			}
		}
		else
		{
			if( v->next->is_ear == true ) // Not an ear any more. Delete from ear list.
			{
				v->next->is_ear = false;
				
				std::vector<LinkedVertice*>::iterator it;
				for( it = ear_list.begin(); it != ear_list.end(); ++it )
				{
					if( (*it) == v->next )
					{
						ear_list.erase(it);
						break;
					}
				}
			}
		}

		if( is_ear(*v->previous) )
		{
			if( v->previous->is_ear == false ) // not marked as an ear yet. Mark it, and add to the list.
			{
				v->previous->is_ear = true;
				ear_list.push_back(v->previous);
			}
		}
		else
		{
			if( v->previous->is_ear == true ) // Not an ear any more. Delete from ear list.
			{
				v->previous->is_ear = false;
				
				std::vector<LinkedVertice*>::iterator it;
				for( it = ear_list.begin(); it != ear_list.end(); ++it )
				{
					if( (*it) == v->previous )
					{
						ear_list.erase(it);
						break;
					}
				}
			}
		}

/*		cl_write_console_line("Ear list:");
		for( std::vector<LinkedVertice*>::iterator it = ear_list.begin(); it != ear_list.end(); ++it )
		{
			cl_write_console_line("    (%1,%2)", (*it)->x, (*it)->y );
		}
		cl_write_console_line("");
*/

		tri_count++;

	}

	// cl_write_console_line("num triangles - final: %1", tri_count ); 

	return result;
}
Exemplo n.º 3
0
vector<Triangle> Math::triangulate(const vector<Vertex> &polygon)
{
	if (polygon.size() < 3)
		throw love::Exception("Not a polygon");
	else if (polygon.size() == 3)
		return vector<Triangle>(1, Triangle(polygon[0], polygon[1], polygon[2]));

	// collect list of connections and record leftmost item to check if the polygon
	// has the expected winding
	vector<size_t> next_idx(polygon.size()), prev_idx(polygon.size());
	size_t idx_lm = 0;
	for (size_t i = 0; i < polygon.size(); ++i)
	{
		const Vertex &lm = polygon[idx_lm], &p = polygon[i];
		if (p.x < lm.x || (p.x == lm.x && p.y < lm.y))
			idx_lm = i;
		next_idx[i] = i+1;
		prev_idx[i] = i-1;
	}
	next_idx[next_idx.size()-1] = 0;
	prev_idx[0] = prev_idx.size()-1;

	// check if the polygon has the expected winding and reverse polygon if needed
	if (!is_oriented_ccw(polygon[prev_idx[idx_lm]], polygon[idx_lm], polygon[next_idx[idx_lm]]))
		next_idx.swap(prev_idx);

	// collect list of concave polygons
	list<const Vertex *> concave_vertices;
	for (size_t i = 0; i < polygon.size(); ++i)
	{
		if (!is_oriented_ccw(polygon[prev_idx[i]], polygon[i], polygon[next_idx[i]]))
			concave_vertices.push_back(&polygon[i]);
	}

	// triangulation according to kong
	vector<Triangle> triangles;
	size_t n_vertices = polygon.size();
	size_t current = 1, skipped = 0, next, prev;
	while (n_vertices > 3)
	{
		next = next_idx[current];
		prev = prev_idx[current];
		const Vertex &a = polygon[prev], &b = polygon[current], &c = polygon[next];
		if (is_ear(a,b,c, concave_vertices))
		{
			triangles.push_back(Triangle(a,b,c));
			next_idx[prev] = next;
			prev_idx[next] = prev;
			concave_vertices.remove(&b);
			--n_vertices;
			skipped = 0;
		}
		else if (++skipped > n_vertices)
		{
			throw love::Exception("Cannot triangulate polygon.");
		}
		current = next;
	}
	next = next_idx[current];
	prev = prev_idx[current];
	triangles.push_back(Triangle(polygon[prev], polygon[current], polygon[next]));

	return triangles;
}