DIRECTORY
CoordSys,
Matrix3d,
Rope,
SV3d,
SVError,
SVModelTypes,
SVSceneTypes,
SVTransforms,
SVVector3d;

SVTransformsImpl: PROGRAM
IMPORTS CoordSys, Matrix3d, Rope, SVError, SVVector3d
EXPORTS SVTransforms =
BEGIN

Assembly: TYPE = SVSceneTypes.Assembly;
AssemblyList: TYPE = SVSceneTypes.AssemblyList;
Camera: TYPE = SVModelTypes.Camera;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
CoordSysList: TYPE = SVModelTypes.CoordSysList;
Matrix4by4: TYPE = SV3d.Matrix4by4;
Point3d: TYPE = SV3d.Point3d;
Scene: TYPE = SVSceneTypes.Scene;
Shape: TYPE = SVSceneTypes.Shape;
Vector: TYPE = SV3d.Vector;


IncTransf: PUBLIC PROC [C: CoordSystem, D: CoordSystem, M: Matrix4by4, DFixed: BOOL _ FALSE] = {
P: CoordSystem;

IF C.parent = NIL THEN ERROR; -- cannot translate WORLD for now
IF D = NIL THEN ERROR;
P _ C.parent;
IF MatrixHasScaling[M] THEN {
SVError.Append["SVTransform.IncTransf got illegal matrix.  Ignored."];
SVError.Blink[];
RETURN};

SELECT TRUE FROM
D.parent = NIL => { -- D = WORLD
CWORLD, WORLDP, PWORLD: Matrix4by4;
CWORLD _ CoordSys.FindInTermsOfWorld[C];
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
C.mat _ Matrix3d.MatMult[Matrix3d.MatMult[WORLDP, M], CWORLD];
};
C = D => { -- local tranformation
C.mat _ Matrix3d.MatMult[C.mat, M];
};
D = P => { -- transformation relative to parent
C.mat _ Matrix3d.MatMult[M, C.mat];
};
ENDCASE => { -- general transformation
CWORLD, DWORLD, CD, WORLDP, PWORLD: Matrix4by4;
CWORLD _ CoordSys.FindInTermsOfWorld[C];
DWORLD _ CoordSys.FindInTermsOfWorld[D]; -- we will preserve this relationship if DFixed
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
CD _ CoordSys.FindAInTermsOfB[C, D];
C.mat _ Matrix3d.MatMult[Matrix3d.MatMult[Matrix3d.MatMult[WORLDP, DWORLD], M], CD];
IF DFixed THEN {
DPWORLD, DDP: Matrix4by4;
DPWORLD _ CoordSys.FindInTermsOfWorld[D.parent];
DDP _ Matrix3d.WorldToLocal[DPWORLD, DWORLD];
D.mat _ DDP;
};
};
};

IncTransfMatrix: PUBLIC PROC [C: CoordSystem, DWORLD: Matrix4by4, M: Matrix4by4] = {
P: CoordSystem;
CWORLD, CD, WORLDP, PWORLD: Matrix4by4;

IF C.parent = NIL THEN ERROR; -- cannot translate WORLD for now
P _ C.parent;
IF MatrixHasScaling[M] THEN {
SVError.Append["SVTransform.IncTransfMatrix got illegal matrix.  Ignored."];
SVError.Blink[];
RETURN};

CWORLD _ CoordSys.FindInTermsOfWorld[C];
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
CD _ Matrix3d.WorldToLocal[DWORLD, CWORLD];
C.mat _ Matrix3d.MatMult[Matrix3d.MatMult[Matrix3d.MatMult[WORLDP, DWORLD], M], CD];
};


PlaneOriginRotate: PUBLIC PROC [C: CoordSystem, D: CoordSystem, degrees: REAL, plane: NAT] = {
M, PivotWORLD, CWORLD, DWORLD: Matrix4by4;
origin: Point3d;
xAxis, yAxis, zAxis: Vector;

CWORLD _ CoordSys.FindInTermsOfWorld[C];
DWORLD _ CoordSys.FindInTermsOfWorld[D];
origin _ Matrix3d.OriginOfMatrix[CWORLD];
xAxis _ Matrix3d.XAxisOfMatrix[DWORLD];
yAxis _ Matrix3d.YAxisOfMatrix[DWORLD];
zAxis _ Matrix3d.ZAxisOfMatrix[DWORLD];
PivotWORLD _ Matrix3d.MakeMatFromAxes[xAxis, yAxis, zAxis, origin];

SELECT plane FROM
1 => M _ Matrix3d.MakeRotateXMat[degrees];
2 => M _ Matrix3d.MakeRotateYMat[degrees];
3 => M _ Matrix3d.MakeRotateZMat[degrees];
ENDCASE => ERROR;
IncTransfMatrix[C, PivotWORLD, M];
};

AbsTransf: PUBLIC PROC [C: CoordSystem, D: CoordSystem, N: Matrix4by4, DFixed: BOOL _ FALSE] = {
P: CoordSystem;

IF Rope.Equal[C.name, "SCREEN", TRUE] THEN {C.mat _ N; RETURN};
IF C.parent = NIL THEN ERROR; -- cannot transform WORLD.
IF D = NIL THEN ERROR;
P _ C.parent;
IF MatrixHasScaling[N] THEN {
SVError.Append["SVTransform.AbsTransf got illegal matrix.  Ignored."];
SVError.Blink[];
RETURN};

SELECT TRUE FROM
D.parent = NIL => { -- D = WORLD
WORLDP, PWORLD: Matrix4by4;
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
C.mat _ Matrix3d.MatMult[WORLDP, N];
};
C = D => { -- local tranformation
C.mat _ Matrix3d.MatMult[C.mat, N];
};
D = P => { -- transformation relative to parent
C.mat _ N;
};
ENDCASE => { -- general transformation
DWORLD, WORLDP, PWORLD: Matrix4by4;
DWORLD _ CoordSys.FindInTermsOfWorld[D];
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
C.mat _ Matrix3d.MatMult[Matrix3d.MatMult[WORLDP, DWORLD], N];
IF DFixed THEN {
DPWORLD, DDP: Matrix4by4;
DPWORLD _ CoordSys.FindInTermsOfWorld[D.parent];
DDP _ Matrix3d.WorldToLocal[DPWORLD, DWORLD];
D.mat _ DDP;
};
};
};

