-- File: SVEditUserImplB.mesa
-- Last edited by Bier on March 22, 1983 2:24 pm
-- Author: Eric Bier in October 1982
-- Contents: All of the procedures called by SVEditTool when menus and buttons are pressed

DIRECTORY
 BasicObject3d,
 DisplayList3d,
 GraphicsColor,
IO,
 Matrix3d,
 Menus,
 MessageWindow,
 Rope,
 Scratchpad2d,
 SVDisplayListFiling,
 SVEditUser,
 SVPolygon2d,
 SVViewerTools,
 SVViewerUser,
 SweepGeometry,
 ViewerClasses,
 ViewerTools;

SVEditUserImplB: CEDAR PROGRAM
IMPORTS BasicObject3d, DisplayList3d, IO, Matrix3d, MessageWindow, Rope, SweepGeometry, Scratchpad2d, SVDisplayListFiling, SVEditUser, SVPolygon2d, SVViewerTools, SVViewerUser, ViewerTools
EXPORTS SVEditUser =

BEGIN

Assembly: TYPE = DisplayList3d.Assembly;
AssemblyList: TYPE = DisplayList3d.AssemblyList;
AssemblyGenerator: TYPE = DisplayList3d.AssemblyGenerator;
Color: TYPE = GraphicsColor.Color;
EditToolData: TYPE = SVEditUser.EditToolData;
LightSource: TYPE = DisplayList3d.LightSource;
LinearMesh: TYPE = SweepGeometry.LinearMesh;
MasterObject: TYPE = DisplayList3d.MasterObject;
Matrix4by4: TYPE = Matrix3d.Matrix4by4;
MouseButton: TYPE = Menus.MouseButton;
NameAlreadyPresent: SIGNAL = DisplayList3d.NameAlreadyPresent;
Point3d: TYPE = Matrix3d.Point3d;
Polygon: TYPE = SVPolygon2d.Polygon;
RevoluteMesh: TYPE = SweepGeometry.RevoluteMesh;
Path: TYPE = SVPolygon2d.Path;
Scene: TYPE = DisplayList3d.Scene;
Viewer: TYPE = ViewerClasses.Viewer;
ViewerCell: TYPE = REF ViewerCellObj;
ViewerCellObj: TYPE = SVEditUser.ViewerCellObj;
ViewerToolData: TYPE = SVViewerUser.ViewerToolData;
ViewerPictureData: TYPE = SVViewerUser.ViewerPictureData;

-- Basic Shapes

SphereRec: TYPE = REF SphereRecObj;
SphereRecObj: TYPE = BasicObject3d.SphereRecObj;

BlockRec: TYPE = REF BlockRecObj;
BlockRecObj: TYPE = BasicObject3d.BlockRecObj;

CylinderRec: TYPE = REF CylinderRecObj;
CylinderRecObj: TYPE = BasicObject3d.CylinderRecObj;

ConeRec: TYPE = REF ConeRecObj;
ConeRecObj: TYPE = BasicObject3d.ConeRecObj;

TorusRec: TYPE = REF TorusRecObj;
TorusRecObj: TYPE = BasicObject3d.TorusRecObj;

AddSphere: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
-- if mouseButton = red or yellow, then make sure this assembly name is unique and add a new sphere by this name. if mouseButton = blue, then find the old assembly by this name. Make sure it is a primitive assembly. Let it refer to sphere as its master object and use the new scalar values.
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 sphereName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 radius: REAL ← SVViewerTools.GetReal[editToolData.sphereSection.radius, 200];
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;

 sphereMO: MasterObject;
 moFound: BOOL;
 sphereRec: SphereRec;
 moRadius: REAL;

 [sphereMO, moFound] ← DisplayList3d.FindObjectFromName["sphere", scene];
