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 ); */ }
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; }