TugTransf: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem, N: Matrix4by4] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
AbsTransf[tugBoat, D, N];
AbsTransf[C, tugBoat, F];
};

TugTransfLeaveTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem, N: Matrix4by4] = {
F: Matrix4by4;
saveTugMat: Matrix4by4 _ tugBoat.mat;

F _ CoordSys.FindAInTermsOfB[C, tugBoat];
AbsTransf[tugBoat, D, N];
AbsTransf[C, tugBoat, F];
tugBoat.mat _ saveTugMat;
};


Translate: PUBLIC PROC [C: CoordSystem, D: CoordSystem, tx, ty, tz: REAL, DFixed: BOOL _ FALSE] = {
M: Matrix4by4;
M _ Matrix3d.MakeTranslateMat[tx, ty, tz];
IncTransf[C, D, M, DFixed];
};

XRotate: PUBLIC PROC [C: CoordSystem, D: CoordSystem, degrees: REAL, DFixed: BOOL _ FALSE] = {
M: Matrix4by4;
M _ Matrix3d.MakeRotateXMat[degrees];
IncTransf[C, D, M, DFixed];
};

YRotate: PUBLIC PROC [C: CoordSystem, D: CoordSystem, degrees: REAL, DFixed: BOOL _ FALSE] = {
M: Matrix4by4;
M _ Matrix3d.MakeRotateYMat[degrees];
IncTransf[C, D, M, DFixed];
};

ZRotate: PUBLIC PROC [C: CoordSystem, D: CoordSystem, degrees: REAL, DFixed: BOOL _ FALSE] = {
M: Matrix4by4;
M _ Matrix3d.MakeRotateZMat[degrees];
IncTransf[C, D, M, DFixed];
};


AbsTranslateOnly: PUBLIC PROC [C: CoordSystem, D: CoordSystem, vD: Point3d] = {
P: CoordSystem; -- parent of C
vP: Vector;

IF Rope.Equal[C.name, "SCREEN", TRUE] THEN {
C.mat[1][4] _ vD[1];
C.mat[2][4] _ vD[2];
C.mat[3][4] _ vD[3];
RETURN};
IF C.parent = NIL THEN ERROR; -- cannot transform WORLD.
IF D = NIL THEN ERROR;
P _ C.parent;

SELECT TRUE FROM
D.parent = NIL => { -- D = WORLD
WORLDP, PWORLD: Matrix4by4;
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
vP _ Matrix3d.Update[WORLDP, vD];
C.mat[1][4] _ vP[1];
C.mat[2][4] _ vP[2];
C.mat[3][4] _ vP[3];
};
C = D => { -- local tranformation
C.mat _ Matrix3d.LocalTranslate[C.mat, vD[1], vD[2], vD[3]];
};
D = P => { -- transformation relative to parent
C.mat[1][4] _ vD[1];
C.mat[2][4] _ vD[2];
C.mat[3][4] _ vD[3];
};
ENDCASE => { -- general transformation
DWORLD, WORLDP, PWORLD: Matrix4by4;
DWORLD _ CoordSys.FindInTermsOfWorld[D];
PWORLD _ CoordSys.FindInTermsOfWorld[P];
WORLDP _ Matrix3d.Inverse[PWORLD];
vP _ Matrix3d.Update[WORLDP, Matrix3d.Update[DWORLD, vD]];
C.mat[1][4] _ vP[1];
C.mat[2][4] _ vP[2];
C.mat[3][4] _ vP[3];
};
};

Align: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
CD: Matrix4by4;
xAxisChoices, zAxisChoices: ARRAY[1..3] OF NAT;
xAxis, zAxis, newXAxis, newYAxis, newZAxis: Vector;
xNegArray, zNegArray: ARRAY[1..3] OF BOOL;
origin: Point3d;

CD _ CoordSys.FindAInTermsOfB[C, D];

xAxis _ Matrix3d.XAxisOfMatrix[CD];
zAxis _ Matrix3d.ZAxisOfMatrix[CD];
origin _ Matrix3d.OriginOfMatrix[CD];
[xAxisChoices, xNegArray] _ IndicesOfMax[xAxis]; -- Find largest component
[zAxisChoices, zNegArray] _ IndicesOfMax[zAxis];
IF zAxisChoices[1] = xAxisChoices[1] THEN zAxisChoices[1] _ zAxisChoices[2];
newXAxis _ [0,0,0];
newXAxis[xAxisChoices[1]] _ SVVector3d.Magnitude[xAxis];
IF xNegArray[xAxisChoices[1]] THEN
newXAxis[xAxisChoices[1]] _ -newXAxis[xAxisChoices[1]];
newZAxis _ [0,0,0];
newZAxis[zAxisChoices[1]] _ SVVector3d.Magnitude[zAxis];
IF zNegArray[zAxisChoices[1]] THEN
newZAxis[zAxisChoices[1]] _ -newZAxis[zAxisChoices[1]];
newYAxis _ SVVector3d.CrossProduct[newZAxis, newXAxis];
CD _ Matrix3d.MakeMatFromAxes[newXAxis, newYAxis, newZAxis, origin];
 
AbsTransf[C, D, CD];
}; -- end of Align

