<> <> <> <> 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 << This direction is now taken. z axis must find another.>> [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]; }; <> <<>> <> <> <> <> <> <> <> <> <> <> <<}; -- end of TellAboutCameraAndWorld1>> <<>> 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]; }; <> <> <<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.>> 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.