Dispatcher
From TrainzOnline
(Difference between revisions)
(Created page with "TBD: Update text TBD: Repost or update additional informations after reposting the registered objectsoup * CONTCRANE: Repost a goid list of reachable stacks. The contcrane i...") |
|||
| Line 1: | Line 1: | ||
TBD: Update text | TBD: Update text | ||
| − | TBD: Repost or update additional informations after reposting the registered objectsoup | + | '''TBD: Repost or update additional informations after reposting the registered objectsoup.''' |
| + | * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. | ||
| + | * CONTSTACK: ??? | ||
| + | * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero. '''''TBD: What happens if the stack it attached to does not exist? Possibly handled as a free container?''''' | ||
| − | * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. | + | ==Asset files pre version 0.1== |
| − | * CONTSTACK: ??? | + | The files compile errorless and the messaging runs well. No more functionality implemented and tested in this pre version. |
| − | * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero. | + | |
| + | ===config.txt=== | ||
| + | <CODE> | ||
| + | kuid <kuid2:215489:110000:1> | ||
| + | username "aCTS DISPATCHER Library V1" | ||
| + | kind "Library" | ||
| + | category-class "YL" | ||
| + | trainz-build 4.6 | ||
| + | |||
| + | description "aCTS DISPATCHER Library V1" | ||
| + | |||
| + | script "acts_dispatcher.gs" | ||
| + | class "acts_dispatcher" | ||
| + | |||
| + | thumbnails | ||
| + | { | ||
| + | 0 | ||
| + | { | ||
| + | image "acts_dispatcher_thumb.jpg" | ||
| + | width 240 | ||
| + | height 180 | ||
| + | } | ||
| + | } | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_dispatcher.gs=== | ||
| + | <CODE> | ||
| + | include "acts_global_values.gs" | ||
| + | include "acts_tools_script.gs" | ||
| + | |||
| + | //----------------------------------------------------------------------------- | ||
| + | // aCTS Dispatcher V0.1 Central Script - acts_dispatcher | ||
| + | //----------------------------------------------------------------------------- | ||
| + | // X acts_dispatcher <-- acts_dispatcher_script | ||
| + | // X acts_dispatcher_script <-- acts_dispatcher_globals | ||
| + | // X acts_dispatcher_globals <-- acts_global_values | ||
| + | // acts_global_values <-- MapObject | ||
| + | //----------------------------------------------------------------------------- | ||
| + | |||
| + | //----------------------------------------------------------------------------- | ||
| + | class acts_dispatcher_globals isclass acts_global_values | ||
| + | { | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Store from dispatcher received object registration values to the | ||
| + | // respective dispatchers sub soup. The sub soups register ids run as int | ||
| + | // from 0 ... The received id -1 tells, that the object isn't yet | ||
| + | // registered. | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Because the register id number list gets gaps while unregistering it will | ||
| + | // be nessecary to have some gap filling methods additionally. See | ||
| + | // AppendInsertUpdateObjectDataSoups and FindObjectSoupEntry methods. | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // AssetInstanceSoup { | ||
| + | // ObjectDataSoup { ... }, Only container, contstack, contcrane | ||
| + | // LocationSoup { ... }, Only container, contstack, contcrane | ||
| + | // OrientationSoup { ... }, Only container, contstack, contcrane | ||
| + | // SkinDataSoup { ... }, Only container | ||
| + | // ContentDataSoup { ... }, Only container | ||
| + | // X DispatcherDataSoup { ... } Only dispatcher | ||
| + | // X ContainerSoups { ... } Only dispatcher | ||
| + | // X ContstackSoups { ... } Only dispatcher | ||
| + | // X ContcraneSoups { ... } Only dispatcher | ||
| + | // } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | Soup ContainerSoups = Constructors.NewSoup(); | ||
| + | Soup ContstackSoups = Constructors.NewSoup(); | ||
| + | Soup ContcraneSoups = Constructors.NewSoup(); | ||
| + | //--------------------------------------------------------------------------- | ||
| + | Soup DispatcherDataSoup = Constructors.NewSoup(); | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // ObjectDataSoup received from and posted to objects. | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // ObjectDataSoup { goid GameObjectID, type string, dispID int, | ||
| + | // length int, height int, | ||
| + | // stack goid, place int, Only container | ||
| + | // active bool, action string }, | ||
| + | // activ: true means the object sended a register message while session run. | ||
| + | // All objects were set false while initialising dispatcher and if | ||
| + | // they stay false their entries will be deleted next initialising. | ||
| + | // actions: ["APPENDED", "INSERTED", "UPDATED"]; | ||
| + | //--------------------------------------------------------------------------- | ||
| + | GameObjectID dispgoid = me.GetGameObjectID(); | ||
| + | string objecttype; | ||
| + | GameObjectID objectgoid; | ||
| + | //--------------------------------------------------------------------------- | ||
| + | }; | ||
| + | |||
| + | class acts_dispatcher_script isclass acts_dispatcher_globals | ||
| + | { | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void SetProperties(Soup soup) // Callback method after Init method | ||
| + | { | ||
| + | inherited(soup); | ||
| + | //------------------------------------------------------------------------- | ||
| + | DispatcherDataSoup.Copy(soup.GetNamedSoup("DispatcherData")); | ||
| + | ContainerSoups.Copy(soup.GetNamedSoup("ContainerSoups")); | ||
| + | ContstackSoups.Copy(soup.GetNamedSoup("ContstackSoups")); | ||
| + | ContcraneSoups.Copy(soup.GetNamedSoup("ContcraneSoups")); | ||
| + | //------------------------------------------------------------------------- | ||
| + | isSetPropertiesMethodFinnished = true; | ||
| + | PostMessage(me,"OBJECTINIT","SETPROPS_FINNISH",0); | ||
| + | return; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public Soup GetProperties(void) // Callback method before closing session | ||
| + | { | ||
| + | Soup soup = inherited(); | ||
| + | //------------------------------------------------------------------------- | ||
| + | DispatcherDataSoup.SetNamedTag("firstrun",false); | ||
| + | //------------------------------------------------------------------------- | ||
| + | soup.SetNamedSoup("DispatcherData",DispatcherDataSoup); | ||
| + | soup.SetNamedSoup("ContainerSoups",ContainerSoups); | ||
| + | soup.SetNamedSoup("ContstackSoups",ContstackSoups); | ||
| + | soup.SetNamedSoup("ContcraneSoups",ContcraneSoups); | ||
| + | //------------------------------------------------------------------------- | ||
| + | return soup; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void WorldInitHandler(Message msg) | ||
| + | { | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " [" + dispgoid.SerialiseToString() + "]" | ||
| + | + " DISPATCHER GOT WORLDINIT MESSAGE [" | ||
| + | + msg.major+"] ["+msg.minor+"]"); | ||
| + | //------------------------------------------------------------------------- | ||
| + | // If one of the two methods (Init or SetProperties) isn't finished yet, | ||
| + | // post "World","ModuleInit" message a little bit later again. | ||
| + | // So it is guaranteed that the Init and SetProperties methods are finished | ||
| + | // as well as the "World","ModuleInit" message tells to be save using the | ||
| + | // World.GetCurrentModule method. | ||
| + | //------------------------------------------------------------------------- | ||
| + | if (!(isSetPropertiesMethodFinnished and isInitMethodFinnished)) | ||
| + | { | ||
| + | //---------------------------------------------------------------------- | ||
| + | // While first run and before first session save for libraries the | ||
| + | // SetProperties methon will not run, whle no soup stored. If this case | ||
| + | // isn't handeled, the repost of "World","ModuleInit" runs infinitly. | ||
| + | //---------------------------------------------------------------------- | ||
| + | if (!DispatcherDataSoup.GetNamedTagAsBool("firstrun")) | ||
| + | PostMessage(me, "World", "ModuleInit", 0.1); | ||
| + | } | ||
| + | //------------------------------------------------------------------------- | ||
| + | isWorldInitFinnished = true; | ||
| + | PostMessage(me, "OBJECTINIT", "WORLD_INIT_FINNISHED", 0.0); | ||
| + | //------------------------------------------------------------------------- | ||
| + | return; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void ObjectInitHandler(Message msg) | ||
| + | { | ||
| + | //------------------------------------------------------------------------- | ||
| + | // Until the Trainz core send the "World","ModuleInit" message it is not | ||
| + | // guarented to decide with the World.GetCurrentModule method to be in the | ||
| + | // returned module! | ||
| + | //------------------------------------------------------------------------- | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " [" + dispgoid.SerialiseToString() + "]" | ||
| + | + " DISPATCHER GOT MESSAGE ["+msg.major+"] ["+msg.minor+"]"); | ||
| + | //-------------------------------------------------------------------------*/ | ||
| + | if (msg.dst==me and msg.major=="OBJECTINIT") | ||
| + | { | ||
| + | //----------------------------------------------------------------------- | ||
| + | if (msg.minor=="INIT_FINNISHED") | ||
| + | { | ||
| + | //--------------------------------------------------------------------- | ||
| + | // Not used yet | ||
| + | //--------------------------------------------------------------------- | ||
| + | } | ||
| + | //----------------------------------------------------------------------- | ||
| + | if (msg.minor=="SETPROPS_FINNISHED") | ||
| + | { | ||
| + | //--------------------------------------------------------------------- | ||
| + | // If DispatcherDataSoup is empty, this is the first call unsaved call | ||
| + | //--------------------------------------------------------------------- | ||
| + | if (DispatcherDataSoup.CountTags()==0) | ||
| + | DispatcherDataSoup.SetNamedTag("firstrun",true); | ||
| + | } | ||
| + | //----------------------------------------------------------------------- | ||
| + | if (msg.minor=="WORLD_INIT_FINNISHED") | ||
| + | { | ||
| + | //--------------------------------------------------------------------- | ||
| + | // Do no module only, driver module only or surveyor module only | ||
| + | // related initiations | ||
| + | //--------------------------------------------------------------------- | ||
| + | if (World.GetCurrentModule() == World.DRIVER_MODULE) | ||
| + | { | ||
| + | //------------------------------------------------------------------- | ||
| + | // Not used yet | ||
| + | //------------------------------------------------------------------- | ||
| + | } | ||
| + | //--------------------------------------------------------------------- | ||
| + | if (World.GetCurrentModule() == World.SURVEYOR_MODULE) | ||
| + | { | ||
| + | //------------------------------------------------------------------- | ||
| + | // Not used yet | ||
| + | //------------------------------------------------------------------- | ||
| + | } | ||
| + | //--------------------------------------------------------------------- | ||
| + | if (World.GetCurrentModule() == World.NO_MODULE) | ||
| + | { | ||
| + | //------------------------------------------------------------------- | ||
| + | // Not used yet | ||
| + | //------------------------------------------------------------------- | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Search the objects soup for next free entry gap. Parameter dsp is the | ||
| + | // object's type dispatcher sub soup (ContainerSoups, ContstackSoups or | ||
| + | // ContcraneSoups). Method returns a soup. | ||
| + | // soup { entry int, action string, active bool } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | Soup FindObjectSoupEntry(GameObjectID goid, Soup dsp) | ||
| + | { | ||
| + | int entry; | ||
| + | string action; | ||
| + | Soup rsp = Constructors.NewSoup(); | ||
| + | rsp.SetNamedTag("active",true); | ||
| + | int i; | ||
| + | for (i=0; i<dsp.CountTags(); i++) | ||
| + | { | ||
| + | entry = Str.ToInt(dsp.GetIndexedTagName(i)); | ||
| + | Soup sp = dsp.GetNamedSoup(entry); | ||
| + | if (sp.GetNamedTagAsGameObjectID("goid")==goid) // TBD: goid compar ison | ||
| + | { | ||
| + | rsp.SetNamedTag("entry",entry); | ||
| + | rsp.SetNamedTag("action","UPDATED"); | ||
| + | return rsp; | ||
| + | } | ||
| + | } | ||
| + | entry = actsTools.GetObjectSoupGap(dsp); | ||
| + | if (entry==dsp.CountTags()) rsp.SetNamedTag("action","APPENDED"); | ||
| + | else rsp.SetNamedTag("action","INSERTED"); | ||
| + | rsp.SetNamedTag("entry",entry); | ||
| + | return rsp; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Search the goid and update, insert or append the soup to register | ||
| + | // Parameter osp is the posted ObjectDataSoup. The other three are the | ||
| + | // dispatcher's object soups subsoups. | ||
| + | //--------------------------------------------------------------------------- | ||
| + | void AppendInsertUpdateObjectDataSoups(Soup osp, | ||
| + | Soup ContSps, Soup StackSps, Soup CraneSps) | ||
| + | { | ||
| + | //------------------------------------------------------------------------- | ||
| + | string type = osp.GetNamedTag("type"); | ||
| + | GameObjectID objgoid = osp.GetNamedTagAsGameObjectID("type"); | ||
| + | Soup objsps = Constructors.NewSoup(); | ||
| + | if (type == "CONTAINER") objsps = ContSps; | ||
| + | if (type == "CONTSTACK") objsps = StackSps; | ||
| + | if (type == "CONTCRANE") objsps = CraneSps; | ||
| + | Soup entry = FindObjectSoupEntry(objgoid, objsps); | ||
| + | // entry { entry int, active bool, action string } | ||
| + | // actions = ["APPENDED", "INSERTED", "UPDATED"]; | ||
| + | osp.SetNamedTag("active", true); | ||
| + | osp.SetNamedTag("action", entry.GetNamedTag("action")); | ||
| + | objsps.SetNamedSoup(entry.GetNamedTagAsInt("entry"), osp); | ||
| + | //------------------------------------------------------------------------- | ||
| + | // Post retour that register is updated | ||
| + | //------------------------------------------------------------------------- | ||
| + | GameObject obj = Router.GetGameObject(objgoid); | ||
| + | PostMessage(obj, "DISPATCHER", | ||
| + | "OBJECTSOUP_" + entry.GetNamedTag("action"), osp, 0.0); | ||
| + | //------------------------------------------------------------------------- | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " [" + dispgoid.SerialiseToString() + "]" | ||
| + | + " DISPATCHER OBJECTSOUP " + entry.GetNamedTag("action") | ||
| + | + " " + type + " GOID [" + objgoid.SerialiseToString() + "]"); | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " CONTENT OF " + entry.GetNamedTag("action") + " SOUP FROM GOID" | ||
| + | + " [" + objgoid.SerialiseToString() + "]"); | ||
| + | if (acts_debug) actsTools.ShowSoup(osp,"OSP=>"); | ||
| + | //-------------------------------------------------------------------------*/ | ||
| + | return; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void RegisterHandler(Message msg) | ||
| + | { | ||
| + | if (msg.dst==me and msg.major=="REGISTER") | ||
| + | { | ||
| + | //----------------------------------------------------------------------- | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " ["+dispgoid.SerialiseToString()+"]" | ||
| + | + " DISPATCHER GOT MESSAGE FROM OBJECT [" | ||
| + | + (cast<GameObject>msg.src).GetGameObjectID().SerialiseToString() | ||
| + | + "] [" + msg.major + "] [" + msg.minor + "]"); | ||
| + | //-----------------------------------------------------------------------*/ | ||
| + | if (msg.minor=="REGISTER_ME") | ||
| + | { | ||
| + | //--------------------------------------------------------------------- | ||
| + | // Update, insert or append the ObjectDataSoup | ||
| + | //--------------------------------------------------------------------- | ||
| + | Soup RegDataSoup = Constructors.NewSoup(); | ||
| + | RegDataSoup.Copy(cast<Soup>msg.paramSoup); | ||
| + | //--------------------------------------------------------------------- | ||
| + | if (acts_debug) Interface.Log(Interface.GetTimeStamp() | ||
| + | + " SOUP CONTENT OF 'DataSoup To Register' GOID" | ||
| + | + " [" + dispgoid.SerialiseToString() + "]"); | ||
| + | if (acts_debug) actsTools.ShowSoup(RegDataSoup,"=>"); | ||
| + | //--------------------------------------------------------------------- | ||
| + | AppendInsertUpdateObjectDataSoups(RegDataSoup, | ||
| + | ContainerSoups, ContstackSoups, ContcraneSoups); | ||
| + | //--------------------------------------------------------------------- | ||
| + | // TBD: Repost or update additional informations | ||
| + | // * CONTCRANE: Repost a goid list of reachable stacks. The contcrane | ||
| + | // itself informs the stacks about it's object data to update the | ||
| + | // maximum count of stackable containers. | ||
| + | // * CONTSTACK: ??? | ||
| + | // * CONTAINER: If a container has no stack place, randomly attach | ||
| + | // him to a free stack place and repost it. In case there is no | ||
| + | // one, repost an empty stack goid with place zero. | ||
| + | // TBD: What happens if the stack it attached to does not exist? | ||
| + | // Possibly handled as a free container? | ||
| + | //--------------------------------------------------------------------- | ||
| + | } | ||
| + | //----------------------------------------------------------------------- | ||
| + | } | ||
| + | return; | ||
| + | } | ||
| + | }; | ||
| + | |||
| + | class acts_dispatcher isclass acts_dispatcher_script | ||
| + | { | ||
| + | public void Init() | ||
| + | { | ||
| + | inherited(); | ||
| + | //------------------------------------------------------------------------- | ||
| + | // Make shure that the right module is set for World.GetCurrentModle() | ||
| + | // (see world.gs lines 939ff.) to start driver only or surveyor only | ||
| + | // related initiations and tell me, if my Init and SetProperties methods | ||
| + | // are finished | ||
| + | //------------------------------------------------------------------------- | ||
| + | AddHandler(me, "World", "ModuleInit", "WorldInitHandler"); | ||
| + | AddHandler(me, "OBJECTINIT", "", "ObjectInitHandler"); | ||
| + | AddHandler(me, "REGISTER", "", "RegisterHandler"); | ||
| + | //------------------------------------------------------------------------- | ||
| + | // Set asset special initial values | ||
| + | //------------------------------------------------------------------------- | ||
| + | objecttype = "DISPATCHER"; | ||
| + | //------------------------------------------------------------------------- | ||
| + | isInitMethodFinnished = true; | ||
| + | PostMessage(me,"OBJECTINIT","INIT_FINNISHED",0.0); // Init method finnished | ||
| + | return; | ||
| + | } | ||
| + | }; | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_global_values.gs=== | ||
| + | <CODE> | ||
| + | include "mapobject.gs" | ||
| + | |||
| + | //----------------------------------------------------------------------------- | ||
| + | // Common aCTS values V0.1 - Dispatcher, Container, Stack, Crane Tools Script | ||
| + | //----------------------------------------------------------------------------- | ||
| + | |||
| + | class acts_global_values isclass MapObject | ||
| + | { | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Global variables | ||
| + | //--------------------------------------------------------------------------- | ||
| + | bool acts_debug = true; | ||
| + | //--------------------------------------------------------------------------- | ||
| + | float baseboardwidth = 720; | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Technical values from normatives | ||
| + | // -------------------------------------------------------------------------- | ||
| + | int container_length_10ft = 2991; // in [mm] | ||
| + | int container_length_20ft = 6058; // in [mm] | ||
| + | int container_length_40ft = 12192; // in [mm] | ||
| + | int container_length_45ft = 13716; // in [mm] | ||
| + | int container_length_53ft = 16154; // in [mm] | ||
| + | // -------------------------------------------------------------------------- | ||
| + | int container_width = 2438; // in [mm] | ||
| + | int container_height = 2591; // in [mm] | ||
| + | int container_deltahc = 305; // in [mm] | ||
| + | // -------------------------------------------------------------------------- | ||
| + | bool isWorldInitFinnished = false; | ||
| + | bool isInitMethodFinnished = false; | ||
| + | bool isSetPropertiesMethodFinnished = false; | ||
| + | //--------------------------------------------------------------------------- | ||
| + | }; | ||
| + | </CODE> | ||
| + | |||
| + | ===acts_tools_script.gs.gs=== | ||
| + | <CODE> | ||
| + | include "acts_global_values.gs" | ||
| + | |||
| + | //----------------------------------------------------------------------------- | ||
| + | // Common aCTS methods V0.1 - Dispatcher, Container, Stack, Crane Tools Script | ||
| + | //----------------------------------------------------------------------------- | ||
| + | |||
| + | final static class actsTools isclass acts_global_values | ||
| + | { | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Log soup content of a soup of soups only and without subsoups | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void ShowSoup(Soup sp, string ind) | ||
| + | { | ||
| + | if (sp.CountTags()!=0) | ||
| + | { | ||
| + | int i; | ||
| + | for (i=0; i<sp.CountTags(); i++) | ||
| + | if (acts_debug) Interface.Log(ind + sp.GetIndexedTagName(i) | ||
| + | + " ["+sp.GetNamedTag(sp.GetIndexedTagName(i))+"]"); | ||
| + | } | ||
| + | return; | ||
| + | } | ||
| + | public void ShowSoups(Soup soup, string indent) | ||
| + | { | ||
| + | string ind = "="+indent; | ||
| + | int sc = soup.CountTags(); | ||
| + | int i; | ||
| + | for (i=0; i<sc; i++) | ||
| + | { | ||
| + | if (acts_debug) Interface.Log(indent + i + ".SubSoup"); | ||
| + | actsTools.ShowSoup(soup.GetNamedSoup(i),ind); | ||
| + | } | ||
| + | return; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Set all ObjectSoups active false and get the last insert gap | ||
| + | // TBD: Starting with a sorted soup | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public void ResetObjectSoups(Soup soup) | ||
| + | { | ||
| + | int i; | ||
| + | int gap = soup.CountTags();; | ||
| + | for (i=0; i<soup.CountTags(); i++) | ||
| + | { | ||
| + | int tn = Str.ToInt(soup.GetIndexedTagName(i)); | ||
| + | Soup sp = soup.GetNamedSoup(tn); | ||
| + | if (sp.GetNamedTagAsBool("active")) | ||
| + | { | ||
| + | sp.SetNamedTag("active",false); | ||
| + | soup.SetNamedSoup(tn,sp); | ||
| + | } else soup.RemoveNamedTag(tn); | ||
| + | } | ||
| + | return; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Return the first indexed gap in existing objectsoups tagnames | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public int GetObjectSoupGap(Soup soup) | ||
| + | { | ||
| + | int i; | ||
| + | for (i=0; i<soup.CountTags(); i++) | ||
| + | if (soup.GetIndexForNamedTag(i)==-1) return i; | ||
| + | return soup.CountTags(); | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Generate soup representation from WorldCoordinate | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public Soup WCoordToSoup(WorldCoordinate pos) | ||
| + | { | ||
| + | Soup sp = Constructors.NewSoup(); | ||
| + | sp.SetNamedTag("bbx",pos.baseboardX); | ||
| + | sp.SetNamedTag("bby",pos.baseboardY); | ||
| + | sp.SetNamedTag("px",pos.x); | ||
| + | sp.SetNamedTag("py",pos.y); | ||
| + | sp.SetNamedTag("pz",pos.z); | ||
| + | return sp; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Generate WorldCoordinate from its soup representation | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public WorldCoordinate WCoordFromSoup(Soup sp) | ||
| + | { | ||
| + | WorldCoordinate WC; | ||
| + | WC.baseboardX = sp.GetNamedTagAsInt("bbx"); | ||
| + | WC.baseboardY = sp.GetNamedTagAsInt("bby"); | ||
| + | WC.x = sp.GetNamedTagAsFloat("px"); | ||
| + | WC.y = sp.GetNamedTagAsFloat("py"); | ||
| + | WC.z = sp.GetNamedTagAsFloat("pz"); | ||
| + | return WC; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Normalize the WC to baseboard width | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public WorldCoordinate WCoordNormalize(WorldCoordinate WC) | ||
| + | { | ||
| + | WorldCoordinate nWC; | ||
| + | //------------------------------------------------------------------------- | ||
| + | int bx = WC.x * 1000.0 / baseboardwidth; // Basebord delta | ||
| + | if (WC.x < 0.0) bx--; | ||
| + | nWC.baseboardX = WC.baseboardX + bx; | ||
| + | nWC.x = WC.x - bx * baseboardwidth; | ||
| + | //------------------------------------------------------------------------- | ||
| + | int by = WC.y * 1000.0 / baseboardwidth; // Basebord delta | ||
| + | if (WC.y < 0.0) by--; | ||
| + | nWC.baseboardY = WC.baseboardX + by; | ||
| + | nWC.y = WC.y - by * baseboardwidth; | ||
| + | //------------------------------------------------------------------------- | ||
| + | nWC.z = WC.z; | ||
| + | return nWC; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Adjust baseboard from one WorlCoordinate to another | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public WorldCoordinate | ||
| + | WCoordAdjustBaseboard(WorldCoordinate frWC, WorldCoordinate toWC) | ||
| + | { | ||
| + | WorldCoordinate adjWC; | ||
| + | //------------------------------------------------------------------------- | ||
| + | adjWC.x = toWC.x + (frWC.baseboardX - toWC.baseboardX)*baseboardwidth; | ||
| + | adjWC.baseboardX = frWC.baseboardX; | ||
| + | adjWC.y = toWC.y + (frWC.baseboardY - toWC.baseboardY)*baseboardwidth; | ||
| + | adjWC.baseboardY = frWC.baseboardY; | ||
| + | adjWC.z = toWC.z; | ||
| + | //------------------------------------------------------------------------- | ||
| + | return adjWC; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Generate soup representation from Orientation | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public Soup OrientationToSoup(Orientation rot) | ||
| + | { | ||
| + | Soup sp = Constructors.NewSoup(); | ||
| + | sp.SetNamedTag("gx",rot.rx * 1800.0 / Math.PI); | ||
| + | sp.SetNamedTag("gy",rot.ry * 1800.0 / Math.PI); | ||
| + | sp.SetNamedTag("gz",rot.rz * 1800.0 / Math.PI); | ||
| + | sp.SetNamedTag("rx",rot.rx); | ||
| + | sp.SetNamedTag("ry",rot.ry); | ||
| + | sp.SetNamedTag("rz",rot.rz); | ||
| + | return sp; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Generate Orientation from its soup representation | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public Orientation OrientationFromSoup(Soup sp) | ||
| + | { | ||
| + | Orientation OR; | ||
| + | OR.rx = sp.GetNamedTagAsFloat("rx"); | ||
| + | OR.ry = sp.GetNamedTagAsFloat("ry"); | ||
| + | OR.rz = sp.GetNamedTagAsFloat("rz"); | ||
| + | return OR; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Adjust location and orientation to even mm and even 1/10° inplace | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public bool AutoAdjustTransformation(WorldCoordinate W, Orientation O) | ||
| + | { | ||
| + | float rd; | ||
| + | bool changed = false; | ||
| + | if (W.x<0) rd=-0.0005; else rd=0.0005; // rounding to full [mm] | ||
| + | int wcx = (W.x+rd) * 1000.0; | ||
| + | if (W.y<0) rd=-0.0005; else rd=0.0005; | ||
| + | int wcy = (W.y+rd) * 1000.0; | ||
| + | if (W.z<0) rd=-0.0005; else rd=0.0005; | ||
| + | int wcz = (W.z+rd) * 1000.0; | ||
| + | // rounding to full [1/10°] - here only z-axis, x,y-axis are set to zero | ||
| + | // to make shure the CTS is horizontal plane | ||
| + | if (O.rz<0) rd=-0.5; else rd=0.5; | ||
| + | int orz = O.rz * 1800.0 / Math.PI + rd; | ||
| + | if (W.x != wcx/1000.0) {W.x = wcx/1000.0; changed=true; } | ||
| + | if (W.y != wcy/1000.0) {W.y = wcy/1000.0; changed=true; } | ||
| + | if(W.z != 0.0) { W.z = 0.0; changed=true; } | ||
| + | if(O.rx != 0.0) { O.rx = 0.0; changed=true; } | ||
| + | if(O.ry != 0.0) { O.ry = 0.0; changed=true; } | ||
| + | if(O.rz != orz * Math.PI / 1800.0) | ||
| + | { O.rz = orz * Math.PI / 1800.0; changed=true; } | ||
| + | //------------------------------------------------------------------------- | ||
| + | return changed; | ||
| + | } | ||
| + | //--------------------------------------------------------------------------- | ||
| + | // Auto adjust WorldCoordinate and Orientation to [mm] and [1/10°] | ||
| + | // Adjusts the object and returns original and adjusted WC and OR as soup. | ||
| + | //--------------------------------------------------------------------------- | ||
| + | public Soup AutoAdjustMapObject(MapObject M) | ||
| + | { | ||
| + | //------------------------------------------------------------------------- | ||
| + | // M = cast<MapObject>(me); | ||
| + | //------------------------------------------------------------------------- | ||
| + | bool changed = false; | ||
| + | Soup sp = Constructors.NewSoup(); | ||
| + | WorldCoordinate W = M.GetMapObjectPosition(); | ||
| + | Orientation O = M.GetMapObjectOrientation(); | ||
| + | sp.SetNamedSoup("OriginalLocationSoup", WCoordToSoup(W)); | ||
| + | sp.SetNamedSoup("OriginalOrientationSoup", OrientationToSoup(O)); | ||
| + | changed = AutoAdjustTransformation(W,O); | ||
| + | M.SetMapObjectPosition(W); | ||
| + | M.SetMapObjectOrientation(O); | ||
| + | sp.SetNamedSoup("AdjustedLocationSoup", WCoordToSoup(W)); | ||
| + | sp.SetNamedSoup("AdjustedOrientationSoup", OrientationToSoup(O)); | ||
| + | sp.SetNamedTag("changed", changed); | ||
| + | //------------------------------------------------------------------------- | ||
| + | return sp; | ||
| + | } | ||
| + | }; | ||
| + | </CODE> | ||
[[Category:ACTS]] | [[Category:ACTS]] | ||
Revision as of 00:56, 25 April 2024
TBD: Update text
TBD: Repost or update additional informations after reposting the registered objectsoup. * CONTCRANE: Repost a goid list of reachable stacks. The contcrane itself informs the stacks about it's object data to update the maximum count of stackable containers. * CONTSTACK: ??? * CONTAINER: If a container has no stack place, randomly attach him to a free stack place and repost it. In case there is no one, repost an empty stack goid with place zero. TBD: What happens if the stack it attached to does not exist? Possibly handled as a free container?
Contents |
Asset files pre version 0.1
The files compile errorless and the messaging runs well. No more functionality implemented and tested in this pre version.
config.txt
kuid <kuid2:215489:110000:1>
username "aCTS DISPATCHER Library V1"
kind "Library"
category-class "YL"
trainz-build 4.6
description "aCTS DISPATCHER Library V1"
script "acts_dispatcher.gs"
class "acts_dispatcher"
thumbnails
{
0
{
image "acts_dispatcher_thumb.jpg"
width 240
height 180
}
}
acts_dispatcher.gs
include "acts_global_values.gs"
include "acts_tools_script.gs"
//-----------------------------------------------------------------------------
// aCTS Dispatcher V0.1 Central Script - acts_dispatcher
//-----------------------------------------------------------------------------
// X acts_dispatcher <-- acts_dispatcher_script
// X acts_dispatcher_script <-- acts_dispatcher_globals
// X acts_dispatcher_globals <-- acts_global_values
// acts_global_values <-- MapObject
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class acts_dispatcher_globals isclass acts_global_values
{
//---------------------------------------------------------------------------
// Store from dispatcher received object registration values to the
// respective dispatchers sub soup. The sub soups register ids run as int
// from 0 ... The received id -1 tells, that the object isn't yet
// registered.
//---------------------------------------------------------------------------
// Because the register id number list gets gaps while unregistering it will
// be nessecary to have some gap filling methods additionally. See
// AppendInsertUpdateObjectDataSoups and FindObjectSoupEntry methods.
//---------------------------------------------------------------------------
// AssetInstanceSoup {
// ObjectDataSoup { ... }, Only container, contstack, contcrane
// LocationSoup { ... }, Only container, contstack, contcrane
// OrientationSoup { ... }, Only container, contstack, contcrane
// SkinDataSoup { ... }, Only container
// ContentDataSoup { ... }, Only container
// X DispatcherDataSoup { ... } Only dispatcher
// X ContainerSoups { ... } Only dispatcher
// X ContstackSoups { ... } Only dispatcher
// X ContcraneSoups { ... } Only dispatcher
// }
//---------------------------------------------------------------------------
Soup ContainerSoups = Constructors.NewSoup();
Soup ContstackSoups = Constructors.NewSoup();
Soup ContcraneSoups = Constructors.NewSoup();
//---------------------------------------------------------------------------
Soup DispatcherDataSoup = Constructors.NewSoup();
//---------------------------------------------------------------------------
// ObjectDataSoup received from and posted to objects.
//---------------------------------------------------------------------------
// ObjectDataSoup { goid GameObjectID, type string, dispID int,
// length int, height int,
// stack goid, place int, Only container
// active bool, action string },
// activ: true means the object sended a register message while session run.
// All objects were set false while initialising dispatcher and if
// they stay false their entries will be deleted next initialising.
// actions: ["APPENDED", "INSERTED", "UPDATED"];
//---------------------------------------------------------------------------
GameObjectID dispgoid = me.GetGameObjectID();
string objecttype;
GameObjectID objectgoid;
//---------------------------------------------------------------------------
};
class acts_dispatcher_script isclass acts_dispatcher_globals
{
//---------------------------------------------------------------------------
public void SetProperties(Soup soup) // Callback method after Init method
{
inherited(soup);
//-------------------------------------------------------------------------
DispatcherDataSoup.Copy(soup.GetNamedSoup("DispatcherData"));
ContainerSoups.Copy(soup.GetNamedSoup("ContainerSoups"));
ContstackSoups.Copy(soup.GetNamedSoup("ContstackSoups"));
ContcraneSoups.Copy(soup.GetNamedSoup("ContcraneSoups"));
//-------------------------------------------------------------------------
isSetPropertiesMethodFinnished = true;
PostMessage(me,"OBJECTINIT","SETPROPS_FINNISH",0);
return;
}
//---------------------------------------------------------------------------
public Soup GetProperties(void) // Callback method before closing session
{
Soup soup = inherited();
//-------------------------------------------------------------------------
DispatcherDataSoup.SetNamedTag("firstrun",false);
//-------------------------------------------------------------------------
soup.SetNamedSoup("DispatcherData",DispatcherDataSoup);
soup.SetNamedSoup("ContainerSoups",ContainerSoups);
soup.SetNamedSoup("ContstackSoups",ContstackSoups);
soup.SetNamedSoup("ContcraneSoups",ContcraneSoups);
//-------------------------------------------------------------------------
return soup;
}
//---------------------------------------------------------------------------
public void WorldInitHandler(Message msg)
{
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " [" + dispgoid.SerialiseToString() + "]"
+ " DISPATCHER GOT WORLDINIT MESSAGE ["
+ msg.major+"] ["+msg.minor+"]");
//-------------------------------------------------------------------------
// If one of the two methods (Init or SetProperties) isn't finished yet,
// post "World","ModuleInit" message a little bit later again.
// So it is guaranteed that the Init and SetProperties methods are finished
// as well as the "World","ModuleInit" message tells to be save using the
// World.GetCurrentModule method.
//-------------------------------------------------------------------------
if (!(isSetPropertiesMethodFinnished and isInitMethodFinnished))
{
//----------------------------------------------------------------------
// While first run and before first session save for libraries the
// SetProperties methon will not run, whle no soup stored. If this case
// isn't handeled, the repost of "World","ModuleInit" runs infinitly.
//----------------------------------------------------------------------
if (!DispatcherDataSoup.GetNamedTagAsBool("firstrun"))
PostMessage(me, "World", "ModuleInit", 0.1);
}
//-------------------------------------------------------------------------
isWorldInitFinnished = true;
PostMessage(me, "OBJECTINIT", "WORLD_INIT_FINNISHED", 0.0);
//-------------------------------------------------------------------------
return;
}
//---------------------------------------------------------------------------
public void ObjectInitHandler(Message msg)
{
//-------------------------------------------------------------------------
// Until the Trainz core send the "World","ModuleInit" message it is not
// guarented to decide with the World.GetCurrentModule method to be in the
// returned module!
//-------------------------------------------------------------------------
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " [" + dispgoid.SerialiseToString() + "]"
+ " DISPATCHER GOT MESSAGE ["+msg.major+"] ["+msg.minor+"]");
//-------------------------------------------------------------------------*/
if (msg.dst==me and msg.major=="OBJECTINIT")
{
//-----------------------------------------------------------------------
if (msg.minor=="INIT_FINNISHED")
{
//---------------------------------------------------------------------
// Not used yet
//---------------------------------------------------------------------
}
//-----------------------------------------------------------------------
if (msg.minor=="SETPROPS_FINNISHED")
{
//---------------------------------------------------------------------
// If DispatcherDataSoup is empty, this is the first call unsaved call
//---------------------------------------------------------------------
if (DispatcherDataSoup.CountTags()==0)
DispatcherDataSoup.SetNamedTag("firstrun",true);
}
//-----------------------------------------------------------------------
if (msg.minor=="WORLD_INIT_FINNISHED")
{
//---------------------------------------------------------------------
// Do no module only, driver module only or surveyor module only
// related initiations
//---------------------------------------------------------------------
if (World.GetCurrentModule() == World.DRIVER_MODULE)
{
//-------------------------------------------------------------------
// Not used yet
//-------------------------------------------------------------------
}
//---------------------------------------------------------------------
if (World.GetCurrentModule() == World.SURVEYOR_MODULE)
{
//-------------------------------------------------------------------
// Not used yet
//-------------------------------------------------------------------
}
//---------------------------------------------------------------------
if (World.GetCurrentModule() == World.NO_MODULE)
{
//-------------------------------------------------------------------
// Not used yet
//-------------------------------------------------------------------
}
}
}
}
//---------------------------------------------------------------------------
// Search the objects soup for next free entry gap. Parameter dsp is the
// object's type dispatcher sub soup (ContainerSoups, ContstackSoups or
// ContcraneSoups). Method returns a soup.
// soup { entry int, action string, active bool }
//---------------------------------------------------------------------------
Soup FindObjectSoupEntry(GameObjectID goid, Soup dsp)
{
int entry;
string action;
Soup rsp = Constructors.NewSoup();
rsp.SetNamedTag("active",true);
int i;
for (i=0; i<dsp.CountTags(); i++)
{
entry = Str.ToInt(dsp.GetIndexedTagName(i));
Soup sp = dsp.GetNamedSoup(entry);
if (sp.GetNamedTagAsGameObjectID("goid")==goid) // TBD: goid compar ison
{
rsp.SetNamedTag("entry",entry);
rsp.SetNamedTag("action","UPDATED");
return rsp;
}
}
entry = actsTools.GetObjectSoupGap(dsp);
if (entry==dsp.CountTags()) rsp.SetNamedTag("action","APPENDED");
else rsp.SetNamedTag("action","INSERTED");
rsp.SetNamedTag("entry",entry);
return rsp;
}
//---------------------------------------------------------------------------
// Search the goid and update, insert or append the soup to register
// Parameter osp is the posted ObjectDataSoup. The other three are the
// dispatcher's object soups subsoups.
//---------------------------------------------------------------------------
void AppendInsertUpdateObjectDataSoups(Soup osp,
Soup ContSps, Soup StackSps, Soup CraneSps)
{
//-------------------------------------------------------------------------
string type = osp.GetNamedTag("type");
GameObjectID objgoid = osp.GetNamedTagAsGameObjectID("type");
Soup objsps = Constructors.NewSoup();
if (type == "CONTAINER") objsps = ContSps;
if (type == "CONTSTACK") objsps = StackSps;
if (type == "CONTCRANE") objsps = CraneSps;
Soup entry = FindObjectSoupEntry(objgoid, objsps);
// entry { entry int, active bool, action string }
// actions = ["APPENDED", "INSERTED", "UPDATED"];
osp.SetNamedTag("active", true);
osp.SetNamedTag("action", entry.GetNamedTag("action"));
objsps.SetNamedSoup(entry.GetNamedTagAsInt("entry"), osp);
//-------------------------------------------------------------------------
// Post retour that register is updated
//-------------------------------------------------------------------------
GameObject obj = Router.GetGameObject(objgoid);
PostMessage(obj, "DISPATCHER",
"OBJECTSOUP_" + entry.GetNamedTag("action"), osp, 0.0);
//-------------------------------------------------------------------------
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " [" + dispgoid.SerialiseToString() + "]"
+ " DISPATCHER OBJECTSOUP " + entry.GetNamedTag("action")
+ " " + type + " GOID [" + objgoid.SerialiseToString() + "]");
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " CONTENT OF " + entry.GetNamedTag("action") + " SOUP FROM GOID"
+ " [" + objgoid.SerialiseToString() + "]");
if (acts_debug) actsTools.ShowSoup(osp,"OSP=>");
//-------------------------------------------------------------------------*/
return;
}
//---------------------------------------------------------------------------
public void RegisterHandler(Message msg)
{
if (msg.dst==me and msg.major=="REGISTER")
{
//-----------------------------------------------------------------------
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " ["+dispgoid.SerialiseToString()+"]"
+ " DISPATCHER GOT MESSAGE FROM OBJECT ["
+ (cast<GameObject>msg.src).GetGameObjectID().SerialiseToString()
+ "] [" + msg.major + "] [" + msg.minor + "]");
//-----------------------------------------------------------------------*/
if (msg.minor=="REGISTER_ME")
{
//---------------------------------------------------------------------
// Update, insert or append the ObjectDataSoup
//---------------------------------------------------------------------
Soup RegDataSoup = Constructors.NewSoup();
RegDataSoup.Copy(cast<Soup>msg.paramSoup);
//---------------------------------------------------------------------
if (acts_debug) Interface.Log(Interface.GetTimeStamp()
+ " SOUP CONTENT OF 'DataSoup To Register' GOID"
+ " [" + dispgoid.SerialiseToString() + "]");
if (acts_debug) actsTools.ShowSoup(RegDataSoup,"=>");
//---------------------------------------------------------------------
AppendInsertUpdateObjectDataSoups(RegDataSoup,
ContainerSoups, ContstackSoups, ContcraneSoups);
//---------------------------------------------------------------------
// TBD: Repost or update additional informations
// * CONTCRANE: Repost a goid list of reachable stacks. The contcrane
// itself informs the stacks about it's object data to update the
// maximum count of stackable containers.
// * CONTSTACK: ???
// * CONTAINER: If a container has no stack place, randomly attach
// him to a free stack place and repost it. In case there is no
// one, repost an empty stack goid with place zero.
// TBD: What happens if the stack it attached to does not exist?
// Possibly handled as a free container?
//---------------------------------------------------------------------
}
//-----------------------------------------------------------------------
}
return;
}
};
class acts_dispatcher isclass acts_dispatcher_script
{
public void Init()
{
inherited();
//-------------------------------------------------------------------------
// Make shure that the right module is set for World.GetCurrentModle()
// (see world.gs lines 939ff.) to start driver only or surveyor only
// related initiations and tell me, if my Init and SetProperties methods
// are finished
//-------------------------------------------------------------------------
AddHandler(me, "World", "ModuleInit", "WorldInitHandler");
AddHandler(me, "OBJECTINIT", "", "ObjectInitHandler");
AddHandler(me, "REGISTER", "", "RegisterHandler");
//-------------------------------------------------------------------------
// Set asset special initial values
//-------------------------------------------------------------------------
objecttype = "DISPATCHER";
//-------------------------------------------------------------------------
isInitMethodFinnished = true;
PostMessage(me,"OBJECTINIT","INIT_FINNISHED",0.0); // Init method finnished
return;
}
};
acts_global_values.gs
include "mapobject.gs"
//-----------------------------------------------------------------------------
// Common aCTS values V0.1 - Dispatcher, Container, Stack, Crane Tools Script
//-----------------------------------------------------------------------------
class acts_global_values isclass MapObject
{
//---------------------------------------------------------------------------
// Global variables
//---------------------------------------------------------------------------
bool acts_debug = true;
//---------------------------------------------------------------------------
float baseboardwidth = 720;
//---------------------------------------------------------------------------
// Technical values from normatives
// --------------------------------------------------------------------------
int container_length_10ft = 2991; // in [mm]
int container_length_20ft = 6058; // in [mm]
int container_length_40ft = 12192; // in [mm]
int container_length_45ft = 13716; // in [mm]
int container_length_53ft = 16154; // in [mm]
// --------------------------------------------------------------------------
int container_width = 2438; // in [mm]
int container_height = 2591; // in [mm]
int container_deltahc = 305; // in [mm]
// --------------------------------------------------------------------------
bool isWorldInitFinnished = false;
bool isInitMethodFinnished = false;
bool isSetPropertiesMethodFinnished = false;
//---------------------------------------------------------------------------
};
acts_tools_script.gs.gs
include "acts_global_values.gs"
//-----------------------------------------------------------------------------
// Common aCTS methods V0.1 - Dispatcher, Container, Stack, Crane Tools Script
//-----------------------------------------------------------------------------
final static class actsTools isclass acts_global_values
{
//---------------------------------------------------------------------------
// Log soup content of a soup of soups only and without subsoups
//---------------------------------------------------------------------------
public void ShowSoup(Soup sp, string ind)
{
if (sp.CountTags()!=0)
{
int i;
for (i=0; i<sp.CountTags(); i++)
if (acts_debug) Interface.Log(ind + sp.GetIndexedTagName(i)
+ " ["+sp.GetNamedTag(sp.GetIndexedTagName(i))+"]");
}
return;
}
public void ShowSoups(Soup soup, string indent)
{
string ind = "="+indent;
int sc = soup.CountTags();
int i;
for (i=0; i<sc; i++)
{
if (acts_debug) Interface.Log(indent + i + ".SubSoup");
actsTools.ShowSoup(soup.GetNamedSoup(i),ind);
}
return;
}
//---------------------------------------------------------------------------
// Set all ObjectSoups active false and get the last insert gap
// TBD: Starting with a sorted soup
//---------------------------------------------------------------------------
public void ResetObjectSoups(Soup soup)
{
int i;
int gap = soup.CountTags();;
for (i=0; i<soup.CountTags(); i++)
{
int tn = Str.ToInt(soup.GetIndexedTagName(i));
Soup sp = soup.GetNamedSoup(tn);
if (sp.GetNamedTagAsBool("active"))
{
sp.SetNamedTag("active",false);
soup.SetNamedSoup(tn,sp);
} else soup.RemoveNamedTag(tn);
}
return;
}
//---------------------------------------------------------------------------
// Return the first indexed gap in existing objectsoups tagnames
//---------------------------------------------------------------------------
public int GetObjectSoupGap(Soup soup)
{
int i;
for (i=0; i<soup.CountTags(); i++)
if (soup.GetIndexForNamedTag(i)==-1) return i;
return soup.CountTags();
}
//---------------------------------------------------------------------------
// Generate soup representation from WorldCoordinate
//---------------------------------------------------------------------------
public Soup WCoordToSoup(WorldCoordinate pos)
{
Soup sp = Constructors.NewSoup();
sp.SetNamedTag("bbx",pos.baseboardX);
sp.SetNamedTag("bby",pos.baseboardY);
sp.SetNamedTag("px",pos.x);
sp.SetNamedTag("py",pos.y);
sp.SetNamedTag("pz",pos.z);
return sp;
}
//---------------------------------------------------------------------------
// Generate WorldCoordinate from its soup representation
//---------------------------------------------------------------------------
public WorldCoordinate WCoordFromSoup(Soup sp)
{
WorldCoordinate WC;
WC.baseboardX = sp.GetNamedTagAsInt("bbx");
WC.baseboardY = sp.GetNamedTagAsInt("bby");
WC.x = sp.GetNamedTagAsFloat("px");
WC.y = sp.GetNamedTagAsFloat("py");
WC.z = sp.GetNamedTagAsFloat("pz");
return WC;
}
//---------------------------------------------------------------------------
// Normalize the WC to baseboard width
//---------------------------------------------------------------------------
public WorldCoordinate WCoordNormalize(WorldCoordinate WC)
{
WorldCoordinate nWC;
//-------------------------------------------------------------------------
int bx = WC.x * 1000.0 / baseboardwidth; // Basebord delta
if (WC.x < 0.0) bx--;
nWC.baseboardX = WC.baseboardX + bx;
nWC.x = WC.x - bx * baseboardwidth;
//-------------------------------------------------------------------------
int by = WC.y * 1000.0 / baseboardwidth; // Basebord delta
if (WC.y < 0.0) by--;
nWC.baseboardY = WC.baseboardX + by;
nWC.y = WC.y - by * baseboardwidth;
//-------------------------------------------------------------------------
nWC.z = WC.z;
return nWC;
}
//---------------------------------------------------------------------------
// Adjust baseboard from one WorlCoordinate to another
//---------------------------------------------------------------------------
public WorldCoordinate
WCoordAdjustBaseboard(WorldCoordinate frWC, WorldCoordinate toWC)
{
WorldCoordinate adjWC;
//-------------------------------------------------------------------------
adjWC.x = toWC.x + (frWC.baseboardX - toWC.baseboardX)*baseboardwidth;
adjWC.baseboardX = frWC.baseboardX;
adjWC.y = toWC.y + (frWC.baseboardY - toWC.baseboardY)*baseboardwidth;
adjWC.baseboardY = frWC.baseboardY;
adjWC.z = toWC.z;
//-------------------------------------------------------------------------
return adjWC;
}
//---------------------------------------------------------------------------
// Generate soup representation from Orientation
//---------------------------------------------------------------------------
public Soup OrientationToSoup(Orientation rot)
{
Soup sp = Constructors.NewSoup();
sp.SetNamedTag("gx",rot.rx * 1800.0 / Math.PI);
sp.SetNamedTag("gy",rot.ry * 1800.0 / Math.PI);
sp.SetNamedTag("gz",rot.rz * 1800.0 / Math.PI);
sp.SetNamedTag("rx",rot.rx);
sp.SetNamedTag("ry",rot.ry);
sp.SetNamedTag("rz",rot.rz);
return sp;
}
//---------------------------------------------------------------------------
// Generate Orientation from its soup representation
//---------------------------------------------------------------------------
public Orientation OrientationFromSoup(Soup sp)
{
Orientation OR;
OR.rx = sp.GetNamedTagAsFloat("rx");
OR.ry = sp.GetNamedTagAsFloat("ry");
OR.rz = sp.GetNamedTagAsFloat("rz");
return OR;
}
//---------------------------------------------------------------------------
// Adjust location and orientation to even mm and even 1/10° inplace
//---------------------------------------------------------------------------
public bool AutoAdjustTransformation(WorldCoordinate W, Orientation O)
{
float rd;
bool changed = false;
if (W.x<0) rd=-0.0005; else rd=0.0005; // rounding to full [mm]
int wcx = (W.x+rd) * 1000.0;
if (W.y<0) rd=-0.0005; else rd=0.0005;
int wcy = (W.y+rd) * 1000.0;
if (W.z<0) rd=-0.0005; else rd=0.0005;
int wcz = (W.z+rd) * 1000.0;
// rounding to full [1/10°] - here only z-axis, x,y-axis are set to zero
// to make shure the CTS is horizontal plane
if (O.rz<0) rd=-0.5; else rd=0.5;
int orz = O.rz * 1800.0 / Math.PI + rd;
if (W.x != wcx/1000.0) {W.x = wcx/1000.0; changed=true; }
if (W.y != wcy/1000.0) {W.y = wcy/1000.0; changed=true; }
if(W.z != 0.0) { W.z = 0.0; changed=true; }
if(O.rx != 0.0) { O.rx = 0.0; changed=true; }
if(O.ry != 0.0) { O.ry = 0.0; changed=true; }
if(O.rz != orz * Math.PI / 1800.0)
{ O.rz = orz * Math.PI / 1800.0; changed=true; }
//-------------------------------------------------------------------------
return changed;
}
//---------------------------------------------------------------------------
// Auto adjust WorldCoordinate and Orientation to [mm] and [1/10°]
// Adjusts the object and returns original and adjusted WC and OR as soup.
//---------------------------------------------------------------------------
public Soup AutoAdjustMapObject(MapObject M)
{
//-------------------------------------------------------------------------
// M = cast<MapObject>(me);
//-------------------------------------------------------------------------
bool changed = false;
Soup sp = Constructors.NewSoup();
WorldCoordinate W = M.GetMapObjectPosition();
Orientation O = M.GetMapObjectOrientation();
sp.SetNamedSoup("OriginalLocationSoup", WCoordToSoup(W));
sp.SetNamedSoup("OriginalOrientationSoup", OrientationToSoup(O));
changed = AutoAdjustTransformation(W,O);
M.SetMapObjectPosition(W);
M.SetMapObjectOrientation(O);
sp.SetNamedSoup("AdjustedLocationSoup", WCoordToSoup(W));
sp.SetNamedSoup("AdjustedOrientationSoup", OrientationToSoup(O));
sp.SetNamedTag("changed", changed);
//-------------------------------------------------------------------------
return sp;
}
};