IndicesOfMax: PRIVATE PROC [v: Vector] RETURNS [indices: ARRAY[1..3] OF NAT, negArray: ARRAY[1..3] OF BOOL] = {
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;
IF v[3] < 0 THEN {negArray[3] _ TRUE; v[3] _ -v[3]}
ELSE negArray[3] _ FALSE;
indices _ [1,2,3];
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};
IF v[2] < v[3] THEN {
temp _ v[2]; v[2] _ v[3]; v[3] _ temp;
tempIndex _ indices[2]; indices[2] _ indices[3]; indices[3] _ tempIndex};
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};
};

Abut: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
AbsTranslateOnly[C, D, [0,0,0]];
};

AbutX: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
vD: Vector;

vD _ CoordSys.FindTranslationOfAinTermsOfB[C, D];
AbsTranslateOnly[C, D, [0, vD[2], vD[3]]];
};

AbutY: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
vD: Vector;

vD _ CoordSys.FindTranslationOfAinTermsOfB[C, D];
AbsTranslateOnly[C, D, [vD[1], 0, vD[3]]];
};

AbutZ: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
vD: Vector;

vD _ CoordSys.FindTranslationOfAinTermsOfB[C, D];
AbsTranslateOnly[C, D, [vD[1], vD[2], 0]];
};

NormalizeRot: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
oldMat, newMat: Matrix4by4;
oldMat _ CoordSys.FindAInTermsOfB[a: C, b: D];
newMat _ Matrix3d.NormalizeNoRotation[oldMat];
AbsTransf[C, D, newMat];
};

