diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index 9aa4424c31..491641d34d 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -263,7 +263,6 @@ void CAIRO_GAL_BASE::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, doub auto endAngleS = angle_xform( aEndAngle ); double centerAngle = endAngleS - startAngleS; - auto startPointS = roundp( xform ( aCenterPoint + VECTOR2D( aRadius, 0.0 ).Rotate( startAngleS ) ) ); auto endPointS = roundp( xform ( aCenterPoint + @@ -296,6 +295,57 @@ void CAIRO_GAL_BASE::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, doub } +void CAIRO_GAL_BASE::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, + double aEndAngle, double aWidth ) +{ + if( isFillEnabled ) + { + lineWidth = aWidth; + isStrokeEnabled = true; + isFillEnabled = false; + DrawArc( aCenterPoint, aRadius, aStartAngle, aEndAngle ); + isFillEnabled = true; + isStrokeEnabled = false; + return; + } + + syncLineWidth(); + SWAP( aStartAngle, >, aEndAngle ); + + auto width = ::roundp( xform( aWidth / 2.0 ) ); + auto r = ::roundp( xform( aRadius ) ); + auto startAngleS = angle_xform( aStartAngle ); + auto endAngleS = angle_xform( aEndAngle ); + + auto mid = roundp( xform( aCenterPoint ) ); + auto startPointS = VECTOR2D( r, 0.0 ).Rotate( startAngleS ); + auto endPointS = VECTOR2D( r, 0.0 ).Rotate( endAngleS ); + + cairo_save( currentContext ); + + cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + + cairo_translate( currentContext, mid.x, mid.y ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, 0, 0, r - width, startAngleS, endAngleS ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, 0, 0, r + width, startAngleS, endAngleS ); + + cairo_new_sub_path( currentContext ); + cairo_arc_negative( currentContext, startPointS.x, startPointS.y, width, startAngleS, startAngleS + M_PI ); + + cairo_new_sub_path( currentContext ); + cairo_arc( currentContext, endPointS.x, endPointS.y, width, endAngleS, endAngleS + M_PI ); + + cairo_restore( currentContext ); + flushPath(); + + isElementAdded = true; +} + + void CAIRO_GAL_BASE::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 81a1bcab74..7f450e2207 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -762,6 +762,102 @@ 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 ) + { + // Arcs of zero radius are a circle of aWidth diameter + if( aWidth > 0 ) + DrawCircle( aCenterPoint, aWidth / 2.0 ); + + return; + } + + // Swap the angles, if start angle is greater than end angle + SWAP( aStartAngle, >, aEndAngle ); + + const double alphaIncrement = calcAngleStep( aRadius ); + + 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 076962b115..e40253a796 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -91,6 +91,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 0d51596d0b..f2fffbb839 100644 --- a/include/gal/graphics_abstraction_layer.h +++ b/include/gal/graphics_abstraction_layer.h @@ -134,6 +134,26 @@ 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. + * + * TODO: Unify Arc routines + * + * @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. + * @param aWidth is the thickness of the arc (pen size). + */ + 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 322e157cba..d14fd0921b 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -119,6 +119,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/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index c68016d6a6..e833e9276a 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -930,13 +930,10 @@ void PCB_PAINTER::draw( const DRAWSEGMENT* aSegment, int aLayer ) break; case S_ARC: - - m_gal->SetLineWidth( thickness ); - m_gal->SetIsFill( false ); - m_gal->SetIsStroke( true ); - m_gal->DrawArc( start, aSegment->GetRadius(), + m_gal->DrawArcSegment( start, aSegment->GetRadius(), DECIDEG2RAD( aSegment->GetArcAngleStart() ), - DECIDEG2RAD( aSegment->GetArcAngleStart() + aSegment->GetAngle() ) ); + DECIDEG2RAD( aSegment->GetArcAngleStart() + aSegment->GetAngle() ), + thickness ); break; case S_CIRCLE: