Drawing Arcs and Circles
| Chapter 18. The DrawingArea Widget |

## Drawing Arcs and Circles

With Cairo, the same function is used to draw arcs, circles, or ellipses: `Cairo::Context::arc()`. This function takes five arguments. The first two are the coordinates of the center point of the arc, the third argument is the radius of the arc, and the final two arguments define the start and end angle of the arc. All angles are defined in radians, so drawing a circle is the same as drawing an arc from 0 to 2 * M_PI radians. An angle of 0 is in the direction of the positive X axis (in user-space). An angle of M_PI/2 radians (90 degrees) is in the direction of the positive Y axis (in user-space). Angles increase in the direction from the positive X axis toward the positive Y axis. So with the default transformation matrix, angles increase in a clockwise direction. (Remember that the positive Y axis points downwards.)

To draw an ellipse, you can scale the current transformation matrix by different amounts in the X and Y directions. For example, to draw an ellipse with center at `x`, `y` and size `width`, `height`:

    context->save();
    context->translate(x, y);
    context->scale(width / 2.0, height / 2.0);
    context->arc(0.0, 0.0, 1.0, 0.0, 2 * M_PI);
    context->restore();

### Example

Here's an example of a simple program that draws an arc, a circle and an ellipse into a drawing area.

Figure 18.5. Drawing Area - Arcs

Source Code

File: `myarea.h` (For use with gtkmm 4)

    #ifndef GTKMM_EXAMPLE_MYAREA_H
    #define GTKMM_EXAMPLE_MYAREA_H

    #include <gtkmm/drawingarea.h>

    class MyArea : public Gtk::DrawingArea
    {
    public:
      MyArea();
      virtual ~MyArea();

    protected:
      void on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height);
    };

    #endif // GTKMM_EXAMPLE_MYAREA_H

File: `main.cc` (For use with gtkmm 4)

    #include "myarea.h"
    #include <gtkmm/application.h>
    #include <gtkmm/window.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();

    protected:
      MyArea m_area;
    };

    ExampleWindow::ExampleWindow()
    {
      set_title("DrawingArea");
      set_child(m_area);
    }

    int main(int argc, char** argv)
    {
      auto app = Gtk::Application::create("org.gtkmm.example");

      return app->make_window_and_run<ExampleWindow>(argc, argv);
    }

File: `myarea.cc` (For use with gtkmm 4)

    #include "myarea.h"
    #include <cairomm/context.h>
    #include <cmath>

    MyArea::MyArea()
    {
      set_draw_func(sigc::mem_fun(*this, &MyArea::on_draw));
    }

    MyArea::~MyArea()
    {
    }

    void MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr, int width, int height)
    {
      const int lesser = std::min(width, height);

      // coordinates for the center of the window
      const int xc = width / 2;
      const int yc = height / 2;

      cr->set_line_width(lesser * 0.02);  // outline thickness changes
                                          // with window size

      // first draw a simple unclosed arc
      cr->save();
      cr->arc(width / 3.0, height / 4.0, lesser / 4.0, -(M_PI / 5.0), M_PI);
      cr->close_path();   // line back to start point
      cr->set_source_rgb(0.0, 0.8, 0.0);
      cr->fill_preserve();
      cr->restore();  // back to opaque black
      cr->stroke();   // outline it

      // now draw a circle
      cr->save();
      cr->arc(xc, yc, lesser / 4.0, 0.0, 2.0 * M_PI); // full circle
      cr->set_source_rgba(0.0, 0.0, 0.8, 0.6);    // partially translucent
      cr->fill_preserve();
      cr->restore();  // back to opaque black
      cr->stroke();

      // and finally an ellipse
      double ex, ey, ew, eh;
      // center of ellipse
      ex = xc;
      ey = 3.0 * height / 4.0;
      // ellipse dimensions
      ew = 3.0 * width / 4.0;
      eh = height / 3.0;

      cr->save();

      cr->translate(ex, ey);  // make (ex, ey) == (0, 0)
      cr->scale(ew / 2.0, eh / 2.0);  // for width: ew / 2.0 == 1.0
                                      // for height: eh / 2.0 == 1.0

      cr->arc(0.0, 0.0, 1.0, 0.0, 2 * M_PI);  // 'circle' centered at (0, 0)
                                              // with 'radius' of 1.0

      cr->set_source_rgba(0.8, 0.0, 0.0, 0.7);
      cr->fill_preserve();
      cr->restore();  // back to opaque black
      cr->stroke();
    }

There are a couple of things to note about this example code. Again, the only real difference between this example and the previous ones is the `on_draw()` function, so we'll limit our focus to that function. In addition, the first part of the function is nearly identical to the previous examples, so we'll skip that portion.

Note that in this case, we've expressed nearly everything in terms of the height and width of the window, including the width of the lines. Because of this, when you resize the window, everything scales with the window. Also note that there are three drawing sections in the function and each is wrapped with a `save()`/`restore()` pair so that we're back at a known state after each drawing.

The section for drawing an arc introduces one new function, `close_path()`. This function will in effect draw a straight line from the current point back to the first point in the path. There is a significant difference between calling `close_path()` and manually drawing a line back to the starting point, however. If you use `close_path()`, the lines will be nicely joined together. If you use `line_to()` instead, the lines will end at the same point, but Cairo won't do any special joining.

| Drawing counter-clockwise
The function `Cairo::Context::arc_negative()` is exactly the same as `Cairo::Context::arc()` but the angles go the opposite direction.

Drawing Curved Lines |  | Drawing Text