Normalize: PUBLIC PROC [C: CoordSystem, D: CoordSystem] = {
AbsTransf[C, D, Matrix3d.Identity[]];
};
NormalizeRotTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
NormalizeRot[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
NormalizeTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
Normalize[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
AlignTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
Align[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
AbutTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
Abut[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
AbutXTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
AbutX[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
AbutYTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
AbutY[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};
AbutZTug: PUBLIC PROC [C: CoordSystem, tugBoat: CoordSystem, D: CoordSystem] = {
F: Matrix4by4 _ CoordSys.FindAInTermsOfB[C, tugBoat];
AbutZ[tugBoat, D];
AbsTransf[C, tugBoat, F, TRUE];
};

DirtyAssembly: PUBLIC PROC [a: Assembly] = {
WITH a.shape SELECT FROM
shape: Shape => {
a.coordSys.dirty _ TRUE;
};
alist: AssemblyList => {
a.coordSys.dirty _ TRUE;
DirtyAssemblyList[alist];
};
ENDCASE => ERROR;
}; -- end of DirtyAssembly

 DirtyAssemblyList: PRIVATE PROC [alist: AssemblyList] = {
FOR list: LIST OF Assembly _ alist.list, list.rest UNTIL list = NIL DO
DirtyAssembly[list.first];
ENDLOOP;
};

TidyUpCoordSysTree: PUBLIC PROC [root: CoordSystem] = {
parent: CoordSystem _ root.parent;
IF root.scalarsOnly THEN {
IF root.children # NIL THEN ERROR; -- scalars-only coordinate systems must be leaves.
root.scalars _ Matrix3d.TidyUpVector[root.scalars];
}
ELSE {
root.mat _ Matrix3d.TidyUpMatrix[root.mat];
IF root.children # NIL THEN { -- Process the children as well
FOR list: CoordSysList _ root.children, list.rest UNTIL list = NIL DO
TidyUpCoordSysTree[list.first];
ENDLOOP;
};
};
}; -- end of TidyUpCoordSysTree

TellAboutCameraAndWorld: PUBLIC PROC [root: CoordSystem, camera: Camera, scene: Scene] = {
camera.coordSys.wrtWorld _ CoordSys.FindInTermsOfWorld[camera.coordSys];
TellAboutCameraAndWorldAux[root, camera, scene];
};

TellAboutCameraAndWorldAux: PRIVATE PROC [root: CoordSystem, camera: Camera, scene: Scene] = {
parent: CoordSystem _ root.parent;
IF root.scalarsOnly THEN {
IF root.children # NIL THEN ERROR; -- scalars only coordinate systems must be leaves.
root.wrtCamera _ Matrix3d.LocalScale[CoordSys.FindInTermsOfCamera[parent, camera.coordSys], root.scalars[1], root.scalars[2], root.scalars[3]];
root.wrtWorld _ Matrix3d.LocalScale[CoordSys.FindInTermsOfWorld[parent], root.scalars[1], root.scalars[2], root.scalars[3]];
root.cameraWRTlocal _ Matrix3d.Inverse[root.wrtCamera];
root.worldWRTlocal _ Matrix3d.Inverse[root.wrtWorld];
}
ELSE {
root.wrtCamera _ CoordSys.FindInTermsOfCamera[root, camera.coordSys];
root.wrtWorld _ CoordSys.FindInTermsOfWorld[root];
root.cameraWRTlocal _ Matrix3d.Inverse[root.wrtCamera];
root.worldWRTlocal _ Matrix3d.Inverse[root.wrtWorld];
IF root.children # NIL THEN { -- Process the children as well
FOR list: CoordSysList _ root.children, list.rest UNTIL list = NIL DO
TellAboutCameraAndWorldAux[list.first, camera, scene];
ENDLOOP;
};
};
}; -- end of TellAboutCameraAndWorldAux

 TellAboutCameraAndWorldInList: PRIVATE PROC [clist: CoordSysList, camera: Camera, scene: Scene] = {
FOR list: CoordSysList _ clist, list.rest UNTIL list = NIL DO
TellAboutCameraAndWorld[list.first, camera, scene];
ENDLOOP;
};

TellAboutParent: PUBLIC PROC [cs: CoordSystem] = {
cs.wrtWorld _ Matrix3d.MatMult[cs.parent.wrtWorld, cs.mat];
cs.wrtCamera _ Matrix3d.MatMult[cs.parent.wrtCamera, cs.mat];
cs.worldWRTlocal _ Matrix3d.Inverse[cs.wrtWorld];
cs.cameraWRTlocal _ Matrix3d.Inverse[cs.wrtCamera];
};



ScalePrimitive: PUBLIC PROC [a: Assembly, sx, sy, sz: REAL] = {
shape: Shape;
scalarCS: CoordSystem;
IF NOT ISTYPE[a.shape, Shape] THEN ERROR;
shape _ NARROW[a.shape];
scalarCS _ shape.coordSys;
scalarCS.scalars[1] _ scalarCS.scalars[1]*sx;
scalarCS.scalars[2] _ scalarCS.scalars[2]*sy;
scalarCS.scalars[3] _ scalarCS.scalars[3]*sz;
};

ScalePrimitives: PUBLIC PROC [a: Assembly, sx, sy, sz: REAL] = {
WITH a.shape SELECT FROM
shape: Shape => ScalePrimitive[a, sx, sy, sz];
alist: AssemblyList => {
FOR list: LIST OF Assembly _ alist.list, list.rest UNTIL list = NIL DO
ScalePrimitives[list.first, sx, sy, sz];
ENDLOOP;
};
ENDCASE; -- IF a.shape = NIL or something else, do nothing.
};

ScaleEven: PUBLIC PROC [a: Assembly, cs: CoordSystem, scalar: REAL] = {
displacements: Vector;
WITH a.shape SELECT FROM
shape: Shape => {
ScalePrimitive[a, scalar, scalar, scalar];
displacements _ CoordSys.FindTranslationOfAinTermsOfB[a.coordSys, cs];
displacements _ SVVector3d.Scale[displacements, scalar];
AbsTranslateOnly[a.coordSys, cs, displacements];
};
alist: AssemblyList => {
FOR list: LIST OF Assembly _ alist.list, list.rest UNTIL list = NIL DO
ScaleEven[list.first, a.coordSys, scalar];
ENDLOOP;
displacements _ CoordSys.FindTranslationOfAinTermsOfB[a.coordSys, cs];
displacements _ SVVector3d.Scale[displacements, scalar];
AbsTranslateOnly[a.coordSys, cs, displacements];
};
ENDCASE; -- IF a.shape = NIL or something else, do nothing.
};

AssemblyHasNoChildren: PUBLIC ERROR = CODE;
ScaleEvenChildren: PUBLIC PROC [a: Assembly, cs: CoordSystem, scalar: REAL] ~ {
WITH a.shape SELECT FROM
shape: Shape => ERROR AssemblyHasNoChildren;
alist: AssemblyList => {
FOR list: LIST OF Assembly _ alist.list, list.rest UNTIL list = NIL DO
ScaleEven[list.first, list.first.coordSys, scalar];
ENDLOOP;
};
ENDCASE => ERROR AssemblyHasNoChildren; -- IF a.shape = NIL or something else, report a problem.
};

ScaleDistancesChildren: PUBLIC PROC [a: Assembly, cs: CoordSystem, sx, sy, sz: REAL] = {
displacements: Vector;
WITH a.shape SELECT FROM
shape: Shape => ERROR AssemblyHasNoChildren;
alist: AssemblyList => {
FOR list: LIST OF Assembly _ alist.list, list.rest UNTIL list = NIL DO
displacements _ CoordSys.FindTranslationOfAinTermsOfB[list.first.coordSys, cs];
displacements[1] _ displacements[1]*sx;
displacements[2] _ displacements[2]*sy;
displacements[3] _ displacements[3]*sz;
AbsTranslateOnly[list.first.coordSys, cs, displacements];
ENDLOOP;
};
ENDCASE => ERROR AssemblyHasNoChildren; -- IF a.shape = NIL or something else, report a problem.
};

ScaleAndShear: PUBLIC PROC [a: Assembly, cs: CoordSystem, sx, sy, sz: REAL] = {
};
ScaleNoShear: PUBLIC PROC [a: Assembly, cs: CoordSystem, sx, sy, sz: REAL] = {
};
Scale: PUBLIC PROC [a: Assembly, cs: CoordSystem, sx, sy, sz: REAL] = {
IF ISTYPE[a.shape, Shape] AND cs = a.coordSys THEN ScalePrimitive[a, sx, sy, sz]
ELSE ScaleEven[a, cs, sx];
};

MatrixHasScaling: PRIVATE PROC [mat: Matrix4by4] RETURNS [BOOL] = {
sx, sy, sz: REAL;
almostZero: REAL _ 1.0e-4;
[sx, sy, sz] _ Matrix3d.ScaleFromMatrix[mat];
IF ABS[sx - 1.0] > almostZero OR ABS[sy-1.0] > almostZero OR ABS[sz - 1.0] > almostZero
THEN RETURN[TRUE]
ELSE RETURN [FALSE];
};

END.
�����File: SVTransformsImpl.mesa
Last edited by Bier on January 4, 1985 6:07:07 pm PST
Copyright c 1984 by Xerox Corporation.  All rights reserved.
Contents: Procedures for Scaling, Translating, and Rotating assemblies with respect to an arbitrary coordinate system
Incrementally transform C with respect to D by M.  If D is a descendent of C, this could result in D moving as well.  If this is not desired, set DFixed to TRUE and IncTransf makes sure that D doesn't move.
Make sure that D hasn't moved.
Rotates C about an axis parallel to the plane axis of D, passing thru the origin of C.
Absolutely transform C with respect to D by M.  If D is a descendent of C, this could result in D moving as well.  If this is not desired, set DFixed to TRUE and AbsTransf makes sure that D doesn't move.
Now make sure that D hasn't moved.
Like TugTransf, but returns the Tugboat to its original position.
A set of routines which call IncTransf

Simple rotate C's coordsys wrt D by degrees about the x axis
Simple rotate C's coordsys wrt D by degrees about the y axis
Simple rotate C's coordsys wrt D by degrees about the z axis
Here is an example of the way these operations used to be performed.  This is fairly fast because it uses Matrix3d.RotateAboutXAxis instead of Matrix3d.MatMult, but the IncTransf, AbsTransf, TugTransf pathway is much cleaner.
XRotateAwrtB: PUBLIC PROC [a: CoordSystem, b: CoordSystem, degrees: REAL] = {
aWorld, bWorld, aInTermsOfb, newAWorld, withRespectToWorld, aInTermsOfWRT: Matrix4by4;
parent: CoordSystem;
IF b = NIL THEN ERROR
ELSE bWorld _ CoordSys.FindInTermsOfWorld[b];
aWorld _ CoordSys.FindInTermsOfWorld[a];
aInTermsOfb _ IF a = b THEN Matrix3d.Identity[] ELSE Matrix3d.WorldToLocal[bWorld,aWorld];
aInTermsOfb _ Matrix3d.RotateAboutXAxis[aInTermsOfb, degrees]; -- must be a global translate.
newAWorld _ Matrix3d.MatMult[bWorld, aInTermsOfb];
IF a.parent = NIL THEN ERROR; -- cannot translate WORLD for now
parent _ a.parent;
withRespectToWorld _ CoordSys.FindInTermsOfWorld[parent];
aInTermsOfWRT _ Matrix3d.WorldToLocal[withRespectToWorld, newAWorld];
a.mat _ aInTermsOfWRT;
};

ScaleAwrtB: PRIVATE PROC [a: CoordSystem, b: CoordSystem, sx, sy, sz: REAL] = {
Because scaling is only allowed at primitive assemblies, we define the arbitrary scaling of an assembly with respect to a coordinate system as follows:  If the assembly is a primitive, change its scalar vector 
aWorld, bWorld, aInTermsOfb, newAWorld, withRespectToWorld, aInTermsOfWRT: Matrix4by4;
parent: CoordSystem;
IF b = NIL THEN ERROR
ELSE bWorld _ CoordSys.FindInTermsOfWorld[b];
aWorld _ CoordSys.FindInTermsOfWorld[a];
aInTermsOfb _ IF a = b THEN Matrix3d.Identity[] ELSE Matrix3d.WorldToLocal[bWorld,aWorld];
aInTermsOfb _ Matrix3d.Scale[aInTermsOfb, sx, sy, sz]; -- must be a global translate.
newAWorld _ Matrix3d.MatMult[bWorld, aInTermsOfb];
IF a.parent = NIL THEN ERROR; -- cannot translate WORLD for now
parent _ a.parent;
withRespectToWorld _ CoordSys.FindInTermsOfWorld[parent];
aInTermsOfWRT _ Matrix3d.WorldToLocal[withRespectToWorld, newAWorld];
a.mat _ aInTermsOfWRT;
};

A set of routines which call AbsTransf

Places C so that the rotation from C to D remains as it is, but the translation becomes vD.
Find CD.  Compute the magnitude of its axes.  Make CD have axes of the same magnitude, aligned with respect to the nearest axes of D.
 This direction is now taken.  z axis must find another.
zAxis gets second choice if xAxis has its first choice
Bubble sort
Leaving the rotation of C as it is, put C's origin coincident with the origin of D.
Leave the rotation of C as it is.  Put C's origin in the x = 0 plane of D.
Leave the rotation of C as it is.  Put C's origin in the y = 0 plane of D.
Leave the rotation of C as it is.  Put C's origin in the z = 0 plane of D.
Leave translation between C and D as is.  The axes of C become parallel to the axes of D.
C becomes identical to D.

A set of routines which specialize TugTransf

Routines for updating cached matrices:

TellAboutCameraAndWorld1: PUBLIC PROC [a: Assembly, camera: Camera, scene: Scene] = {
Flatten the tree to get the leaf assemblies then update their cached values. 
camera.coordSys.wrtWorld _ CoordSys.FindInTermsOfWorld[camera.coordSys];
FOR list: LIST OF Assembly _ DisplayList3d.ListOfPrimAssemblies[a, scene], list.rest
UNTIL list = NIL DO
list.first.coordSys.wrtCamera _  Matrix3d.LocalScale[CoordSys.FindInTermsOfCamera[list.first.coordSys, camera.coordSys],  list.first.scalars[1], list.first.scalars[2], list.first.scalars[3]];
list.first.coordSys.wrtWorld _  Matrix3d.LocalScale[CoordSys.FindInTermsOfWorld[list.first.coordSys], list.first.scalars[1], list.first.scalars[2], list.first.scalars[3]];
list.first.coordSys.cameraWRTlocal _ Matrix3d.Inverse[list.first.coordSys.wrtCamera];
list.first.coordSys.worldWRTlocal _ Matrix3d.Inverse[list.first.coordSys.wrtWorld];
ENDLOOP;
}; -- end of TellAboutCameraAndWorld1

This assembly has moved.  Mark its coordinate system and those of its children as dirty.
If a component is almost a multiple of .5, make it exactly so.
Tree walk through the tree and concatenate all matrices (will later concatenate matrices as it goes).  This computes values for intermediate matrices as well as primitive matrices.  Can be started using any assembly as root.
Our matrices result from scaling our parent's matrices.
Updates the wrtWorld, and wrtCamera fields of cs by premultiplying cs.mat by cs.parent.wrtWorld and cs.parent.wrtCamera respectively
Scaling operations (IncTransf derivatives but more complicated).
There are five ways to scale a cluster assembly
1) (ScalePrimitives)  Scale each primitive in place, evenly or differentially.
2) (ScaleEven)  If sx = sy = sz.  Scale primitives in place and then translate all intermediate assemblies so the cluster assembly scales evenly as a unit
3) (ScaleNoShear)  IF sx # sy or sy # sz.  Scale the primitives evenly so that their dimension in the direction of scaling increases or decreases to the same quantity it would have reached by method 3.  This preserves shape of primitives.   Global shape is not preserved (but almost).
4) (ScaleEvenChildren) Perform a ScaleEven on each of the children of the cluster assembly but leave their relative translations fixed.  This is equivalent to performing a ScaleEven (child, child's cs, scalar) on each child individually.
5) (ScaleDistancesChildren) Doesn't change the size or shape of any of the children of assembly.  Simply translates all of the children as they would be translated by a Scale even of assembly.
Just a bit tricky.
If a is a Primitive and cs is any coordinate frame, just scale and translate it from the center of cs by scalar times its current translation.
If a is a cluster, and cs is any coordinate frame, evenly scale each component of a about a's center, then translate a as a unit, the appropriate distance from the center of cs.
now translate a's coordSys so that its displacement from the origin of cs is scaled by scalar
Recursively scale subassemblies with respect to their own coordinate systems
Now translate a's coordSys so that its displacement from the origin of cs is scaled by scalar
For each child of a, find its current displacement from the center of cs.  Scale this displacement by [sx, sy, sz].
not yet implemented.

