X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=Xserver%2Flib%2Ffont%2FType1%2Fspaces.c;fp=Xserver%2Flib%2Ffont%2FType1%2Fspaces.c;h=0000000000000000000000000000000000000000;hp=f026420fd9667851e6192dcacd822651c6d3d4fa;hb=ce66b81460e5353db09d45c02339d4583fbda255;hpb=7772d71ffd742cfc9b7ff214659d16c5bb56a391 diff --git a/Xserver/lib/font/Type1/spaces.c b/Xserver/lib/font/Type1/spaces.c deleted file mode 100644 index f026420..0000000 --- a/Xserver/lib/font/Type1/spaces.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* $XConsortium: spaces.c,v 1.8 95/06/08 23:20:39 gildea Exp $ */ -/* Copyright International Business Machines, Corp. 1991 - * All Rights Reserved - * Copyright Lexmark International, Inc. 1991 - * All Rights Reserved - * - * License to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of IBM or Lexmark not be - * used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF - * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY - * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, - * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE - * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT - * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE - * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE - * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL - * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - * THIS SOFTWARE. - */ - /* SPACES CWEB V0021 ******** */ -/* -:h1 id=spaces.SPACES Module - Handles Coordinate Spaces - -This module is responsible for handling the TYPE1IMAGER "XYspace" object. - -&author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com) - - -:h3.Include Files -*/ -#include "objects.h" -#include "spaces.h" -#include "paths.h" -#include "pictures.h" -#include "fonts.h" -#include "arith.h" -#include "trig.h" - -static void FindFfcn(); -static void FindIfcn(); -/* -:h3.Entry Points Provided to the TYPE1IMAGER User -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ - -/* -:h3.Entry Points Provided to Other Modules -*/ - -/* -In addition, other modules call the SPACES module through function -vectors in the "XYspace" structure. The entry points accessed that -way are "FConvert()", "IConvert()", and "ForceFloat()". -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ -/* -:h3.Macros and Typedefs Provided to Other Modules - -:h4.Duplicating and Killing Spaces - -Destroying XYspaces is so simple we can do it with a -macro: -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ -/* -On the other hand, duplicating XYspaces is slightly more difficult -because of the need to keep a unique ID in the space, see -:hdref refid=dupspace.. - -:h4.Fixed Point Pel Representation - -We represent pel positions with fixed point numbers. This does NOT -mean integer, but truly means fixed point, with a certain number -of binary digits (FRACTBITS) representing the fractional part of the -pel. -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ -/* -:h2.Data Structures for Coordinate Spaces and Points -*/ -/* -:h3 id=matrix.Matrices - -TYPE1IMAGER uses 2x2 transformation matrices. We'll use C notation for -such a matrix (M[2][2]), the first index being rows, the second columns. -*/ - -/* -:h3.The "doublematrix" Structure - -We frequently find it desirable to store both a matrix and its -inverse. We store these in a "doublematrix" structure. -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ - -/* -:h3.The "XYspace" Structure - -The XYspace structure represents the XYspace object. -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ -#define RESERVED 10 /* 'n' IDs are reserved for invalid & immortal spaces */ -/* -*/ -#define NEXTID ((SpaceID < RESERVED) ? (SpaceID = RESERVED) : ++SpaceID) - -static unsigned int SpaceID = 1; - -struct XYspace *CopySpace(S) - register struct XYspace *S; -{ - S = (struct XYspace *)Allocate(sizeof(struct XYspace), S, 0); - S->ID = NEXTID; - return(S); -} -/* -:h3.The "fractpoint" Structure - -A fractional point is just a "fractpel" x and y: -*/ - -/*SHARED LINE(S) ORIGINATED HERE*/ - -/* -:h3.Lazy Evaluation of Matrix Inverses - -Calculating the inverse of a matrix is somewhat involved, and we usually -do not need them. So, we flag whether or not the space has the inverse -already calculated: -*/ - -#define HASINVERSE(flag) ((flag)&0x80) - -/* -The following macro forces a space to have an inverse: -*/ - -#define CoerceInverse(S) if (!HASINVERSE((S)->flag)) { \ - MatrixInvert((S)->tofract.normal, (S)->tofract.inverse); (S)->flag |= HASINVERSE(ON); } -/* -:h3.IDENTITY Space - -IDENTITY space is (logically) the space corresponding to the identity -transformation matrix. However, since all our transformation matrices -have a common FRACTFLOAT scale factor to convert to 'fractpel's, that -is actually what we store in 'tofract' matrix of IDENTITY: -*/ - -static struct XYspace identity = { SPACETYPE, ISPERMANENT(ON) + ISIMMORTAL(ON) - + HASINVERSE(ON), 2, /* added 3-26-91 PNM */ - NULL, NULL, - NULL, NULL, NULL, NULL, - INVALIDID + 1, 0, - FRACTFLOAT, 0.0, 0.0, FRACTFLOAT, - 1.0/FRACTFLOAT, 0.0, 0.0, 1.0/FRACTFLOAT, - 0, 0, 0, 0 }; -struct XYspace *IDENTITY = &identity; - -/* -*/ -#define MAXCONTEXTS 16 - -static struct doublematrix contexts[MAXCONTEXTS]; - -#ifdef notdef - -static int nextcontext = 1; - -/*SHARED LINE(S) ORIGINATED HERE*/ - -#ifdef __STDC__ -#define pointer void * -#else -#define pointer char * -#endif - -/* -:h3.FindDeviceContext() - Find the Context Given a Device - -This routine, given a device, returns the index of the device's -transformation matrix in the context array. If it cannot find it, -it will allocate a new array entry and fill it out. -*/ - -static int FindDeviceContext(device) - pointer device; /* device token */ -{ - double M[2][2]; /* temporary matrix */ - float Xres,Yres; /* device resolution */ - int orient = -1; /* device orientation */ - int rc = -1; /* return code for QueryDeviceState */ - - if (rc != 0) /* we only bother with this check once */ - abort("Context: QueryDeviceState didn't work"); - - M[0][0] = M[1][0] = M[0][1] = M[1][1] = 0.0; - - switch (orient) { - case 0: - M[0][0] = Xres; M[1][1] = -Yres; - break; - case 1: - M[1][0] = Yres; M[0][1] = Xres; - break; - case 2: - M[0][0] = -Xres; M[1][1] = Yres; - break; - case 3: - M[1][0] = -Yres; M[0][1] = -Xres; - break; - default: - abort("QueryDeviceState returned invalid orientation"); - } - return(FindContext(M)); -} - -/* -:h3.FindContext() - Find the Context Given a Matrix - -This routine, given a matrix, returns the index of that matrix matrix in -the context array. If it cannot find it, it will allocate a new array -entry and fill it out. -*/ - -int FindContext(M) - double M[2][2]; /* array to search for */ -{ - register int i; /* loop variable for search */ - for (i=0; i < nextcontext; i++) - if (M[0][0] == contexts[i].normal[0][0] && M[1][0] == contexts[i].normal[1][0] - && M[0][1] == contexts[i].normal[0][1] && M[1][1] == contexts[i].normal[1][1]) - break; - - if (i >= nextcontext) { - if (i >= MAXCONTEXTS) - abort("Context: out of them"); - LONGCOPY(contexts[i].normal, M, sizeof(contexts[i].normal)); - MatrixInvert(M, contexts[i].inverse); - nextcontext++; - } - - return(i); -} - -/* -:h3.Context() - Create a Coordinate Space for a Device - -This user operator is implemented by first finding the device context -array index, then transforming IDENTITY space to create an appropriate -cooridnate space. -*/ - -struct XYspace *Context(device, units) - pointer device; /* device token */ - double units; /* multiples of one inch */ -{ - double M[2][2]; /* device transformation matrix */ - register int n; /* will hold device context number */ - register struct XYspace *S; /* XYspace constructed */ - - IfTrace2((MustTraceCalls),"Context(%x, %f)\n", device, &units); - - ARGCHECK((device == NULL), "Context of NULLDEVICE not allowed", - NULL, IDENTITY, (0), struct XYspace *); - ARGCHECK((units == 0.0), "Context: bad units", NULL, IDENTITY, (0), struct XYspace *); - - n = FindDeviceContext(device); - - LONGCOPY(M, contexts[n].normal, sizeof(M)); - - M[0][0] *= units; - M[0][1] *= units; - M[1][0] *= units; - M[1][1] *= units; - - S = (struct XYspace *)Xform(IDENTITY, M); - - S->context = n; - return(S); -} -#endif - -/* -:h3.ConsiderContext() - Adjust a Matrix to Take Out Device Transform - -Remember, we have :f/x times U times D/ and :f/M/ and and we want :f/x -times U times M times D/. An easy way to do this is to calculate -:f/D sup <-1> times M times D/, because: -:formula. -x times U times D times D sup <-1> times M times D = x times U times M times D -:formula. -So this subroutine, given an :f/M/and an object, finds the :f/D/ for that -object and modifies :f/M/ so it is :f/D sup <-1> times M times D/. -*/ - -static void ConsiderContext(obj, M) - register struct xobject *obj; /* object to be transformed */ - register double M[2][2]; /* matrix (may be changed) */ -{ - register int context; /* index in contexts array */ - - if (obj == NULL) return; - - if (ISPATHTYPE(obj->type)) { - struct segment *path = (struct segment *) obj; - - context = path->context; - } - else if (obj->type == SPACETYPE) { - struct XYspace *S = (struct XYspace *) obj; - - context = S->context; - } - else if (obj->type == PICTURETYPE) { - - } - else - context = NULLCONTEXT; - - if (context != NULLCONTEXT) { - MatrixMultiply(contexts[context].inverse, M, M); - MatrixMultiply(M, contexts[context].normal, M); - } -} - -/* -:h2.Conversion from User's X,Y to "fractpel" X,Y - -When the user is building paths (lines, moves, curves, etc.) he passes -the control points (x,y) for the paths together with an XYspace. We -must convert from the user's (x,y) to our internal representation -which is in pels (fractpels, actually). This involves transforming -the user's (x,y) under the coordinate space transformation. It is -important that we do this quickly. So, we store pointers to different -conversion functions right in the XYspace structure. This allows us -to have simpler special case functions for the more commonly -encountered types of transformations. - -:h3.Convert(), IConvert(), and ForceFloat() - Called Through "XYspace" Structure - -These are functions that fit in the "convert" and "iconvert" function -pointers in the XYspace structure. They call the "xconvert", "yconvert", -"ixconvert", and "iyconvert" as appropriate to actually do the work. -These secondary routines come in many flavors to handle different -special cases as quickly as possible. -*/ - -static void FXYConvert(pt, S, x, y) - register struct fractpoint *pt; /* point to set */ - register struct XYspace *S; /* relevant coordinate space */ - register double x,y; /* user's coordinates of point */ -{ - pt->x = (*S->xconvert)(S->tofract.normal[0][0], S->tofract.normal[1][0], x, y); - pt->y = (*S->yconvert)(S->tofract.normal[0][1], S->tofract.normal[1][1], x, y); -} - -static void IXYConvert(pt, S, x, y) - register struct fractpoint *pt; /* point to set */ - register struct XYspace *S; /* relevant coordinate space */ - register long x,y; /* user's coordinates of point */ -{ - pt->x = (*S->ixconvert)(S->itofract[0][0], S->itofract[1][0], x, y); - pt->y = (*S->iyconvert)(S->itofract[0][1], S->itofract[1][1], x, y); -} - -/* -ForceFloat is a substitute for IConvert(), when we just do not have -enough significant digits in the coefficients to get high enough -precision in the answer with fixed point arithmetic. So, we force the -integers to floats, and do the arithmetic all with floats: -*/ - -static void ForceFloat(pt, S, x, y) - register struct fractpoint *pt; /* point to set */ - register struct XYspace *S; /* relevant coordinate space */ - register long x,y; /* user's coordinates of point */ -{ - (*S->convert)(pt, S, (double) x, (double) y); -} - -/* -:h3.FXYboth(), FXonly(), FYonly() - Floating Point Conversion - -These are the routines we use when the user has given us floating -point numbers for x and y. FXYboth() is the general purpose routine; -FXonly() and FYonly() are special cases when one of the coefficients -is 0.0. -*/ - -static fractpel FXYboth(cx, cy, x, y) - register double cx,cy; /* x and y coefficients */ - register double x,y; /* user x,y */ -{ - register double r; /* temporary float */ - - r = x * cx + y * cy; - return((fractpel) r); -} - -/*ARGSUSED*/ -static fractpel FXonly(cx, cy, x, y) - register double cx,cy; /* x and y coefficients */ - register double x,y; /* user x,y */ -{ - register double r; /* temporary float */ - - r = x * cx; - return((fractpel) r); -} - -/*ARGSUSED*/ -static fractpel FYonly(cx, cy, x, y) - register double cx,cy; /* x and y coefficients */ - register double x,y; /* user x,y */ -{ - register double r; /* temporary float */ - - r = y * cy; - return((fractpel) r); -} - -/* -:h3.IXYboth(), IXonly(), IYonly() - Simple Integer Conversion - -These are the routines we use when the user has given us integers for -x and y, and the coefficients have enough significant digits to -provide precise answers with only "long" (32 bit?) multiplication. -IXYboth() is the general purpose routine; IXonly() and IYonly() are -special cases when one of the coefficients is 0. -*/ - -static fractpel IXYboth(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return(x * cx + y * cy); -} - -/*ARGSUSED*/ -static fractpel IXonly(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return(x * cx); -} - -/*ARGSUSED*/ -static fractpel IYonly(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return(y * cy); -} - - -/* -:h3.FPXYboth(), FPXonly(), FPYonly() - More Involved Integer Conversion - -These are the routines we use when the user has given us integers for -x and y, but the coefficients do not have enough significant digits to -provide precise answers with only "long" (32 bit?) multiplication. -We have increased the number of significant bits in the coefficients -by FRACTBITS; therefore we must use "double long" (64 bit?) -multiplication by calling FPmult(). FPXYboth() is the general purpose -routine; FPXonly() and FPYonly() are special cases when one of the -coefficients is 0. - -Note that it is perfectly possible for us to calculate X with the -"FP" method and Y with the "I" method, or vice versa. It all depends -on how the functions in the XYspace structure are filled out. -*/ - -static fractpel FPXYboth(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return( FPmult(x, cx) + FPmult(y, cy) ); -} - -/*ARGSUSED*/ -static fractpel FPXonly(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return( FPmult(x, cx) ); -} - -/*ARGSUSED*/ -static fractpel FPYonly(cx, cy, x, y) - register fractpel cx,cy; /* x and y coefficients */ - register long x,y; /* user x,y */ -{ - return( FPmult(y, cy) ); -} - - - -/* -:h3.FillOutFcns() - Determine the Appropriate Functions to Use for Conversion - -This function fills out the "convert" and "iconvert" function pointers -in an XYspace structure, and also fills the "helper" -functions that actually do the work. -*/ - -static void FillOutFcns(S) - register struct XYspace *S; /* functions will be set in this structure */ -{ - S->convert = FXYConvert; - S->iconvert = IXYConvert; - - FindFfcn(S->tofract.normal[0][0], S->tofract.normal[1][0], &S->xconvert); - FindFfcn(S->tofract.normal[0][1], S->tofract.normal[1][1], &S->yconvert); - FindIfcn(S->tofract.normal[0][0], S->tofract.normal[1][0], - &S->itofract[0][0], &S->itofract[1][0], &S->ixconvert); - FindIfcn(S->tofract.normal[0][1], S->tofract.normal[1][1], - &S->itofract[0][1], &S->itofract[1][1], &S->iyconvert); - - if (S->ixconvert == NULL || S->iyconvert == NULL) - S->iconvert = ForceFloat; -} - -/* -:h4.FindFfcn() - Subroutine of FillOutFcns() to Fill Out Floating Functions - -This function tests for the special case of one of the coefficients -being zero: -*/ - -static void FindFfcn(cx, cy, fcnP) - register double cx,cy; /* x and y coefficients */ - register fractpel (**fcnP)(); /* pointer to function to set */ -{ - if (cx == 0.0) - *fcnP = FYonly; - else if (cy == 0.0) - *fcnP = FXonly; - else - *fcnP = FXYboth; -} - -/* -:h4.FindIfcn() - Subroutine of FillOutFcns() to Fill Out Integer Functions - -There are two types of integer functions, the 'I' type and the 'FP' type. -We use the I type functions when we are satisfied with simple integer -arithmetic. We used the FP functions when we feel we need higher -precision (but still fixed point) arithmetic. If all else fails, -we store a NULL indicating that this we should do the conversion in -floating point. -*/ - -static void FindIfcn(cx, cy, icxP, icyP, fcnP) - register double cx,cy; /* x and y coefficients */ - register fractpel *icxP,*icyP; /* fixed point coefficients to set */ - register fractpel (**fcnP)(); /* pointer to function to set */ -{ - register fractpel imax; /* maximum of cx and cy */ - - *icxP = cx; - *icyP = cy; - - if (cx != (float) (*icxP) || cy != (float) (*icyP)) { -/* -At this point we know our integer approximations of the coefficients -are not exact. However, we will still use them if the maximum -coefficient will not fit in a 'fractpel'. Of course, we have little -choice at that point, but we haven't lost that much precision by -staying with integer arithmetic. We have enough significant digits -so that -any error we introduce is less than one part in 2:sup/16/. -*/ - - imax = MAX(ABS(*icxP), ABS(*icyP)); - if (imax < (fractpel) (1<<(FRACTBITS-1)) ) { -/* -At this point we know our integer approximations just do not have -enough significant digits for accuracy. We will add FRACTBITS -significant digits to the coefficients (by multiplying them by -1<x; - y = pt->y; - *xp = S->tofract.inverse[0][0] * x + S->tofract.inverse[1][0] * y; - *yp = S->tofract.inverse[0][1] * x + S->tofract.inverse[1][1] * y; -} - -/* -:h2.Transformations -*/ -/* -:h3 id=xform.Xform() - Transform Object in X and Y - -TYPE1IMAGER wants transformations of objects like paths to be identical -to transformations of spaces. For example, if you scale a line(1,1) -by 10 it should yield the same result as generating the line(1,1) in -a coordinate space that has been scaled by 10. - -We handle fonts by storing the accumulated transform, for example, SR -(accumulating on the right). Then when we map the font through space TD, -for example, we multiply the accumulated font transform on the left by -the space transform on the right, yielding SRTD in this case. We will -get the same result if we did S, then R, then T on the space and mapping -an unmodified font through that space. -*/ - -struct xobject *t1_Xform(obj, M) - register struct xobject *obj; /* object to transform */ - register double M[2][2]; /* transformation matrix */ -{ - if (obj == NULL) - return(NULL); - - if (obj->type == FONTTYPE) { - register struct font *F = (struct font *) obj; - - F = UniqueFont(F); - return((struct xobject*)F); - } - if (obj->type == PICTURETYPE) { -/* -In the case of a picture, we choose both to update the picture's -transformation matrix and keep the handles up to date. -*/ - register struct picture *P = (struct picture *) obj; - register struct segment *handles; /* temporary path to transform handles */ - - P = UniquePicture(P); - handles = PathSegment(LINETYPE, P->origin.x, P->origin.y); - handles = Join(handles, - PathSegment(LINETYPE, P->ending.x, P->ending.y) ); - handles = (struct segment *)Xform((struct xobject *) handles, M); - P->origin = handles->dest; - P->ending = handles->link->dest; - KillPath(handles); - return((struct xobject *)P); - } - - if (ISPATHTYPE(obj->type)) { - struct XYspace pseudo; /* local temporary space */ - PseudoSpace(&pseudo, M); - return((struct xobject *) PathTransform(obj, &pseudo)); - } - - - if (obj->type == SPACETYPE) { - register struct XYspace *S = (struct XYspace *) obj; - -/* replaced ISPERMANENT(S->flag) with S->references > 1 3-26-91 PNM */ - if (S->references > 1) - S = CopySpace(S); - else - S->ID = NEXTID; - - MatrixMultiply(S->tofract.normal, M, S->tofract.normal); - /* - * mark inverted matrix invalid: - */ - S->flag &= ~HASINVERSE(ON); - - FillOutFcns(S); - return((struct xobject *) S); - } - - return(ArgErr("Untransformable object", obj, obj)); -} - -/* -:h3.Transform() - Transform an Object - -This is the external user's entry point. -*/ -struct xobject *t1_Transform(obj, cxx, cyx, cxy, cyy) - struct xobject *obj; - double cxx,cyx,cxy,cyy; /* 2x2 transform matrix elements in row order */ -{ - double M[2][2]; - - IfTrace1((MustTraceCalls),"Transform(%z,", obj); - IfTrace4((MustTraceCalls)," %f %f %f %f)\n", &cxx, &cyx, &cxy, &cyy); - - M[0][0] = cxx; - M[0][1] = cyx; - M[1][0] = cxy; - M[1][1] = cyy; - ConsiderContext(obj, M); - return(Xform(obj, M)); -} -/* -:h3.Scale() - Special Case of Transform() - -This is a user operator. -*/ - -struct xobject *t1_Scale(obj, sx, sy) - struct xobject *obj; /* object to scale */ - double sx,sy; /* scale factors in x and y */ -{ - double M[2][2]; - IfTrace3((MustTraceCalls),"Scale(%z, %f, %f)\n", obj, &sx, &sy); - M[0][0] = sx; - M[1][1] = sy; - M[1][0] = M[0][1] = 0.0; - ConsiderContext(obj, M); - return(Xform(obj, M)); -} - -/* -:h3 id=rotate.Rotate() - Special Case of Transform() - -We special-case different settings of 'degrees' for performance -and accuracy within the DegreeSin() and DegreeCos() routines themselves. -*/ - -#ifdef notdef -struct xobject *xiRotate(obj, degrees) - struct xobject *obj; /* object to be transformed */ - double degrees; /* degrees of COUNTER-clockwise rotation */ -{ - double M[2][2]; - - - IfTrace2((MustTraceCalls),"Rotate(%z, %f)\n", obj, °rees); - - M[0][0] = M[1][1] = DegreeCos(degrees); - M[1][0] = - (M[0][1] = DegreeSin(degrees)); - ConsiderContext(obj, M); - return(Xform(obj, M)); -} -#endif - -/* -:h3.PseudoSpace() - Build a Coordinate Space from a Matrix - -Since we have built all this optimized code that, given an (x,y) and -a coordinate space, yield transformed (x,y), it seems a shame not to -use the same logic when we need to multiply an (x,y) by an arbitrary -matrix that is not (initially) part of a coordinate space. This -subroutine takes the arbitrary matrix and builds a coordinate -space, with all its nifty function pointers. -*/ - -void PseudoSpace(S, M) - struct XYspace *S; /* coordinate space structure to fill out */ - double M[2][2]; /* matrix that will become 'tofract.normal' */ -{ - S->type = SPACETYPE; - S->flag = ISPERMANENT(ON) + ISIMMORTAL(ON); - S->references = 2; /* 3-26-91 added PNM */ - S->tofract.normal[0][0] = M[0][0]; - S->tofract.normal[1][0] = M[1][0]; - S->tofract.normal[0][1] = M[0][1]; - S->tofract.normal[1][1] = M[1][1]; - - FillOutFcns(S); -} - -/* -:h2 id=matrixa.Matrix Arithmetic - -Following the convention in Newman and Sproull, :hp1/Interactive -Computer Graphics/, -matrices are organized: -:xmp. - | cxx cyx | - | cxy cyy | -:exmp. -A point is horizontal, for example: -:xmp. - [ x y ] -:exmp. -This means that: -:formula/x prime = cxx times x + cxy times y/ -:formula/y prime = cyx times x + cyy times y/ -I've seen the other convention, where transform matrices are -transposed, equally often in the literature. -*/ - -/* -:h3.MatrixMultiply() - Implements Multiplication of Two Matrices - -Implements matrix multiplication, A * B = C. - -To remind myself, matrix multiplication goes rows of A times columns -of B. -The output matrix may be the same as one of the input matrices. -*/ -void MatrixMultiply(A, B, C) - register double A[2][2],B[2][2]; /* input matrices */ - register double C[2][2]; /* output matrix */ -{ - register double txx,txy,tyx,tyy; - - txx = A[0][0] * B[0][0] + A[0][1] * B[1][0]; - txy = A[1][0] * B[0][0] + A[1][1] * B[1][0]; - tyx = A[0][0] * B[0][1] + A[0][1] * B[1][1]; - tyy = A[1][0] * B[0][1] + A[1][1] * B[1][1]; - - C[0][0] = txx; - C[1][0] = txy; - C[0][1] = tyx; - C[1][1] = tyy; -} -/* -:h3.MatrixInvert() - Invert a Matrix - -My reference for matrix inversion was :hp1/Elementary Linear Algebra/ -by Paul C. Shields, Worth Publishers, Inc., 1968. -*/ -void MatrixInvert(M, Mprime) - double M[2][2]; /* input matrix */ - double Mprime[2][2]; /* output inverted matrix */ -{ - register double D; /* determinant of matrix M */ - register double txx,txy,tyx,tyy; - - txx = M[0][0]; - txy = M[1][0]; - tyx = M[0][1]; - tyy = M[1][1]; - - D = M[1][1] * M[0][0] - M[1][0] * M[0][1]; - if (D == 0.0) - abort("MatrixInvert: can't"); - - Mprime[0][0] = tyy / D; - Mprime[1][0] = -txy / D; - Mprime[0][1] = -tyx / D; - Mprime[1][1] = txx / D; -} -/* -:h2.Initialization, Queries, and Debug -*/ -/* -:h3.InitSpaces() - Initialize Constant Spaces - -For compatibility, we initialize a coordinate space called USER which -maps 72nds of an inch to pels on the default device. -*/ - -struct XYspace *USER = &identity; - -void InitSpaces() -{ - extern char *DEFAULTDEVICE; - - IDENTITY->type = SPACETYPE; - FillOutFcns(IDENTITY); - - contexts[NULLCONTEXT].normal[1][0] - = contexts[NULLCONTEXT].normal[0][1] - = contexts[NULLCONTEXT].inverse[1][0] - = contexts[NULLCONTEXT].inverse[0][1] = 0.0; - contexts[NULLCONTEXT].normal[0][0] - = contexts[NULLCONTEXT].normal[1][1] - = contexts[NULLCONTEXT].inverse[0][0] - = contexts[NULLCONTEXT].inverse[1][1] = 1.0; - - USER->flag |= ISIMMORTAL(ON); - CoerceInverse(USER); -} -/* -:h3.QuerySpace() - Returns the Transformation Matrix of a Space - -Since the tofract matrix of an XYspace includes the scale factor -necessary to produce fractpel results (i.e., FRACTFLOAT), this -must be taken out before we return the matrix to the user. Fortunately, -this is simple: just multiply by the inverse of IDENTITY! -*/ - -void QuerySpace(S, cxxP, cyxP, cxyP, cyyP) - register struct XYspace *S; /* space asked about */ - register double *cxxP,*cyxP,*cxyP,*cyyP; /* where to put answer */ -{ - double M[2][2]; /* temp matrix to build user's answer */ - - if (S->type != SPACETYPE) { - ArgErr("QuerySpace: not a space", S, NULL); - return; - } - MatrixMultiply(S->tofract.normal, IDENTITY->tofract.inverse, M); - *cxxP = M[0][0]; - *cxyP = M[1][0]; - *cyxP = M[0][1]; - *cyyP = M[1][1]; -} - -/* -:h3.FormatFP() - Format a Fixed Point Pel - -We format the pel as "dddd.XXXX", where XX's are hexidecimal digits, -and the dd's are decimal digits. This might be a little confusing -mixing hexidecimal and decimal like that, but it is convenient -to use for debug. - -We make sure we have N (FRACTBITS/4) digits past the decimal point. -*/ -#define FRACTMASK ((1<> FRACTBITS, s); -} - -/* -:h3.DumpSpace() - Display a Coordinate Space -*/ -/*ARGSUSED*/ -void DumpSpace(S) - register struct XYspace *S; -{ - IfTrace4(TRUE,"--Coordinate space at %x,ID=%d,convert=%x,iconvert=%x\n", - S, S->ID, S->convert, S->iconvert); - IfTrace2(TRUE," | %12.3f %12.3f |", - &S->tofract.normal[0][0], &S->tofract.normal[0][1]); - IfTrace2(TRUE," [ %p %p ]\n", S->itofract[0][0], S->itofract[0][1]); - IfTrace2(TRUE," | %12.3f %12.3f |", - &S->tofract.normal[1][0], &S->tofract.normal[1][1]); - IfTrace2(TRUE," [ %p %p ]\n", S->itofract[1][0], S->itofract[1][1]); -}