[cairo] [patch] enable projective transformations

Bill Spitzak spitzak at gmail.com
Tue Aug 17 17:22:28 PDT 2010

Maarten Bosmans wrote:

> Yes, this is exactly what I implemented in the suggested patch. But
> the 3x3 matrix in Cairo only stores 8 values and assumes the last one
> always to be zero. Pixman uses a double[][] array, so this is taken
> care of in _cairo_matrix_to_pixman_matrix.

I think you meant the last entry is always 1, not zero. I am trying to 
figure out if arbitrary transforms can make this entry become zero, as 
that would prevent normalization. But I think that will only happen for 
degenerate cases that we do not need to worry about.

> What is this z-axis you're talking about, it sounds very intriguing ;-)
> Remember, there's no 3d here, projective transformation in 2d is just
> messing with the third coordinate from the 2d homogeneous system.

I was imagining a rather simple api called cairo_projection(d) which (in 
a 4x4 description) multiplies the matrix by this:

	| 1 0 0 0 |
	| 0 1 0 0 |
	| 0 0 0 0 |
	| 0 0 d 1 |

This would be the only operation that produces a matrix where the last 
row is not the identity. The result of this is that an object at z==1/d 
would be drawn 1/2 the size of an object at z==0, and the scale would be 
around 0,0. (Possibly -d should be used so positive z is toward the camera).

The user could get arbitrary projections by first scaling and 
translating to indicate where to draw the z=0 plane, then calling this, 
then doing further 3D transformations to rotate the z=0 plane in space 
and translate the origin.

Since the 'd' is in the third column which is thrown away if this is 
reduced to a 3x3 matrix, it means the intermediate result cannot be this 
3x3 matrix if this is to work, a 4x4 matrix is needed to keep d so it 
can influence further transforms.

So what I am trying to say is that (IMHO) if we want a user-friendly 
method of setting the projection matrix then 3D transforms must be 
possible and 4x4 matrix used. This also implies that paths should be 3D 
translated. It might mean that the z coordinate of paths should be 
settable just like the x and y.

The alternative, which is quite possible, is that users are only 
interested and can only get a 3D transform of a source surface, 
specified by setting the entire 3x3 matrix with an 8 or 9 variable API. 
But I kind of feel that if that is what is wanted, why does Cairo do any 
transforms at all, it could instead have direct setting of the current 
stroke and font matrixes along with the surface matrix, but instead it 
provides translate/rotate/scale api.

> Unless I don't understand you correctly, this is already the case.
> Notice how in my example drawing the black transformed stroke is of
> even width. I think the converse of getting a gradually thinner stroke
> is much more difficult to achieve.

Yes I agree your output is correct and showing "line width locking", and 
also easier to render as the path can be reduced to 2D before stroking. 
However as currently defined Cairo scales line widths by the CTM. If 3D 
transforms are allowed I think this means lines that are drawn further 
away should be scaled since the transform reduces to something 
indistinguishable from a scale. I don't think that is wanted so I think 
the fix is to change Cairo, including 2D, to do line width locking. Also 
font transform locking for the same reason.

More information about the cairo mailing list