File: SVCoordSys2dImpl.mesa
Last edited by Bier on January 28, 1987 2:21:11 pm PST
Contents: Routines for manipulating coordinate systems with respect to each other in 2 dimensions. Unlike Coordsystems which are told about WORLD and CAMERA at draw time, CoordSystem2d's are told about Pad every time they are updated. This only makes sense if the updated coordsys has no sons. The general case will be implemented later.
DIRECTORY
SV2d, SVCoordSys2d, SVMatrix2d, SVModelTypes, SVVector2d;
SVCoordSys2dImpl: CEDAR PROGRAM
IMPORTS SVMatrix2d, SVVector2d
EXPORTS SVCoordSys2d =
BEGIN
Matrix3by3: TYPE = SV2d.Matrix3by3;
Point2d: TYPE = SV2d.Point2d;
Vector2d: TYPE = SVVector2d.Vector2d;
CoordSystem2d: TYPE = REF CoordSystem2dObj;
CoordSystem2dObj: TYPE = SVModelTypes.CoordSystem2dObj;
TellCoordSysAboutPad:
PUBLIC
PROC [cs: CoordSystem2d] = {
cs.localWRTPad ← FindInTermsOfPad[cs];
cs.padWRTLocal ← SVMatrix2d.Inverse[cs.localWRTPad];
};
CreateCoordSys:
PUBLIC
PROC [mat: Matrix3by3, withRespectTo: CoordSystem2d]
RETURNS [newCS: CoordSystem2d] = {
newCS ← NEW[CoordSystem2dObj];
newCS.mat ← mat;
newCS.localWRTPad ← SVMatrix2d.Identity[];
newCS.padWRTLocal ← SVMatrix2d.Identity[];
newCS.withRespectTo ← withRespectTo;
TellCoordSysAboutPad[newCS];
};
PadToScreen:
PUBLIC
PROC [padPoint: Point2d, screen: CoordSystem2d]
RETURNS [screenPoint: Point2d] = {
screenPoint ← SVMatrix2d.Update[screen.localWRTPad, padPoint];
};
ScreenToPad:
PUBLIC
PROC [screenPoint: Point2d, screen: CoordSystem2d]
RETURNS [padPoint: Point2d] = {
padPoint ← SVMatrix2d.Update[screen.padWRTLocal, padPoint];
};
FindInTermsOfPad:
PUBLIC
PROC [cs: CoordSystem2d]
RETURNS [mat: Matrix3by3] = {
thisCS, nextCS: CoordSystem2d;
thisCS ← cs;
IF thisCS = NIL THEN RETURN [SVMatrix2d.Identity[]];
mat ← cs.mat;
UNTIL thisCS.withRespectTo =
NIL
DO
nextCS ← thisCS.withRespectTo;
mat ← SVMatrix2d.MatMult[nextCS.mat, mat];
thisCS ← nextCS;
ENDLOOP;
};
FindAinTermsOfB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d]
RETURNS [aInTermsOfb: Matrix3by3] = {
aPad, bPad: Matrix3by3;
aPad ← FindInTermsOfPad[a];
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aInTermsOfb ← SVMatrix2d.WorldToLocal[bPad,aPad];
};
FindTranslationOfAinTermsOfB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d]
RETURNS [displacements: Vector2d] = {
aInTermsOfb: Matrix3by3;
IF b = NIL THEN aInTermsOfb ← FindInTermsOfPad[a]
ELSE aInTermsOfb ← FindAinTermsOfB[a, b];
displacements ← SVMatrix2d.OriginOfMatrix[aInTermsOfb];
};
PutAinTermsOfB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d]
RETURNS [aInTermsOfb: Matrix3by3] = {
Finds the matrix and redefines CoordSystem a to be in terms of b from now on.
aPad, bPad: Matrix3by3;
aPad ← FindInTermsOfPad[a];
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aInTermsOfb ← SVMatrix2d.WorldToLocal[bPad,aPad];
a.withRespectTo ← b;
a.mat ← aInTermsOfb;
TellCoordSysAboutPad[a];
};
PlaceAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL, aWRTb: Matrix3by3] = {
Places a in PAD so that the transform from b to a is aWRTb. Updates a with respect to its immediate reference (a.withRespectTo) accordingly.
aPad, bPad, withRespectToPad, aInTermsOfWRT: Matrix3by3;
withRespectTo: CoordSystem2d;
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aPad ← SVMatrix2d.MatMult[bPad, aWRTb];
withRespectTo ← a.withRespectTo;
withRespectToPad ← FindInTermsOfPad[withRespectTo];
aInTermsOfWRT ← SVMatrix2d.WorldToLocal[withRespectToPad, aPad];
a.mat ← aInTermsOfWRT;
TellCoordSysAboutPad[a];
};
PlaceTranslationAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL, origin: Point2d] = {
Places a in PAD so that the rotation from a to b remains as it is, but the translation is set to origin. Updates a with respect to its immediate reference (a.withRespectTo) accordingly.
aWRTb: Matrix3by3 ← FindAinTermsOfB[a, b];
aPad, bPad, withRespectToPad, aInTermsOfWRT: Matrix3by3;
withRespectTo: CoordSystem2d;
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aWRTb[1][3] ← origin[1];
aWRTb[2][3] ← origin[2];
aPad ← SVMatrix2d.MatMult[bPad, aWRTb];
withRespectTo ← a.withRespectTo;
withRespectToPad ← FindInTermsOfPad[withRespectTo];
aInTermsOfWRT ← SVMatrix2d.WorldToLocal[withRespectToPad, aPad];
a.mat ← aInTermsOfWRT;
TellCoordSysAboutPad[a];
};
TranslateAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL, tx, ty:
REAL] = {
aPad, bPad, aInTermsOfb, newAWorld, withRespectToWorld, aInTermsOfWRT: Matrix3by3;
withRespectTo: CoordSystem2d;
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aPad ← FindInTermsOfPad[a];
aInTermsOfb ← IF a = b THEN SVMatrix2d.Identity[]
ELSE SVMatrix2d.WorldToLocal[bPad, aPad];
aInTermsOfb ← SVMatrix2d.Translate[aInTermsOfb, tx, ty]; -- must be a global translate.
newAWorld ← SVMatrix2d.MatMult[bPad, aInTermsOfb];
withRespectTo ← a.withRespectTo;
withRespectToWorld ← FindInTermsOfPad[withRespectTo];
aInTermsOfWRT ← SVMatrix2d.WorldToLocal[withRespectToWorld, newAWorld];
a.mat ← aInTermsOfWRT;
TellCoordSysAboutPad[a];
};
RotateCCWAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL, degrees:
REAL] = {
aPad, bPad, aInTermsOfb, newAWorld, withRespectToPad, aInTermsOfWRT: Matrix3by3;
withRespectTo: CoordSystem2d;
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aPad ← FindInTermsOfPad[a];
aInTermsOfb ← IF a = b THEN SVMatrix2d.Identity[]
ELSE SVMatrix2d.WorldToLocal[bPad,aPad];
aInTermsOfb ← SVMatrix2d.RotateCCW[aInTermsOfb, degrees]; -- must be a global translate.
newAWorld ← SVMatrix2d.MatMult[bPad, aInTermsOfb];
withRespectTo ← a.withRespectTo;
withRespectToPad ← FindInTermsOfPad[withRespectTo];
aInTermsOfWRT ← SVMatrix2d.WorldToLocal[withRespectToPad, newAWorld];
a.mat ← aInTermsOfWRT;
TellCoordSysAboutPad[a];
};
IndicesOfMax:
PRIVATE
PROC [v: Vector2d]
RETURNS [indices:
ARRAY[1..2]
OF
NAT, negArray:
ARRAY[1..2]
OF
BOOL] = {
Bubble sort
temp: REAL;
tempIndex: NAT;
IF v[1] < 0 THEN {negArray[1] ← TRUE; v[1] ← -v[1]}
ELSE negArray[1] ← FALSE;
IF v[2] < 0 THEN {negArray[2] ← TRUE; v[2] ← -v[2]}
ELSE negArray[2] ← FALSE;
indices ← [1,2];
IF v[1] < v[2]
THEN {
temp ← v[1]; v[1] ← v[2]; v[2] ← temp;
tempIndex ← indices[1]; indices[1] ← indices[2]; indices[2] ← tempIndex};
};
AlignAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL] = {
Rotate A as little as possible to align its two axes parallel to two of the axes of B (though not necessarily the same two).
aPad, bPad, aInTermsOfb, newAPad, withRespectToPad, aInTermsOfWRT: Matrix3by3;
withRespectTo: CoordSystem2d;
xAxisChoices: ARRAY[1..2] OF NAT;
xAxis, newXAxis, yAxis, newYAxis: Vector2d;
xNegArray: ARRAY[1..2] OF BOOL;
origin: Point2d;
angle: REAL;
IF b = NIL THEN bPad ← SVMatrix2d.Identity[]
ELSE bPad ← FindInTermsOfPad[b];
aPad ← FindInTermsOfPad[a];
aInTermsOfb ← IF a = b THEN SVMatrix2d.Identity[] ELSE
SVMatrix2d.WorldToLocal[bPad,aPad];
xAxis ← SVMatrix2d.XAxisOfMatrix[aInTermsOfb];
yAxis ← SVMatrix2d.YAxisOfMatrix[aInTermsOfb];
origin ← SVMatrix2d.OriginOfMatrix[aInTermsOfb];
angle ← SVVector2d.SmallestAngleBetweenVectors[xAxis, yAxis];
[xAxisChoices, xNegArray] ← IndicesOfMax[xAxis];
-- Find largest component
This is the new x axis direction.
newXAxis ← [0,0];
newXAxis[xAxisChoices[1]] ← SVVector2d.Magnitude[xAxis];
IF xNegArray[xAxisChoices[1]]
THEN newXAxis[xAxisChoices[1]] ← -newXAxis[xAxisChoices[1]];
newYAxis ← SVVector2d.VectorPlusAngle[newXAxis, angle];
Preserve angle between x axis and y axis
newYAxis ← SVVector2d.Scale[newYAxis, SVVector2d.Magnitude[yAxis]];
Preserve magnitude of axes
aInTermsOfb ← SVMatrix2d.MakeMatFromAxes[newXAxis, newYAxis, origin];
newAPad ← SVMatrix2d.MatMult[bPad, aInTermsOfb];
withRespectTo ← a.withRespectTo;
withRespectToPad ← FindInTermsOfPad[withRespectTo];
aInTermsOfWRT ← SVMatrix2d.WorldToLocal[withRespectToPad, newAPad];
a.mat ← aInTermsOfWRT;
TellCoordSysAboutPad[a];
};
AbutAwrtB:
PUBLIC
PROC [a: CoordSystem2d, b: CoordSystem2d ←
NIL] = {
Equivalent to PlaceTranslationAwrtB where origin = [0, 0]
PlaceTranslationAwrtB[a, b, [0, 0]];
};
These perform the named transform but do not change the coordinate system with respect to which CoordSystem a is defined.
When b is NIL, assumes b = PAD.
For local transforms, let b = a.
END.