← Back to team overview

kicad-developers team mailing list archive

[PATCH] Add method to GAL for drawing arc segments

 

This new GAL API is needed for drawing outlined arc segments (like
DrawSegment() does for straight segments) because the current API DrawArc()
treats filled arcs like pie pieces, which is not what is needed for
GerbView.

Best,
Jon
From 596b288c755b8f2034cf0a50370243be9d02869d Mon Sep 17 00:00:00 2001
From: Jon Evans <jon@xxxxxxxxxxxxx>
Date: Wed, 8 Mar 2017 21:44:48 -0500
Subject: [PATCH] Add DrawArcSegment() GAL method, to support drawing outlined
 arcs

---
 common/gal/cairo/cairo_gal.cpp           | 47 +++++++++++++++++
 common/gal/opengl/opengl_gal.cpp         | 90 ++++++++++++++++++++++++++++++++
 include/gal/cairo/cairo_gal.h            |  4 ++
 include/gal/graphics_abstraction_layer.h | 17 ++++++
 include/gal/opengl/opengl_gal.h          |  4 ++
 5 files changed, 162 insertions(+)

diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp
index 060c411..61f78c0 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 1a98b8b..1c1781d 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 4d95bbb..cb96442 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 530e684..4029c26 100644
--- a/include/gal/graphics_abstraction_layer.h
+++ b/include/gal/graphics_abstraction_layer.h
@@ -134,6 +134,23 @@ public:
     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.
      *
      * @param aStartPoint   is the start point of the rectangle.
diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h
index 5ed2d7d..bc257aa 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;
 
-- 
2.7.4


Follow ups