DIRECTORY CoordSys, IO, Matrix3d, Rope, SV2d, SV3d, SVModelTypes; CoordSysImpl: PROGRAM IMPORTS Matrix3d, IO, Rope EXPORTS CoordSys = BEGIN CoordSystem: TYPE = REF CoordSysObj; CoordSysObj: TYPE = SVModelTypes.CoordSysObj; CoordSysList: TYPE = SVModelTypes.CoordSysList; Matrix4by4: TYPE = SV3d.Matrix4by4; Point2d: TYPE = SV2d.Point2d; Point3d: TYPE = SV3d.Point3d; Vector: TYPE = SV3d.Vector; globalNumberStream: IO.STREAM; -- initialized in Init[]. CreateRoot: PUBLIC PROC [name: Rope.ROPE] RETURNS [newCS: CoordSystem] = { newCS _ NEW[CoordSysObj _ [name: name, scalarsOnly: FALSE, scalars: [1,1,1], mat: Matrix3d.Identity[], wrtCamera: Matrix3d.Identity[], wrtWorld: Matrix3d.Identity[], cameraWRTlocal: Matrix3d.Identity[], worldWRTlocal: Matrix3d.Identity[], parent: NIL, children: NIL, dirty: TRUE]]; }; CreateCoordSysInTree: PUBLIC PROC [name: Rope.ROPE, mat: Matrix4by4, parent: CoordSystem, root: CoordSystem] RETURNS [newCS: CoordSystem] = { IF CoordSysNameIsPresent[name, root] THEN SIGNAL NameAlreadyExists; newCS _ NEW[CoordSysObj _ [name: name, scalarsOnly: FALSE, scalars: [1,1,1], mat: mat, wrtCamera: Matrix3d.Identity[], wrtWorld: Matrix3d.Identity[], cameraWRTlocal: Matrix3d.Identity[], worldWRTlocal: Matrix3d.Identity[], parent: parent]]; IF parent # NIL THEN { parent.children _ AppendCoordSysToList[newCS, parent.children]; }; }; NameAlreadyExists: PUBLIC SIGNAL = CODE; CreateScalarsOnlyCoordSysInTree: PUBLIC PROC [name: Rope.ROPE, scalars: Vector, parent: CoordSystem, root: CoordSystem] RETURNS [newCS: CoordSystem] = { IF CoordSysNameIsPresent[name, root] THEN SIGNAL NameAlreadyExists; newCS _ NEW[CoordSysObj _ [name: name, scalarsOnly: TRUE, scalars: scalars, mat: Matrix3d.Identity[], wrtCamera: Matrix3d.Identity[], wrtWorld: Matrix3d.Identity[], cameraWRTlocal: Matrix3d.Identity[], worldWRTlocal: Matrix3d.Identity[], parent: parent]]; IF parent # NIL THEN { parent.children _ AppendCoordSysToList[newCS, parent.children]; }; }; CopyCoordSysFromAnyTree: PUBLIC PROC [source: CoordSystem, newName: Rope.ROPE, parent: CoordSystem, root: CoordSystem] RETURNS [newCS: CoordSystem] = { IF CoordSysNameIsPresent[newName, root] THEN SIGNAL NameAlreadyExists; newCS _ NEW[CoordSysObj _ [name: newName, scalarsOnly: source.scalarsOnly, scalars: source.scalars, mat: source.mat, wrtCamera: Matrix3d.Identity[], wrtWorld: Matrix3d.Identity[], cameraWRTlocal: Matrix3d.Identity[], worldWRTlocal: Matrix3d.Identity[], parent: parent, dirty: TRUE]]; IF parent # NIL THEN { parent.children _ AppendCoordSysToList[newCS, parent.children]; }; }; ResetScalars: PUBLIC PROC [cs: CoordSystem, scalars: Vector] = { IF NOT cs.scalarsOnly THEN ERROR; cs.scalars _ scalars; }; GetScalars: PUBLIC PROC [cs: CoordSystem] RETURNS [scalars: Vector] = { IF NOT cs.scalarsOnly THEN ERROR; scalars _ cs.scalars; }; AttemptToCreateCoordSysWithScaling: PUBLIC SIGNAL = CODE; DeleteCoordSysAndChildren: PUBLIC PROC [cs: CoordSystem, root: CoordSystem] = { parent: CoordSystem _ cs.parent; DeleteCoordSysLocal[cs]; parent.children _ DeleteCoordSysFromList[cs, parent.children]; }; DeleteCoordSysLocal: PRIVATE PROC [cs: CoordSystem] = { next: CoordSysList; IF cs.children # NIL THEN { FOR children: CoordSysList _ cs.children, next UNTIL children = NIL DO DeleteCoordSysLocal[children.first]; next _ children.rest; children.first _ NIL; children.rest _ NIL; ENDLOOP; cs.children _ NIL; }; cs.parent _ NIL; }; DeleteCoordSysFromList: PROC [cs: CoordSystem, list: CoordSysList] RETURNS [CoordSysList] = { before, l, after: CoordSysList; [before, l, after] _ FindCoordSysAndNeighbors[cs, list]; IF before = NIL THEN RETURN [after] ELSE { l.rest _ NIL; l.first _ NIL; before.rest _ after; RETURN[list]; }; }; AppendCoordSysToList: PROC [cs: CoordSystem, list: CoordSysList] RETURNS [CoordSysList] = { z: CoordSysList _ list; IF z = NIL THEN RETURN[CONS[cs,NIL]]; UNTIL z.rest = NIL DO z _ z.rest; ENDLOOP; z.rest _ CONS[cs,NIL]; RETURN[list]; }; MakeListFromTree: PUBLIC PROC [root: CoordSystem] RETURNS [csl: CoordSysList] = { pos, end: CoordSysList; i: NAT _ 0; end _ csl _ CONS[root, NIL]; FOR pos _ csl, pos.rest UNTIL pos = NIL DO IF pos.first.children # NIL THEN { FOR children: CoordSysList _ pos.first.children, children.rest UNTIL children = NIL DO end.rest _ CONS[children.first, NIL]; end _ end.rest; i _ i+1; IF i > 2000 THEN ERROR; ENDLOOP; }; ENDLOOP; }; FindCoordSysInTree: PUBLIC PROC [name: Rope.ROPE, root: CoordSystem] RETURNS [cs: CoordSystem] = { success: BOOL; [cs, success] _ FindCoordSysInTreeAux[name, root]; IF NOT success THEN SIGNAL CoordSysNotFound; }; FindCoordSysInTreeAux: PUBLIC PROC [name: Rope.ROPE, root: CoordSystem] RETURNS [cs: CoordSystem, success: BOOL] = { IF root.children = NIL THEN IF Rope.Equal[name, root.name, TRUE] THEN { cs _ root; success _ TRUE; } ELSE { cs _ NIL; success _ FALSE; } ELSE { IF Rope.Equal[name, root.name, TRUE] THEN { cs _ root; success _ TRUE; RETURN; }; FOR children: CoordSysList _ root.children, children.rest UNTIL children = NIL DO [cs, success] _ FindCoordSysInTreeAux[name, children.first]; IF success THEN RETURN; ENDLOOP; cs _ NIL; success _ FALSE; }; }; CoordSysNameIsPresent: PUBLIC PROC [name: Rope.ROPE, root: CoordSystem] RETURNS [BOOL] = { IF root = NIL THEN RETURN [FALSE]; IF root.children = NIL THEN RETURN[Rope.Equal[name, root.name, TRUE]] ELSE { IF Rope.Equal[name, root.name, TRUE] THEN RETURN[TRUE]; FOR children: CoordSysList _ root.children, children.rest UNTIL children = NIL DO IF CoordSysNameIsPresent[name, children.first] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; }; FindCoordSysInList: PUBLIC PROC [name: Rope.ROPE, csl: CoordSysList] RETURNS [cs: CoordSystem] = { l: CoordSysList _ csl; IF l = NIL THEN ERROR CoordSysListEmpty; UNTIL l = NIL DO IF Rope.Equal[l.first.name, name] THEN BEGIN cs _ l.first; RETURN END; l _ l.rest; ENDLOOP; SIGNAL CoordSysNotFound; }; CoordSysNotFound: PUBLIC SIGNAL = CODE; CoordSysListEmpty: PUBLIC SIGNAL = CODE; FindCoordSysAndNeighbors: PUBLIC PROC [C: CoordSystem, csl: CoordSysList] RETURNS [beforeCS, cs, afterCS: CoordSysList] = { lastL: CoordSysList _ NIL; l: CoordSysList _ csl; IF l = NIL THEN ERROR CoordSysNotFound; UNTIL l = NIL DO IF l.first = C THEN { beforeCS _ lastL; cs _ l; afterCS _ l.rest; RETURN}; lastL _ l; l _ l.rest; ENDLOOP; SIGNAL CoordSysNotFound; }; BaseAndNumber: PUBLIC PROC [name: Rope.ROPE] RETURNS [base: Rope.ROPE, number: NAT] = { index: INT; rest: Rope.ROPE; numStream: IO.STREAM; index _ Rope.Find[name, "."]; IF index = -1 THEN RETURN[name, 0]; -- if there is no decimal, pretend we have name.0 base _ Rope.Substr[name, 0, index]; rest _ Rope.Substr[name, index+1]; numStream _ IO.RIS[rest, globalNumberStream]; number _ IO.GetInt[numStream]; IO.Reset[numStream]; }; UniqueNameWithSuffix: PUBLIC PROC [oldName: Rope.ROPE, suffix: Rope.ROPE, root: CoordSystem] RETURNS [unique: Rope.ROPE] = { base: Rope.ROPE; num: NAT; [base, num] _ BaseAndNumber[oldName]; unique _ IO.PutFR["%g%g.%g", [rope[base]], [rope[suffix]], [integer[num]]]; unique _ UniqueNameFrom[unique, root]; }; UniqueNameFrom: PUBLIC PROC [name: Rope.ROPE, root: CoordSystem] RETURNS [unique: Rope.ROPE] = { maxNum: NAT _ 0; targetBase, base: Rope.ROPE; g: CoordSysList _ MakeListFromTree[root]; targetNum, num, targetLen: NAT; len: INT; c, firstC: CHAR; [targetBase, targetNum] _ BaseAndNumber[name]; targetLen _ Rope.Length[targetBase]; firstC _ Rope.Fetch[targetBase, 0]; FOR csl: CoordSysList _ g, csl.rest UNTIL csl = NIL DO len _ Rope.Find[csl.first.name, "."]; IF len = -1 THEN LOOP; -- A name without a decimal point is a zero. Doesn't increment maxNum. IF len # targetLen THEN LOOP; -- Clearly not the same name. c _ Rope.Fetch[csl.first.name, 0]; IF c = firstC THEN { -- cheap tests failed. Pay the piper. [base, num] _ BaseAndNumber[csl.first.name]; IF Rope.Equal[base, targetBase, TRUE] THEN maxNum _ MAX[num, maxNum]; }; ENDLOOP; unique _ IO.PutFR["%g.%g", [rope[targetBase]], [integer[maxNum+1]]]; }; CameraToScreen: PUBLIC PROC [cameraPoint2d: Point2d, screenCoordSys: CoordSystem] RETURNS [screenPoint2d: Point2d] = { screenPoint2d[1] _ cameraPoint2d[1] - screenCoordSys.mat[1][4]; screenPoint2d[2] _ cameraPoint2d[2] - screenCoordSys.mat[2][4]; }; ScreenToCamera: PUBLIC PROC [screenPoint2d: Point2d, screenCoordSys: CoordSystem] RETURNS [cameraPoint2d: Point2d] = { cameraPoint2d[1] _ screenPoint2d[1] + screenCoordSys.mat[1][4]; cameraPoint2d[2] _ screenPoint2d[2] + screenCoordSys.mat[2][4]; }; FromCSToCS: PUBLIC PROC [pt: Point3d, currentCS: CoordSystem, newCS: CoordSystem] RETURNS [newPt: Point3d] = TRUSTED { currentNew: Matrix4by4; currentNew _ FindAInTermsOfB[currentCS, newCS]; newPt _ Matrix3d.Update[currentNew, pt]; }; FromCSToCSMat: PUBLIC PROC [mat: Matrix4by4, currentCS: CoordSystem, newCS: CoordSystem] RETURNS [newMat: Matrix4by4] = TRUSTED { currentNew: Matrix4by4; currentNew _ FindAInTermsOfB[currentCS, newCS]; newMat _ Matrix3d.MatMult[currentNew, mat]; }; FindInTermsOfWorld: PUBLIC PROC [cs: CoordSystem] RETURNS [mat: Matrix4by4] = { thisCS, nextCS: CoordSystem; thisCS _ cs; IF cs.scalarsOnly THEN mat _ Matrix3d.MakeScaleMat[cs.scalars[1], cs.scalars[2], cs.scalars[3]] ELSE mat _ cs.mat; UNTIL thisCS.parent = NIL DO nextCS _ thisCS.parent; mat _ Matrix3d.MatMult[nextCS.mat, mat]; thisCS _ nextCS; ENDLOOP; }; FindInTermsOfCamera: PUBLIC PROC [cs: CoordSystem, camera: CoordSystem] RETURNS [mat: Matrix4by4] = { inWorld: Matrix4by4 _ FindInTermsOfWorld[cs]; cameraWRTWorld: Matrix4by4 _ FindInTermsOfWorld[camera]; mat _ Matrix3d.WorldToLocal[cameraWRTWorld,inWorld]; }; FindWorldInTermsOf: PUBLIC PROC [cs: CoordSystem] RETURNS [mat: Matrix4by4] = { csWORLD: Matrix4by4 _ FindInTermsOfWorld[cs]; mat _ Matrix3d.Inverse[csWORLD]; }; FindCameraInTermsOf: PUBLIC PROC [cs: CoordSystem, camera: CoordSystem] RETURNS [mat: Matrix4by4] = { csWorld: Matrix4by4 _ FindInTermsOfWorld[cs]; cameraWorld: Matrix4by4 _ FindInTermsOfWorld[camera]; mat _ Matrix3d.WorldToLocal[csWorld, cameraWorld]; }; FindAInTermsOfB: PUBLIC PROC [a: CoordSystem, b: CoordSystem] RETURNS [aInTermsOfb: Matrix4by4] = { aWorld, bWorld: Matrix4by4; aWorld _ FindInTermsOfWorld[a]; bWorld _ FindInTermsOfWorld[b]; aInTermsOfb _ Matrix3d.WorldToLocal[bWorld,aWorld]; }; FindTranslationOfAinTermsOfB: PUBLIC PROC [a: CoordSystem, b: CoordSystem] RETURNS [displacements: Vector] = { aInTermsOfb: Matrix4by4 _ FindAInTermsOfB[a,b]; displacements _ Matrix3d.OriginOfMatrix[aInTermsOfb]; }; PutAInTermsOfB: PUBLIC PROC [a: CoordSystem, b: CoordSystem] RETURNS [aInTermsOfb: Matrix4by4] = { aWorld, bWorld: Matrix4by4; aWorld _ FindInTermsOfWorld[a]; bWorld _ FindInTermsOfWorld[b]; aInTermsOfb _ Matrix3d.WorldToLocal[bWorld,aWorld]; a.parent _ b; a.mat _ aInTermsOfb; }; Init: PROC = { globalNumberStream _ IO.RIS["273"]; }; END. FFile: CoordSysImpl.mesa Last edited by Bier on January 3, 1985 11:37:55 pm PST Author: Eric Bier in the summer of 1982 Contents: Allocation and access to a user-specified set of named coordinate systems Old CreateCoordSys error checking: Check that mat has no scaling components almostZero: REAL _ 1.0e-4; 1.0e-7 is too small. Wow, subtraction has real floating point fuzz. [x, y, z] _ Matrix3d.ScaleFromMatrix[mat]; IF ABS[x - 1.0] > almostZero OR ABS[y-1.0] > almostZero OR ABS[z - 1.0] > almostZero THEN SIGNAL AttemptToCreateCoordSysWithScaling; First make sure the name is unique. Add this coordinate system as a child of its parent, if any. First make sure the name is unique. Add this coordinate system as a child of its parent, if any. Like CreateCoordSysInTree but uses the matrix from the old CoordSys. If source is a scalars-only coordsys, then newCS will be as well. First make sure the name is unique. Add this coordinate system as a child of its parent, if any. Breakup cs and everything below. Note that this leaves cs's parent pointing to cs. A copy of List.Nconc1 for CoordSysList instead of LIST OF REF ANY Makes a list in Breadth-first order. Signals CoordSysNotFound if that is the case. BaseAndNumber: PUBLIC PROC [name: Rope.ROPE] RETURNS [base: Rope.ROPE, number: NAT] = { Currently finds the "number" after the first decimal point. Should find the last decimal point and use only digits after that. noNumber: BOOL _ FALSE; nameStream: IO.STREAM; next: CHAR; nameStream _ IO.RIS[name]; base _ ReadAlpha[nameStream]; next _ nameStream.GetChar[ !IO.EndOfStream => {noNumber _ TRUE; CONTINUE}]; IF noNumber THEN number _ 0 ELSE IF next = '. THEN number _ IO.GetInt[nameStream] ELSE number _ 0; }; ReadAlpha: PRIVATE PROC [s: IO.STREAM] RETURNS [base: Rope.ROPE] = { skip: INT; [base, skip] _ IO.GetTokenRope[s, AlphaBreakProc]; }; AlphaBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = TRUSTED { RETURN[IF char = '. THEN break ELSE other] }; Currently finds the "number" after the first decimal point. Should find the last decimal point and use only digits after that. Takes a solidviews name, like "teapot.73". Adds the suffix to the basename and fixes the number to ensure uniqueness. If the suffix were "$$tool", then UniqueNameWithSuffix might return "teapot$$tool.89". Finds any digits on the end of the name. Looks through the coordSys tree extracting a digit and base name from each name. Finds the maximum number, adds one, reconcatenates and returns. UniqueNameFrom: PUBLIC PROC [name: Rope.ROPE, root: CoordSystem] RETURNS [unique: Rope.ROPE] = { Finds any digits on the end of the name. Looks through the coordSys tree extracting a digit and base name from each name. Finds the maximum number, adds one, reconcatenates and returns. maxNum: NAT _ 0; targetBase, base: Rope.ROPE; g: CoordSysList _ MakeListFromTree[root]; targetNum, num: NAT; [targetBase, targetNum] _ BaseAndNumber[name]; FOR csl: CoordSysList _ g, csl.rest UNTIL csl = NIL DO [base, num] _ BaseAndNumber[csl.first.name]; IF Rope.Equal[base, targetBase, TRUE] THEN maxNum _ MAX[num, maxNum]; ENDLOOP; unique _ IO.PutFR["%g.%g", [rope[targetBase]], [integer[maxNum+1]]]; }; Currently, the SCREEN coordinate frame may only contain a translation. This operation then is like Matrix3d.Update[CAMERASCREEN, cameraPoint2d] but faster. Currently, the SCREEN coordinate frame may only contain a translation. This operation then is like Matrix3d.Update[SCREENCAMERA, screenPoint2d] but faster. Takes ptcurrentCS and returns ptnewCS. Takes matcurrentCS and returns matnewCS. For local transforms, call these procedures with b = a. Êÿ– "cedar" style˜Iheadšœ™Iprocšœ6™6Lšœ'™'LšœS™SL˜šÏk ˜ Lšœ ˜ Lšœ˜Lšœ ˜ Lšœ˜Lšœ˜Lšœ˜Lšœ ˜ —L˜Lšœ˜Lšœ œ˜Lšœ ˜Lš˜˜Lšœ œœ ˜$Lšœ œ˜-Lšœœ˜/Lšœ œ˜#Lšœ œ˜Lšœ œ˜Lšœœ˜L˜—L˜L™"Lšœ(™(šœ™LšœD™D—Lšœ*™*šœœœœœœœ™ZLšœ$™*L™—Lšœœœ˜8L˜š Ïn œœœ œœ˜JLš œœ)œ¾œ œ œ˜™L˜L˜—š žœœœ œ;œ˜L™#Lšœ#œœ˜Cšœœå˜ðL™<—šœ œœ˜Lšœ?˜?L˜—Lšœ˜—Lšœ˜(L˜šžœ œ œ;œ˜˜L™#Lšœ#œœ˜Cšœœô˜ÿL™<—šœ œœ˜Lšœ?˜?L˜—Lšœ˜L˜—š žœœœ%œ*œ˜—Lšœ‡™‡L™#Lšœ&œœ˜Fšœœ‰œ˜›L™<—šœ œœ˜Lšœ?˜?L˜—Lšœ˜L˜—šž œ œ'˜@Lšœ!˜!Lšœ˜L˜—šž œ œœ˜GLšœ!˜!Lšœ˜L˜—L˜Lšœ$œœœ˜9L˜šžœ œ)˜OLšœ ˜ Lšžœ ˜Lšœ>˜>L˜L˜—šžœœœ˜7L™SLšœ˜šœœœ˜šœ,œ œ˜FLšœ$˜$Lšœ˜Lšœœ˜Lšœœ˜—Lšœ˜Lšœœ˜L˜—Lšœ œ˜L˜L˜—šžœœ'œ˜]Lšœ˜Lšœ8˜8Lšœ œœœ˜#šœ˜Lšœ œ˜ Lšœ œ˜Lšœ˜Lšœ˜ L˜—L˜L˜—šžœœ'œ˜[JšœA™AJšœ˜Jš œœœœœœ˜%Jšœ œœ œ˜*Jšœ œœ˜Jšœ˜ Jšœ˜—L˜šžœœœœ˜QL™$L˜Lšœœ˜ Lšœ œœ˜šœœœ˜*šœœœ˜"šœS˜VLšœ œœ˜%L˜L˜Lšœ œœ˜—Lšœ˜L˜——Lšœ˜L˜L˜—š žœœœ œœ˜bJšœ œ˜Jšœ2˜2Jšœœ œœ˜,J˜—J˜š žœœœ œœœ˜tšœœ˜šœœœ˜+Jšœ ˜ Jšœ œ˜J˜—šœ˜Jšœœ˜ Jšœ œ˜J˜——šœ˜šœœœ˜+Jšœ ˜ Jšœ œ˜Jšœ˜J˜—šœ7œ œ˜QJšœ<˜