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();
Here's an example of a simple program that draws an arc, a circle and an ellipse into a drawing area.
File: myarea.h
(For use with gtkmm 3, not gtkmm 2)
#ifndef GTKMM_EXAMPLE_MYAREA_H #define GTKMM_EXAMPLE_MYAREA_H #include <gtkmm/drawingarea.h> class MyArea : public Gtk::DrawingArea { public: MyArea(); virtual ~MyArea(); protected: //Override default signal handler: bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override; }; #endif // GTKMM_EXAMPLE_MYAREA_H
File: main.cc
(For use with gtkmm 3, not gtkmm 2)
#include "myarea.h" #include <gtkmm/application.h> #include <gtkmm/window.h> int main(int argc, char** argv) { auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); Gtk::Window win; win.set_title("DrawingArea"); MyArea area; win.add(area); area.show(); return app->run(win); }
File: myarea.cc
(For use with gtkmm 3, not gtkmm 2)
#include "myarea.h" #include <cairomm/context.h> #include <cmath> MyArea::MyArea() { } MyArea::~MyArea() { } bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { // This is where we draw on the window Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); const int height = allocation.get_height(); const int lesser = MIN(width, height); // coordinates for the center of the window int xc, yc; xc = width / 2; 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(); return true; }
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
|