not yet implemented.

�Ê×��˜�Iheadšœ™Jšœ5™5Jšœ
Ïmœ1™<Jšœu™uJ˜�šÏk	˜	Jšœ	˜	Jšœ	˜	J˜J˜J˜Jšœ
˜
Jšœ
˜
Jšœ
˜
Jšœ˜—J˜�Jšœž˜Jšžœ.˜5Jšžœ˜Jšž˜˜�Jšœ
žœ˜'Jšœžœ˜/Jšœžœ˜#Jšœ
žœ˜-Jšœžœ˜/Jšœžœ˜#Jšœ	žœ˜Jšœžœ˜!Jšœ!˜!Jšœžœ˜J˜�J˜�—šÏn	œžœžœžœžœžœžœžœ˜`Jšœžœžœžœžœžœžœ8žœžœ™ÎIprocšžœ˜L˜�Lšžœžœ
žœžœžœÏc!˜?Lš
žœžœžœžœžœ˜Lšžœžœ˜
šžœžœžœ˜JšœF˜FJšœ˜Jšžœ˜—L˜�Lšžœžœž˜šžœ
žœ ˜ Lš	žÐkuœž¡Ïuž¢œ
˜#Lšž¢œžœ˜(Lšž¢œžœ˜(LšÐks¡œž¢œ˜"Lš
žœ)ž¡œžœž¢œ˜>L˜—šžœžœ ˜!Lšžœžœžœ˜#L˜—šžœžœ $˜/Lšžœžœžœ˜#L˜—šžœ ˜&Lšž¢œž¢œž¡¢ž¡¢ž¢œ
˜/Lšž¢œžœ˜(Lšž¡œžœ %œ 	˜XLšž¢œžœ˜(Lš£¡œž¢œ˜"Lšž¢œ"˜$Lš
žœ:£¡œž¢œžœž¡œ˜Tšžœžœ˜L™Lšž¡œž¡œ
˜Lšž¡œžœ	˜0Lš	ž¡œž¡œž¡œ˜-Lšžœž¡œ˜L˜—L˜—Lšœ˜L˜�—š
Ÿœžœžœžœž¡œžœ˜TLšžœ˜Lšž¢œž¡œ¢ž¡œ¢ž¢œ
˜'L˜�Lšžœžœ
žœžœžœ !˜?Lšžœžœ˜
šžœžœžœ˜JšœL˜LJšœ˜Jšžœ˜—L˜�Lšž¢œžœ˜(Lšž¢œžœ˜(Lš£¡œž¢œ˜"Lš	ž¢œž¢œž¢œ˜+Lš
žœ:£¡œž¢œžœž¡œ˜TLšœ˜L˜�J˜�—šŸœžœžœžœžœžœ	žœ˜^J™VJš	žœ¢ž¡¢ž¡œ
˜*Jšœ˜Jšœ˜J˜�Jšž¡œžœ˜(Jšž¡œžœ˜(Jšœ!ž¡œ˜)Jšœž¡œ˜'Jšœž¡œ˜'Jšœž¡œ˜'Jšœ¢œ9˜CJ˜�Jšžœž˜Jšœžœ$˜*Jšœžœ$˜*Jšœžœ$˜*Jšžœžœ˜Lšœžœ¢œžœ˜"Jšœ˜J˜�—šŸ	œžœžœžœžœžœžœžœ˜`Jšœžœžœžœžœžœžœ8žœžœ™ËLšžœ˜L˜�Lšžœžœžœžœžœžœžœ˜?Lšžœžœ
žœžœžœ ˜8Lš
žœžœžœžœžœ˜Lšžœžœ˜
šžœžœžœ˜JšœF˜FJšœ˜Jšžœ˜—L˜�Lšžœžœž˜šžœ
žœ ˜ Lšž¡¢ž¡œ
˜Lšž¡œžœ˜(Lš£¡œž¡œ˜"Lšžœž¡œžœ˜$L˜—šžœžœ ˜!Lšžœžœžœ˜#L˜—šžœžœ $˜/Lšžœžœ˜
L˜—šžœ ˜&Lš	ž¡¢ž¡¢ž¡œ
˜#Lšž¡œžœ˜(Lšž¡œžœ˜(Lš£¡œž¡œ˜"Lš
žœ)£¡œž¡œžœ˜>šžœžœ˜L™"Lšž¡œž¡œ
˜Lšž¡œžœ	˜0Lš	ž¡œž¡œž¡œ˜-Lšžœž¡œ˜L˜—L˜—Lšœ˜L˜�—šŸ	œžœžœžœ%žœžœ˜`Jšžœ(žœ˜5Jšœžœžœ˜Jšœ
žœžœ˜J˜J˜�—š
Ðbnœžœžœ%žœžœ˜hJ™AJšžœ
˜Jšœ%˜%J˜�Jšžœžœ˜)Jšœžœžœ˜Jšœ
žœžœ˜Jšœ˜J˜J˜�J˜�—JšœŸ	™&J™�šŸ	œžœžœžœžœžœ
žœžœ˜cLšžœ
˜Lšžœ)˜*Lšœ
žœžœžœ˜Lšœ˜L˜�—šŸœžœžœžœžœžœ
žœžœ˜^Jšœ<™<Jšžœ
˜Lšžœ$˜%Lš	œ
žœžœžœžœ˜Jšœ˜J˜�—šŸœžœžœžœžœžœ
žœžœ˜^Jšœ<™<Jšžœ
˜Lšžœ$˜%Lš	œ
žœžœžœžœ˜Jšœ˜J˜�—šŸœžœžœžœžœžœ
žœžœ˜^Jšœ<™<Jšžœ
˜Lšžœ$˜%Lš	œ
žœžœžœžœ˜Jšœ˜J˜�—J˜�Lšœá™ášŸœžœžœ+žœ™MLšœV™VLšœ™Lšžœžœžœž™Lšžœ)™-Lšœ(™(Lšœžœžœžœ&™ZLšœ? ™]Lšœ2™2Lš	žœžœžœžœ !™?Lšœ™Lšœ9™9LšœE™ELšœ™Lšœ™L™�—šŸ
œžœžœ.žœ™OLšœÒ™ÒLšœV™VLšœ™Lšžœžœžœž™Lšžœ)™-Lšœ(™(Lšœžœžœžœ&™ZLšœ7 ™ULšœ2™2Lš	žœžœžœžœ !™?Lšœ™Lšœ9™9LšœE™ELšœ™Lšœ™—J™�JšœŸ	™&J™�šŸœžœžœ#¢œ˜OLšœY¢œ™[Lšžœ˜Lšœ¢œ	˜L˜�šžœžœžœžœ˜,Lšžœ¢œ˜Lšžœ¢œ˜Lšžœ¢œ˜Lšžœ˜—Lšžœžœ
žœžœžœ ˜8Lš
žœžœžœžœžœ˜Lšžœžœ˜
L˜�Lšžœžœž˜šžœ
žœ ˜ Lšž¡¢ž¡œ
˜Lšž¡œžœ˜(Lš£¡œž¡œ˜"Lšœ¢œž¡œ¢œ˜!Lšžœ¢œ˜Lšžœ¢œ˜Lšžœ¢œ˜L˜—šžœžœ ˜!Lšžœžœ¢œ¢œ¢œ¢œ¢œ˜<L˜—šžœžœ $˜/Lšžœ¢œ˜Lšžœ¢œ˜Lšžœ¢œ˜L˜—šžœ ˜&Lš	ž¡¢ž¡¢ž¡œ
˜#Lšž¡œžœ˜(Lšž¡œžœ˜(Lš£¡œž¡œ˜"Lšœ¢œž¡œž¡œ¢œ˜:Lšžœ¢œ˜Lšžœ¢œ˜Lšžœ¢œ˜L˜—Lšœ˜L˜�—š
Ÿœžœžœžœžœ˜7Lšœ¢œ-¢œP™…Lšž¡œ
˜Lšœžœžœžœ˜/Lšœ3˜3Lšœžœžœžœ˜*Lšœ˜L˜�Lšž¡œžœžœ˜$L˜�Lšœž¡œ˜#Lšœž¡œ˜#Lšœ!ž¡œ˜%Lšœ1 ˜JLšœ8™8Lšœ0˜0Lšžœ#žœ#˜LLšœ6™6Lšœ˜Lšœ8˜8šžœž˜"Lšœ7˜7—Lšœ˜Lšœ8˜8šžœž˜"Lšœ7˜7—Lšœ7˜7Lšž¡œB˜DLšœ˜Lšœ
žœžœž¡œ˜Lšœ˜L˜�—šŸœžœžœ
žœžœžœžœžœžœžœ˜oLšœ™Lšœžœ˜Lšœžœ˜Lšžœ
žœžœ˜3Lšžœžœ˜Lšžœ
žœžœ˜3Lšžœžœ˜Lšžœ
žœžœ˜3Lšžœžœ˜Lšœ˜šžœ
žœ˜Lšœ&˜&LšœI˜I—šžœ
žœ˜Lšœ&˜&LšœI˜I—šžœ
žœ˜Lšœ&˜&LšœI˜I—Lšœ˜L˜�—šŸœžœžœ%˜6L™SL˜ Lšœ˜L˜�—šŸœžœžœ%˜7L™JLšœ¢œ	˜L˜�Lšœ¢œ)žœžœ˜1Lš
œžœžœ¡œ¢œ¡œ¢œ˜*Lšœ˜L˜�—šŸœžœžœ%˜7L™JLšœ¢œ	˜L˜�Lšœ¢œ)žœžœ˜1Lš
œžœžœ¢œ¡œ¡œ¢œ˜*Lšœ˜L˜�—šŸœžœžœ%˜7L™JLšœ¢œ	˜L˜�Lšœ¢œ)žœžœ˜1Lš
œžœžœ¢œ¡œ¢œ¡œ˜*Lšœ˜L˜�—šŸœžœžœžœ˜>L™YJšœ˜Jšœ.˜.Jšœ.˜.Jšœ˜J˜L˜�—šŸ	œžœžœžœ˜;L™Lšœ%˜%L˜—J™�Jšœ#Ÿ	™,J™�š
Ÿœžœžœžœ%žœ˜WJšžœ(žœ˜5JšÏbœ
žœ˜Jšœ
žœžœ˜Jšœ˜—š
Ÿœžœžœžœ%žœ˜TJšžœ(žœ˜5Jš¥	œ
žœ˜Jšœ
žœžœ˜Jšœ˜—šŸœžœžœ;˜PJšœ5˜5Jš¥œ
˜Jšœžœ˜Jšœ˜—šŸœžœžœ;˜OJšœ5˜5Jš¥œ
˜Jšœžœ˜Jšœ˜—š
Ÿœžœžœžœ%žœ˜PJšžœ(žœ˜5Jš¥œ
žœ˜Jšœ
žœžœ˜Jšœ˜—š
Ÿœžœžœžœ%žœ˜PJšžœ(žœ˜5Jš¥œ
žœ˜Jšœ
žœžœ˜Jšœ˜—š
Ÿœžœžœžœ%žœ˜PJšžœ(žœ˜5Jš¥œ
žœ˜Jšœ
žœžœ˜Jšœ˜J˜�—Jšœ¥œ™&J™�šŸœžœžœ0™UJ™MJšœH™HJšžœžœžœC™Tšžœžœž™Jšœ¿™¿Jšœ«™«JšœU™UJšœS™S—Jšžœ™Jšœ "™%J™�—šŸ
œžœžœ˜,J™Xšžœ	žœž˜šœ˜Jšœžœ˜Jšœ˜—šœ˜Jšœžœ˜Jšœ˜Jšœ˜—Jšžœžœ˜—Jšœ ˜J˜�—šœŸœžœžœ˜:šžœžœžœ"žœžœž˜FJšœ˜—Jšžœ˜Jšœ˜—J˜�šŸœžœžœ˜7J™>Jšœ"˜"šžœžœ˜Jš	žœžœžœžœ 2˜UJšœ3˜3J˜—šžœ˜Jšœ+˜+šžœžœžœ ˜=šžœ/žœžœž˜EJš¥œ
˜—Jšžœ˜Jšœ˜—Jšœ˜—Jšœ ˜J˜�—šŸœžœžœ6˜ZJšœà™àJšœH˜HJšœ0˜0J˜J˜�—šŸœžœžœ6˜^Jšœ"˜"šžœžœ˜š	žœžœžœžœ 2˜UJ™7—Jšœ˜Jšœ|˜|Jšœ7˜7Jšœ5˜5J˜—šžœ˜JšœE˜EJšœ2˜2Jšœ7˜7Jšœ5˜5šžœžœžœ ˜=šžœ/žœžœž˜EJš¥œ˜6—Jšžœ˜Jšœ˜—Jšœ˜—Jšœ $˜'J˜�—šœŸœžœžœ8˜dšžœ'žœžœž˜=Jšœ3˜3—Jšžœ˜Jšœ˜J˜�—šŸœžœžœ˜2Lšœ„™„Lšœ;˜;Lšœ=˜=Lšœ1˜1Lšœ3˜3Lšœ˜—J˜�Jš¥œ9™@˜�Jšœ/™/JšœN™NJšœš™šJšœœ™œJšœí™íJ™À—J˜�šŸœžœžœžœ˜?Jšœ
˜
J˜Jš
žœžœžœžœžœ˜)Jšœ˜Jšœ˜Jšœ-˜-Jšœ-˜-Jšœ-˜-Jšœ˜J˜�—šŸœžœžœžœ˜@šžœ	žœž˜Jšœ.˜.šœ˜šžœžœžœ"žœžœž˜FJšœ(˜(—Jšžœ˜Jšœ˜—Jšžœ 3˜;—Jšœ˜J˜�—šŸ	œžœžœ(žœ˜GJ™J™ŽJ™±Jšœ˜šžœ	žœž˜šœ˜Jšœ*˜*Jšœ]™]JšœF˜FJšœ8˜8Jšœ0˜0Jšœ˜—šœ˜šžœžœžœ"žœžœž˜Fšœ*˜*JšœL™L——Jšžœ˜Jšœ]™]JšœF˜FJšœ8˜8Jšœ0˜0Jšœ˜—Jšžœ 2˜;—Jšœ˜J˜�—Jšœžœžœžœ˜+šŸœžœ(žœ˜Ošžœ	žœž˜Jšœ,˜,šœ˜šžœžœžœ"žœžœž˜FJšœ3˜3—Jšžœ˜Jšœ˜—Jšžœ 9˜`—Jšœ˜—šŸœžœ,žœ˜XJšœs™sJšœ˜šžœ	žœž˜Jšœžœ˜,šœ˜šžœžœžœ"žœžœž˜FJšœO˜OJšœ'˜'Jšœ'˜'Jšœ'˜'Jšœ9˜9—Jšžœ˜Jšœ˜—Jšžœžœ 9˜`—Jšœ˜—šŸ
œžœ,žœ˜OJšœ˜Jšœ™—šŸœžœ,žœ˜NJšœ˜Jšœ™—šŸœžœžœ,žœ˜GJšžœžœžœžœ˜PJšžœ˜Jšœ˜—J˜�š
Ÿœžœžœžœžœ˜CJšœžœ˜Jšœžœ
˜Jšœ-˜-Jšžœžœžœžœžœžœ˜WJšžœžœžœ˜Jšžœžœžœ˜Jšœ˜—J˜�Jšžœ˜—�…—����AÂ��z'��