[cairo] Line widths and coordinate system transformations

Dirk Schönberger dirk.schoenberger at sz-online.de
Thu Jun 5 06:23:18 PDT 2008

> For my gtkmm-based application, I am writing a custom xy-plot widget
> into which I can draw some lines and curves using cairomm. To get rid of
> permanent manual coordinate transformations, it is very handy to
> translate and scale the drawing coordinate system into alignment with
> the plot axis. This works very well.
> I have, however, a problem with the resulting line width. Usually, x
> and y axis are not equally scaled which results in the pen having
> different widths depending on the direction of the line.
> I have attached a sample screenshot to illustrate the problem (I hope
> that's okay with the list -- it's really tiny). In this example, the
> horizontal axis goes from 0 to 9, whereas the vertical axis goes from 0
> to 1. Consequently, lines that are drawn horizontally are much thicker
> than vertical lines (the requested line width with
> Cairo::Context::set_line_width() remained unchanged).
> What I would like to have constant user-visible line widths in all
> directions.
> As a bonus, it would also be nice to specify a constant line width in
> pixels, completely independant of the scaling. But that'd really be a
> bonus -- for now, I'd already be happy with scale-dependant but
> direction-independant line widths.
> I am aware that I could achieve that by using the same scale in x and y
> direction. However, that would make drawing much harder, as I would
> have to do the transformations for each point individually and
> manually, which is something that I'd really, really like to avoid.
> In particular, this very same effect seems to imply that it is not
> possible to draw an ellipse outline with constant line width with
> Cairo. Is that correct?

As far as I know, the feature is possible, but not really obvious.
The main idea to know is that even if you save/restore a context, the
current path is not part of the context.
So basically you create your path in another context than that you use to
render it,
The "path creation" context can have a deformed scale, while the "path
rendering" context should have a uniform scale to get uniform line width.

The following is some sample code I nicked from some cairo tutorial, I
hope you can read the source code.

cr.LineWidth = 0.1;

cr.Scale(0.5, 1);
cr.Translate(1, 0);
cr.Arc(0.5, 0.5, 0.40, 0, 2 * Math.PI);

This really should be part of some kind of FAQ ;)

In order to get a constant linewidth in pixels you need to play around
with inverse transformations (InverseTransformDistance), but the tutorial
in question seems to be not quite helpful in order to get working code:


Transforms have three major uses. First they allow you to set up a
coordinate system that's easy to think in and work in, yet have the output
be of any size. Second they allow you to make helper functions that work
at or around a (0, 0) but can be applied anywhere in the output image.
Thirdly they let you deform the image, turning a circular arc into an
elliptical arc, etc. Transforms are a way of setting up a relation between
two coordinate systems. The device-space coordinate system is tied to the
surface, and cannot change. The user-space coordinate system matches that
space by default, but can be changed for the above reasons. The helper
functions TransformPoint
and TransformDistance
tell you what the device-coordinates are for a user-coordinates position
or distance. Correspondingly InverseTransformPoint
and InverseTransformDistance
tell you user-coordinates for a device-coordinates position or distance.
Remember to send positions through the non-distance variant, and relative
moves or other distances through the distance variant.



More information about the cairo mailing list