<> <> <> <> <> <> <> <> <> <> DIRECTORY Basics, IntTransDefs, Real; IntTrans: CEDAR PROGRAM IMPORTS Basics, Real EXPORTS IntTransDefs = BEGIN OPEN IntTransDefs; <> DividedTransform: TYPE = REF DividedTransformRecord _ NIL; DividedTransformRecord: TYPE = RECORD[ type: [ident..translate+rotscale], a11,a21,a12,a22: REAL, a31,a32: INT]; Context: TYPE = IntTransDefs.Transform; T: DividedTransform = NEW[DividedTransformRecord]; <> contextStack: ContextStack _ NIL; TH: Transform = NEW[TransformRecord]; --Top of current context, in homogeneous form LH: Transform = NEW[TransformRecord]; <> inTransforms,needsDivision: BOOLEAN; --state flags Identity: TransformRecord = [ type: ident, a11: 1, a21: 0, a31: 0, a12: 0, a22: 1, a32: 0, a33: 1]; InitTransformation: PUBLIC PROCEDURE RETURNS [BOOLEAN] = <> BEGIN contextStack _ NIL; TH^ _ Identity; LH^ _ Identity; inTransforms _ TRUE; needsDivision _ TRUE; RETURN[TRUE]; END; FinishTransformation: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN RETURN[TRUE]; END; FreezeContext: PUBLIC PROCEDURE RETURNS[cs: ContextStack] = <> BEGIN Push[]; cs _ contextStack; contextStack _ NIL; -- I guess... END; SwapContext: PUBLIC PROCEDURE[cs: ContextStack] = BEGIN contextStack _ cs; Pop[]; END; Push: PUBLIC PROCEDURE = <> BEGIN IF inTransforms THEN Concatenate[LH,TH,TH]; contextStack _ CONS[NEW[TransformRecord _ TH^], contextStack]; LH^ _ Identity; inTransforms _ TRUE; needsDivision _ TRUE; END; Pop: PUBLIC PROCEDURE = <> BEGIN IF contextStack = NIL THEN ERROR TransformationStackUnderflow; TH^ _ contextStack.first^; contextStack _ contextStack.rest; inTransforms _ FALSE; needsDivision _ TRUE; END; Rotate: PUBLIC PROCEDURE[xRot,yRot: INT] = <> BEGIN t: REAL; IF ~inTransforms THEN ERROR TransformationBadContext; BEGIN OPEN LH; SELECT TRUE FROM xRot = 0 => BEGIN t _ -a12; a12 _ a11; a11 _ t; t _ -a22; a22 _ a21; a21 _ t; t _ -a32; a32 _ a31; a31 _ t; IF yRot<0 THEN a33 _ -a33; END; yRot = 0 => IF xRot<0 THEN a33 _ -a33; ENDCASE => BEGIN c: REAL = xRot; s: REAL = yRot; t _ a11*c - a12*s; a12 _ a11*s + a12*c; a11 _ t; t _ a21*c - a22*s; a22 _ a21*s + a22*c; a21 _ t; t _ a31*c - a32*s; a32 _ a31*s + a32*c; a31 _ t; a33 _ a33*Real.SqRt[c*c + s*s]; END; type _ Basics.BITOR[type,rotscale]; END; END; Translate: PUBLIC PROCEDURE[xTrans,yTrans: INT] = <> BEGIN xT: REAL _ xTrans; yT: REAL _ yTrans; IF ~inTransforms THEN ERROR TransformationBadContext; BEGIN OPEN LH; a31 _ a31 + a33*xT; a32 _ a32 + a33*yT; type _ Basics.BITOR[type,translate]; END; END; Mirror: PUBLIC PROCEDURE[coord: CoordName] = <> BEGIN IF ~inTransforms THEN ERROR TransformationBadContext; BEGIN OPEN LH; SELECT coord FROM x => BEGIN a11 _ -a11; a21 _ -a21; a31 _ -a31; END; y => BEGIN a12 _ -a12; a22 _ -a22; a32 _ -a32; END; ENDCASE; type _ Basics.BITOR[type,rotscale]; END; END; Scale: PUBLIC PROCEDURE[numerator,denominator: INT] = <> BEGIN num: REAL _ numerator; denom: REAL _ denominator; IF ~inTransforms THEN ERROR TransformationBadContext; BEGIN OPEN LH; a11 _ a11*num; a21 _ a21*num; a31 _ a31*num; a12 _ a12*num; a22 _ a22*num; a32 _ a32*num; a33 _ a33*denom; type _ Basics.BITOR[type,rotscale]; END; END; GetLocal: PUBLIC PROCEDURE RETURNS[localTransform: TransformRecord] = <> BEGIN RETURN[LH^]; END; local: Transform _ NEW[TransformRecord]; ApplyLocal: PUBLIC PROCEDURE[transform: TransformRecord] = <> BEGIN IF ~inTransforms THEN ERROR TransformationBadContext; local^ _ transform; Concatenate[LH,local,LH]; END; GetCurrent: PUBLIC PROCEDURE RETURNS[currentTransform: TransformRecord] = <> BEGIN IF inTransforms THEN BEGIN Concatenate[LH,TH,TH]; inTransforms _ FALSE; END; RETURN[TH^]; END; TransformPoint: PUBLIC PROCEDURE[x,y: INT] RETURNS[xT,yT: INT] = <> BEGIN SELECT TRUE FROM inTransforms => BEGIN Concatenate[LH,TH,TH]; inTransforms _ FALSE; DivideTransform[TH,T]; needsDivision _ FALSE; END; needsDivision => BEGIN DivideTransform[TH,T]; needsDivision _ FALSE; END; ENDCASE; BEGIN OPEN T; SELECT type FROM ident => BEGIN xT _ x; yT _ y; END; translate => BEGIN xT _ x + a31; yT _ y + a32; END; rotscale => BEGIN X: REAL = x; Y: REAL = y; xT _ Real.Round[X*a11 + Y*a21]; yT _ Real.Round[X*a12 + Y*a22]; END; ENDCASE => BEGIN X: REAL = x; Y: REAL = y; xT _ a31 + Real.Round[X*a11 + Y*a21]; yT _ a32 + Real.Round[X*a12 + Y*a22]; END; END; END; TransformVector: PUBLIC PROCEDURE[x,y: INT] RETURNS[xT,yT: INT] = <> BEGIN SELECT TRUE FROM inTransforms => BEGIN Concatenate[LH,TH,TH]; inTransforms _ FALSE; DivideTransform[TH,T]; needsDivision _ FALSE; END; needsDivision => BEGIN DivideTransform[TH,T]; needsDivision _ FALSE; END; ENDCASE; BEGIN OPEN T; SELECT type FROM ident, translate => BEGIN xT _ x; yT _ y; END; ENDCASE => BEGIN X: REAL = x; Y: REAL = y; xT _ Real.Round[X*a11 + Y*a21]; yT _ Real.Round[X*a12 + Y*a22]; END; END; END; RTransformPoint: PUBLIC PROCEDURE[x,y: REAL] RETURNS[xT,yT: REAL] = <> BEGIN IF inTransforms THEN BEGIN Concatenate[LH,TH,TH]; inTransforms _ FALSE; END; BEGIN OPEN TH; SELECT type FROM ident => BEGIN xT _ x; yT _ y; END; translate => BEGIN xT _ x + a31; yT _ y + a32; END; rotscale => BEGIN xT _ (x*a11 + y*a21)/a33; yT _ (x*a12 + y*a22)/a33; END; ENDCASE => BEGIN xT _ (a31 + x*a11 + y*a21)/a33; yT _ (a32 + x*a12 + y*a22)/a33; END; END; END; RTransformVector: PUBLIC PROCEDURE[x,y: REAL] RETURNS[xT,yT: REAL] = <> BEGIN IF inTransforms THEN BEGIN Concatenate[LH,TH,TH]; inTransforms _ FALSE; END; BEGIN OPEN TH; SELECT type FROM ident, translate => BEGIN xT _ x; yT _ y; END; ENDCASE => BEGIN xT _ (x*a11 + y*a21)/a33; yT _ (x*a12 + y*a22)/a33; END; END; END; Concatenate: PROCEDURE [A,B,C: Transform] = < C, A=C or B=C is OK>> BEGIN SELECT TRUE FROM A.type=ident => IF C#B THEN C^ _ B^; --(not uncommon for ApplyLocal) B.type=ident => IF C#A THEN C^ _ A^; ENDCASE => BEGIN T: TransformRecord; T.a11 _ A.a11*B.a11 + A.a12*B.a21; T.a21 _ A.a21*B.a11 + A.a22*B.a21; T.a31 _ A.a31*B.a11 + A.a32*B.a21 + A.a33*B.a31; T.a12 _ A.a11*B.a12 + A.a12*B.a22; T.a22 _ A.a21*B.a12 + A.a22*B.a22; T.a32 _ A.a31*B.a12 + A.a32*B.a22 + A.a33*B.a32; T.a33 _ A.a33*B.a33; T.type _ Basics.BITOR[A.type,B.type]; C^ _ T; END; END; DivideTransform: PROCEDURE[AH: Transform, A: DividedTransform] = < A>> BEGIN IF AH.a33=1 THEN BEGIN A.a11 _ AH.a11; A.a21 _ AH.a21; A.a31 _ Real.Round[AH.a31]; A.a12 _ AH.a12; A.a22 _ AH.a22; A.a32 _ Real.Round[AH.a32]; END ELSE BEGIN ah33: REAL = AH.a33; A.a11 _ AH.a11/ah33; A.a21 _ AH.a21/ah33; A.a31 _ Real.Round[AH.a31/ah33]; A.a12 _ AH.a12/ah33; A.a22 _ AH.a22/ah33; A.a32 _ Real.Round[AH.a32/ah33]; END; A.type _ AH.type; END; TransformationStackUnderflow: PUBLIC ERROR = CODE; TransformationBadContext: PUBLIC ERROR = CODE; END.