SVSceneImplB.mesa
Last edited by Bier on May 25, 1987 5:30:17 pm PDT
Copyright © 1984 by Xerox Corporation. All rights reserved.
DIRECTORY
AtomButtonsTypes, CoordSys, SVGraphics, Feedback, GList, Imager, ImagerColor, ImagerColorPrivate, ImagerTransformation, IO, Rope, SV2d, SV3d, SVArtwork, SVAssembly, SVBasicTypes, SVBoundBox, SVMasterObject, SVModelTypes, SVRayTypes, SVScene, SVScenePrivate, SVSceneTypes, SVSelect, SVUtility, ViewerClasses;
SVSceneImplB: CEDAR PROGRAM
IMPORTS CoordSys, SVGraphics, Feedback, GList, Imager, ImagerColor, ImagerColorPrivate, IO, Rope, SVArtwork, SVAssembly, SVBoundBox, SVMasterObject, SVScene, SVScenePrivate, SVSelect, SVUtility
EXPORTS SVScene, SVScenePrivate =
BEGIN
Imported Types
BoundBox: TYPE = SVBasicTypes.BoundBox;
Camera: TYPE = SVModelTypes.Camera;
Classification: TYPE = SVRayTypes.Classification;
Color: TYPE = Imager.Color;
CoordSysList: TYPE = SVModelTypes.CoordSysList;
CoordSystem: TYPE = SVModelTypes.CoordSystem;
CSGTree: TYPE = SVRayTypes.CSGTree;
DrawStyle: TYPE = SVModelTypes.DrawStyle;
FeedbackData: TYPE = AtomButtonsTypes.FeedbackData;
FileCamera: TYPE = REF FileCameraObj;
FileCameraObj: TYPE = SVSceneTypes.FileCameraObj;
FileCameraList: TYPE = SVSceneTypes.FileCameraList;
FrameBox: TYPE = SVSceneTypes.FrameBox;
Matrix4by4: TYPE = SV3d.Matrix4by4;
Plane: TYPE = SV3d.Plane;
Point2d: TYPE = SV2d.Point2d;
Point3d: TYPE = SV3d.Point3d;
PointSetOp: TYPE = SVRayTypes.PointSetOp; -- {union, intersection, difference}
Poly3d: TYPE = SV3d.Poly3d;
Primitive: TYPE = SVRayTypes.Primitive;
Ray: TYPE = SVRayTypes.Ray;
Shape: TYPE = SVSceneTypes.Shape;
SliceDescriptor: TYPE = SVSceneTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = SVSceneTypes.SliceDescriptorGenerator;
Vector3d: TYPE = SV3d.Vector3d;
Viewer: TYPE = ViewerClasses.Viewer;
DisplayList Types
Databases, Scenes, Assemblies, and Lightsources
Database: TYPE = REF DatabaseObj;
DatabaseObj: TYPE = SVSceneTypes.DatabaseObj;
Scene: TYPE = REF SceneObj;
SceneObj: TYPE = SVSceneTypes.SceneObj;
Artwork: TYPE = SVModelTypes.Artwork;
Slice: TYPE = REF SliceObj;
SliceObj: TYPE = SVSceneTypes.SliceObj;
ToolData: TYPE = REF ToolDataObj;
ToolDataObj: TYPE = SVSceneTypes.ToolDataObj;
SliceList: TYPE = REF SliceListObj;
SliceListObj: TYPE = SVSceneTypes.SliceListObj;
LightSource: TYPE = REF LightSourceObj;
LightSourceObj: TYPE = SVModelTypes.LightSourceObj;
LightSourceList: TYPE = SVModelTypes.LightSourceList;
Master Object Class Types
MasterObjectClass: TYPE = REF MasterObjectClassObj;
MasterObjectClassObj: TYPE = SVSceneTypes.MasterObjectClassObj;
MasterObjectClassList: TYPE = SVSceneTypes.MasterObjectClassList;
FileoutProc: TYPE = SVSceneTypes.FileoutProc;
FileinProc: TYPE = SVSceneTypes.FileinProc;
Master Object Types
MasterObject: TYPE = REF MasterObjectRec;
MasterObjectRec: TYPE = SVSceneTypes.MasterObjectRec;
MasterObjectList: TYPE = SVSceneTypes.MasterObjectList;
FileoutPolyProc: TYPE = SVSceneTypes.FileoutPolyProc;
RayCastProc: TYPE = SVRayTypes.RayCastProc;
RayCastNoBBoxesProc: TYPE = SVRayTypes.RayCastNoBBoxesProc;
RayCastBoundingSpheresProc: TYPE = SVRayTypes.RayCastBoundingSpheresProc;
GetHedronProc: TYPE = SVSceneTypes.GetHedronProc;
PreprocessProc: TYPE = SVSceneTypes.PreprocessProc;
LineDrawProc: TYPE = SVSceneTypes.LineDrawProc;
NormalsDrawProc: TYPE = SVSceneTypes.NormalsDrawProc;
CountSurfProc: TYPE = SVSceneTypes.CountSurfProc;
GetSurfProc: TYPE = SVSceneTypes.GetSurfProc;
PlanarSurface: TYPE = REF PlanarSurfaceObj;
PlanarSurfaceObj: TYPE = SVSceneTypes.PlanarSurfaceObj;
PlanarSurfaceList: TYPE = SVSceneTypes.PlanarSurfaceList;
DrawPlanarSurfaceProc: TYPE = SVSceneTypes.DrawPlanarSurfaceProc;
DrawSubBoxesProc: TYPE = SVSceneTypes.DrawSubBoxesProc;
DrawSubSpheresProc: TYPE = SVSceneTypes.DrawSubSpheresProc;
Delete Parts of the Scene Tree
DeleteMasterObjectNamed: PUBLIC PROC [moName: Rope.ROPE, scene: Scene] RETURNS [found: BOOL] = {
mo, beforeMo, afterMo: MasterObjectList;
[beforeMo, mo, afterMo, found] ← SVScenePrivate.FindMasterObjectAndNeighborsFromName[moName, scene.masterObjects];
IF NOT found THEN RETURN;
IF beforeMo = NIL THEN scene.masterObjects ← afterMo
ELSE beforeMo.rest ← afterMo;
}; -- end of DeleteMasterObjectNamed
MasterObjectIsUsed: PUBLIC PROC [mo: MasterObject, scene: Scene] RETURNS [used: BOOL] = {
shape: Shape;
IF Rope.Equal[mo.class.name, "sphere"] OR Rope.Equal[mo.class.name, "cylinder"] OR Rope.Equal[mo.class.name, "cone"] OR Rope.Equal[mo.class.name, "halfSpace"] THEN
RETURN[TRUE];
FOR primitiveAssemblies: LIST OF Slice ←
SVScene.ListOfPrimAssemblies[scene.assembly, scene], primitiveAssemblies.rest
UNTIL primitiveAssemblies = NIL DO
shape ← NARROW[primitiveAssemblies.first.shape];
IF shape.mo = mo THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
DeleteMasterObjectIfUnused: PUBLIC PROC [mo: MasterObject, scene: Scene] RETURNS [found: BOOL] = {
shape: Shape;
For now, we won't delete the built-in instances.
IF Rope.Equal[mo.class.name, "sphere"] OR Rope.Equal[mo.class.name, "block"] OR Rope.Equal[mo.class.name, "cylinder"] OR Rope.Equal[mo.class.name, "cone"] OR Rope.Equal[mo.class.name, "halfSpace"] THEN
RETURN[TRUE];
FOR primitiveAssemblies: LIST OF Slice ←
SVScene.ListOfPrimAssemblies[scene.assembly, scene], primitiveAssemblies.rest
UNTIL primitiveAssemblies = NIL DO
shape ← NARROW[primitiveAssemblies.first.shape];
IF shape.mo = mo THEN RETURN[TRUE];
ENDLOOP;
found ← DeleteMasterObjectNamed[mo.name, scene];
}; -- end of DeleteMasterObjectIfUnused
DeleteCoordSysAndChildren: PUBLIC PROC [cs: CoordSystem, scene: Scene] = {
CoordSys.DeleteCoordSysAndChildren[cs, scene.coordSysRoot];
}; -- end of DeleteCoordSysNamed
DeleteLightSourceNamed: PUBLIC PROC [lsName: Rope.ROPE, scene: Scene] = {
ls, beforeLS, afterLS: LightSourceList;
notFound: BOOLFALSE;
[beforeLS, ls, afterLS] ← SVScenePrivate.FindLightSourceAndNeighborsFromName[lsName, scene.lightSources
!SVScenePrivate.LightSourceNotFound => {notFound ← TRUE; CONTINUE}];
IF notFound THEN RETURN;
IF beforeLS = NIL THEN scene.lightSources ← afterLS
ELSE beforeLS.rest ← afterLS;
}; -- end of DeleteLightSourceNamed
ClearScene: PUBLIC PROC [scene: Scene] = {
scene.assembly.shape ← NEW[SliceListObj ← [NIL, union] ];
ClearCoordSystems[scene];
ClearMasterObjects[scene];
};
ClearCoordSystems: PUBLIC PROC [scene: Scene] = {
Removes all but WORLD, SCREEN and sceneAssembly.
Assumes for now that WORLD, and SCREEN are the first 2 coordsystems on the list.
world: CoordSystem ← scene.coordSysRoot;
DeleteCoordSysAndChildren[CoordSys.GetSceneAssembly[world], scene];
};
ClearMasterObjects: PUBLIC PROC [scene: Scene] = {
Removes all but "block", "sphere", "cone", and "cylinder" from current scene.
Assumes for now that "sphere","cone", and "cylinder", and "block" are the first five master objects.
z: MasterObjectList ← scene.masterObjects; -- "sphere"
z ← z.rest;-- "block"
z ← z.rest;-- "cone"
z ← z.rest;-- "cylinder"
z.rest ← NIL;-- cut off the rest
};
DeleteSubassemblyFromAssembly: PUBLIC PROC [subassembly: Slice, assembly: Slice, scene: Scene] RETURNS [success: BOOL] = {
IF ISTYPE[assembly.shape, SliceList] THEN
[assembly.shape, success] ← RemoveFromAssemblyList[subassembly,
NARROW[assembly.shape, SliceList], scene]
ELSE ERROR;
};
RemoveFromAssemblyList: PROC [a: Slice, al: SliceList, scene: Scene] RETURNS [newAl: SliceList, success: BOOL] = {
Tree walk through the assembly deleting all of its coordinate systems. Then, cut the assembly loose and feed it to the garbage collector.
lastAssemblyList: LIST OF Slice ← al.list;
DeleteAllAssembliesSittingOn[a, scene];
IF lastAssemblyList.first = a THEN {-- first item on the list
DeleteAssemblyAndSons[a, scene];
al.list ← lastAssemblyList.rest;
RETURN[al, TRUE];
};
FOR l: LIST OF Slice ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
DeleteAssemblyAndSons[a, scene];
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
TemporaryRemoveFromAssemblyList: PUBLIC PROC [a: Slice, al: SliceList, scene: Scene] RETURNS [newAl: SliceList, success: BOOL] = {
A simple list remove operation. Does not break up the assembly and its sons, nor does it delete their coordinate systems. This routine is called by MoveToFrontOfAssembly to splice an assembly out of an SliceList.
lastAssemblyList: LIST OF Slice ← al.list;
IF lastAssemblyList.first = a THEN {-- first item on the list
al.list ← lastAssemblyList.rest; RETURN[al, TRUE] };
FOR l: LIST OF Slice ← lastAssemblyList.rest, l.rest UNTIL l = NIL DO
IF l.first = a THEN {
success ← TRUE;
lastAssemblyList.rest ← l.rest; -- splice out a
newAl ← al;
RETURN;
}
ELSE lastAssemblyList ← lastAssemblyList.rest;
ENDLOOP;
success ← FALSE;
};
DeleteAssemblyAndSons: PROC [a: Slice, scene: Scene] = {
DeleteCoordSysAndChildren[a.coordSys, scene];
};
DeleteAllPrimitivesOfClass: PUBLIC PROC [className: Rope.ROPE, scene: Scene, feedback: FeedbackData] = {
className must be a master object class, e.g. "sphere" or "jack". All primitive (leaf) assemblies refering to shapes of this class will be deleted in subtree rooted at root.
moClass: MasterObjectClass;
success: BOOL;
[moClass, success] ← SVMasterObject.FindClassFromName[className];
IF NOT success THEN {
Feedback.Append[feedback, Rope.Cat["DeleteAllPrimitivesOfClass: Couldn't find class ", className, "."], oneLiner];
Feedback.Blink[feedback];
};
DeleteAllOfClassAux[moClass, scene.assembly, scene];
};
DeleteAllOfClassAux: PROC [moClass: MasterObjectClass, root: Slice, scene: Scene] = {
WITH root.shape SELECT FROM
shape: Shape => {
child, parent: Slice;
success: BOOL;
IF shape.mo.class = moClass THEN {
[child, parent] ← SVScene.FindAssemblyFromName[root.name, scene];
IF child # root THEN ERROR;
success ← SVScene.DeleteSubassemblyFromAssembly[child, parent, scene];
Removes assembly from the assemblyList of superAssembly and deletes the coordinate systems of all of its children.
IF NOT success THEN ERROR;
};
};
alist: SliceList => {
FOR list: LIST OF Slice ← alist.list, list.rest UNTIL list = NIL DO
DeleteAllOfClassAux[moClass, list.first, scene];
ENDLOOP;
};
ENDCASE => ERROR;
};
DeleteAllAssembliesSittingOn: PUBLIC PROC [chair: Slice, scene: Scene] = {
All assemblies A such that A.sittingOn = chair.name will be deleted along with their children.
DeleteAllSittingOnAux[chair.name, scene.assembly, scene];
};
DeleteAllSittingOnAux: PROC [chairName: Rope.ROPE, root: Slice, scene: Scene] = {
child, parent: Slice;
success: BOOL;
IF Rope.Equal[root.sittingOn, chairName, TRUE] THEN {
[child, parent] ← SVScene.FindAssemblyFromName[root.name, scene];
IF child # root THEN ERROR;
success ← SVScene.DeleteSubassemblyFromAssembly[child, parent, scene];
Removes assembly from the assemblyList of superAssembly and deletes the coordinate systems of all of its children.
IF NOT success THEN ERROR;
RETURN;
};
WITH root.shape SELECT FROM
shape: Shape => {};
alist: SliceList => {
FOR list: LIST OF Slice ← alist.list, list.rest UNTIL list = NIL DO
DeleteAllSittingOnAux[chairName, list.first, scene];
ENDLOOP;
};
ENDCASE => ERROR;
};
We will certainly delete the coincident of all movee's. We may also delete an assembly indirectly referenced by a selection. Worst of all, we may delete an assembly and forget to delete the hooks which are on it. This last may be fixed soon.
DeleteAllSelected: PUBLIC PROC [scene: Scene, camera: Camera] RETURNS [bBox: BoundBox] = {
sliceDescGen: SliceDescriptorGenerator;
assembly, superAssembly: Slice;
success: BOOLTRUE;
bBox ← SVBoundBox.BoundBoxOfSelected[scene, camera, normal];
sliceDescGen ← SVSelect.SelectedSlices[scene, normal];
FOR coin: Slice ← SVSelect.NextSlice[sliceDescGen], SVSelect.NextSlice[sliceDescGen] UNTIL coin = NIL DO
[assembly, superAssembly, success] ←
SVScene.FindAssemblyFromName[coin.name, scene];
IF NOT success THEN LOOP;
SVSelect.DeselectEntireSlice[assembly, scene, hot];
success ← SVScene.DeleteSubassemblyFromAssembly[assembly, superAssembly, scene];
Removes assembly from superAssembly; deletes the coordinate systems of its children.
IF NOT success THEN ERROR;
ENDLOOP;
SVSelect.DeselectAll[scene, normal];
};
Copy Parts of the Scene Tree
CopyAssemblyAndSonsRename: PUBLIC PROC [assembly: Slice, scene: Scene, prefix: Rope.ROPE, parent: Slice, feedback: FeedbackData] RETURNS [copy: Slice] = {
For copying assemblies within the same scene. The copies can refer to the same master object records as other objects in this scene. The prefix rope is prepended to the names of each node as it is copied to distinguish it from the original. CreateClusterAssemblyAtExistingCoordSys is used for filing in, so it doesn't do all we would like. We must wire up parents to the children manually.
moFound: BOOL;
IF NewNamesAlreadyPresent[assembly, scene, prefix] THEN SIGNAL SVScene.NameAlreadyPresent;
WITH assembly.shape SELECT FROM
alist: SliceList => {-- assembly is a composite assembly.
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: Rope.Concat[prefix, assembly.name], mat: CoordSys.GetMat[assembly.coordSys], parent: parent.coordSys, root: scene.coordSysRoot];
copy ← SVAssembly.CreateClusterAssemblyAtExistingCoordSys[Rope.Concat[prefix, assembly.name], alist.pointSetOp, scene, copyCS];
FOR list: LIST OF Slice ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsRename[list.first, scene, prefix, copy, feedback];
CopyAssemblyAndSonsRename returns an assembly which is complete and wired up to parent.
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: Rope.Concat[prefix, assembly.name], mat: CoordSys.GetMat[assembly.coordSys], parent: parent.coordSys, root: scene.coordSysRoot];
[copy, moFound] ← SVAssembly.CreatePrimitiveAtExistingCoordSys[Rope.Concat[prefix, assembly.name], shape.mo.name, CoordSys.GetScalars[shape.coordSys], scene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR; -- for some reason the master object which assembly refers to is not registered in the scene (report this to SolidviewsSupport).
};
ENDCASE => ERROR;
SVAssembly.ConnectAssemblyToParent[copy, parent];
}; -- end of CopyAssemblyAndSons
CopyAssemblyAndSonsNoRename: PUBLIC PROC [assembly: Slice, newScene: Scene, parent: Slice, feedback: FeedbackData] RETURNS [copy: Slice] = {
For copying an assembly from one scene to another. This presents problems since the needed masterobject may not be already present in the target scene. We assume that procedure MergeAssemblyIntoScene has already added the necessary master objects. No prefix is added. We just pray that there are no name conflicts. CreateClusterAssemblyAtExistingCoordSys is used for filing in, so it doesn't do all we would like. We must wire up parents to the children manually.
moFound: BOOL;
IF SVScene.AnyNamesAlreadyPresent[assembly, newScene] THEN SIGNAL SVScene.NameAlreadyPresent;
WITH assembly.shape SELECT FROM
alist: SliceList => {-- assembly is a composite assembly.
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: assembly.name, mat: CoordSys.GetMat[assembly.coordSys], parent: parent.coordSys, root: newScene.coordSysRoot];
copy ← SVAssembly.CreateClusterAssemblyAtExistingCoordSys[assembly.name, alist.pointSetOp, newScene, copyCS];
FOR list: LIST OF Slice ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsNoRename[list.first, newScene, copy, feedback];
CopyAssemblyAndSonsNoRename returns an assembly which is complete and wired up to parent.
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem ← CoordSys.CreateCoordSysInTree[name: assembly.name, mat: CoordSys.GetMat[assembly.coordSys], parent: parent.coordSys, root: newScene.coordSysRoot];
[copy, moFound] ← SVAssembly.CreatePrimitiveAtExistingCoordSys[assembly.name, shape.mo.name, CoordSys.GetScalars[shape.coordSys], newScene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR; -- for some reason the master object which assembly refers to is not registered in the scene (report this to SolidviewsSupport).
};
ENDCASE => ERROR;
SVAssembly.ConnectAssemblyToParent[assembly, parent];
}; -- end of CopyAssemblyAndSonsNoRename
ReadAlpha: PROC [s: IO.STREAM] RETURNS [base: Rope.ROPE] = {
skip: INT;
[base, skip] ← IO.GetTokenRope[s, AlphaBreakProc];
};
AlphaBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = {
RETURN[IF char = '. THEN break ELSE other]
};
FindUniqueAssemblyNum: PROC [scene: Scene] RETURNS [num: NAT] = {
num ← FindUniqueAssemblyNumAux[scene.assembly];
num ← num + 1;
};
FindUniqueAssemblyNumAux: PROC [assembly: Slice] RETURNS [num: NAT] = {
Finds an integer such that "<name>.<num>" is unique in the scene of assembly for all strings <name>. i.e. Find the highest .num extension in the tree rooted at assembly.
thisNum: NAT;
WITH assembly.shape SELECT FROM
alist: SliceList => {-- assembly is a composite assembly.
[----, num] ← CoordSys.BaseAndNumber[assembly.name];
FOR l: LIST OF Slice ← alist.list, l.rest UNTIL l = NIL DO
thisNum ← FindUniqueAssemblyNumAux[l.first];
num ← MAX[num, thisNum];
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
[----, num] ← CoordSys.BaseAndNumber[assembly.name];
};
ENDCASE => ERROR;
};
CopyAssemblyAndSonsUniqueNames: PUBLIC PROC [assembly: Slice, oldScene: Scene, newScene: Scene, parent: Slice, feedback: FeedbackData] RETURNS [copy: Slice] = {
oldScene is the scene assembly belongs to. newScene is the scene copy will belong to. parent must be an assembly in the new scene.
num: NAT;
success: BOOL;
num ← FindUniqueAssemblyNum[newScene];
IF oldScene = newScene THEN
copy ← CopyAssemblyAndSonsUniqueNamesAux[assembly, newScene, parent, num, feedback]
ELSE {
success ← CopyNeededMasterObjects[assembly, oldScene, newScene];
IF NOT success THEN {
Feedback.Append[feedback, Rope.Cat["Masterobject name conflict scenes: ", oldScene.name, "/", newScene.name], oneLiner];
Feedback.Blink[feedback];
RETURN;
};
copy ← CopyAssemblyAndSonsUniqueNamesAux[assembly, newScene, parent, num, feedback];
};
};
CopyAssemblyAndSonsUniqueNamesAux: PUBLIC PROC [assembly: Slice, newScene: Scene, parent: Slice, num: NAT, feedback: FeedbackData] RETURNS [copy: Slice] = {
An attempt to do it right. For assembly and all of its successors, we find an integer a just high enough so that if name.# becomes name.a then all names will be unique. We copy the assembly and its successors and rename them this way.
CopyAssemblyAndSonsUniqueNamesAux returns an assembly which is complete and wired up to parent.
thisBase, unique: Rope.ROPE;
thisNum: NAT;
moFound: BOOL;
WITH assembly.shape SELECT FROM
alist: SliceList => {-- assembly is a composite assembly.
copyCS: CoordSystem;
[thisBase, thisNum] ← CoordSys.BaseAndNumber[assembly.name];
unique ← IO.PutFR["%g.%g", [rope[thisBase]], [integer[num]]];
copyCS ← CoordSys.CreateCoordSysInTree[name: unique,
mat: CoordSys.GetMat[assembly.coordSys],
parent: parent.coordSys,
root: newScene.coordSysRoot];
copy ← SVAssembly.CreateClusterAssemblyAtExistingCoordSys[unique, alist.pointSetOp, newScene, copyCS];
FOR list: LIST OF Slice ← alist.list, list.rest UNTIL list = NIL DO
[] ← CopyAssemblyAndSonsUniqueNamesAux[list.first, newScene, copy, num, feedback];
ENDLOOP;
};
shape: Shape => { -- assembly is a primitive assembly
artworkCopy: Artwork ← SVArtwork.Copy[assembly.artwork];
copyCS: CoordSystem;
oldMO, newMO: MasterObject;
[thisBase, thisNum] ← CoordSys.BaseAndNumber[assembly.name];
unique ← IO.PutFR["%g.%g",[rope[thisBase]], [integer[num]]];
copyCS ← CoordSys.CreateCoordSysInTree[
name: unique,
mat: CoordSys.GetMat[assembly.coordSys],
parent: parent.coordSys,
root: newScene.coordSysRoot];
oldMO ← shape.mo;
newMO ← oldMO.class.copy[oldMO, unique];
SVScene.AddMasterObjectToScene[newMO, newScene];
[copy, moFound] ← SVAssembly.CreatePrimitiveAtExistingCoordSys[unique, newMO.name, CoordSys.GetScalars[shape.coordSys], newScene, copyCS, artworkCopy, assembly.isTool];
IF NOT moFound THEN ERROR;
};
ENDCASE => ERROR;
SVAssembly.ConnectAssemblyToParent[copy, parent];
};
AddMOsToScene: PROC [moList: MasterObjectList, scene: Scene] = {
We assume that none of the mo's in moList is already in scene
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
scene.masterObjects ← SVUtility.AppendToMasterObjects[list.first, scene.masterObjects];
ENDLOOP;
};
CopyMOList: PROC [moList: MasterObjectList] RETURNS [copyList: MasterObjectList] = {
copyList ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
copyList ← SVUtility.AppendToMasterObjects[SVScene.CopyMasterObject[list.first], copyList];
ENDLOOP;
};
CopyNeededMasterObjects: PUBLIC PROC [assembly: Slice, fromScene, toScene: Scene] RETURNS [success: BOOL] = {
Makes a list of all of the masterobjects needed. Compares this list to the list of masterobjects available in the new scene, subtracting any that are available. Copies those that are still needed and adds them to the new scene. Assumes that if two master objects have the same name, they are the same.
moList: MasterObjectList;
toMoList: MasterObjectList;
neededList: MasterObjectList;
success ← TRUE;
moList ← SVScene.MasterObjectsOfAssembly[assembly, fromScene];
toMoList ← SVScene.MasterObjectsOfScene[toScene];
neededList ← SVScenePrivate.MoListMinusMoList[moList, toMoList];
neededList ← CopyMOList[neededList];
AddMOsToScene[neededList, toScene];
};
Other List Auxiliaries
Removing Duplicates
RemoveDuplicateMOs: PUBLIC PROC [moList: MasterObjectList] RETURNS [uniqueList: MasterObjectList] = {
**** Naive algorithm for now. Go through moList. Add anything to uniqueList which it doesn't already have
thisMO: MasterObject;
uniqueList ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
thisMO ← list.first;
IF NOT ObjectNameInList[thisMO.name, uniqueList] THEN
uniqueList ← CONS[thisMO, uniqueList];
ENDLOOP;
};
ObjectNameInList: PROC [moName: Rope.ROPE, moList: MasterObjectList] RETURNS [BOOL]= {
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
IF Rope.Equal[list.first.name, moName, TRUE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
MoListMinusMoList: PUBLIC PROC [moList1, moList2: MasterObjectList] RETURNS [moList1MinusmoList2: MasterObjectList] = {
Find all elements of moList1 which are not in moList2
moList1MinusmoList2 ← NIL;
FOR list: MasterObjectList ← moList1, list.rest UNTIL list = NIL DO
IF NOT ObjectNameInList[list.first.name, moList2] THEN
moList1MinusmoList2 ← CONS[list.first, moList1MinusmoList2];
ENDLOOP;
};
CopyMasterObjectList: PUBLIC PROC [moList: MasterObjectList] RETURNS [copy: MasterObjectList] = {
Currently this has O[n2] behavior. Since moList typically has 4 elements, this is alright. Improve if moList grows.
copy ← NIL;
FOR list: MasterObjectList ← moList, list.rest UNTIL list = NIL DO
copy ← SVUtility.AppendToMasterObjects[list.first, copy];
ENDLOOP;
};
Find Scene Entities from their Names
NewNamesAlreadyPresent: PUBLIC PROC [assembly: Slice, scene: Scene, prefix: Rope.ROPE] RETURNS [BOOL] = {
newName: Rope.ROPE ← Rope.Concat[prefix, assembly.name];
IF SVScene.AssemblyNameIsPresent[newName, scene] THEN RETURN [TRUE];
WITH assembly.shape SELECT FROM
shape: Shape => RETURN[FALSE];
aList: SliceList => RETURN[NewNamesAlreadyPresentInList[aList, scene, prefix]];
ENDCASE => RETURN[FALSE];
};
NewNamesAlreadyPresentInList: PROC [assemblyList: SliceList, scene: Scene, prefix: Rope.ROPE] RETURNS [BOOL] = {
FOR list: LIST OF Slice ← assemblyList.list, list.rest UNTIL list = NIL DO
IF NewNamesAlreadyPresent[list.first, scene, prefix] THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
Draw Parts of the Scene Tree
DrawScene: PUBLIC PROC [dc: Imager.Context, scene: Scene, camera: Camera, except: Slice ← NIL] = {
DrawSceneAux: SAFE PROC = {
SVGraphics.Clip[dc, camera];
SELECT camera.style FROM
wire => DrawWireAssemblies[dc, scene, camera];
shaded => DrawShadedAssemblies[dc, scene, camera, clippedBy, except];
normals => DrawNormalsAssemblies[dc, scene, camera];
ENDCASE => SIGNAL NotYetImplemented;
Draw the current bounding frame if there is one.
IF NOT camera.frame.fullScreen THEN {
SetColor[dc, camera, Imager.black];
SVGraphics.DrawFrame[dc, camera];
};
};
clippedBy: Imager.Rectangle ← [0.0, 0.0, 8.5*72.0, 11.0*72.0];
Imager.DoSaveAll[dc, DrawSceneAux];
};
NotYetImplemented: PUBLIC SIGNAL = CODE;
DrawWireAssemblies: PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
found: BOOL;
assembly: Slice;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← SVScene.FindAssemblyFromName[assemblyName, scene
!SVScene.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVAssembly.Draw[assembly, dc, scene, camera];
};
ENDLOOP;
};
DrawShadedAssemblies: PROC [dc: Imager.Context, scene: Scene, camera: Camera, clippedBy: Imager.Rectangle, except: Slice ← NIL] = {
assemblyName: Rope.ROPE;
assembly: Slice;
found: BOOL;
Draw a background color.
SetColor[dc, camera, scene.backgroundColor];
Imager.MaskRectangle[dc, clippedBy];
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← SVScene.FindAssemblyFromName[assemblyName, scene
!SVScene.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVAssembly.Draw[assembly, dc, scene, camera];
};
ENDLOOP;
};
DrawNormalsAssemblies: PROC [dc: Imager.Context, scene: Scene, camera: Camera] = {
assemblyName: Rope.ROPE;
assembly: Slice;
found: BOOL;
FOR list: LIST OF Rope.ROPE ← camera.visibleAssemblies, list.rest UNTIL list = NIL DO
assemblyName ← list.first;
found ← TRUE;
[assembly, ----] ← SVScene.FindAssemblyFromName[assemblyName, scene
!SVScene.AssemblyNotFound => {found ← FALSE; CONTINUE}];
IF found THEN {
SVAssembly.Draw[assembly, dc, scene, camera];
};
ENDLOOP;
};
SetColor: PROC [dc: Imager.Context, camera: Camera, color: Color] = {
IF camera.colorFilm THEN Imager.SetColor[dc, color]
ELSE {
intensity: REAL ← ImagerColorPrivate.IntensityFromColor[NARROW[color]];
Imager.SetColor[dc, ImagerColor.ColorFromGray[1.0-intensity]]};
};
SaveSelections: PUBLIC PROC [scene: Scene] = {
scene.savedSelected.normal ← NARROW[GList.Append[scene.selected.normal, NIL]];
this is a trick to make a copy of the list quickly. The list will be modified in place later on.
};
RestoreSelections: PUBLIC PROC [scene: Scene] = {
normalSelectedList: LIST OF SliceDescriptor ← scene.savedSelected.normal;
SVSelect.DeselectAll[scene, normal];
FOR list: LIST OF SliceDescriptor ← normalSelectedList, list.rest UNTIL list = NIL DO
SVSelect.SelectSlice[list.first, scene, normal];
ENDLOOP;
};
END.