Today I got the new permission logic working. It uses a simpler and more consistent mechanism for determining whether new entities can go into exclusive components and the Path components that feed them. When an entity is ready to be forwarded to the next component it has to check to see if the next component (including the Path components that feed them) is open. It does this by comparing the number of entities in the destination component (and feeding paths) to the maximum capacity of the destination component.
Here’s how the Queue and Process components, each of which can be linked to multiple, incoming Path components, count the number of entities present. Notice that the method also sets the open/closed status for the component, but not the open/closed status for the incoming Path components. This status sets the color of the component when it is drawn. Green and red indicate open and closed, respectively.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
this.currentCount = function() { var count = 0; if (this.exclusive) { //start with entities already in component count = this.countInQueue; //add entities in feeding paths for (var i=0; i<this.previousComponentCount; i++) { if (this.previousComponentList[i].componentType == "Path") { count += this.previousComponentList[i].currentCount(); } } } return count; }; this.isOpen = function() { if (this.exclusive) { if (this.currentCount() < this.maxCapacity) { this.openStatus = true; } else { this.openStatus = false; } } return this.openStatus; //if not exclusive should be set to true by default }; |
Here’s how the Path component does it. Note that this method is recursive to count the entities in multiple Path components linked in series. It has the side-effect of setting the open/closed status for each Path and destination component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
this.isOpen = function() { this.openStatus = true; if (!this.exclusive) { if (this.entityQueue.length > 0) { if (this.traverseQueue[0] < (10 + 2)) { if (this.previousComponent.componentType == "Path") { this.openStatus = false; } } } } else { this.openStatus = this.nextComponent.isOpen(); } return this.openStatus; }; |
The isOpen
calls are made whenever an entity is testing to see whether it can enter a component, when it enters a component, and in some cases when it leaves a component. If an entity entering a Path or destination component and brought the system up to its capacity you can imagine that it might have a problem moving between components in the system. I therefore found it necessary to add a permissionToMove flag in the entity object. This is set to true whenever an entity is received by an exclusive Path component and set to false whenever an entity is received by a non-Path component (that also isn’t an Entry or Exit component).
When an entity leaves a non-Path component it checks to see if leaves the component in an open status (which it should always do). If so, it reaches back to all the incoming paths to set their statuses to open as well. Here’s the forwardEntity
code for the Queue and Process components.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
this.forwardEntity = function() { //ProcessComponent var dest = -1; ... find the destination ... if (dest >= 0) { if (this.countInQueue > this.countInProcess) { var entity = this.entityQueue.pop(); //TODO: are we testing to ensure the next entity is really available if (entity) { //TODO: since we've tested above this should not be necessary //calculate how long item was in process this.exitResidenceTime = globalSimClock - entity.getLocalEntryTime(); this.exitTime = globalSimClock; this.exitEntityID = entity.entityID; this.activity = "forward entity"; this.endExitDisplayTime = globalSimClock+this.displayDelay; this.endAllDisplayTime = this.endExitDisplayTime; feq.newItem(this.endExitDisplayTime,this,"clearExitDisplay"); displayProgressText("Process comp. "+this.componentID+" forwards entity: "+this.exitEntityID+" at time "+globalSimClock.toFixed(6)); this.countInQueue--; this.isOpen(); if (this.exclusive && this.openStatus) { for (var i=0; i<this.previousComponentCount; i++) { //go back and clear the incoming paths if (this.previousComponentList[i].getComponentType() == "Path") { this.previousComponentList[i].setPreviousOpen(); } } this.pullFromPrevious(); } this.nextComponentList[this.nextComponentIndex].receiveEntity(entity); } } } }; |
Here’s the setPreviousOpen
method from the Path component.
1 2 3 4 5 6 |
this.setPreviousOpen = function() { this.openStatus = true; if (this.previousComponent.getComponentType == "Path") { this.previousComponent.setPreviousOpen(); } }; |
It occurs to me that the entire isOpen
mechanism doesn’t need to be invoked when an external entity wants to test to see if it can enter. It may be that, since the openStatus
of each component should be properly set based on events, we can simplify things by testing against that status directly.