diff options
Diffstat (limited to 'generic/Transfo.c')
-rw-r--r-- | generic/Transfo.c | 754 |
1 files changed, 0 insertions, 754 deletions
diff --git a/generic/Transfo.c b/generic/Transfo.c deleted file mode 100644 index d9cee9f..0000000 --- a/generic/Transfo.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * Transfo.c -- Implementation of transformation routines. - * - * Authors : Patrick Lecoanet. - * Creation date : - * - * $Id$ - */ - -/* - * Copyright (c) 1993 - 2005 CENA, Patrick Lecoanet -- - * - * See the file "Copyright" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - */ - -/* - * This package deals with *AFFINE* 3x3 matrices. - * This means that you should not try to feed it with matrices - * containing perspective changes. It is assumed that the third - * column is always [0 0 1] as this is the case for affine matrices. - * Furthermore affine matrices are known to be invertible (non singular). - * Despite this, various tests are done to test the invertibility because - * of numerical precision or limit. - * Any of the operations in this module yield an affine matrix. Composition - * of two affine matrices and inversion of an affine matrix result in an - * affine matrix (Affine matrices Group property). Rotation, translation - * anamorphic scaling, xy skew and yx skew also preserve the property. - * - */ - - -#include "Item.h" -#include "Geo.h" -#include "Transfo.h" -#include "Types.h" - -#include <stdlib.h> - - -static const char rcsid[] = "$Imagine: Transfo.c,v 1.7 1997/01/24 14:33:37 lecoanet Exp $"; -static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; - - - -/* - ************************************************************************* - * - * The transformation primitives are based on affines matrices retricted - * to the following pattern: - * - * x x 0 - * x x 0 - * x x 1 - * - * It is necessary to feed only those matrices to the Transfo primitives - * as they do optimizations based on the properties of affine matrices. - * Furthermore the package stores only the first two columns, the third - * is constant. There is no way to describe perspective transformation - * with these transformation matrices. - * - ************************************************************************* - */ - -/* - ************************************************************************* - * - * ZnTransfoNew -- - * Create a new transformation and return it initialized to - * identity. - * - ************************************************************************* - */ -ZnTransfo * -ZnTransfoNew() -{ - ZnTransfo *t; - - t = (ZnTransfo *) ZnMalloc(sizeof(ZnTransfo)); - ZnTransfoSetIdentity(t); - - return t; -} - - -/* - ************************************************************************* - * - * ZnTransfoDuplicate -- - * Create a new transformation identical to the model t. - * - ************************************************************************* - */ -ZnTransfo * -ZnTransfoDuplicate(ZnTransfo *t) -{ - ZnTransfo *nt; - - nt = (ZnTransfo *) ZnMalloc(sizeof(ZnTransfo)); - if (t) { - *nt = *t; - } - else { - ZnTransfoSetIdentity(nt); - } - - return nt; -} - - -/* - ************************************************************************* - * - * ZnTransfoFree -- - * Delete a transformation and free its memory. - * - ************************************************************************* - */ -void -ZnTransfoFree(ZnTransfo *t) -{ - ZnFree(t); -} - - -/* - ************************************************************************* - * - * ZnPrintTransfo -- - * Print the transfo matrix on stdout. - * - ************************************************************************* - */ -void -ZnPrintTransfo(ZnTransfo *t) -{ - /* - * sx 0 cos(rot) sin(rot) 1 tan(skewy) 1 0 - * 0 sy -sin(rot) cos(rot) tan(skewx) 1 0 1 - * 0 0 0 0 0 0 tx ty - */ - if (t) { - printf("(%5g %5g\n %5g %5g\n %5g %5g)\n", - t->_[0][0], t->_[0][1], - t->_[1][0], t->_[1][1], - t->_[2][0], t->_[2][1]); - } - else { - printf("(%5g %5g\n %5g %5g\n %5g %5g)\n", - 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); - } -} - - -/* - ************************************************************************* - * - * ZnTransfoIsIdentity -- - * Tell if the given transfo is (close to) identity. - * - ************************************************************************* - */ -ZnBool -ZnTransfoIsIdentity(ZnTransfo *t) -{ - ZnReal tmp; - ZnBool res = False; - - tmp = t->_[0][0] - 1.0; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - tmp = t->_[1][1] - 1.0; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - tmp = t->_[0][1]; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - tmp = t->_[1][0]; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - tmp = t->_[2][0]; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - tmp = t->_[2][1]; - res = res & ((tmp < PRECISION_LIMIT) && (tmp > -PRECISION_LIMIT)); - return res; -} - - -/* - ************************************************************************* - * - * ZnTransfoSetIdentity -- - * Initialize the given transfo to identity. - * - ************************************************************************* - */ -void -ZnTransfoSetIdentity(ZnTransfo *t) -{ - t->_[0][0] = 1; - t->_[0][1] = 0; - t->_[1][0] = 0; - t->_[1][1] = 1; - t->_[2][0] = 0; - t->_[2][1] = 0; -} - - -/* - ************************************************************************* - * - * ZnTransfoCompose -- - * Combine two transformations t1 and t2 by post-concatenation. - * Returns the resulting transformation. - * t2 can be NULL, meaning identity transform. This is used in - * the toolkit to optimize some cases. - * - * All the parameters must be distincts transforms. - * - ************************************************************************* - */ -ZnTransfo * -ZnTransfoCompose(ZnTransfo *res, - ZnTransfo *t1, - ZnTransfo *t2) -{ - if ((t1 != NULL) && (t2 != NULL)) { - register float tmp; - - tmp = t1->_[0][0]; - res->_[0][0] = tmp*t2->_[0][0] + t1->_[0][1]*t2->_[1][0]; - res->_[0][1] = tmp*t2->_[0][1] + t1->_[0][1]*t2->_[1][1]; - tmp = t1->_[1][0]; - res->_[1][0] = tmp*t2->_[0][0] + t1->_[1][1]*t2->_[1][0]; - res->_[1][1] = tmp*t2->_[0][1] + t1->_[1][1]*t2->_[1][1]; - tmp = t1->_[2][0]; - res->_[2][0] = tmp*t2->_[0][0] + t1->_[2][1]*t2->_[1][0] + t2->_[2][0]; - res->_[2][1] = tmp*t2->_[0][1] + t1->_[2][1]*t2->_[1][1] + t2->_[2][1]; - } - else if (t1 == NULL) { - if (res != t2) { - *res = *t2; - } - } - else if (t2 == NULL) { - if (res != t2) { - *res = *t1; - } - } - else { - ZnTransfoSetIdentity(res); - } - - return res; -} - - -/* - ************************************************************************* - * - * ZnTransfoInvert -- - * Compute the inverse of the given matrix and return it. This - * function makes the assumption that the matrix is affine to - * optimize the job. Do not give it a general matrix, this will - * fail. This code is from Graphics Gems II. Anyway an affine - * matrix is always invertible for affine matrices form a sub - * group of the non-singular matrices. - * - ************************************************************************* - */ -ZnTransfo * -ZnTransfoInvert(ZnTransfo *t, - ZnTransfo *inv) -{ - float pos, neg, temp, det_l; - - if (t == NULL) { - ZnTransfoSetIdentity(inv); - return inv; - } - - /* - * Compute the determinant of the upper left 2x2 sub matrix to see - * if it is singular. - */ - pos = neg = 0.0; - temp = t->_[0][0] * t->_[1][1]; - if (temp >= 0.0) { - pos += temp; - } - else { - neg += temp; - } - temp = - t->_[0][1] * t->_[1][0]; - if (temp >= 0.0) { - pos += temp; - } - else { - neg += temp; - } - det_l = pos + neg; - temp = det_l / (pos - neg); /* Why divide by (pos - neg) ?? */ - - if (ABS(temp) < PRECISION_LIMIT) { - ZnWarning("ZnTransfoInvert : singular matrix\n"); - return NULL; - } - - det_l = 1 / det_l; - inv->_[0][0] = t->_[1][1] * det_l; - inv->_[0][1] = - t->_[0][1] * det_l; - inv->_[1][0] = - t->_[1][0] * det_l; - inv->_[1][1] = t->_[0][0] * det_l; - /* - * The code below is equivalent to: - * inv->_[2][0] = (t->_[1][0] * t->_[2][1] - t->_[1][1] * t->_[2][0]) * det_l; - * inv->_[2][1] = - (t->_[0][0] * t->_[2][1] - t->_[0][1] * t->_[2][0]) * det_l; - * - * with some operations factored (already computed) to increase speed. - */ - inv->_[2][0] = - (inv->_[0][0] * t->_[2][0] + inv->_[1][0] * t->_[2][1]); - inv->_[2][1] = - (inv->_[0][1] * t->_[2][0] + inv->_[1][1] * t->_[2][1]); - - return inv; -} - - -/* - ************************************************************************* - * - * ZnTransfoDecompose -- - * Decompose an affine matrix into translation, scale, skew and - * rotation. The different values are stored in the locations - * pointed to by the pointer parameters. If some values are not - * needed a NULL pointer can be given instead. The resulting skew - * shews x coordinate when y change. - * This code is taken from Graphics Gems II. - * - ************************************************************************* - */ -void -ZnTransfoDecompose(ZnTransfo *t, - ZnPoint *scale, - ZnPoint *trans, - ZnReal *rotation, - ZnReal *skewxy) -{ - ZnTransfo local; - float skew, len, rot, det; - - if (t == NULL) { - /* Identity transform */ - if (scale) { - scale->x = 1.0; - scale->y = 1.0; - } - if (trans) { - trans->x = 0.0; - trans->y = 0.0; - } - if (rotation) { - *rotation = 0.0; - } - if (skewxy) { - *skewxy = 0.0; - } - //printf("Transfo is identity\n"); - return; - } - - det = (t->_[0][0]*t->_[1][1] - t->_[0][1]*t->_[1][0]); - if (ABS(det) < PRECISION_LIMIT) { - ZnWarning("ZnTransfoDecompose : singular matrix\n"); - return; - } - - local = *t; - //ZnPrintTransfo(&local); - /* Get translation part if needed */ - if (trans) { - trans->x = ABS(local._[2][0]) < PRECISION_LIMIT ? 0 : local._[2][0]; - trans->y = ABS(local._[2][1]) < PRECISION_LIMIT ? 0 : local._[2][1]; - } - if (!scale && !skewxy && !rotation) { - return; - } - - /* Get scale and skew */ - len = (float) sqrt(local._[0][0]*local._[0][0] + - local._[0][1]*local._[0][1]); /* Get x scale from 1st row */ - if (scale) { - scale->x = len < PRECISION_LIMIT ? 0.0 : len; - } - local._[0][0] /= len; /* Normalize 1st row */ - local._[0][1] /= len; - skew = (local._[0][0]*local._[1][0] + - local._[0][1]*local._[1][1]); /* Skew is dot product of 1st row & 2nd row */ - /* Make the 2nd row orthogonal to the 1st row - * by linear combinaison: - * row1.x = row1.x + row0.x*-skew & - * row1.y = row1.y + row0.y*-skew - */ - local._[1][0] -= local._[0][0]*skew; - local._[1][1] -= local._[0][1]*skew; - len = (float) sqrt(local._[1][0]*local._[1][0] + - local._[1][1]*local._[1][1]); /* Get y scale from 2nd row */ - if (scale) { - scale->y = len < PRECISION_LIMIT ? 0.0 : len; - } - - if (!skewxy && !rotation) { - return; - } - - local._[1][0] /= len; /* Normalize 2nd row */ - local._[1][1] /= len; - skew /= len; - if (skewxy) { - *skewxy = ABS(skew) < PRECISION_LIMIT ? 0.0 : skew; - //printf("skew %f\n", *skewxy); - } - - if (!rotation) { - return; - } - - //printf("Matrix after scale & skew extracted\n"); - //ZnPrintTransfo(&local); - /* Get rotation */ - /* Check for a coordinate system flip. If det of upper-left 2x2 - * is -1, there is a reflection. If the rotation is < 180° negate - * the y scale. If the rotation is > 180° then negate the x scale - * and report a rotation between 0 and 180°. This dissymetry is - * the result of computing (z) rotation from the first row (x component - * of the axis system basis). - */ - det = (local._[0][0]*local._[1][1]- local._[0][1]*local._[1][0]); - - rot = (float) atan2(local._[0][1], local._[0][0]); - if (rot < 0) { - rot = (2 * (float) M_PI) + rot; - } - rot = rot < PRECISION_LIMIT ? 0 : rot; - if (rot >= M_PI) { - /*rot -= M_PI; Why that, I'll have to check Graphic Gems ??? */ - if (scale && det < 0) { - scale->x *= -1; - } - } - else if (scale && det < 0) { - scale->y *= -1; - } - - //printf("scalex %f\n", scale->x); - //printf("scaley %f\n", scale->y); - //printf("rotation %f\n", rot*180.0/3.1415); - - if (rotation) { - *rotation = rot; - } -} - - -/* - ************************************************************************* - * - * ZnTransfoEqual -- - * Return True if t1 and t2 are equal (i.e they have the same - * rotation, skew scales and translations). If include_translation - * is True the translations are considered in the test. - * - ************************************************************************* - */ -ZnBool -ZnTransfoEqual(ZnTransfo *t1, - ZnTransfo *t2, - ZnBool include_translation) -{ - if (include_translation) { - return (t1->_[0][0] == t2->_[0][0] && - t1->_[0][1] == t2->_[0][1] && - t1->_[1][0] == t2->_[1][0] && - t1->_[1][1] == t2->_[1][1] && - t1->_[2][0] == t2->_[2][0] && - t1->_[2][1] == t2->_[2][1]); - } - else { - return (t1->_[0][0] == t2->_[0][0] && - t1->_[0][1] == t2->_[0][1] && - t1->_[1][0] == t2->_[1][0] && - t1->_[1][1] == t2->_[1][1]); - } -} - - -/* - ************************************************************************* - * - * ZnTransfoHasSkew -- - * Return True if t has a skew factor in x or y or describe a - * rotation or both. - * - ************************************************************************* - */ -ZnBool -ZnTransfoHasSkew(ZnTransfo *t) -{ - return t->_[0][1] != 0.0 || t->_[1][0] != 0.0; -} - - -/* - ************************************************************************* - * - * ZnTransfoIsTranslation -- - * Return True if t is a pure translation. - * - ************************************************************************* - */ -ZnBool -ZnTransfoIsTranslation(ZnTransfo *t) -{ - if (!t) { - return True; - } - return (t->_[0][0] == 1.0 && - t->_[0][1] == 0.0 && - t->_[1][0] == 0.0 && - t->_[1][1] == 1.0); -} - - -/* - ************************************************************************* - * - * ZnTransformPoint -- - * Apply the transformation to the point. The point is - * modified and returned as the value of the function. - * It is safe for p and xp to be the same point (structure). - * A NULL transformation means identity. This is only used - * in the toolkit to optimize some cases. It should never - * happen in user code. - * - ************************************************************************* - */ -ZnPoint * -ZnTransformPoint(ZnTransfo *t, - register ZnPoint *p, - ZnPoint *xp) -{ - if (t == NULL) { - xp->x = p->x; - xp->y = p->y; - } - else { - ZnReal a; - a = t->_[0][0]*p->x + t->_[1][0]*p->y + t->_[2][0]; - xp->y = t->_[0][1]*p->x + t->_[1][1]*p->y + t->_[2][1]; - xp->x = a; - } - return xp; -} - - -/* - ************************************************************************* - * - * ZnTransformPoints -- - * Apply the transformation to the points in p returning points in xp. - * It is safe for p and xp to be the same array of ponits. - * The number of points is in num. - * A NULL transformation means identity. This is only used - * in the toolkit to optimize some cases. It should never - * happen in user code. - * - ************************************************************************* - */ -void -ZnTransformPoints(ZnTransfo *t, - ZnPoint *p, - ZnPoint *xp, - unsigned int num) -{ - if (t == NULL) { - memcpy(xp, p, sizeof(ZnPoint)*num); - } - else { - unsigned int i; - - for (i = 0; i < num; i++) { - ZnReal a; - a = t->_[0][0]*p[i].x + t->_[1][0]*p[i].y + t->_[2][0]; - xp[i].y = t->_[0][1]*p[i].x + t->_[1][1]*p[i].y + t->_[2][1]; - xp[i].x = a; - } - } -} - - -/* - ************************************************************************* - * - * ZnTranslate -- - * Translate the given transformation by delta_x, delta_y. Returns - * the resulting transformation. If abs is true, delta_x and - * delta_y are used to set the translation instead of adding deltas. - * - ************************************************************************* - */ -ZnTransfo * -ZnTranslate(ZnTransfo *t, - ZnReal delta_x, - ZnReal delta_y, - ZnBool abs) -{ - if (abs) { - t->_[2][0] = (float) delta_x; - t->_[2][1] = (float) delta_y; - } - else { - t->_[2][0] = t->_[2][0] + (float) delta_x; - t->_[2][1] = t->_[2][1] + (float) delta_y; - } - - return t; -} - -/* - ************************************************************************* - * - * ZnScale -- - * Scale the given transformation by scale_x, scale_y. Returns the - * resulting transformation. - * - ************************************************************************* - */ -ZnTransfo * -ZnScale(ZnTransfo *t, - ZnReal scale_x, - ZnReal scale_y) -{ - t->_[0][0] = t->_[0][0] * (float) scale_x; - t->_[0][1] = t->_[0][1] * (float) scale_y; - t->_[1][0] = t->_[1][0] * (float) scale_x; - t->_[1][1] = t->_[1][1] * (float) scale_y; - t->_[2][0] = t->_[2][0] * (float) scale_x; - t->_[2][1] = t->_[2][1] * (float) scale_y; - - return t; -} - - -/* - ************************************************************************* - * - * ZnRotateRad -- - * Rotate the given transformation by angle radians - * counter-clockwise around the origin. Returns the resulting - * transformation. - * - ************************************************************************* - */ -ZnTransfo * -ZnRotateRad(ZnTransfo *t, - ZnReal angle) -{ - float c = (float) cos(angle); - float s = (float) sin(angle); - float tmp; - - tmp = t->_[0][0]; - t->_[0][0] = tmp*c - t->_[0][1]*s; - t->_[0][1] = tmp*s + t->_[0][1]*c; - tmp = t->_[1][0]; - t->_[1][0] = tmp*c - t->_[1][1]*s; - t->_[1][1] = tmp*s + t->_[1][1]*c; - tmp = t->_[2][0]; - t->_[2][0] = tmp*c - t->_[2][1]*s; - t->_[2][1] = tmp*s + t->_[2][1]*c; - - return t; -} - - -/* - ************************************************************************* - * - * ZnRotateDeg -- - * Rotate the given transformation by angle degrees - * counter-clockwise around the origin. Returns the resulting - * transformation. - * - ************************************************************************* - */ -ZnTransfo * -ZnRotateDeg(ZnTransfo *t, - ZnReal angle) -{ - return ZnRotateRad(t, ZnDegRad(angle)); -} - - -/* - ************************************************************************* - * - * ZnSkewRad -- - * Skew the given transformation by x_angle and y_angle radians - * counter-clockwise around the origin. Returns the resulting - * transformation. - * - ************************************************************************* - */ -ZnTransfo * -ZnSkewRad(ZnTransfo *t, - ZnReal skew_x, - ZnReal skew_y) -{ - float sx = (float) tan(skew_x); - float sy = (float) tan(skew_y); - float tmp; - - tmp = t->_[0][0]; - t->_[0][0] = tmp + t->_[0][1]*sx; - t->_[0][1] = tmp*sy + t->_[0][1]; - tmp = t->_[1][0]; - t->_[1][0] = tmp + t->_[1][1]*sx; - t->_[1][1] = tmp*sy + t->_[1][1]; - tmp = t->_[2][0]; - t->_[2][0] = tmp + t->_[2][1]*sx; - t->_[2][1] = tmp*sy + t->_[2][1]; - - return t; -} - - -/* - ************************************************************************* - * - * ZnSkewDeg -- - * Skew the given transformation by x_angle and y_angle degrees - * counter-clockwise around the origin. Returns the resulting - * transformation. - * - ************************************************************************* - */ -ZnTransfo * -ZnSkewDeg(ZnTransfo *t, - ZnReal skew_x, - ZnReal skew_y) -{ - return ZnSkewRad(t, ZnDegRad(skew_x), ZnDegRad(skew_y)); -} - - -#undef PRECISION_LIMIT - - |