IF NOT moFound THEN ERROR;
 sphereRec ← NARROW[sphereMO.mainBody];
 moRadius ← sphereRec.radius;
 radius ← radius/moRadius;

  -- we need to know the size of the master object in order to know what scalars to use to achieve a sphere of the size requested by the user.

  IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  [newAssembly, ----] ←
   DisplayList3d.CreatePrimitiveAssembly[sphereName, "sphere", [radius, radius, radius], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[]
  ! DisplayList3d.NameAlreadyPresent => {
   MessageWindow.Append["This sphere name is already registered. Try another.",TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  mo, oldMo: MasterObject;
  [assembly, success] ← SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  [mo, moFound] ← DisplayList3d.FindObjectFromName["sphere", scene];
  IF NOT moFound THEN ERROR;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add sphere to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  moFound ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT moFound THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  assembly.scalars ← [radius, radius, radius];
  };
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddSphere

AddBlock: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 x, y, z: REAL;
 blockName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;

 blockMO: MasterObject;
 moFound: BOOL;
 blockRec: BlockRec;
 [blockMO, moFound] ← DisplayList3d.FindObjectFromName["block", scene];
IF NOT moFound THEN ERROR;
 blockRec ← NARROW[blockMO.mainBody];
  -- we need to know the size of the master object in order to know what scalars to use to achieve a block of the size requested by the user
  
 [x, y, z] ← SVViewerTools.GetThreeReals[editToolData.blockSection.xyz];
 x ← x/blockRec.x; y ← y/blockRec.y; z ← z/blockRec.z;

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  [newAssembly, ----] ← DisplayList3d.CreatePrimitiveAssembly[blockName, "block", [x, y, z], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[]
  ! NameAlreadyPresent => {MessageWindow.Append["This block name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  mo, oldMo: MasterObject;
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  [mo, moFound] ← DisplayList3d.FindObjectFromName["block", scene];
  IF NOT moFound THEN ERROR;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add block to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  moFound ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT moFound THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  assembly.scalars ← [x, y, z];
  };
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddBlock

AddCyl: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 cylName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 radius: REAL ← SVViewerTools.GetReal[editToolData.cylinderSection.radius, 200];
 height: REAL ← SVViewerTools.GetReal[editToolData.cylinderSection.height, 300];
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;

 cylMO: MasterObject;
 moFound: BOOL;
 cylinderRec: CylinderRec;
 [cylMO, moFound] ← DisplayList3d.FindObjectFromName["cylinder", scene];
IF NOT moFound THEN ERROR;
 cylinderRec ← NARROW[cylMO.mainBody];
-- we need to know the size of the master object in order to know what scalars to use to achieve a cylinder of the size requested by the user

 radius ← radius/cylinderRec.radius; height ← height/cylinderRec.height;

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  [newAssembly, ----] ←
   DisplayList3d.CreatePrimitiveAssembly[cylName, "cylinder", [radius, height, radius], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[]
  ! NameAlreadyPresent => {MessageWindow.Append["This cyl name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  mo, oldMo: MasterObject;
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  [mo, moFound] ← DisplayList3d.FindObjectFromName["cylinder", scene];
  IF NOT moFound THEN ERROR;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add cylinder to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  moFound ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT moFound THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  assembly.scalars ← [radius, height, radius];
  };
  
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddCyl

AddCone: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 coneName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 radius: REAL ← SVViewerTools.GetReal[editToolData.coneSection.radius, 200];
 height: REAL ← SVViewerTools.GetReal[editToolData.coneSection.height, 300];
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;

 coneMO: MasterObject;
 moFound: BOOL;
 coneRec: ConeRec;
 [coneMO, moFound] ← DisplayList3d.FindObjectFromName["cone", scene];
IF NOT moFound THEN ERROR;
 coneRec ← NARROW[coneMO.mainBody];
-- we need to know the size of the master object in order to know what scalars to use to achieve a cylinder of the size requested by the user

 radius ← radius/coneRec.radius; height ← height/coneRec.height;

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  [newAssembly, ----] ←
   DisplayList3d.CreatePrimitiveAssembly[coneName, "cone", [radius, height, radius], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[]
  ! NameAlreadyPresent => {MessageWindow.Append["This cone name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  mo, oldMo: MasterObject;
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  [mo, moFound] ← DisplayList3d.FindObjectFromName["cone", scene];
  IF NOT moFound THEN ERROR;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add cone to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  moFound ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT moFound THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  assembly.scalars ← [radius, height, radius];
  };

 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddCone

AddTorus: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton,
  shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 torusName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 mo, oldMo: MasterObject;
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;
 bigRadius, sectionRadius: REAL;
 moFound: BOOL;
  
 bigRadius ← SVViewerTools.GetReal[editToolData.torusSection.bigRadius, 100];
 sectionRadius ← SVViewerTools.GetReal[editToolData.torusSection.sectionRadius, 100];
-- create a new torus master object
 mo ← BasicObject3d.TorusMakeMasterObject[torusName, bigRadius, sectionRadius];

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  DisplayList3d.AddMasterObjectToScene[mo, scene];
  [newAssembly, moFound] ←
   DisplayList3d.CreatePrimitiveAssembly[torusName, torusName, [1,1,1], scene];
  IF NOT moFound THEN ERROR;
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[] 
  ! NameAlreadyPresent => {MessageWindow.Append["This assembly name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add torus to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  moFound ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT moFound THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  assembly.scalars ← [1,1,1];
  };

 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddTorus

AddRevo: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scratchpad: Viewer ← editToolData.scratchpad;
 linesOfLongitude: NAT ← 10;
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 revName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];
 mo, oldMo: MasterObject;
 revMesh: RevoluteMesh;
 path: Path;
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;
  
-- create a new linear master object
  path ← Scratchpad2d.GetPath[scratchpad];
  IF path.len = 0 THEN {
   MessageWindow.Append["There is no 2d shape in the scratchpad", TRUE];
   MessageWindow.Blink[];
   RETURN};
  revMesh ← SweepGeometry.RevoluteSweep[path, linesOfLongitude];
  mo ← BasicObject3d.RevoSweepMakeMasterObject[revName, revMesh];

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  DisplayList3d.AddMasterObjectToScene[mo, scene];
  [newAssembly, ----] ←
   DisplayList3d.CreatePrimitiveAssembly[revName, revName, [1,1,1], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[] 
  ! NameAlreadyPresent => {MessageWindow.Append["This revo name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add revolute sweep to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  mo.name ← DisplayList3d.UniqueNameFrom[mo.name, scene];
  DisplayList3d.AddMasterObjectToScene[mo, scene];
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  success ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT success THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  -- leave assembly.scalars as they were;
  };
  
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddRevolute


AddLinear: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scratchpad: Viewer ← editToolData.scratchpad;
 scene: Scene ← editToolData.sceneSection.currentScene;
 errorStream: IO.STREAM;
 errorRope: Rope.ROPE;
 addSucceeds: BOOLTRUE;
 frontDepth, backDepth: REAL;
 lengthRope: Rope.ROPE;
 mo, oldMo: MasterObject;
 linMesh: LinearMesh;
 path: Path;
 poly: Polygon;
 newAssembly, superAssembly, assembly: Assembly;
 success: BOOL;
 linName: Rope.ROPE ← ViewerTools.GetContents[editToolData.sceneSection.assemblyName];

 lengthRope ← ViewerTools.GetContents[editToolData.linSection.depth];
 frontDepth ← SVViewerTools.GetReal[editToolData.linSection.depth, 100]/2.0;
 backDepth ← -frontDepth;

-- create a new linear master object
  path ← Scratchpad2d.GetPath[scratchpad];
  poly ← SVPolygon2d.PathToPolygon[path];
  linMesh ← SweepGeometry.LinearSweep[poly, frontDepth, backDepth];
  mo ← BasicObject3d.LinSweepMakeMasterObject[linName, linMesh];

IF mouseButton = red OR mouseButton = yellow THEN {
  [superAssembly, success] ← SVEditUser.GetSuper[editToolData];
  IF NOT success THEN RETURN;
  DisplayList3d.AddMasterObjectToScene[mo, scene];
  [newAssembly, ----] ←
   DisplayList3d.CreatePrimitiveAssembly[linName, linName, [1,1,1], scene];
  DisplayList3d.AddSubassemblyToAssembly[newAssembly, superAssembly, scene, Matrix3d.Identity[]
  ! NameAlreadyPresent => {MessageWindow.Append["This linear sweep name is already registered. Try another.",TRUE]; MessageWindow.Blink[]; addSucceeds ← FALSE; CONTINUE};
  DisplayList3d.AttemptToAddSubassemblyToPrimitive => {
   MessageWindow.Append["Attempt To Add Subassembly To Primitive", TRUE];
   MessageWindow.Blink[];
   addSucceeds ← FALSE; CONTINUE}];
  IF NOT addSucceeds THEN RETURN;
  }
ELSE {-- mouseButton = blue
  [assembly, success] ←
   SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT success THEN RETURN;
  IF NOT ISTYPE[assembly.object, MasterObject] THEN {
   errorStream ← IO.CreateOutputStreamToRope[];
   errorStream.PutF["Can't add linear sweep to a cluster assembly [%g]",[rope[assembly.name]]];
   errorRope ← IO.GetOutputStreamRope[errorStream];
   MessageWindow.Append[errorRope, TRUE];
   MessageWindow.Blink[];
   RETURN};
  mo.name ← DisplayList3d.UniqueNameFrom[mo.name, scene];
  DisplayList3d.AddMasterObjectToScene[mo, scene];
  oldMo ← NARROW[assembly.object];
  assembly.object ← mo;
  success ← DisplayList3d.DeleteMasterObjectIfUnused[oldMo, scene];
  IF NOT success THEN {MessageWindow.Append[Rope.Cat["Old master object ", oldMo.name, "mysteriously disappeared. Save your work"]];
  MessageWindow.Blink[] };
  -- leave assembly.scalars alone
  };

 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of AddLinear


Copy: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton, shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 wrt, assembly, assemblyCopy: Assembly;
 prefix: Rope.ROPE ← ViewerTools.GetContents[editToolData.copySection.prefix];
 found, success: BOOL;
 [assembly, found] ←
  SVEditUser.GetAssembly[editToolData.copySection.assemblyName, scene];
IF NOT found THEN RETURN;
 [wrt, found] ← SVEditUser.GetAssembly[editToolData.sceneSection.wrt, scene];
IF NOT found THEN RETURN;
 success ← TRUE;
 assemblyCopy ← DisplayList3d.CopyAssemblyAndSons[assembly, scene, prefix
  !DisplayList3d.NameAlreadyPresent => {success ← FALSE; CONTINUE}];
IF NOT success THEN {
  MessageWindow.Append["Some name in assembly is already present"];
  MessageWindow.Blink[];
  RETURN;
  };
 assemblyCopy.coordSys.mat ← assembly.coordSys.mat;
 SVDisplayListFiling.AddSubassemblyToAssemblyWithCS[assemblyCopy,
                  wrt, scene, assemblyCopy.coordSys];
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 }; -- end of Copy

Rename: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton,
  shift, control: BOOL] = TRUSTED {
  editToolData: EditToolData ← NARROW[clientData];
  scene: Scene ← editToolData.sceneSection.currentScene;
  assembly: Assembly;
  found: BOOL;
  newName: Rope.ROPE ← ViewerTools.GetContents[editToolData.renameSection.newName];
  [assembly, found] ←
  SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
  IF NOT found THEN RETURN;
  DisplayList3d.RenameAssembly[assembly, newName, scene];
  ViewerTools.SetContents[editToolData.sceneSection.assemblyName, assembly.name];
  SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
  };
   
Move: PUBLIC PROC [parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton,
  shift, control: BOOL] = TRUSTED {
 editToolData: EditToolData ← NARROW[clientData];
 scene: Scene ← editToolData.sceneSection.currentScene;
 assembly, wrt: Assembly;
 found, wrtIsPrimitive: BOOL;
 [assembly, found] ←
  SVEditUser.GetAssembly[editToolData.sceneSection.assemblyName, scene];
IF NOT found THEN RETURN;
 [wrt, found] ←
  SVEditUser.GetAssembly[editToolData.sceneSection.wrt, scene];
IF NOT found THEN RETURN;
 wrtIsPrimitive ← FALSE;
 DisplayList3d.MoveSubassembly[assembly, wrt, scene
  !DisplayList3d.AttemptToAddSubassemblyToPrimitive =>
   {wrtIsPrimitive ← TRUE; CONTINUE}];
IF wrtIsPrimitive THEN {
  MessageWindow.Append["Can't move assembly to a primitive", TRUE];
  MessageWindow.Blink[];
  };
 SVViewerUser.SceneNewVersion[editToolData.currentViewerToolData];
 SVEditUser.DrawSceneInternal[parent, clientData, mouseButton, shift, control];
 };
  
  
END.