diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 52093d4aa0..9480cf5fc0 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -199,6 +199,8 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo cairo_save( currentContext ); + cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + cairo_translate( currentContext, aStartPoint.x, aStartPoint.y ); cairo_rotate( currentContext, lineAngle ); @@ -255,6 +257,51 @@ void CAIRO_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aS } +void CAIRO_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, + double aEndAngle, double aWidth ) +{ + SWAP( aStartAngle, >, aEndAngle ); + + if( isFillEnabled ) + { + cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, aStartAngle, aEndAngle ); + cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + cairo_stroke( currentContext ); + } + else + { + double width = aWidth / 2.0; + VECTOR2D startPoint( cos( aStartAngle ) * aRadius, + sin( aStartAngle ) * aRadius ); + VECTOR2D endPoint( cos( aEndAngle ) * aRadius, + sin( aEndAngle ) * aRadius ); + + cairo_save( currentContext ); + + cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + + cairo_translate( currentContext, aCenterPoint.x, aCenterPoint.y ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, 0, 0, aRadius - width, aStartAngle, aEndAngle ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, 0, 0, aRadius + width, aStartAngle, aEndAngle ); + + cairo_new_sub_path( currentContext ); + cairo_arc_negative( currentContext, startPoint.x, startPoint.y, width, aStartAngle, aStartAngle + M_PI ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, endPoint.x, endPoint.y, width, aEndAngle, aEndAngle + M_PI ); + + cairo_restore( currentContext ); + flushPath(); + } + + isElementAdded = true; +} + + void CAIRO_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { // Calculate the diagonal points diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 390dd0f01d..97b5f19b99 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -589,6 +589,96 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a } +void OPENGL_GAL::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, + double aEndAngle, double aWidth ) +{ + if( aRadius <= 0 ) + return; + + // Swap the angles, if start angle is greater than end angle + SWAP( aStartAngle, >, aEndAngle ); + + const double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS; + + Save(); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 ); + + if( isStrokeEnabled ) + { + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + + double width = aWidth / 2.0; + VECTOR2D startPoint( cos( aStartAngle ) * aRadius, + sin( aStartAngle ) * aRadius ); + VECTOR2D endPoint( cos( aEndAngle ) * aRadius, + sin( aEndAngle ) * aRadius ); + + drawStrokedSemiCircle( startPoint, width, aStartAngle + M_PI ); + drawStrokedSemiCircle( endPoint, width, aEndAngle ); + + VECTOR2D pOuter( cos( aStartAngle ) * ( aRadius + width ), + sin( aStartAngle ) * ( aRadius + width ) ); + + VECTOR2D pInner( cos( aStartAngle ) * ( aRadius - width ), + sin( aStartAngle ) * ( aRadius - width ) ); + + double alpha; + + for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement ) + { + VECTOR2D pNextOuter( cos( alpha ) * ( aRadius + width ), + sin( alpha ) * ( aRadius + width ) ); + VECTOR2D pNextInner( cos( alpha ) * ( aRadius - width ), + sin( alpha ) * ( aRadius - width ) ); + + DrawLine( pOuter, pNextOuter ); + DrawLine( pInner, pNextInner ); + + pOuter = pNextOuter; + pInner = pNextInner; + } + + // Draw the last missing part + if( alpha != aEndAngle ) + { + VECTOR2D pLastOuter( cos( aEndAngle ) * ( aRadius + width ), + sin( aEndAngle ) * ( aRadius + width ) ); + VECTOR2D pLastInner( cos( aEndAngle ) * ( aRadius - width ), + sin( aEndAngle ) * ( aRadius - width ) ); + + DrawLine( pOuter, pLastOuter ); + DrawLine( pInner, pLastInner ); + } + } + + if( isFillEnabled ) + { + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + SetLineWidth( aWidth ); + + VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius ); + double alpha; + + for( alpha = aStartAngle + alphaIncrement; alpha <= aEndAngle; alpha += alphaIncrement ) + { + VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius ); + DrawLine( p, p_next ); + + p = p_next; + } + + // Draw the last missing part + if( alpha != aEndAngle ) + { + VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius ); + DrawLine( p, p_last ); + } + } + + Restore(); +} + + void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { // Compute the diagonal points of the rectangle diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index fa46bba895..63740ad5d3 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -115,6 +115,10 @@ public: virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle ) override; + /// @copydoc GAL::DrawArcSegment() + virtual void DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, + double aStartAngle, double aEndAngle, double aWidth ) override; + /// @copydoc GAL::DrawRectangle() virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override; diff --git a/include/gal/graphics_abstraction_layer.h b/include/gal/graphics_abstraction_layer.h index f12888a665..c9b9fac9b4 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -133,6 +133,23 @@ public: virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle ) {}; + /** + * @brief Draw an arc segment. + * + * This method differs from DrawArc() in what happens when fill/stroke are on or off. + * DrawArc() draws a "pie piece" when fill is turned on, and a thick stroke when fill is off. + * DrawArcSegment() with fill *on* behaves like DrawArc() with fill *off*. + * DrawArcSegment() with fill *off* draws the outline of what it would have drawn with fill on. + * + * @param aCenterPoint is the center point of the arc. + * @param aRadius is the arc radius. + * @param aStartAngle is the start angle of the arc. + * @param aEndAngle is the end angle of the arc. + */ + virtual void + DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, + double aEndAngle, double aWidth ) {}; + /** * @brief Draw a rectangle. * diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index a9bc36d206..e58ce4b2fc 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -129,6 +129,10 @@ public: virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle ) override; + /// @copydoc GAL::DrawArcSegment() + virtual void DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, + double aStartAngle, double aEndAngle, double aWidth ) override; + /// @copydoc GAL::DrawRectangle() virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) override;