File: Filein3dImpl.mesa
Last edited by Bier on January 28, 1987 12:47:04 pm PST
Copyright © 1984 by Xerox Corporation. All rights reserved.
Contents: Recreates a 3d database from a 3d text file of the sort produced by Fileout3d.mesa.
Note: When you change this file, you may wish to update versionRope in SVSceneImplA.
DIRECTORY
CoordSys, CSG, SVScene, Filein3d, FS, Imager, ImagerColor, IO, Rope, SV2d, SV3d, SVArtwork, SVError, SVModelTypes, SVSceneTypes, SweepGeometry, TFI3d;
Filein3dImpl:
CEDAR PROGRAM
IMPORTS CoordSys, CSG, SVScene, FS, ImagerColor, IO, Rope, SVArtwork, SVError, TFI3d
EXPORTS Filein3d =
BEGIN
ArtworkClass: TYPE = SVModelTypes.ArtworkClass;
Assembly: TYPE = SVSceneTypes.Assembly;
AssemblyList: TYPE = SVSceneTypes.AssemblyList;
Artwork: TYPE = SVModelTypes.Artwork;
Color: TYPE = Imager.Color;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
CoordSysList: TYPE = SVModelTypes.CoordSysList;
FileCamera: TYPE = SVSceneTypes.FileCamera;
LightSource: TYPE = SVModelTypes.LightSource;
LightSourceList: TYPE = LIST OF LightSource;
MasterObject: TYPE = SVSceneTypes.MasterObject;
MasterObjectList: TYPE = SVSceneTypes.MasterObjectList;
MasterObjectClass: TYPE = SVSceneTypes.MasterObjectClass;
Material: TYPE = SVModelTypes.Material;
Matrix3by3: TYPE = SV2d.Matrix3by3;
Matrix4by4: TYPE = SV3d.Matrix4by4;
NameList: TYPE = LIST OF Rope.ROPE;
OMap: TYPE = SVModelTypes.OMap;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
PointSetOp: TYPE = SVSceneTypes.PointSetOp; -- {union, intersection, difference}
Scene: TYPE = SVSceneTypes.Scene;
SMap: TYPE = SVModelTypes.SMap;
SpaceFunction: TYPE = REF SpaceFunctionObj;
SpaceFunctionObj: TYPE = SVModelTypes.SpaceFunctionObj;
Vector: TYPE = SV3d.Vector;
LinearMesh: TYPE = REF LinearMeshRecord;
LinearMeshRecord: TYPE = SweepGeometry.LinearMeshRecord;
RevoluteMesh: TYPE = REF RevoluteMeshRecord;
RevoluteMeshRecord: TYPE = SweepGeometry.RevoluteMeshRecord;
LinearMeshArray: TYPE = SweepGeometry.LinearMeshArray;
RevoluteMeshArray: TYPE = SweepGeometry.RevoluteMeshArray;
FileinScene:
PUBLIC
PROC [scene: Scene, f:
IO.
STREAM, wdirForAIS: Rope.
ROPE] = {
csList: CoordSysList;
worldCS: CoordSystem;
sceneName: Rope.ROPE;
version: REAL;
restOfVersionRope: Rope.ROPE;
TFI3d.ReadBlankAndRope[f, "File:"];
TFI3d.ReadBlank[f];
[] ← TFI3d.ReadWord[f];
TFI3d.ReadWhiteSpace[f];
TFI3d.ReadRope[f, "3D file for scene:"];
TFI3d.ReadBlank[f];
sceneName ← TFI3d.ReadWord[f];
TFI3d.ReadWhiteSpace[f];
TFI3d.ReadRope[f, "Produced by Solidviews Version"];
TFI3d.ReadBlank[f];
version ← TFI3d.ReadReal[f];
restOfVersionRope ← TFI3d.ReadLine[f];
IF version >= 2.0 THEN ReadOptions[f, scene];
IF scene.lightSources =
NIL
THEN {
ambientLight: LightSource ← SVScene.CreateAmbientLightSource["Ambient", ImagerColor.ColorFromRGB[[0.2,0.2,0.2]]];
scene.lightSources ← CONS[ambientLight, NIL];
};
TFI3d.ReadBlank[f];
csList ← FileinCoordSystems[f, scene];
FileinLightSources[f, scene];
worldCS ← CoordSys.FindCoordSysInList["WORLD", csList];
FileinObjects[f, scene];
scene.assembly ← FileinAssembly[f, scene, csList, version, wdirForAIS];
IF version >= 3.0 THEN FileinCameras[f, scene, csList, version]
ELSE scene.cameras ← SVScene.InitialCameraList[];
IF version >= 3.0 THEN FileinCameraOrder[f, scene]
ELSE scene.cameraOrder ← LIST["Front"];
TFI3d.ReadBlank[f];
TFI3d.ReadRope[f, "END"];
f.Close[];
};
ReadOptions:
PROCEDURE [f:
IO.
STREAM, scene: Scene] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOL ← FALSE;
TFI3d.ReadBlank[f];
UNTIL twoCRsFound
DO
[keyWord, good] ← TFI3d.ReadKeyWord[f];
IF
NOT good
THEN {
nextChar ← IO.PeekChar[f];
IF nextChar =
IO.
CR
THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
good ← TFI3d.ReadHorizontalBlank[f];
IF
NOT good
THEN {
nextChar ← IO.PeekChar[f];
IF nextChar =
IO.
CR
THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
option ← TFI3d.ReadLine[f];
ProcessOption[keyWord, option, scene];
nextChar ← IO.PeekChar[f];
IF nextChar =
IO.
CR
THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
ENDLOOP;
};
ProcessOption:
PROC [keyWord: Rope.
ROPE, option: Rope.
ROPE, scene: Scene] = {
SELECT TRUE FROM
Known Options
Rope.Equal[keyWord, "background color",
FALSE] => {
scene.backgroundColor ← TFI3d.ReadColor[IO.RIS[option]];
};
Rope.Equal[keyWord, "shadows",
FALSE] => {
good, truth: BOOL;
[truth, good] ← TFI3d.ReadBool[IO.RIS[option]];
IF NOT good THEN RETURN;
scene.shadows ← truth;
};
Rope.Equal[keyWord, "ambient",
FALSE] => {
color: Color;
ls: LightSource;
color ← TFI3d.ReadColor[IO.RIS[option]];
ls ← SVScene.CreateAmbientLightSource["Ambient", color];
SVScene.AddLightSourceToScene[ls, scene];
};
ENDCASE;
}; -- end of ProcessOption
FileinCoordSystems:
PROC [f:
IO.
STREAM, scene: Scene]
RETURNS [csList: CoordSysList] = {
count: NAT;
mat: Matrix4by4;
newCS: CoordSystem;
csName, wrtName: Rope.ROPE;
csList ← NIL;
TFI3d.ReadRope[f, "CoordSystems"];
TFI3d.ReadWhiteSpace[f];
TFI3d.ReadRope[f, "["];
count ← TFI3d.ReadNAT[f];
TFI3d.ReadRope[f, "]:"]; TFI3d.ReadWhiteSpace[f];
FOR i:
NAT
IN[1..count]
DO
TFI3d.ReadRope[f, "CoordSys:"];
csName ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadWhiteSpace[f];
TFI3d.ReadRope[f, "mat:"];
TFI3d.ReadBlank[f];
mat ← TFI3d.FileinMatrix[f];
TFI3d.ReadBlankAndRope[f, "withRespectTo:"];
wrtName ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadWhiteSpace[f];
SELECT
TRUE
FROM
Rope.Equal[csName,"WORLD"] => {
newCS ← CoordSys.CreateRoot["WORLD"];
WORLD must be defined with respect to NIL, and must be the identity matrix.
scene.coordSysRoot ← newCS;
csList ← AppendToCoordSystems[newCS, csList];
};
Rope.Equal[csName,"SCREEN"] => {};
SCREEN must be in terms of NIL.
The matrix between them must be a translation
SCREEN is ignored since it depends on viewer size and shouldn't be in these files anyway.
ENDCASE => {
Other coord systems are unrestricted. Create them with the new data.
wrtCS: CoordSystem ← CoordSys.FindCoordSysInList[wrtName, csList];
newCS ← CoordSys.CreateCoordSysInTree[csName,mat,wrtCS,scene.coordSysRoot];
csList ← AppendToCoordSystems[newCS, csList];
};
All coordinate systems other than screen and world will be added to the scene's coord sys list (not the same as csList!) when assemblies (see FileinAssemblies) are added.
ENDLOOP;
}; -- end of FileinCoordSystems
AppendToCoordSystems:
PROC [cs: CoordSystem, list: CoordSysList]
RETURNS [CoordSysList] = {
A copy of List.Nconc1 for CoordSysList instead of LIST OF REF ANY
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];
};
FileinLightSources:
PROC [f:
IO.
STREAM, scene: Scene] = {
count: NAT;
thisLS: LightSource;
lsName: Rope.ROPE;
point3d: Point3d;
color: Color;
TFI3d.ReadRope[f, "LightSources"];
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadNAT[f];
TFI3d.ReadRope[f, "]:"]; TFI3d.ReadWhiteSpace[f];
FOR i:
NAT
IN[1..count]
DO
TFI3d.ReadRope[f, "LightSource:"];
lsName ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadBlankAndRope[f, "position:"];
TFI3d.ReadBlank[f];
point3d ← TFI3d.ReadPoint3d[f];
TFI3d.ReadBlankAndRope[f, "color:"];
TFI3d.ReadBlank[f];
color ← TFI3d.ReadColor[f];
TFI3d.ReadWhiteSpace[f];
thisLS ← SVScene.CreateLightSource[lsName, point3d, color];
SVScene.AddLightSourceToScene[thisLS, scene];
ENDLOOP;
};
FileinCameras:
PROC [f:
IO.
STREAM, scene: Scene, csList: CoordSysList, version:
REAL] = {
worldCS: CoordSystem ← CoordSys.FindCoordSysInList["WORLD", csList];
count: NAT;
fileCamera: FileCamera;
TFI3d.ReadBlankAndRope[f, "Cameras"];
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadNAT[f];
TFI3d.ReadRope[f, "]:"]; TFI3d.ReadWhiteSpace[f];
FOR i:
NAT
IN[1..count]
DO
fileCamera ← TFI3d.ReadCamera[f, worldCS, scene, version];
SVScene.AddCameraToScene[fileCamera, scene];
ENDLOOP;
};
FileinCameraOrder:
PROC [f:
IO.
STREAM, scene: Scene] = {
count: NAT;
fileCameraName: Rope.ROPE;
TFI3d.ReadBlankAndRope[f, "Initial Camera Order"];
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadNAT[f];
TFI3d.ReadRope[f, "]:"];
IF count > 0
THEN {
TFI3d.ReadBlank[f];
fileCameraName ← TFI3d.ReadWord[f];
SVScene.AddCameraOrderNameToScene[fileCameraName, scene];
FOR i:
NAT
IN[2..count]
DO
TFI3d.ReadBlankAndRope[f, ","];
TFI3d.ReadBlank[f];
fileCameraName ← TFI3d.ReadWord[f];
SVScene.AddCameraOrderNameToScene[fileCameraName, scene];
ENDLOOP;
};
TFI3d.ReadBlank[f];
};
ReadArtwork:
PRIVATE
PROC [f:
IO.
STREAM, csList: CoordSysList, defaultCS: CoordSystem, wdir: Rope.
ROPE, version:
REAL]
RETURNS [artwork: Artwork] = {
source, isColorRope, nextWord, aisFileName: Rope.ROPE ← NIL;
surface: REF ANY;
material: Material;
mat: Matrix3by3;
color: Imager.Color;
isColorFile: BOOL;
sMap: SMap;
oMap: OMap;
resolution: REAL;
success: BOOL;
csName, className: Rope.ROPE;
coordSys: CoordSystem;
class: ArtworkClass;
IF version > 5.2 THEN {
TFI3d.ReadBlankAndRope[f, "coordSys: "];
csName ← TFI3d.ReadBlankAndWord[f];
IF Rope.Equal[csName, "NIL"] THEN coordSys ← NIL
ELSE coordSys ← CoordSys.FindCoordSysInList[csName, csList];
TFI3d.ReadBlankAndRope[f, "class: "];
className ← TFI3d.ReadBlankAndWord[f];
class ← RopeToArtworkClass[className];
}
ELSE {
coordSys ← defaultCS;
class ← simpleSurface;
};
TFI3d.ReadBlankAndRope[f, "material:"];
TFI3d.ReadBlank[f];
material ← TFI3d.ReadMaterial[f];
TFI3d.ReadBlankAndRope[f, "surface:"];
surface ← TFI3d.ReadSurface[f];
IF (surface #
NIL)
AND class # spaceFunction
THEN {
nextWord ← TFI3d.ReadBlankAndWord[f];
SELECT
TRUE
FROM
Rope.Equal[nextWord, "source:"] => {
-- oMap and sMap are defaulted
source ← TFI3d.ReadBlankAndWord[f];
SELECT
TRUE
FROM
ISTYPE[surface, SVModelTypes.Tube] => {oMap ← tubeO; sMap ← tubeS};
ISTYPE[surface, SVModelTypes.Box] => {oMap ← orthogonal; sMap ← unfoldedBox};
ENDCASE => ERROR;
};
Rope.Equal[nextWord, "SMap:"] => {
TFI3d.ReadBlank[f];
sMap ← TFI3d.ReadSMap[f];
TFI3d.ReadBlankAndRope[f, "OMap:"];
TFI3d.ReadBlank[f];
oMap ← TFI3d.ReadOMap[f];
TFI3d.ReadBlankAndRope[f, "source:"];
source ← TFI3d.ReadBlankAndWord[f];
};
ENDCASE => ERROR;
isColorRope ← TFI3d.ReadBlankAndWord[f];
SELECT
TRUE
FROM
Rope.Equal[isColorRope, "colorFile", FALSE] => isColorFile ← TRUE;
Rope.Equal[isColorRope, "bwFile", FALSE] => isColorFile ← FALSE;
ENDCASE => ERROR;
TFI3d.ReadBlankAndRope[f, "resolution:"];
TFI3d.ReadBlank[f];
resolution ← TFI3d.ReadReal[f];
TFI3d.ReadBlankAndRope[f, "mat:"];
TFI3d.ReadBlank[f];
mat ← TFI3d.FileinMatrix3by3[f];
success ← TRUE;
[aisFileName,,] ←
FS.ExpandName[source, wdir
!
FS.Error => {
IF error.group = user
THEN {
success ← FALSE;
SVError.Append[error.explanation, oneLiner];
CONTINUE;
};
}];
IF NOT success THEN ERROR SVArtwork.FileNotFound;
TFI3d.ReadBlankAndRope[f, "color:"];
TFI3d.ReadBlank[f];
color ← TFI3d.ReadColor[f];
artwork ← SVArtwork.CreateFileArtwork[coordSys, material, surface, oMap, sMap, aisFileName, isColorFile, color, resolution, mat]; -- may generate ERROR SVArtwork.FileNotFound
}
ELSE {
IF surface =
NIL
AND class#spaceFunction
THEN {
TFI3d.ReadBlankAndRope[f, "color:"];
TFI3d.ReadBlank[f];
color ← TFI3d.ReadColor[f];
artwork ← SVArtwork.CreateColorArtwork[color, material]
}
ELSE {
spaceFunction: SpaceFunction;
TFI3d.ReadBlankAndRope[f, "scalars:"];
spaceFunction ← NEW[SpaceFunctionObj];
TFI3d.ReadBlank[f];
spaceFunction.scalars ← TFI3d.ReadPoint3d[f];
TFI3d.ReadBlankAndRope[f, "func: colorcube"];
artwork ← SVArtwork.Create3DArtwork[coordSys, material, spaceFunction];
};
};
};
RopeToArtworkClass:
PROC [className: Rope.
ROPE]
RETURNS [class: ArtworkClass] = {
SELECT TRUE FROM
Rope.Equal[className, "justColor"] => class ← justColor;
Rope.Equal[className, "simpleSurface"] => class ← simpleSurface;
Rope.Equal[className, "spaceFunction"] => class ← spaceFunction;
ENDCASE => ERROR;
};
FileinAssembly:
PROC [f:
IO.
STREAM, scene: Scene, csList: CoordSysList, version:
REAL, wdirForAIS: Rope.
ROPE]
RETURNS [thisA: Assembly] = {
thisCS: CoordSystem;
artwork: Artwork;
scalars: Vector;
primOrComp: Rope.ROPE;
asName, csName, opRope, chairName: Rope.ROPE;
pointSetOp: PointSetOp;
subAssemblies: LIST OF Assembly;
TFI3d.ReadBlankAndRope[f, "Assembly:"];
asName ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadBlankAndRope[f, ","];
TFI3d.ReadBlankAndRope[f, "coordSys:"];
csName ← TFI3d.ReadBlankAndWord[f];
thisCS ← CoordSys.FindCoordSysInList[csName, csList];
TFI3d.ReadBlankAndRope[f, ","];
primOrComp ← TFI3d.ReadBlankAndWord[f];
SELECT TRUE FROM
Rope.Equal[primOrComp, "Composite",
FALSE] => {
TFI3d.ReadBlankAndRope[f, "artwork:"];
TFI3d.ReadBlank[f];
artwork ← ReadArtwork[f, csList, thisCS, wdirForAIS, version];
TFI3d.ReadBlankAndRope[f, "subassemblies"];
TFI3d.ReadBlankAndRope[f, "["];
IF version < 5.2 THEN TFI3d.ReadBlankAndRope[f, "point set op:"];
opRope ← TFI3d.ReadBlankAndWord[f];
pointSetOp ← CSG.RopeToPointSetOp[opRope];
TFI3d.ReadBlankAndRope[f, "]"];
TFI3d.ReadWhiteSpace[f];
[] ← FileinSubassemblyNames[f];
thisA ← SVScene.CreateClusterAssemblyAtExistingCoordSys[asName, pointSetOp, scene, thisCS, FALSE, NIL];
thisA.artwork ← artwork;
subAssemblies ← FileinAssemblies[f, scene, csList, version, wdirForAIS];
WireUpAssemblyToSubassemblies[thisA, subAssemblies, scene];
};
Rope.Equal[primOrComp, "Primitive",
FALSE] => {
obName: Rope.ROPE;
masterObjectFound: BOOL;
TFI3d.ReadBlankAndRope[f, "scalars:"];
TFI3d.ReadBlank[f];
scalars ← TFI3d.ReadPoint3d[f];
TFI3d.ReadBlankAndRope[f, "artwork:"];
TFI3d.ReadBlank[f];
artwork ← ReadArtwork[f, csList, thisCS, wdirForAIS, version];
TFI3d.ReadBlankAndRope[f, "object:"];
obName ← TFI3d.ReadBlankAndWord[f];
[thisA, masterObjectFound] ←
SVScene.CreatePrimitiveAtExistingCoordSys[asName, obName, scalars, scene, thisCS, artwork, FALSE, NIL];
IF NOT masterObjectFound THEN ERROR MasterObjectNotFound;
IF version >= 5.3
AND Rope.Equal[obName, "jack",
FALSE]
THEN {
TFI3d.ReadBlankAndRope[f, "sittingOn:"];
chairName ← TFI3d.ReadBlankAndWord[f];
IF Rope.Equal[chairName, "NIL", FALSE] THEN thisA.sittingOn ← NIL
ELSE thisA.sittingOn ← chairName;
};
};
ENDCASE => SIGNAL ErrorInAssemblyFileout;
}; -- end of FileinAssembly
MasterObjectNotFound: PUBLIC ERROR = CODE;
FileinAssemblies:
PROC [f:
IO.
STREAM, scene: Scene, csList: CoordSysList, version:
REAL, wdirForAIS: Rope.
ROPE]
RETURNS [asList:
LIST
OF Assembly] = {
count: NAT;
thisA: Assembly;
asList ← NIL;-- initially
TFI3d.ReadBlankAndRope[f, "Subassemblies"];
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadBlankAndNAT[f];
TFI3d.ReadBlankAndRope[f, "]:"]; TFI3d.ReadWhiteSpace[f];
FOR i:
NAT
IN[1..count]
DO
thisA ← FileinAssembly[f, scene, csList, version, wdirForAIS];
asList ← AppendToAssemblyList[thisA, asList];
ENDLOOP;
};
ErrorInAssemblyFileout: PUBLIC SIGNAL = CODE;
WireUpAssemblyToSubassemblies:
PROC [assem: Assembly, subA:
LIST
OF Assembly, scene: Scene] = {
thisSub: Assembly;
FOR al:
LIST
OF Assembly ← subA, al.rest
UNTIL al =
NIL
DO
thisSub ← al.first;
SVScene.ConnectAssemblyToParent[thisSub, assem];
ENDLOOP;
};
AppendToAssemblyList:
PROC [as: Assembly, list:
LIST
OF Assembly]
RETURNS [
LIST
OF Assembly] = {
A copy of List.Nconc1 for AssemblyListObj instead of LIST OF REF ANY
z: LIST OF Assembly ← list;
IF z = NIL THEN RETURN[CONS[as,NIL]];
UNTIL z.rest =
NIL
DO z ← z.rest;
ENDLOOP;
z.rest ← CONS[as,NIL];
RETURN[list];
};
AppendToNameList:
PROC [name: Rope.
ROPE, list: NameList]
RETURNS [NameList] = {
A copy of List.Nconc1 for NameList instead of LIST OF REF ANY.
z: NameList ← list;
IF z = NIL THEN RETURN[CONS[name,NIL]];
UNTIL z.rest =
NIL
DO z ← z.rest;
ENDLOOP;
z.rest ← CONS[name,NIL];
RETURN[list];
};
FileinSubassemblyNames:
PROC [f:
IO.
STREAM]
RETURNS [nameList: NameList] = {
count: NAT;
thisName: Rope.ROPE;
nameList ← NIL;
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadBlankAndNAT[f];
TFI3d.ReadBlankAndRope[f, "]:"];
TFI3d.ReadBlankAndRope[f, "("];
IF count = 0 THEN {TFI3d.ReadBlankAndRope[f, ")"]; RETURN;};
thisName ← TFI3d.ReadBlankAndWord[f];
nameList ← AppendToNameList[thisName, nameList];
FOR i:
NAT
IN[2..count]
DO
TFI3d.ReadRope[f, ", "];
thisName ← TFI3d.ReadBlankAndWord[f];
nameList ← AppendToNameList[thisName, nameList];
ENDLOOP;
TFI3d.ReadBlankAndRope[f, ")"];
TFI3d.ReadWhiteSpace[f];
};
FileinObjects:
PROC [f:
IO.
STREAM, scene: Scene] = {
count: NAT;
obName, obClass: Rope.ROPE;
moClass: MasterObjectClass;
moClassFound: BOOL;
mo: MasterObject;
TFI3d.ReadRope[f, "Objects"];
TFI3d.ReadBlankAndRope[f, "["];
count ← TFI3d.ReadNAT[f];
TFI3d.ReadRope[f, "]:"];
TFI3d.ReadWhiteSpace[f];
FOR i:
NAT
IN[1..count]
DO
TFI3d.ReadBlankAndRope[f, "Master Object:"];
obName ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadWhiteSpace[f];
TFI3d.ReadRope[f, "class:"];
obClass ← TFI3d.ReadBlankAndWord[f];
TFI3d.ReadBlank[f];
[moClass, moClassFound] ← SVScene.FindClassFromName[obClass];
IF NOT moClassFound THEN ERROR MasterObjectClassNotFound;
mo ← moClass.filein[f, obName];
SVScene.AddMasterObjectToScene[mo, scene];
ENDLOOP;-- next master object
TFI3d.ReadBlank[f];
}; -- end of FileinObjects
MasterObjectClassNotFound: PUBLIC ERROR = CODE;
END.