lytico / xwt

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

matrix change from append to prepend

lytico opened this issue · comments

http://cairographics.org/manual/cairo-cairo-matrix-t.html
http://cgit.freedesktop.org/cairo/tree/src/cairo-matrix.c
quotes from cairo-matrix.c:

/**

  • cairo_matrix_rotate:

  • @matrix: a #cairo_matrix_t

  • @radians: angle of rotation, in radians. The direction of rotation

  • is defined such that positive angles rotate in the direction from

  • the positive X axis toward the positive Y axis. With the default

  • axis orientation of cairo, positive angles rotate in a clockwise

  • direction.
    *

  • Applies rotation by @radians to the transformation in

  • @matrix. The effect of the new transformation is to first rotate the

  • coordinates by @radians, then apply the original transformation

  • to the coordinates.
    *

  • Since: 1.0
    **/
    void
    cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
    {
    cairo_matrix_t tmp;

    cairo_matrix_init_rotate (&tmp, radians);

    cairo_matrix_multiply (matrix, &tmp, matrix);
    }

/**

  • cairo_matrix_init:

  • @matrix: a #cairo_matrix_t

  • @XX: xx component of the affine transformation

  • @yx: yx component of the affine transformation

  • @xy: xy component of the affine transformation

  • @yy: yy component of the affine transformation

  • @x0: X translation component of the affine transformation

  • @y0: Y translation component of the affine transformation
    *

  • Sets @matrix to be the affine transformation given by

  • @XX, @yx, @xy, @yy, @x0, @y0. The transformation is given

  • by:

  • x_new = xx * x + xy * y + x0;

  • y_new = yx * x + yy * y + y0;

  • *
  • Since: 1.0
    **/
    void
    cairo_matrix_init (cairo_matrix_t *matrix,
    double xx, double yx,

       double xy, double yy,
       double x0, double y0)
    

    {
    matrix->xx = xx; matrix->yx = yx;
    matrix->xy = xy; matrix->yy = yy;
    matrix->x0 = x0; matrix->y0 = y0;
    }

/**

  • cairo_matrix_multiply:

  • @Result: a #cairo_matrix_t in which to store the result

  • @A: a #cairo_matrix_t

  • @b: a #cairo_matrix_t
    *

  • Multiplies the affine transformations in @A and @b together

  • and stores the result in @Result. The effect of the resulting

  • transformation is to first apply the transformation in @A to the

  • coordinates and then apply the transformation in @b to the

  • coordinates.
    *

  • It is allowable for @Result to be identical to either @A or @b.
    *

  • Since: 1.0
    */
    /

  • XXX: The ordering of the arguments to this function corresponds

  •  to [row_vector]_A_B. If we want to use column vectors instead,
    
  •  then we need to switch the two arguments and fix up all
    
  •  uses.
    

    */
    void
    cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
    {
    cairo_matrix_t r;

    r.xx = a->xx * b->xx + a->yx * b->xy;
    r.yx = a->xx * b->yx + a->yx * b->yy;

    r.xy = a->xy * b->xx + a->yy * b->xy;
    r.yy = a->xy * b->yx + a->yy * b->yy;

    r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
    r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;

    *result = r;
    }

Referencing the same Cairo source code as you have above, any transform (such as 'rotate' that you show) first initialises a temporary matrix &tmp, then multiplies 'this' by it - that is, the 'a' matrix above is &tmp, 'b' is 'this', and r = a * b is equivalent to this = &tmp * this . The matrix multiplication code above is identical to Prepend from the Xwt.Matrix code:-

public void Prepend (Matrix matrix)
{
    var _m11 = matrix.M11 * M11 + matrix.M12 * M21;
    var _m12 = matrix.M11 * M12 + matrix.M12 * M22;
    var _m21 = matrix.M21 * M11 + matrix.M22 * M21;
    var _m22 = matrix.M21 * M12 + matrix.M22 * M22;

    var _offsetX = matrix.OffsetX * M11 + matrix.OffsetY * M21 + OffsetX;
    var _offsetY = matrix.OffsetX * M12 + matrix.OffsetY * M22 + OffsetY;

    M11 = _m11;
    M12 = _m12;
    M21 = _m21;
    M22 = _m22;
    OffsetX = _offsetX;
    OffsetY = _offsetY;
}

where the Xwt and Cairo matrix components correspond as:

M11 = xx,  M12 = yx,
M12 = xy,  M22 = yy. 

This confirms that Cairo uses Prepend for each successive transform that is applied to the matrix ('this'). This is also the way that all the Backend Context transforms behave, and I've recently added a Drawing page to the Wiki which I hope clarifies things a bit more.

What isn't clear to me is why the System.Media.Matrix code, from which Xwt.Matrix is taken, uses Append as the default mode for all its transforms (Scale, Rotate, Translate, Skew), but provides Prepend as well.

sorry, i have red params order of multiply as a,b,result, so i got append, which is wrong.
its really hard to read code on smartphone screens :-(

Thanks, lytico, for your input on this one. It gets confusing because different backends can use a different matrix layout for Affine Transforms (as per Java), and if the transposed one is used, the order needs to be Append! However, the Xwt.Matrix code corresponds to using a Row Vector, and the normal layout that I've described in the Wiki Drawing page. Hope it's not intruded on your holiday/travelling too much!