void CL_EarClipTriangulator_Impl::end_hole()
{
	create_lists(false);

	target_array = &vertices;

	// To be able to triangulate holes the inner and outer vertice arrays are connected
	// so that there isn't actually any hole, just a single polygon with a small gap
	// eliminating the hole.
	//
	// 1. find point on inner contour closest to a vertice on the outer contour.
	//
	// 2. Create bridge start and end points by offsetting the new vertices a bit along the edges to the next and prev vertices.
	// 

	LinkedVertice *outer_vertice = 0;
	LinkedVertice *segment_start;
	LinkedVertice *segment_end;
	CL_Pointf inner_point;
	float inner_point_rel;
	float distance = FLT_MAX;

	for (unsigned int vertex_cnt = 0; vertex_cnt < vertices.size(); vertex_cnt++)
	{
		CL_Pointf tmp_outer_point = CL_Pointf(vertices[vertex_cnt]->x,vertices[vertex_cnt]->y);

		for (unsigned int hole_cnt = 0; hole_cnt < hole.size(); hole_cnt++)
		{

			CL_Pointf tmp_line_start(hole[hole_cnt]->x, hole[hole_cnt]->y);
			CL_Pointf tmp_line_end(hole[hole_cnt]->next->x, hole[hole_cnt]->next->y);
			
			CL_Pointf tmp_inner_point = CL_LineMath::closest_point(tmp_outer_point, tmp_line_start, tmp_line_end);
			
			float tmp_distance = tmp_inner_point.distance(tmp_outer_point);
			
			if( tmp_distance < distance  )
			{
				inner_point_rel = CL_LineMath::closest_point_relative(tmp_outer_point, tmp_line_start, tmp_line_end);
				distance = tmp_distance;
				outer_vertice = vertices[vertex_cnt];
				inner_point = tmp_inner_point;
				segment_start = hole[hole_cnt];
				segment_end = hole[hole_cnt]->next;
			}
		}
	}

	LinkedVertice *outer_bridge_start = new LinkedVertice();
	LinkedVertice *outer_bridge_end = new LinkedVertice();
	LinkedVertice *inner_bridge_start = new LinkedVertice();
	LinkedVertice *inner_bridge_end = new LinkedVertice();

	//  offset new points along old edges
	CL_Pointf outer_point(outer_vertice->x, outer_vertice->y);

	set_bridge_vertice_offset( outer_bridge_start, outer_point, 0.0,             outer_vertice, outer_vertice->previous, 1 );
	set_bridge_vertice_offset( outer_bridge_end,   outer_point, 0.0,             outer_vertice, outer_vertice->next, 1 );
	set_bridge_vertice_offset( inner_bridge_start, inner_point, inner_point_rel, segment_start, segment_end, 1 );
	set_bridge_vertice_offset( inner_bridge_end,   inner_point, inner_point_rel, segment_start, segment_end, -1 );

	// update next pointers to ignore old vertices

	// connections between inner and outer contours
	outer_bridge_start->next = inner_bridge_start;
	inner_bridge_end->next = outer_bridge_end;

	// connections between new and old vertices: outer contour
	outer_bridge_end->next = outer_vertice->next;
	outer_vertice->previous->next = outer_bridge_start;

	// connections between new and old vertices: inner contour
	inner_bridge_start->next = segment_end;
	segment_start->next = inner_bridge_end;

	delete outer_vertice;
	outer_vertice = 0;

	if( inner_point_rel == 0.0 ) // if split point is at line end, remove inner vertex
	{
		segment_start->previous->next = inner_bridge_end;
		delete segment_start;
		segment_start = 0;
	}
	if( inner_point_rel == 1.0 ) // if split point is at line end, remove inner vertex
	{
		inner_bridge_start->next = segment_end->next;
		delete segment_end;
		segment_end = 0;
	}

	hole.clear();

	// rebuild the vector...
	vertices.clear();

	LinkedVertice *test = inner_bridge_start;
	do
	{
		vertices.push_back(test);
		test = test->next;
	} while( test != inner_bridge_start );

	// print the bridge start and end points:
/*	cl_write_console_line("outer_point: %1 %2", outer_point.x, outer_point.y );
	cl_write_console_line("inner_point: %1 %2", inner_point.x, inner_point.y );
	cl_write_console_line("inner_bridge_end: %1 %2", inner_bridge_end->x, inner_bridge_end->y );
	cl_write_console_line("outer_bridge_end: %1 %2", outer_bridge_end->x, outer_bridge_end->y );
	cl_write_console_line("inner_bridge_start: %1 %2", inner_bridge_start->x, inner_bridge_start->y );
	cl_write_console_line("outer_bridge_start: %1 %2", outer_bridge_start->x, outer_bridge_start->y );
*/
}
Esempio n. 2
0
std::unique_ptr<RenderQueue> BREW::CreateSpinnerDrawable( std::shared_ptr<const Spinner> spinner ) const {
	auto color = GetProperty<sf::Color>( "Color", spinner );
	auto background_color = GetProperty<sf::Color>( "BackgroundColor", spinner );
	auto steps = GetProperty<unsigned int>( "Steps", spinner );
	auto inner_radius = GetProperty<float>( "InnerRadius", spinner );
	auto rod_thickness = GetProperty<float>( "RodThickness", spinner );
	auto stopped_alpha = GetProperty<unsigned int>( "StoppedAlpha", spinner );
	auto radius = std::min( spinner->GetAllocation().width, spinner->GetAllocation().height ) / 2.f;

	std::unique_ptr<RenderQueue> queue( new RenderQueue );

	// Make sure steps is sane.
	steps = std::max( steps, 3u );

	// SFML does this too, for compatibility reasons, so lay off the flame :P
	static const auto two_pi = 3.141592654f * 2.f;

	sf::Vector2f center_offset( spinner->GetAllocation().width / 2.f, spinner->GetAllocation().height / 2.f );

	// We just have to produce the spinner in stopped state.
	// The class itself will take care of the started state.
	auto blend = ( 255.f - static_cast<float>( stopped_alpha ) ) / 255.f;

	sf::Color stop_color(
		static_cast<sf::Uint8>( static_cast<float>( color.r ) * ( 1.f - blend ) + static_cast<float>( background_color.r ) * blend ),
		static_cast<sf::Uint8>( static_cast<float>( color.g ) * ( 1.f - blend ) + static_cast<float>( background_color.g ) * blend ),
		static_cast<sf::Uint8>( static_cast<float>( color.b ) * ( 1.f - blend ) + static_cast<float>( background_color.b ) * blend )
	);

	auto started = spinner->Started();
	auto current_stage = spinner->GetStage();

	for( unsigned int index = 0; index < steps; index++ ) {
		// Time for some hardcore trigonometry...
		sf::Vector2f inner_point(
			std::cos( two_pi * static_cast<float>( index ) / -static_cast<float>( steps ) ) * inner_radius,
			std::sin( two_pi * static_cast<float>( index ) / -static_cast<float>( steps ) ) * inner_radius
		);

		sf::Vector2f outer_point(
			std::cos( two_pi * static_cast<float>( index ) / -static_cast<float>( steps ) ) * radius,
			std::sin( two_pi * static_cast<float>( index ) / -static_cast<float>( steps ) ) * radius
		);

		unsigned int rod_stage = ( current_stage + index ) % steps;

		auto rod_alpha = static_cast<float>( rod_stage ) / ( static_cast<float>( steps ) - 1.f );

		sf::Color rod_color(
			static_cast<sf::Uint8>( static_cast<float>( color.r ) * ( 1.f - rod_alpha ) + static_cast<float>( background_color.r ) * rod_alpha ),
			static_cast<sf::Uint8>( static_cast<float>( color.g ) * ( 1.f - rod_alpha ) + static_cast<float>( background_color.g ) * rod_alpha ),
			static_cast<sf::Uint8>( static_cast<float>( color.b ) * ( 1.f - rod_alpha ) + static_cast<float>( background_color.b ) * rod_alpha )
		);

		queue->Add(
			Renderer::Get().CreateLine(
				inner_point + center_offset,
				outer_point + center_offset,
				started ? rod_color : stop_color,
				rod_thickness
			)
		);
	}

	return queue;
}