Skyscraper 2.0
controller.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Dispatch Controller Object
3 The Skyscraper Project - Version 2.0
4 Copyright (C)2004-2024 Ryan Thoryk
5 https://www.skyscrapersim.net
6 https://sourceforge.net/projects/skyscraper/
7 Contact - ryan@skyscrapersim.net
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
24#include "globals.h"
25#include "sbs.h"
26#include "elevator.h"
27#include "elevatorcar.h"
28#include "floor.h"
29#include "callstation.h"
30#include "profiler.h"
31#include "controller.h"
32
33namespace SBS {
34
36{
37 //create a dispatch controller object
38
39 //set up SBS object
40 SetValues("DispatchController", "Dispatch Controller " + ToString(number), false);
41
42 Number = number;
43 Range = 5;
44 DestinationDispatch = false;
45 MaxPassengers = 5;
46 Hybrid = false;
47 Reprocess = false;
48 bottom_floor = 0;
49 top_floor = 0;
50 recheck = 0;
51
52 EnableLoop(true);
53
54 Report("Created");
55}
56
58{
59 //unregister from parent
60 if (sbs->FastDelete == false && parent_deleting == false)
61 sbs->RemoveController(this);
62}
63
65{
66 //this function runs for every registered dispatch controller via timer callback
67
68 //only run if power is enabled
69 if (sbs->GetPower() == false)
70 return;
71
72 //process pending requests
74
75 //check arrivals
77}
78
80{
81 //check elevators to see if any have arrived
82 //for DD mode, dispatch to destination floor
83 //for standard mode, turn off call buttons and remove route
84
85 SBS_PROFILE("DispatchController::CheckArrivals");
86
87 for (size_t i = 0; i < Elevators.size(); i++)
88 {
89 Elevator *elev = sbs->GetElevator(Elevators[i].number);
90
91 //determine if elevator has arrived
92 if (Elevators[i].arrived == true)
93 {
94 //step through requests table and find a request that matches the arrived elevator
95 for (size_t j = 0; j < Routes.size(); j++)
96 {
97 //get request's direction of travel
98 int direction_dd = 0;
99 bool direction_standard = false;
100 if (Routes[j].destination == true)
101 {
102 if (Routes[j].starting_floor < Routes[j].destination_floor)
103 direction_dd = 1;
104 else
105 direction_dd = -1;
106 }
107 else
108 {
109 if (Routes[j].direction == 1)
110 direction_standard = true;
111 else
112 direction_standard = false;
113 }
114
115 //if route matches elevator
116 if (Routes[j].processed == true && Routes[j].assigned_elevator == Elevators[i].number)
117 {
118 if (Routes[j].destination == true)
119 {
120 //destination dispatch mode
121
122 bool route_direction = false;
123 if (direction_dd == 1)
124 route_direction = true;
125
126 //if request matches the elevator arrival, assignment and direction
127 if (Routes[j].starting_floor == Elevators[i].arrival_floor && Elevators[i].assigned == true && route_direction == Elevators[i].arrival_direction)
128 {
129 bool result = false;
130
131 //dispatch elevator to destination floor for each registered assignment
132 for (size_t k = 0; k < Elevators[i].assigned_destination.size(); k++)
133 {
134 if (Routes[j].destination_floor == Elevators[i].assigned_destination[k])
135 {
136 DispatchElevator(true, Elevators[i].number, Routes[j].destination_floor, direction_dd, false);
137 result = true;
138 }
139 }
140
141 //remove route from table
142 if (result == true)
143 {
145 j--;
146 }
147 }
148 }
149 else
150 {
151 //standard mode
152
153 //if request matches the elevator arrival and assignment
154 if (Routes[j].starting_floor == Elevators[i].arrival_floor && Elevators[i].arrival_direction == direction_standard)
155 {
156 //turn off related call buttons
157 if (Routes[j].station)
158 {
159 if (direction_standard == true)
160 Routes[j].station->UpLight(false);
161 else
162 Routes[j].station->DownLight(false);
163 }
164
165 //remove route from table
167 j--;
168 }
169 }
170 }
171 }
172 }
173 }
174}
175
177{
178 //remove a destination dispatch route
179
180 //only run if power is enabled
181 if (sbs->GetPower() == false)
182 return;
183
184 for (size_t i = 0; i < Routes.size(); i++)
185 {
186 if (Routes[i].starting_floor == route.starting_floor && Routes[i].destination_floor == route.destination_floor)
187 {
188 Report("Removing route " + ToString(i) + " from floors " + ToString(route.starting_floor) + " to " + ToString(route.destination_floor));
189 Routes.erase(Routes.begin() + i);
190 return;
191 }
192 }
193}
194
195bool DispatchController::RequestRoute(CallStation *station, int starting_floor, int destination_floor)
196{
197 //request a destination dispatch route
198
199 SBS_PROFILE("DispatchController::RequestRoute");
200
201 //only run if power is enabled
202 if (sbs->GetPower() == false)
203 return false;
204
205 if (DestinationDispatch == false)
206 {
207 if (station)
208 station->Error();
209 ReportError("RequestRoute: Destination Dispatch not enabled");
210 return false;
211 }
212
213 if (starting_floor == destination_floor)
214 {
215 if (station)
216 station->Error();
217 ReportError("RequestRoute: Floors are the same");
218 return false;
219 }
220
221 Report("Requesting route from origin floor " + ToString(starting_floor) + " to destination floor " + ToString(destination_floor));
222
223 //make sure floors are valid
224 if (!sbs->GetFloor(starting_floor) || !sbs->GetFloor(destination_floor))
225 {
226 if (station)
227 station->Error(1);
228 return ReportError("Invalid floor");
229 }
230
231 //make sure this controller has elevators that serve the specified floors
232 if (IsServicedFloor(starting_floor) == false)
233 {
234 if (station)
235 station->Error(0);
236 return ReportError("No elevators found for floor " + ToString(starting_floor));
237 }
238 if (IsServicedFloor(destination_floor) == false)
239 {
240 if (station)
241 station->Error(0);
242 return ReportError("No elevators found for floor " + ToString(destination_floor));
243 }
244
245 //check to make sure elevator objects are valid
246 bool isvalid = false;
247 for (size_t i = 0; i < Elevators.size(); i++)
248 {
249 Elevator *elevator = sbs->GetElevator(Elevators[i].number);
250 if (elevator)
251 {
252 isvalid = true;
253 break;
254 }
255 }
256 if (isvalid == false)
257 {
258 if (station)
259 station->Error();
260 return ReportError("No valid elevators found");
261 }
262
263 //use existing entry if found
264 for (size_t i = 0; i < Routes.size(); i++)
265 {
266 if (Routes[i].starting_floor == starting_floor && Routes[i].destination_floor == destination_floor && Routes[i].requests < MaxPassengers)
267 {
268 //create a new route if max passengers has been reached
269 if (Routes[i].requests >= MaxPassengers && Elevators.size() > 1)
270 break;
271
272 Routes[i].requests++;
273 Report("Route has " + ToString(Routes[i].requests) + " total requests");
274
275 //report on indicator for new request
276 if (Routes[i].assigned_elevator > 0)
277 {
278 Elevator *e = sbs->GetElevator(Routes[i].assigned_elevator);
279
280 if (Routes[i].station && e)
281 Routes[i].station->ReportElevator(e);
282 }
283 return true;
284 }
285 }
286
287 //otherwise add route request to table
288 Route route;
289 route.starting_floor = starting_floor;
290 route.destination_floor = destination_floor;
291 route.requests = 1;
292 route.processed = false;
293 route.station = station;
294 route.assigned_elevator = 0;
295 route.direction = 0;
296 route.destination = true;
297 Report("Adding destination route " + ToString((int)Routes.size()) + " from floor " + ToString(starting_floor) + " to floor " + ToString(destination_floor));
298 Routes.emplace_back(route);
299
300 return true;
301}
302
303bool DispatchController::CallElevator(CallStation *station, bool direction)
304{
305 //call an elevator (request a standard route)
306
307 SBS_PROFILE("DispatchController::CallElevator");
308
309 //only run if power is enabled
310 if (sbs->GetPower() == false)
311 return false;
312
313 if (DestinationDispatch == true && Hybrid == false)
314 {
315 if (station)
316 station->Error();
317 ReportError("RequestRoute: Destination Dispatch is enabled");
318 return false;
319 }
320
321 if (!station)
322 return false;
323
324 int floor = 0;
325 floor = station->GetFloor();
326
327 Report("Calling an elevator from origin floor " + ToString(floor));
328
329 //make sure this controller has elevators that serve the specified floor
330 if (IsServicedFloor(floor) == false)
331 {
332 if (station)
333 station->Error(1);
334 return ReportError("No elevators found for floor " + ToString(floor));
335 }
336
337 //check to make sure elevator objects are valid
338 bool isvalid = false;
339 for (size_t i = 0; i < Elevators.size(); i++)
340 {
341 Elevator *elevator = sbs->GetElevator(Elevators[i].number);
342 if (elevator)
343 {
344 isvalid = true;
345 break;
346 }
347 }
348 if (isvalid == false)
349 {
350 if (station)
351 station->Error();
352 return ReportError("No valid elevators found");
353 }
354
355 int dir = 0;
356 if (direction == true)
357 dir = 1;
358 else
359 dir = -1;
360
361 //use existing entry if found
362 for (size_t i = 0; i < Routes.size(); i++)
363 {
364 if (Routes[i].starting_floor == floor && Routes[i].direction == dir)
365 {
366 //report on indicator for new request
367 if (Routes[i].assigned_elevator > 0)
368 {
369 Elevator *e = sbs->GetElevator(Routes[i].assigned_elevator);
370
371 if (Routes[i].station && e)
372 Routes[i].station->ReportElevator(e);
373 }
374 return true;
375 }
376 }
377
378 //otherwise add route request to table
379 Route route;
380 route.starting_floor = floor;
381 route.destination_floor = 0;
382 route.requests = 1;
383 route.processed = false;
384 route.station = station;
385 route.assigned_elevator = 0;
386 route.direction = dir;
387 route.destination = false;
388 Report("Adding standard route " + ToString((int)Routes.size()) + " to floor " + ToString(floor));
389 Routes.emplace_back(route);
390
391 return true;
392}
393
395{
396 //process routes
397
398 SBS_PROFILE("DispatchController::ProcessRoutes");
399
400 for (size_t i = 0; i < Routes.size(); i++)
401 {
402 if (Routes[i].processed == true)
403 {
404 if (ElevatorUnavailable(Routes[i].assigned_elevator) == true)
405 {
406 if (Reprocess == true || Routes[i].destination == false)
407 {
408 //if active elevator becomes unavailable during call wait, reprocess route
409 Report("Assigned elevator " + ToString(Routes[i].assigned_elevator) + " became unavailable, reprocessing route");
410 Routes[i].processed = false;
411 Routes[i].assigned_elevator = 0;
412 }
413 else
414 {
415 //otherwise drop the route
416 Report("Dropping route " + ToString(i) + " for elevator " + ToString(Routes[i].assigned_elevator));
417 Routes.erase(Routes.begin() + i);
418 return;
419 }
420 }
421 else
422 {
423 //if destination dispatch is off, check to see if there's a closer elevator
424 if (Routes[i].destination == false)
425 {
426 recheck++;
427 if (recheck == 100) //don't recheck elevator every frame
428 {
429 recheck = 0;
430 int closest = -1;
431 bool busy = false;
432 closest = FindClosestElevator(busy, false, Routes[i].starting_floor, 0, Routes[i].direction);
433
434 if (closest >= 0)
435 {
436 //if a closer elevator has been found than the elevator actively serving the call,
437 //reprocess the call
438 if (Elevators[closest].number != Routes[i].assigned_elevator && busy == false)
439 {
440 //make sure elevator is idle before continuing
441 Elevator *newelevator = sbs->GetElevator(Elevators[closest].number);
442 if (newelevator->IsIdle() == true)
443 {
444 Elevator *elevator = sbs->GetElevator(Routes[i].assigned_elevator);
445 if (elevator)
446 elevator->CancelHallCall(Routes[i].starting_floor, Routes[i].direction);
447
448 Report("Switching to closer elevator " + ToString(newelevator->Number));
449
450 //unassign elevator
451 Routes[i].assigned_elevator = 0;
452
453 //reset processed state
454 Routes[i].processed = false;
455 }
456 }
457 else
458 continue; //skip route if elevator is still closest
459 }
460 else
461 continue; //skip if a closer elevator is not found
462 }
463 else
464 continue; //skip route if not checking
465 }
466 else
467 continue; //skip route if elevator is still available
468 }
469 }
470
471 int starting_floor = Routes[i].starting_floor;
472 int destination_floor = Routes[i].destination_floor;
473
474 //get closest elevator
475 int closest = -1;
476 bool busy = false;
477 if (Routes[i].direction == 0)
478 closest = FindClosestElevator(busy, true, starting_floor, destination_floor); //destination dispatch mode
479 else
480 closest = FindClosestElevator(busy, false, starting_floor, destination_floor, Routes[i].direction); //standard mode
481
482 //if none found, report an error and withdraw the route
483 if (closest == -1)
484 {
485 Report("ProcessRoutes: No available elevators found");
486 if (Routes[i].station)
487 Routes[i].station->Error();
488
489 //turn off button lights
490 if (Routes[i].station)
491 {
492 if (Routes[i].direction == 1)
493 Routes[i].station->UpLight(false);
494 else
495 Routes[i].station->DownLight(false);
496 }
497
498 Report("Withdrawing route " + ToString(i));
499 Routes.erase(Routes.begin() + i);
500 return;
501 }
502
503 //standard mode
504 if (Routes[i].destination == false && Routes[i].assigned_elevator > 0)
505 {
506 //wait for elevator if busy
507 if (busy == true)
508 return;
509 else
510 {
511 //update elevator's call information
512 for (size_t j = 0; j < Elevators.size(); j++)
513 {
514 if (Elevators[j].number == Routes[i].assigned_elevator)
515 {
516 Call call;
517 call.floor = starting_floor;
518 call.direction = false;
519 if (Routes[i].direction == 1)
520 call.direction = true;
521 Elevators[j].calls.emplace_back(call);
522 break;
523 }
524 }
525
526 //dispatch elevator if available
527 DispatchElevator(false, Routes[i].assigned_elevator, starting_floor, Routes[i].direction, true);
528 Routes[i].processed = true;
529 return;
530 }
531 }
532
533 //get elevator and car for route
534 Elevator* elevator = sbs->GetElevator(Elevators[closest].number);
535
536 Report("Using elevator " + ToString(elevator->Number));
537
538 ElevatorCar *car = elevator->GetCarForFloor(starting_floor);
539 if (!car)
540 return;
541
542 int direction = Routes[i].direction;
543 if (direction == 0)
544 {
545 //determine direction for destination dispatch mode
546 if (destination_floor > starting_floor)
547 direction = 1;
548 else
549 direction = -1;
550 }
551
552 //update destination indicator with elevator ID
553 if (Routes[i].station)
554 Routes[i].station->ReportElevator(elevator);
555
556 //update elevator's call information
557 if (Routes[i].destination == true)
558 {
559 for (size_t j = 0; j < Elevators.size(); j++)
560 {
561 if (Elevators[j].number == elevator->Number)
562 {
563 Elevators[j].destination_floor = destination_floor;
564 Call call;
565 call.floor = starting_floor;
566 call.direction = false;
567 if (direction == 1)
568 call.direction = true;
569 Elevators[j].calls.emplace_back(call);
570 break;
571 }
572 }
573 }
574
575 //assign and dispatch elevator to starting floor
576 AssignElevator(elevator->Number, destination_floor, Routes[i].direction);
577
578 //dispatch elevator in DD mode, dispatch later in standard mode
579 if (Routes[i].destination == true)
580 {
581 DispatchElevator(true, elevator->Number, starting_floor, direction, true);
582 Routes[i].processed = true;
583 }
584
585 Routes[i].assigned_elevator = elevator->Number;
586 }
587}
588
590{
591 //add an elevator to this controller
592
593 //only run if power is enabled
594 if (sbs->GetPower() == false)
595 return false;
596
597 if (!sbs->GetElevator(elevator))
598 return false;
599
600 //exit if already in table
601 for (size_t i = 0; i < Elevators.size(); i++)
602 {
603 if (Elevators[i].number == elevator)
604 return false;
605 }
606
607 //create a new elevator map
608 ElevMap newelevator;
609 newelevator.number = elevator;
610 newelevator.arrived = false;
611 newelevator.arrival_floor = 0;
612 newelevator.arrival_direction = false;
613 newelevator.assigned = false;
614 newelevator.destination_floor = 0;
615 newelevator.calls.clear();
616
617 //assign controller to elevator
618 sbs->GetElevator(elevator)->AddController(Number);
619
620 Report ("Elevator " + ToString(elevator) + " added to dispatch controller " + ToString(Number));
621 Elevators.emplace_back(newelevator);
622
623 //process floor range
625
626 return true;
627}
628
630{
631 //remove an elevator from this controller
632
633 //only run if power is enabled
634 if (sbs->GetPower() == false)
635 return false;
636
637 for (size_t i = 0; i < Elevators.size(); i++)
638 {
639 if (Elevators[i].number == elevator)
640 {
641 Report ("Elevator " + ToString(elevator) + " removed from dispatch controller " + ToString(Number));
642
643 if (sbs->GetElevator(elevator))
645
646 Elevators.erase(Elevators.begin() + i);
647
648 //process floor range
650
651 return true;
652 }
653 }
654 return false;
655}
656
658{
659 //return true if this controller services the specified elevator
660
661 //only run if power is enabled
662 if (sbs->GetPower() == false)
663 return false;
664
665 for (size_t i = 0; i < Elevators.size(); i++)
666 {
667 if (Elevators[i].number == elevator)
668 {
669 if (sbs->Verbose)
670 Report("Services elevator " + ToString(elevator));
671 return true;
672 }
673 }
674 return false;
675}
676
677int DispatchController::FindClosestElevator(bool &busy, bool destination, int starting_floor, int destination_floor, int direction)
678{
679 //finds closest elevator
680 //if destination is true, use Destination Dispatch mode, otherwise use Standard Mode
681
682 SBS_PROFILE("DispatchController::FindClosestElevator");
683
684 //only run if power is enabled
685 if (sbs->GetPower() == false)
686 return -1;
687
688 //initialize values
689 int closest = 0;
690 int closest_busy = -1;
691 int closest_notbusy = -1;
692 bool check = false;
693 int errors = 0;
694 int result = 0;
695
696 if (destination == true)
697 {
698 if (destination_floor > starting_floor)
699 direction = 1;
700 else
701 direction = -1;
702 }
703
704 int count = (int)Elevators.size();
705
706 //exit if no elevators are associated
707 if (count == 0)
708 return -1;
709
710 //search through elevator list
711 if (sbs->Verbose && count > 1)
712 Report("Finding nearest available elevator...");
713
714 //check each elevator associated with this controller to find the closest available one
715 for (int i = 0; i < count; i++)
716 {
717 Elevator *elevator = sbs->GetElevator(Elevators[i].number);
718 if (elevator)
719 {
720 //skip elevator if it doesn't serve the destination floor
721 if (destination == true)
722 {
723 bool serviced = elevator->IsServicedFloor(destination_floor, true);
724 if (serviced == false)
725 continue;
726 }
727
728 ElevatorCar *car = elevator->GetCarForFloor(starting_floor);
729 if (car)
730 {
731 if (sbs->Verbose)
732 Report("Checking elevator " + ToString(elevator->Number) + " car " + ToString(car->Number));
733
734 if (destination == true)
735 {
736 //skip elevator if serving a route with the maximum number of requests
737 if (AtMaxRequests(Elevators[i].number, destination_floor) == true)
738 {
739 if (sbs->Verbose)
740 Report("Skipping elevator " + ToString(elevator->Number) + " due to reached max passengers value");
741 continue;
742 }
743 }
744
745 //if elevator is closer than the previously checked one or we're starting the checks
746 if (abs(car->GetFloor() - starting_floor) < closest || check == false || closest_busy >= 0)
747 {
748 //see if elevator is available for the call
749 result = elevator->AvailableForCall(destination, starting_floor, direction, true);
750
751 //if an elevator is not busy and available, reset closest_busy value
752 if (closest_busy >= 0 && result == 1)
753 {
754 closest_busy = -1;
755 }
756
757 if (result < 2) //available or busy
758 {
759 //skip if elevator has already been assigned for another destination
760 //outside of the serviced floor range but only if multiple elevators are assigned
761 //or direction if in standard mode
762 if (destination == true)
763 {
764 if (IsElevatorAssignedToOther(elevator->Number, destination_floor, 0) == true)
765 {
766 closest_busy = i;
767 continue;
768 }
769 }
770
771 //mark as closest busy elevator
772 if (result == 0)
773 {
774 if (sbs->Verbose && count > 1)
775 Report("Marking - closest so far as busy");
776 closest = abs(car->GetFloor() - starting_floor);
777 closest_busy = i;
778 }
779 else
780 {
781 //mark as closest elevator
782 if (sbs->Verbose && count > 1)
783 Report("Marking - closest so far");
784 closest = abs(car->GetFloor() - starting_floor);
785 closest_notbusy = i;
786 }
787 check = true;
788 }
789 else if (result == 2) //elevator won't service the call
790 errors++;
791 }
792 }
793 }
794 }
795
796 if (errors == count)
797 {
798 //exit if all elevators are in a service mode or return errors
799
800 std::string item;
801 if (count > 1)
802 item = "All elevators";
803 else
804 item = "Elevator";
805
806 Report(item + " unavailable due to service modes or errors");
807
808 return -1;
809 }
810
811 if (check == false)
812 {
813 //exit if no elevator found
814
815 if (sbs->Verbose)
816 Report("No elevator found");
817 return -1;
818 }
819
820 if (closest_notbusy >= 0)
821 {
822 busy = false;
823 return closest_notbusy;
824 }
825 else
826 {
827 busy = true;
828 return closest_busy;
829 }
830}
831
832void DispatchController::Report(const std::string &message)
833{
834 //general reporting function
835 std::string msg = "Dispatch Controller " + ToString(Number) + ": " + message;
836 Object::Report(msg);
837}
838
839bool DispatchController::ReportError(const std::string &message)
840{
841 //general error reporting function
842 std::string msg = "Dispatch Controller " + ToString(Number) + ": " + message;
843 return Object::ReportError(msg);
844}
845
846void DispatchController::ElevatorArrived(int number, int floor, bool direction)
847{
848 //notify controller about an elevator arrival
849
850 SBS_PROFILE("DispatchController::ElevatorArrived");
851
852 //only run if power is enabled
853 if (sbs->GetPower() == false)
854 return;
855
856 for (size_t i = 0; i < Elevators.size(); i++)
857 {
858 //exit if elevator already arrived
859 if (Elevators[i].number == number && Elevators[i].arrived == true)
860 return;
861
862 Floor *floorobj = sbs->GetFloor(floor);
863 if (!floorobj)
864 return;
865
866 if (Elevators[i].number == number)
867 {
868 Report("Elevator " + ToString(number) + " arrived at floor " + ToString(floor) + " (" + floorobj->ID + ")");
869
870 //only set values if arriving at starting floor
871 for (size_t j = 0; j < (int)Elevators[i].calls.size(); j++)
872 {
873 if (Elevators[i].calls[j].floor == floor && Elevators[i].calls[j].direction == direction)
874 {
875 Elevators[i].arrived = true;
876 Elevators[i].arrival_floor = floor;
877 Elevators[i].arrival_direction = direction;
878 Elevators[i].calls.erase(Elevators[i].calls.begin() + j);
879 break;
880 }
881 }
882
883 if (Elevators[i].assigned == true)
884 {
885 //unassign route from elevator in destination dispatch mode
886 for (size_t j = 0; j < Elevators[i].assigned_destination.size(); j++)
887 {
888 if (Elevators[i].assigned_destination[j] == floor)
889 {
890 Elevators[i].assigned_destination.erase(Elevators[i].assigned_destination.begin() + j);
891 break;
892 }
893 }
894
895 //unassign route from elevator in standard mode
896 for (size_t j = 0; j < Elevators[i].assigned_directions.size(); j++)
897 {
898 int direction2 = -1;
899 if (direction == true)
900 direction2 = 1;
901
902 if (Elevators[i].assigned_directions[j] == direction2)
903 {
904 Elevators[i].assigned_directions.erase(Elevators[i].assigned_directions.begin() + j);
905 break;
906 }
907 }
908
909 //unassign elevator if no more routes
910 if (Elevators[i].assigned_destination.size() == 0 && Elevators[i].assigned_directions.size() == 0)
911 Elevators[i].assigned = false;
912 }
913 break;
914 }
915 }
916}
917
918void DispatchController::DispatchElevator(bool destination, int number, int destination_floor, int direction, bool call)
919{
920 //dispatch an elevator to the given destination floor
921
922 //only run if power is enabled
923 if (sbs->GetPower() == false)
924 return;
925
926 Elevator *elevator = sbs->GetElevator(number);
927 Floor *floor = sbs->GetFloor(destination_floor);
928
929 if (elevator && floor)
930 {
931 Report("Dispatching elevator " + ToString(number) + " to floor " + ToString(destination_floor) + " (" + floor->ID + ")");
932
933 int type = 0;
934 if (call == true)
935 type = 1;
936 else if (destination == false)
937 type = 2;
938
939 //add elevator route
940 elevator->AddRoute(destination_floor, direction, type);
941 }
942}
943
944bool DispatchController::IsElevatorAssigned(int number, int destination_floor, int direction)
945{
946 //return true if the specified elevator is assigned to the specified destination floor or direction
947
948 //only run if power is enabled
949 if (sbs->GetPower() == false)
950 return false;
951
952 for (size_t i = 0; i < Elevators.size(); i++)
953 {
954 if (Elevators[i].number == number)
955 {
956 if (direction == 0)
957 {
958 //destination dispatch mode
959 for (size_t j = 0; j < Elevators[i].assigned_destination.size(); j++)
960 {
961 if (Elevators[i].assigned_destination[j] == destination_floor && Elevators[i].assigned == true)
962 return true;
963 }
964 }
965 else
966 {
967 //standard mode
968 for (size_t j = 0; j < Elevators[i].assigned_directions.size(); j++)
969 {
970 if (Elevators[i].assigned_directions[j] == direction && Elevators[i].assigned == true)
971 return true;
972 }
973 }
974 break;
975 }
976 }
977 return false;
978}
979
980bool DispatchController::IsElevatorAssignedToOther(int number, int destination_floor, int direction)
981{
982 //return true if the specified elevator is assigned to a destination floor or direction other than
983 //the specified one, while also taking the serviced floor range into account if more than one elevator is assigned
984
985 //only run if power is enabled
986 if (sbs->GetPower() == false)
987 return false;
988
989 for (size_t i = 0; i < Elevators.size(); i++)
990 {
991 if (Elevators[i].number == number)
992 {
993 if (direction == 0)
994 {
995 //destination dispatch mode
996 if (Elevators[i].assigned == false || Elevators[i].assigned_destination.size() == 0)
997 return false;
998
999 if (Elevators[i].assigned_destination[0] != destination_floor && Elevators[i].assigned == true &&
1000 ((abs(Elevators[i].assigned_destination[0] - destination_floor) > Range) && Elevators.size() > 1))
1001 return true;
1002 else
1003 break;
1004 }
1005 else
1006 {
1007 //standard mode
1008 if (Elevators[i].assigned == false || Elevators[i].assigned_directions.size() == 0)
1009 return false;
1010
1011 if (Elevators[i].assigned_directions[0] != direction && Elevators[i].assigned == true)
1012 return true;
1013 else
1014 break;
1015 }
1016 }
1017 }
1018 return false;
1019}
1020
1021void DispatchController::AssignElevator(int number, int destination_floor, int direction)
1022{
1023 //assign an elevator to the specified destination floor
1024
1025 //only run if power is enabled
1026 if (sbs->GetPower() == false)
1027 return;
1028
1029 for (size_t i = 0; i < Elevators.size(); i++)
1030 {
1031 if (Elevators[i].number == number)
1032 {
1033 Elevators[i].assigned = true;
1034
1035 if (direction == 0) //destination dispatch mode
1036 {
1037 //add floor to assignment list
1038 Elevators[i].assigned_destination.emplace_back(destination_floor);
1039 }
1040 else //standard mode
1041 {
1042 //exit if elevator has already been assigned to the direction
1043 for (size_t j = 0; j < Elevators[i].assigned_directions.size(); j++)
1044 {
1045 if (Elevators[i].assigned_directions[j] == direction)
1046 {
1047 Report("Elevator already assigned to direction");
1048 return;
1049 }
1050 }
1051
1052 //add direction to assignment list
1053 Elevators[i].assigned_directions.emplace_back(direction);
1054 }
1055 }
1056 }
1057}
1058
1060{
1061 //register the specified call station
1062
1063 //only run if power is enabled
1064 if (sbs->GetPower() == false)
1065 return;
1066
1067 //exit if already registered
1068 for (size_t i = 0; i < CallStations.size(); i++)
1069 {
1070 if (CallStations[i] == station)
1071 return;
1072 }
1073
1074 CallStations.emplace_back(station);
1075}
1076
1078{
1079 //unregister the specified call station
1080
1081 //only run if power is enabled
1082 if (sbs->GetPower() == false)
1083 return;
1084
1085 for (size_t i = 0; i < CallStations.size(); i++)
1086 {
1087 if (CallStations[i] == station)
1088 {
1089 CallStations.erase(CallStations.begin() + i);
1090 return;
1091 }
1092 }
1093}
1094
1095std::vector<CallStation*> DispatchController::GetCallStations(int floor)
1096{
1097 //returns list of callstations for the specified floor
1098
1099 std::vector<CallStation*> stationlist;
1100
1101 for (size_t i = 0; i < CallStations.size(); i++)
1102 {
1103 if (CallStations[i]->GetFloor() == floor)
1104 {
1105 stationlist.emplace_back(CallStations[i]);
1106 }
1107 }
1108 return stationlist;
1109}
1110
1111int DispatchController::GetElevatorArrived(int starting_floor, int destination_floor)
1112{
1113 //return the number of the elevator that has arrived, for the specified route
1114 //return 0 if no elevator has arrived yet
1115
1116 //only run if power is enabled
1117 if (sbs->GetPower() == false)
1118 return 0;
1119
1120 for (size_t i = 0; i < Elevators.size(); i++)
1121 {
1122 if (Elevators[i].arrived == true)
1123 {
1124 if (Elevators[i].arrival_floor == starting_floor && Elevators[i].destination_floor == destination_floor)
1125 return Elevators[i].number;
1126 }
1127 }
1128 return 0;
1129}
1130
1132{
1133 //return the number of the elevator that has arrived, for the specified direction
1134 //return 0 if no elevator has arrived yet
1135
1136 //only run if power is enabled
1137 if (sbs->GetPower() == false)
1138 return 0;
1139
1140 for (size_t i = 0; i < Elevators.size(); i++)
1141 {
1142 if (Elevators[i].arrived == true)
1143 {
1144 if (Elevators[i].arrival_floor == floor && Elevators[i].arrival_direction == direction)
1145 return Elevators[i].number;
1146 }
1147 }
1148 return 0;
1149}
1150
1152{
1153 //determine floor range of associated elevators
1154
1155 bool firstrun = true;
1156
1157 for (size_t i = 0; i < Elevators.size(); i++)
1158 {
1159 Elevator *elev = sbs->GetElevator(Elevators[i].number);
1160 if (elev)
1161 {
1162 int carnum = elev->GetCarCount();
1163 for (int j = 1; j <= carnum; j++)
1164 {
1165 ElevatorCar *car = elev->GetCar(j);
1166 if (car)
1167 {
1168 int tmpbottom = car->GetBottomFloor();
1169 int tmptop = car->GetTopFloor();
1170 if (tmpbottom < bottom_floor || firstrun == true)
1171 bottom_floor = tmpbottom;
1172 if (tmptop > top_floor || firstrun == true)
1173 top_floor = tmptop;
1174 firstrun = false;
1175 }
1176 }
1177 }
1178 }
1179}
1180
1182{
1183 //return true if this controller serves the specified floor
1184
1185 for (size_t i = 0; i < Elevators.size(); i++)
1186 {
1187 bool tmp = false;
1188 Elevator *elev = sbs->GetElevator(Elevators[i].number);
1189 if (elev)
1190 tmp = elev->IsServicedFloor(floor);
1191 if (tmp == true)
1192 return true;
1193 }
1194 return false;
1195}
1196
1198{
1199 //enables fire service phase 1 on all elevators associated with this controller
1200
1201 //only run if power is enabled
1202 if (sbs->GetPower() == false)
1203 return false;
1204
1205 bool status = false, status2 = false;
1206
1207 for (size_t i = 0; i < Elevators.size(); i++)
1208 {
1209 Elevator *elevator = sbs->GetElevator(Elevators[i].number);
1210 if (elevator)
1211 status2 = elevator->EnableFireService1(value);
1212 if (status2 == true)
1213 status = true;
1214 }
1215 return status;
1216}
1217
1218bool DispatchController::AtMaxRequests(int elevator, int destination_floor)
1219{
1220 //return true if the specified elevator is at the maximum requests level for the specified destination floor
1221
1222 //only run if power is enabled
1223 if (sbs->GetPower() == false)
1224 return false;
1225
1226 if (DestinationDispatch == false)
1227 return false;
1228
1229 if (!sbs->GetElevator(elevator))
1230 return false;
1231
1232 //get elevator index
1233 int index = -1;
1234 for (size_t i = 0; i < Elevators.size(); i++)
1235 {
1236 if (Elevators[i].number == elevator)
1237 {
1238 index = i;
1239 break;
1240 }
1241 }
1242
1243 //return true if an elevator's assigned DD route has requests at the MaxPassengers value
1244 for (size_t i = 0; i < Routes.size(); i++)
1245 {
1246 for (size_t j = 0; j < Elevators[index].assigned_destination.size(); j++)
1247 {
1248 if (Elevators[index].assigned_destination[j] == destination_floor && Elevators[index].assigned == true)
1249 {
1250 if (Routes[i].requests == MaxPassengers)
1251 return true;
1252 }
1253 }
1254 }
1255
1256 return false;
1257}
1258
1260{
1261 //reset arrival status
1262
1263 //only run if power is enabled
1264 if (sbs->GetPower() == false)
1265 return;
1266
1267 for (size_t i = 0; i < Elevators.size(); i++)
1268 {
1269 if (Elevators[i].number == number)
1270 {
1271 Elevators[i].arrived = false;
1272 Elevators[i].arrival_floor = 0;
1273 Elevators[i].arrival_direction = false;
1274 break;
1275 }
1276 }
1277}
1278
1280{
1281 if (Elevators.empty())
1282 return 0;
1283
1284 Elevator *elevator = sbs->GetElevator(Elevators[0].number);
1285
1286 //return recall floor of first elevator in group
1287 if (elevator)
1288 return elevator->GetRecallFloor();
1289
1290 return 0;
1291}
1292
1294{
1295 //returns true if an elevator has become unavailable during dispatch
1296
1297 //only run if power is enabled
1298 if (sbs->GetPower() == false)
1299 return false;
1300
1301 Elevator *elev = sbs->GetElevator(elevator);
1302
1303 if (elev->InServiceMode() == true)
1304 {
1305 Report("Elevator " + ToString(elevator) + " in service mode");
1306 return true;
1307 }
1308 if (elev->IsRunning() == false)
1309 {
1310 Report("Elevator " + ToString(elevator) + " not running");
1311 return true;
1312 }
1313 if (elev->IsStopped() == true)
1314 {
1315 Report("Elevator " + ToString(elevator) + " stopped");
1316 return true;
1317 }
1318 /*if (elev->Error == true)
1319 {
1320 Report("Elevator " + ToString(elevator) + " movement processing error");
1321 return true;
1322 }*/
1323
1324 return false;
1325}
1326
1331
1333{
1334 return top_floor;
1335}
1336
1338{
1339 //return number of the specified elevator index
1340
1341 if (Elevators.size() == 0)
1342 return 0;
1343
1344 if (index < 0 || index > Elevators.size() - 1)
1345 return 0;
1346 return Elevators[index].number;
1347}
1348
1349bool DispatchController::SameElevators(const std::vector<int> &elevators)
1350{
1351 //return true if the list of elevators matches this controller's elevators
1352
1353 //only run if power is enabled
1354 if (sbs->GetPower() == false)
1355 return false;
1356
1357 if (Elevators.size() != elevators.size())
1358 return false;
1359
1360 for (size_t i = 0; i < Elevators.size(); i++)
1361 {
1362 if (Elevators[i].number != elevators[i])
1363 return false;
1364 }
1365 return true;
1366}
1367
1368bool DispatchController::GetCallStatus(int elevator, int floor, bool &up, bool &down)
1369{
1370 //returns call status for the specified elevator and floor
1371 //returns true if a matching call was found
1372
1373 //only run if power is enabled
1374 if (sbs->GetPower() == false)
1375 return false;
1376
1377 up = false;
1378 down = false;
1379 bool result = false;
1380
1381 for (size_t i = 0; i < Elevators.size(); i++)
1382 {
1383 if (Elevators[i].number == elevator)
1384 {
1385 for (size_t j = 0; j < Elevators[i].calls.size(); j++)
1386 {
1387 if (Elevators[i].calls[j].floor == floor)
1388 {
1389 if (Elevators[i].calls[j].direction == true)
1390 up = true;
1391 else
1392 down = true;
1393
1394 result = true;
1395 }
1396 }
1397 break;
1398 }
1399 }
1400
1401 return result;
1402}
1403
1405{
1406 //return true if an associated elevator serves the specified floor
1407
1408 //only run if power is enabled
1409 if (sbs->GetPower() == false)
1410 return false;
1411
1412 for (size_t i = 0; i < Elevators.size(); i++)
1413 {
1414 Elevator *elev = sbs->GetElevator(Elevators[i].number);
1415 if (elev)
1416 {
1417 if (elev->IsServicedFloor(floor) == true)
1418 return true;
1419 }
1420 }
1421
1422 return false;
1423}
1424
1425}
void Error(bool type=0)
bool IsElevatorAssignedToOther(int number, int destination_floor, int direction)
bool AddElevator(int elevator)
std::vector< Route > Routes
Definition controller.h:121
std::vector< ElevMap > Elevators
Definition controller.h:107
bool IsServicedFloor(int floor)
bool ServesFloor(int floor)
void AssignElevator(int number, int destination_floor, int direction)
bool ServicesElevator(int elevator)
std::vector< CallStation * > GetCallStations(int floor)
bool GetCallStatus(int elevator, int floor, bool &up, bool &down)
bool SameElevators(const std::vector< int > &elevators)
DispatchController(Object *parent, int number)
bool FireService(int value)
int GetElevatorArrived(int starting_floor, int destination_floor)
int FindClosestElevator(bool &busy, bool destination, int starting_floor, int destination_floor, int direction=0)
bool IsElevatorAssigned(int number, int destination_floor, int direction)
bool RemoveElevator(int elevator)
bool ElevatorUnavailable(int elevator)
bool CallElevator(CallStation *station, bool direction)
void UnregisterCallStation(CallStation *station)
bool ReportError(const std::string &message)
int GetElevatorArrivedStandard(int floor, bool direction)
void Report(const std::string &message)
void DispatchElevator(bool destination, int number, int destination_floor, int direction, bool call)
void RegisterCallStation(CallStation *station)
int GetElevator(int index)
bool RequestRoute(CallStation *station, int starting_floor, int destination_floor)
void ResetArrival(int number)
void RemoveRoute(const Route &route)
void ElevatorArrived(int number, int floor, bool direction)
std::vector< CallStation * > CallStations
Definition controller.h:123
bool AtMaxRequests(int elevator, int destination_floor)
int AvailableForCall(bool destination, int floor, int direction, bool report_on_failure=true)
bool EnableFireService1(int value)
void CancelHallCall(int floor, int direction)
ElevatorCar * GetCar(int number)
bool AddRoute(int floor, int direction, int call_type)
Definition elevator.cpp:556
int GetRecallFloor()
void RemoveController(int controller)
ElevatorCar * GetCarForFloor(int number, bool report_on_failure=false)
bool InServiceMode()
bool IsServicedFloor(int floor, bool report=true)
void AddController(int controller)
std::string ID
Definition floor.h:38
virtual bool ReportError(const std::string &message)
Definition object.cpp:84
virtual void Report(const std::string &message)
Definition object.cpp:78
bool parent_deleting
Definition object.h:64
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
void EnableLoop(bool value)
Definition object.cpp:521
Elevator * GetElevator(int number)
Definition sbs.cpp:1746
bool GetPower()
Definition sbs.cpp:4701
Floor * GetFloor(int number)
Definition sbs.cpp:1739
bool FastDelete
Definition sbs.h:188
void RemoveController(DispatchController *controller)
Definition sbs.cpp:2909
bool Verbose
Definition sbs.h:186
std::string ToString(int number)
Definition globals.cpp:279
#define SBS_PROFILE(name)
Definition profiler.h:131