The libart library | |||
---|---|---|---|
<<< Previous Page | Home | Up | Next Page >>> |
void art_affine_point (ArtPoint *dst, const ArtPoint *src, const double affine[6]); void art_affine_invert (double dst_affine[6], const double src_affine[6]); void art_affine_flip (double dst_affine[6], const double src_affine[6], int horz, int vert); void art_affine_to_string (char str[128], const double src[6]); void art_affine_multiply (double dst[6], const double src1[6], const double src2[6]); void art_affine_identity (double dst[6]); void art_affine_scale (double dst[6], double sx, double sy); void art_affine_rotate (double dst[6], double theta); void art_affine_shear (double dst[6], double theta); void art_affine_translate (double dst[6], double tx, double ty); double art_affine_expansion (const double src[6]); int art_affine_rectilinear (const double src[6]); int art_affine_equal (double matrix1[6], double matrix2[6]); |
These API functions allow you to instantiate and manipulate Affine transforms. An Affine transformation is a geometrical transformation which is known to preserve the parallelism of lines but not lengths and angles.
Affine transforms are usually represented using Homogeneous coordinates: given a point (x,y) in the traditional plane, its canonical Homogenous coordinate is (x,y,1). The Affine transforms are represented in Homogeneous coordinates because the transformation of point A by any Affine transformation can be expressed by the multiplication of a 3x3 Matrix and a 3x1 Point vector.
The above property is not trivial. For example, a translation in normal cartesian space results in the addition of a Point vector to the Point vector to transform while in Homogeneous space, the same translation transformation results in a matrix/vector multiplication. To convince you that I am telling you the truth, the diagram below summarizes the different kinds of Affine matrixes used and shows the scaling of point (x,y) by multiplication with a scaling matrix in homogeneous space.
To compose two Affine transforms, all you need to do is to multiply their matrices to get the matrix representing the resulting Affine transform. Given Affines A and B represented the matrices MA and MB, the Affine C = AoB is represented by the matrix MC = MA x MB.
Hopefully, all the above gory details (which are unfortunatly necessary to understand the API) are more or less hidden by the API. LibArt thus represents an Affine transform by an array of six doubles:
Those arrays of six doubles can be easily generated with the art_affine_shear, art_affine_scale, art_affine_rotate, art_affine_translate and art_affine_identity functions which generate the affines corresponding to the given transformations. It is possible to composite Affine transformation's matrices with art_affine_multiply and to invert an Affine transformation: art_affine_invert. Finally, I to apply an Affine transformation to a point, you can use art_affine_point
Affine transformations are reused a little everywhere in LibArt: it is possible to apply them to Vector Paths and pixel buffers. art_vpath_affine_transform, art_bpath_affine_transform and art_rgb_affine are such examples.
void art_affine_point (ArtPoint *dst, const ArtPoint *src, const double affine[6]); |
void art_affine_invert (double dst_affine[6], const double src_affine[6]); |
All non-degenerate affine transforms are invertible. If the original affine is degenerate or nearly so, expect numerical instability and very likely core dumps on Alpha and other fp-picky architectures. Otherwise, dst multiplied with src, or src multiplied with dst will be (to within roundoff error) the identity affine.
void art_affine_flip (double dst_affine[6], const double src_affine[6], int horz, int vert); |
Flips the affine transform. FALSE for both horiz and vert implements a simple copy operation. TRUE for both horiz and vert is a 180 degree rotation. It is ok for src_affine and dst_affine to be equal pointers.
void art_affine_to_string (char str[128], const double src[6]); |
Converts an affine transform into a bit of PostScript code that implements the transform. Special cases of scaling, rotation, and translation are detected, and the corresponding PostScript operators used (this greatly aids understanding the output generated). The identity transform is mapped to the null string.
void art_affine_multiply (double dst[6], const double src1[6], const double src2[6]); |
Multiplies two affine transforms together, i.e. the resulting dst is equivalent to doing first src1 then src2. Note that the PostScript concat operator multiplies on the left, i.e. "M concat" is equivalent to "CTM = multiply (M, CTM)";
It is safe to call this function with dst equal to src1 or src2.
void art_affine_scale (double dst[6], double sx, double sy); |
Sets up a scaling matrix.
void art_affine_rotate (double dst[6], double theta); |
Sets up a rotation matrix. In the standard libart coordinate system, in which increasing y moves downward, this is a counterclockwise rotation. In the standard PostScript coordinate system, which is reversed in the y direction, it is a clockwise rotation.
void art_affine_shear (double dst[6], double theta); |
Sets up a shearing matrix. In the standard libart coordinate system and a small value for theta, || becomes \\. Horizontal lines remain unchanged.
void art_affine_translate (double dst[6], double tx, double ty); |
Sets up a translation matrix.
double art_affine_expansion (const double src[6]); |
Finds the expansion factor, i.e. the square root of the factor by which the affine transform affects area. In an affine transform composed of scaling, rotation, shearing, and translation, returns the amount of scaling.
int art_affine_rectilinear (const double src[6]); |
Determines whether src is rectilinear, i.e. grid-aligned rectangles are transformed to other grid-aligned rectangles. The implementation has epsilon-tolerance for roundoff errors.