/* Libart_LGPL - library of basic graphic primitives * Copyright (C) 1998 Raph Levien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* Simple manipulations with affine transformations */ #include "config.h" #include "art_affine.h" #include "art_misc.h" /* for M_PI */ #include #include /* for sprintf */ #include /* for strcpy */ /* According to a strict interpretation of the libart structure, this routine should go into its own module, art_point_affine. However, it's only two lines of code, and it can be argued that it is one of the natural basic functions of an affine transformation. */ /** * art_affine_point: Do an affine transformation of a point. * @dst: Where the result point is stored. * @src: The original point. @ @affine: The affine transformation. **/ void art_affine_point (ArtPoint *dst, const ArtPoint *src, const gdouble affine[6]) { gdouble x, y; x = src->x; y = src->y; dst->x = x * affine[0] + y * affine[2] + affine[4]; dst->y = x * affine[1] + y * affine[3] + affine[5]; } /** * art_affine_invert: Find the inverse of an affine transformation. * @dst: Where the resulting affine is stored. * @src: The original affine transformation. * * 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_invert (gdouble dst[6], const gdouble src[6]) { gdouble r_det; r_det = 1.0 / (src[0] * src[3] - src[1] * src[2]); dst[0] = src[3] * r_det; dst[1] = -src[1] * r_det; dst[2] = -src[2] * r_det; dst[3] = src[0] * r_det; dst[4] = -src[4] * dst[0] - src[5] * dst[2]; dst[5] = -src[4] * dst[1] - src[5] * dst[3]; } /** * art_affine_multiply: Multiply two affine transformation matrices. * @dst: Where to store the result. * @src1: The first affine transform to multiply. * @src2: The second affine transform to multiply. * * 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_multiply (gdouble dst[6], const gdouble src1[6], const gdouble src2[6]) { gdouble d0, d1, d2, d3, d4, d5; d0 = src1[0] * src2[0] + src1[1] * src2[2]; d1 = src1[0] * src2[1] + src1[1] * src2[3]; d2 = src1[2] * src2[0] + src1[3] * src2[2]; d3 = src1[2] * src2[1] + src1[3] * src2[3]; d4 = src1[4] * src2[0] + src1[5] * src2[2] + src2[4]; d5 = src1[4] * src2[1] + src1[5] * src2[3] + src2[5]; dst[0] = d0; dst[1] = d1; dst[2] = d2; dst[3] = d3; dst[4] = d4; dst[5] = d5; } /** * art_affine_identity: Set up the identity matrix. * @dst: Where to store the resulting affine transform. * * Sets up an identity matrix. **/ void art_affine_identity (gdouble dst[6]) { dst[0] = 1; dst[1] = 0; dst[2] = 0; dst[3] = 1; dst[4] = 0; dst[5] = 0; } /** * art_affine_scale: Set up a scaling matrix. * @dst: Where to store the resulting affine transform. * @sx: X scale factor. * @sy: Y scale factor. * * Sets up a scaling matrix. **/ void art_affine_scale (gdouble dst[6], gdouble sx, gdouble sy) { dst[0] = sx; dst[1] = 0; dst[2] = 0; dst[3] = sy; dst[4] = 0; dst[5] = 0; } /** * art_affine_translate: Set up a translation matrix. * @dst: Where to store the resulting affine transform. * @tx: X translation amount. * @tx: Y translation amount. * * Sets up a translation matrix. **/ void art_affine_translate (gdouble dst[6], gdouble tx, gdouble ty) { dst[0] = 1; dst[1] = 0; dst[2] = 0; dst[3] = 1; dst[4] = tx; dst[5] = ty; } /** * art_affine_expansion: Find the affine's expansion factor. * @src: The affine transformation. * * 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. * * Return value: the expansion factor. **/ gdouble art_affine_expansion (const gdouble src[6]) { return sqrt (fabs (src[0] * src[3] - src[1] * src[2])); }