DIRECTORY RealFns, SV2d, SVMatrix2d, SVVector2d; SVMatrix2dImpl: CEDAR PROGRAM IMPORTS RealFns, SVVector2d EXPORTS SVMatrix2d = BEGIN Matrix3by3: TYPE = ARRAY [1..3] OF ARRAY [1..3] OF REAL; Matrix2by2: TYPE = ARRAY [1..2] OF ARRAY [1..2] OF REAL; Point2d: TYPE = SV2d.Point2d; Vector2d: TYPE = SVVector2d.Vector2d; Identity: PUBLIC PROC [] RETURNS [identityMat: Matrix3by3] = { FOR i: NAT IN [1..3] DO FOR j: NAT IN [1..3] DO identityMat[i][j] _ IF i = j THEN 1 ELSE 0; ENDLOOP; ENDLOOP; }; Update: PUBLIC PROC [mat: Matrix3by3, point: Point2d] RETURNS [newPoint: Point2d] = { FOR i: NAT IN [1..2] DO newPoint[i] _ mat[i][1]*point[1] + mat[i][2]*point[2] + mat[i][3]; ENDLOOP; }; UpdateVector: PUBLIC PROC [mat: Matrix3by3, vec: Vector2d] RETURNS [newVec: Vector2d] = { FOR i: NAT IN [1..2] DO newVec[i] _ mat[i][1]*vec[1] + mat[i][2]*vec[2]; ENDLOOP; }; Scale: PUBLIC PROC [mat: Matrix3by3, sx, sy: REAL] RETURNS [transMat: Matrix3by3] = { FOR j: NAT IN[1..3] DO transMat[1][j] _ mat[1][j]*sx; ENDLOOP; FOR j: NAT IN[1..3] DO transMat[2][j] _ mat[2][j]*sy; ENDLOOP; transMat[3][1] _ transMat[3][2] _ 0.0; transMat[3][3] _ 1.0; }; Translate: PUBLIC PROC [mat: Matrix3by3, dx, dy: REAL] RETURNS [transMat: Matrix3by3] = { i, j: CARDINAL; FOR i IN [1..3] DO-- in the first two columns, the elements are copied FOR j IN [1..2] DO transMat[i][j] _ mat[i][j]; ENDLOOP; ENDLOOP; transMat[1][3] _ mat[1][3] + dx;-- add the translation offset to the last row transMat[2][3] _ mat[2][3] + dy; transMat[3][3] _ 1.0; }; RotateCCW: PUBLIC PROC [mat: Matrix3by3, degrees: REAL] RETURNS [transMat: Matrix3by3] = { sind: REAL _ RealFns.SinDeg[degrees]; cosd: REAL _ RealFns.CosDeg[degrees]; rotMat: Matrix3by3 _ Identity[]; rotMat[1][1] _ rotMat[2][2] _ cosd; rotMat[1][2] _ -sind; rotMat[2][1] _ sind; transMat _ MatMult[rotMat, mat]; }; LocalScale: PUBLIC PROC [mat: Matrix3by3, sx, sy: REAL] RETURNS [transMat: Matrix3by3] = { FOR i: NAT IN[1..2] DO transMat[i][1] _ mat[i][1]*sx; ENDLOOP; FOR i: NAT IN[1..2] DO transMat[i][2] _ mat[i][2]*sy; ENDLOOP; FOR i: NAT IN[1..2] DO transMat[i][3] _ mat[i][3]; ENDLOOP; transMat[3][1] _ transMat[3][2] _ 0.0; transMat[3][3] _ 1.0; }; LocalTranslate: PUBLIC PROC [mat: Matrix3by3, dx, dy: REAL] RETURNS [transMat: Matrix3by3] = { i, j: CARDINAL; FOR i IN [1..3] DO-- in the first two columns, the elements are copied FOR j IN [1..2] DO transMat[i][j] _ mat[i][j]; ENDLOOP; ENDLOOP; transMat[1][3] _ mat[1][1]*dx + mat[1][2]*dy + mat[1][3]; transMat[2][3] _ mat[2][1]*dx + mat[2][2]*dy + mat[2][3]; transMat[3][3] _ 1.0; }; LocalRotateCCW: PUBLIC PROC [mat: Matrix3by3, degrees: REAL] RETURNS [transMat: Matrix3by3] = { sind: REAL _ RealFns.SinDeg[degrees]; cosd: REAL _ RealFns.CosDeg[degrees]; rotMat: Matrix3by3 _ Identity[]; rotMat[1][1] _ rotMat[2][2] _ cosd; rotMat[1][2] _ -sind; rotMat[2][1] _ sind; transMat _ MatMult[mat, rotMat]; }; MatMult: PUBLIC PROC [left, right: Matrix3by3] RETURNS [transMat: Matrix3by3] = { i, j: CARDINAL; FOR i IN [1..2] DO-- The last row is always [0 0 1] FOR j IN [1..2] DO-- In the first two columns, the last element is always zero transMat[i][j] _ left[i][1]*right[1][j] + left[i][2]*right[2][j]; ENDLOOP; ENDLOOP; FOR i IN [1..2] DO-- calculate the last column transMat[i][3] _ left[i][1]*right[1][3] + left[i][2]*right[2][3] + left[i][3]; ENDLOOP; transMat[3][1] _ transMat[3][2] _ 0;-- Last row transMat[3][3] _ 1.0; }; MakeScaleMat: PUBLIC PROC [sx, sy: REAL] RETURNS [scale: Matrix3by3] = { scale _ Identity[]; scale[1][1] _ sx;scale[2][2] _ sy; }; MakeTranslateMat: PUBLIC PROC [dx, dy: REAL] RETURNS [trans: Matrix3by3] = { trans _ Identity[]; trans[1][3] _ dx;trans[2][3] _ dy; }; MakeRotateCCWMat: PUBLIC PROC [degrees: REAL] RETURNS [rot: Matrix3by3] = { sind: REAL _ RealFns.SinDeg[degrees]; cosd: REAL _ RealFns.CosDeg[degrees]; rot _ Identity[]; rot[1][1] _ rot[2][2] _ cosd; rot[1][2] _ -sind; rot[2][1] _ sind; }; MakeMatFromAxes: PUBLIC PROC [xAxis, yAxis: Vector2d, origin: Point2d] RETURNS [mat: Matrix3by3] = { FOR i: NAT IN[1..2] DO mat[i][1] _ xAxis[i]; mat[i][2] _ yAxis[i]; mat[i][3] _ origin[i]; ENDLOOP; mat[3][1] _ mat[3][2] _ 0; mat[3][3] _ 1; }; ScaleFromMatrix: PUBLIC PROC [mat: Matrix3by3] RETURNS [sx, sy: REAL] = { sx _ SVVector2d.Magnitude[[mat[1][1],mat[2][1]]]; sy _ SVVector2d.Magnitude[[mat[1][2],mat[2][2]]]; }; OriginOfMatrix: PUBLIC PROC [mat: Matrix3by3] RETURNS [origin: Point2d] = { origin[1] _ mat[1][3]; origin[2] _ mat[2][3]; }; XAxisOfMatrix: PUBLIC PROC [mat: Matrix3by3] RETURNS [xAxis: Vector2d] = { xAxis[1] _ mat[1][1]; xAxis[2] _ mat[2][1]; }; YAxisOfMatrix: PUBLIC PROC [mat: Matrix3by3] RETURNS [yAxis: Vector2d] = { yAxis[1] _ mat[1][2]; yAxis[2] _ mat[2][2]; }; RotationOfMatrix: PUBLIC PROC [mat: Matrix3by3] RETURNS [degrees: REAL] = { cos, sin: REAL; xAxis, yAxis: Vector2d; xAxis _ XAxisOfMatrix[mat]; yAxis _ YAxisOfMatrix[mat]; xAxis _ SVVector2d.Normalize[xAxis]; yAxis _ SVVector2d.Normalize[yAxis]; cos _ SVVector2d.DotProduct[xAxis, [1,0]]; sin _ - SVVector2d.DotProduct[yAxis, [1,0]]; degrees _ RealFns.ArcTanDeg[sin, cos]; }; Determinant: PUBLIC PROC [mat: Matrix3by3] RETURNS [det: REAL] = { det _ mat[1][1]*mat[2][2]*mat[3][3] + mat[2][1]*mat[3][2]*mat[1][3] + mat[3][1]*mat[1][2]*mat[2][3] - (mat[3][1]*mat[2][2]*mat[1][3] + mat[2][1]*mat[1][2]*mat[3][3] + mat[1][1]*mat[3][2]*mat[2][3]); }; Determinant2by2: PRIVATE PROC [mat: Matrix2by2] RETURNS [det: REAL] = { det _ mat[1][1]*mat[2][2] - mat[2][1]*mat[1][2]; }; Transpose: PUBLIC PROC [mat: Matrix3by3] RETURNS [matT: Matrix3by3] = { FOR i: NAT IN[1..3] DO FOR j: NAT IN[1..3] DO matT[i][j] _ mat[j][i]; ENDLOOP; ENDLOOP; }; Cofactor: PUBLIC PROC [mat: Matrix3by3, row, col: NAT] RETURNS [cof: REAL] = { rowCount, colCount: NAT; exponent: NAT; m2: Matrix2by2; rowCount _ 0; FOR i: NAT IN[1..3] DO IF i = row THEN LOOP; rowCount _ rowCount + 1; colCount _ 0; FOR j: NAT IN[1..3] DO IF j = col THEN LOOP; colCount _ colCount + 1; m2[rowCount][colCount] _ mat[i][j]; ENDLOOP; ENDLOOP; cof _ Determinant2by2[m2]; exponent _ row+col; IF (exponent/2)*2 # exponent THEN cof _ -cof; }; Inverse: PUBLIC PROC [mat: Matrix3by3] RETURNS [inverse: Matrix3by3] = { det: REAL _ Determinant[mat]; IF det = 0 THEN SIGNAL DegenerateInverse; FOR i: NAT IN[1..2] DO FOR j: NAT IN[1..3] DO inverse[i][j] _ Cofactor[mat,j,i]/det; -- transpose as you do it ENDLOOP; ENDLOOP; inverse[3][1] _ inverse[3][2] _ 0.0; inverse[3][3] _ 1.0; -- these would also be the calculated values if we did them in the loop }; DegenerateInverse: PUBLIC SIGNAL = CODE; WorldToLocal: PUBLIC PROC [AinWorld,BinWorld: Matrix3by3] RETURNS [BinTermsOfA: Matrix3by3] = { worldAInverse: Matrix3by3 _ Inverse[AinWorld]; BinTermsOfA _ MatMult[worldAInverse, BinWorld]; }; END. (File: SVMatrix2dImpl.mesa Last edited by Bier on June 1, 1984 4:41:36 pm PDT Author: Eric Bier on January 28, 1987 2:25:18 pm PST Contents: My own package for manipulating Homogenous 3 x 3 matrices. Parallels SVMatrix3d in many places | x' | | (1,1) (1,2) (1,3) | | x | | y' | = | (2,1) (2,2) (2,3) | | y | | 1 | | 0 0 1 | | 1 | vectors can be rotated and scaled, but not translated The next three procedures perform an efficient matrix multiplication as though mat were being multiplied to its left (a transform in reference coordinates) by a matrix which translates or rotates respectively (See Paul). The next three procedures perform an efficient matrix multiplication as though mat were being multiplied on its right (a transform in local coordinates) by a matrix which translates or rotates respectively (See Paul). MatMult is almost a general 3 by 3 matrix operation. However, it assumes that the last row of each matrix is [0 0 1]. Finds out how much this matrix will scale an object it is applied to Take the dot product of normalized xAxis with [1,0]. This should be cosine. Take the dot product of normalized yAxis with [1,0]. This should be - sine. Find the arctan. Interchange rows and columns Returns the determinant of the 2 by 2 matrix which results by crossing off row row and column col in mat. Inverts any matrix of the given form (even with scaling). Find the matrix of Cofactors, transpose it and divide by the determinant Clearly (AinWorld)(BinTermsOfA) = BinWorld; Hence BinTermsOfA = (Inverse[AinWorld])(BinWorld); Κ M˜Iheadšœ™Jšœ2™2Jšœ4™4Jšœi™iJ˜šΟk ˜ Jšœ&˜&—J˜Jšœ ˜Jšœ˜Jšœ ˜Jš˜˜Jš œ œœœœœœ˜8Jš œ œœœœœœ˜8Jšœ œ˜Jšœ œ˜%J˜—šΟnœœœœ˜>šœœœ˜šœœœ˜Jšœœœœ˜+—Jšœ˜—Jšœ˜Jšœ˜—J˜šžœœœ#œ˜UIblockšœ"™"Lšœ%™%Lšœ#™#šœœœ˜JšœB˜B—Jšœ˜Jšœ˜—šž œœœ"œ˜YJšœ5™5šœœœ˜Jšœ0˜0—Jšœ˜Jšœ˜—˜Jšœέ™έ—š žœœœœœ˜Ušœœœ˜Jšœ˜—Jšœ˜šœœœ˜Jšœ˜—Jšœ˜Jšœ&˜&Jšœ˜Jšœ˜—š ž œœœœœ˜YJ˜Jšœœ˜šœœΟc4˜Fšœœ˜Jšœ˜—Jšœ˜—Jšœ˜Jšœ Ÿ-˜MJšœ ˜ Jšœ˜Jšœ˜—š ž œœœœœ˜ZJšœœ˜&Jšœœ˜%Jšœ ˜ Jšœ#˜#Jšœ*˜*Jšœ ˜ Jšœ˜—˜JšœΪ™Ϊ—š ž œœœœœ˜Zšœœœ˜Jšœ˜—Jšœ˜šœœœ˜Jšœ˜—Jšœ˜šœœœ˜Jšœ˜—Jšœ˜Jšœ&˜&Jšœ˜Jšœ˜—š žœœœœœ˜^Jšœœ˜šœœŸ4˜Fšœœ˜Jšœ˜—Jšœ˜—Jšœ˜Jšœ9˜9Jšœ9˜9Jšœ˜Jšœ˜—š žœœœœœ˜_Jšœœ˜&Jšœœ˜%Jšœ ˜ Jšœ#˜#Jšœ*˜*Jšœ ˜ Jšœ˜—J˜šžœœœœ˜QIprocšœv™vM˜Mšœœ˜šœœŸ!˜3šœœŸ<˜NMšœA˜A—Mšœ˜—Jšœ˜šœœŸ˜.JšœO˜O—Jšœ˜Jšœ$Ÿ ˜/Jšœ˜Jšœ˜—Jšœ˜š ž œœœ œœ˜HJšœ˜Jšœ"˜"Jšœ˜—š žœœœ œœ˜LJšœ˜Jšœ"˜"Jšœ˜—š žœœœ œœ˜KJšœœ˜%Jšœœ˜%Jšœ˜Jšœ˜Jšœ$˜$Jšœ˜—šžœœœ+œ˜dšœœœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ˜Jšœ*˜*Jšœ˜—J˜J˜š žœœœœ œ˜IJšœ1˜1Jšœ1˜1JšœD™DJšœ˜—šžœœœœ˜KJšœ˜Jšœ˜Jšœ˜—šž œœœœ˜JJšœ˜Jšœ˜Jšœ˜—šž œœœœ˜JJšœ˜Jšœ˜Jšœ˜—š žœœœœ œ˜KJšœL™LJšœL™LJšœ™Jšœ œ˜Jšœ˜Jšœ˜Jšœ˜Jšœ$˜$Jšœ$˜$Jšœ*˜*Jšœ,˜,Jšœ&˜&Jšœ˜—J˜š ž œœœœœ˜BJšœ%˜%Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜—š žœœœœœ˜GJšœ0˜0Jšœ˜—J˜šž œœœœ˜GJšœ™šœœœ˜šœœœ˜Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—š žœœœœœœ˜NJšœi™iJšœœ˜Jšœ œ˜Jšœ˜Jšœ ˜ šœœœ˜Jšœ œœ˜Jšœ˜Jšœ ˜ šœœœ˜Jšœ œœ˜Jšœ˜Jšœ#˜#—Jšœ˜—Jšœ˜Jšœ˜Jšœ˜Jšœœ ˜-Jšœ˜—šžœœœœ˜HJšœƒ™ƒJšœœ˜Jšœ œœ˜)šœœœ˜šœœœ˜Jšœ'Ÿ˜@—Jšœ˜—Jšœ˜Jšœ$˜$JšœŸG˜\Jšœ˜—Jšœœœœ˜(J˜šž œœœ!œ˜_šœ4™4Jšœ2™2Jšœ.˜.Jšœ/˜/Jšœ˜——J˜Jšœ˜J˜J˜—…—^*Σ