diff --git a/CMakeLists.txt b/CMakeLists.txt index 110c8646371b40c9f8ef8f7da89d152c7521211f..82538f685b5b0abca6071c23a5cd0e0c45462c0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,6 +290,7 @@ set(source_files routing/ff_router/LocalFloorfieldViaFM.cpp routing/ff_router/FloorfieldViaFM.cpp #routing/ff_router/FFKit.cpp + routing/ff_router/UnivFFviaFM.cpp #global_shortest routing/global_shortest/AccessPoint.cpp @@ -355,6 +356,7 @@ set(header_files routing/ff_router/LocalFloorfieldViaFM.h routing/ff_router/FloorfieldViaFM.h #routing/ff_router/FFKit.h + routing/ff_router/UnivFFviaFM.h #general routing/DirectionStrategy.h diff --git a/Simulation.cpp b/Simulation.cpp index 5ee11ed830986ef4d4856f084071562f565f6be8..66d6da09bb02426c1f42a8eb186a51de7c6f23fb 100644 --- a/Simulation.cpp +++ b/Simulation.cpp @@ -249,10 +249,6 @@ bool Simulation::InitArgs() // This should be done after the initialization of the operationalModel // because then, invalid pedestrians have been deleted and FindExit() // has been called. - Log->Write("INFO:\t PreSim of DirectionStrategy starting ..."); - if (!_operationalModel->GetDirection()->PreSim(_building.get())) - return false; - Log->Write("INFO:\t PreSim of DirectionStrategy done"); //other initializations for (auto&& ped: _building->GetAllPedestrians()) { @@ -509,11 +505,11 @@ double Simulation::RunBody(double maxSimTime) if (0==frameNr%writeInterval) { _iod->WriteFrame(frameNr/writeInterval, _building.get()); } - if(!_gotSources && !_periodic /*&& _printPB*/) // @todo: option for print progressbar - // Log->ProgressBar(initialnPeds, initialnPeds-_nPeds, t); - //bar->Progressed(initialnPeds-_nPeds); - else - printf("time: %.2f | %.2f\n", t , maxSimTime); +// if(!_gotSources && !_periodic /*&& _printPB*/) // @todo: option for print progressbar +// // Log->ProgressBar(initialnPeds, initialnPeds-_nPeds, t); +// bar->Progressed(initialnPeds-_nPeds); +// else +// printf("time: %.2f | %.2f\n", t , maxSimTime); // needed to control the execution time PART 2 // time(&endtime); diff --git a/general/Macros.h b/general/Macros.h index 954e8154141e9ef48c9b763a4075722796c2aa5f..d7b28e052c3ed11020ab1c6b64e61127b838677a 100644 --- a/general/Macros.h +++ b/general/Macros.h @@ -162,13 +162,14 @@ enum FFRouterMode { }; enum GridCode { //used in floor fields - WALL = 0, - INSIDE, - OUTSIDE, - OPEN_CROSSING, - OPEN_TRANSITION, - CLOSED_CROSSING, //closed crossings and transitions are marked as walls in "parseBuilding" - CLOSED_TRANSITION + WALL = -10, + INSIDE = -11, + OUTSIDE = -12, + //instead of constants, GridCode stores UID of doors + OPEN_CROSSING = -13, + OPEN_TRANSITION = -14, + CLOSED_CROSSING = -15, //closed crossings and transitions are marked as walls in "parseBuilding" + CLOSED_TRANSITION = -16 }; enum FastMarchingFlags { @@ -181,6 +182,37 @@ enum FastMarchingFlags { FM_OUTSIDE = -7 }; +enum FloorfieldMode { + FF_CENTRALPOINT, + FF_FULL_LINE, + FF_WALL_AVOID, + FF_HOMO_SPEED +}; + +enum MagicNumbers{ + UNKNOWN_DISTANCE, + UNKNOWN_COST, + WALL_ON_COSTARRAY, + TARGET_REGION +}; + +constexpr double magicnum(int i) { + return (i == UNKNOWN_DISTANCE) ? -3.0 : (i == UNKNOWN_COST) ? -2.0 : (i == WALL_ON_COSTARRAY) ? -7.0 : (i == TARGET_REGION) ? 0.0 : NAN; +// switch (i) { +// case UNKNOWN_DISTANCE: +// return -3.0; +// case UNKNOWN_COST: +// return -2.0; +// case WALL_ON_COSTARRAY: +// return -7.0; +// case TARGET_REGION: +// return 0.0; +// default: +// std::cerr << "ERROR: \tunknown magic number " << i << std::endl; +// return NAN; +// } +} + //global functions for convenience inline char xmltob(const char * t, char v = 0) diff --git a/pedestrian/Pedestrian.cpp b/pedestrian/Pedestrian.cpp index 072a018335e073ee5908af2f7c119b761b382c90..fce31355371b4181ea9593e04ed90e3420be47b3 100644 --- a/pedestrian/Pedestrian.cpp +++ b/pedestrian/Pedestrian.cpp @@ -147,7 +147,6 @@ Pedestrian::Pedestrian(const StartDistribution& agentsParameters, Building& buil _tmpFirstOrientation = true; _turninAngle = 0.0; _ellipse = JEllipse(); - //_navLine = new NavLine(); //FIXME? argraf : rather nullptr and Setter includes correct uid (done below) _navLine = nullptr; _router = NULL; _building = NULL; @@ -254,16 +253,11 @@ void Pedestrian::SetExitIndex(int i) void Pedestrian::SetExitLine(const NavLine* l) //FIXME? argraf : _navLine = new NavLine(*l); this would have a navLine with consistent uid (done below) { - //_navLine = l; - //_navLine->SetPoint1(l->GetPoint1()); - //_navLine->SetPoint2(l->GetPoint2()); - if(l) { - _navLine = std::unique_ptr<NavLine>(new NavLine(*l)); - } - /*else if(l && _navLine && *l != *_navLine && l->GetUniqueID() != _navLine->GetUniqueID()){ + if(_navLine) delete _navLine; + if(l) { _navLine = new NavLine(*l); - }*/ + } } void Pedestrian::SetPos(const Point& pos, bool initial) @@ -392,7 +386,7 @@ int Pedestrian::GetExitIndex() const NavLine* Pedestrian::GetExitLine() const { - return _navLine.get(); + return _navLine; } const vector<int>& Pedestrian::GetTrip() const diff --git a/pedestrian/Pedestrian.h b/pedestrian/Pedestrian.h index 3ac426f25fe676dd9c9d0a81ee2e1b7623aba3dc..e8e7538c6f7e6b333039f755aae1548fd8940262 100644 --- a/pedestrian/Pedestrian.h +++ b/pedestrian/Pedestrian.h @@ -91,7 +91,7 @@ private: int _oldSubRoomID; Point _lastE0; - std::unique_ptr<NavLine> _navLine; // current exit line + NavLine* _navLine; // current exit line std::map<int, int>_mentalMap; // map the actual room to a destination std::vector<int> _destHistory; std::vector<int> _trip; diff --git a/routing/DirectionStrategy.cpp b/routing/DirectionStrategy.cpp index 4bdf38282ac328e397d39d287fa012f000988759..e51586b1a01f1fa04be2f2d54f5d91d446a6f921 100644 --- a/routing/DirectionStrategy.cpp +++ b/routing/DirectionStrategy.cpp @@ -410,48 +410,7 @@ void DirectionLocalFloorfield::Init(Building* buildingArg, double stepsize, _initDone = true; } -bool DirectionLocalFloorfield::PreSim(Building* building) { - std::map<int, std::vector<int>> doorsInRoom; - doorsInRoom.clear(); - Log->Write("INFO: \tDirectionLocalFloorfield::PreSim"); - - std::set<std::pair<int, int>> roomsDoorsSet; - roomsDoorsSet.clear(); - auto allPeds = building->GetAllPedestrians(); -#pragma omp parallel - { -#pragma omp for - for (size_t i = 0; i < allPeds.size(); ++i) { - auto ped = allPeds.begin(); - std::advance(ped, i); - if (auto router = dynamic_cast<FFRouter*>((*ped)->GetRouter())) { - auto pedSubroomsDoorSet = router->GetPresumableExitRoute(*ped); -#pragma omp critical(roomsDoorsSet) - for (auto it : pedSubroomsDoorSet) { - roomsDoorsSet.insert(std::make_pair(it.first->GetRoomID(), it.second)); - } - } - } - -#pragma omp for - for (size_t i = 0; i < roomsDoorsSet.size(); ++i) { - auto rdIt = roomsDoorsSet.begin(); - // suboptimal, because a set doesn't provide random-access iterators - std::advance(rdIt, i); - CalcFloorfield(rdIt->first, rdIt->second); -#pragma omp critical(doorsInRoom) - doorsInRoom[rdIt->first].push_back(rdIt->second); - } - } - for (size_t i = 0; i < doorsInRoom.size(); ++i) { - auto roomIt = doorsInRoom.begin(); - std::advance(roomIt, i); - //@todo: ar.graf: plz make switch in ini file and dependand on ini write yes/no (issue 208) - //writeFF(roomIt->first, roomIt->second); - } - return true; -} void DirectionLocalFloorfield::CalcFloorfield(int room, int destUID) { Point dummy; diff --git a/routing/DirectionStrategy.h b/routing/DirectionStrategy.h index a25698bd8499aa9159e619b05473bf409e7bd79c..fb3a5d09bf17aec80627c0e0b8e86c265933cef4 100644 --- a/routing/DirectionStrategy.h +++ b/routing/DirectionStrategy.h @@ -46,41 +46,33 @@ public: DirectionStrategy(); virtual ~DirectionStrategy(); - // Allow the DirectionStrategy to perform some pre-simulation calculation, with all pedestrians - // already set and a valid _exitIndex. Returns true if the initialization was successful. - virtual bool PreSim(Building* building) = 0; virtual Point GetTarget(Room* room, Pedestrian* ped) const = 0; }; class DirectionMiddlePoint : public DirectionStrategy { public: - virtual bool PreSim(Building* building) {(void) building; return true;}; virtual Point GetTarget(Room* room, Pedestrian* ped) const; }; class DirectionMinSeperation : public DirectionStrategy { public: - virtual bool PreSim(Building* building) {(void) building; return true;}; virtual Point GetTarget(Room* room, Pedestrian* ped) const; }; class DirectionMinSeperationShorterLine : public DirectionStrategy { public: - virtual bool PreSim(Building* building) {(void) building; return true;}; virtual Point GetTarget(Room* room, Pedestrian* ped) const; }; class DirectionInRangeBottleneck : public DirectionStrategy { public: - virtual bool PreSim(Building* building) {(void) building; return true;}; virtual Point GetTarget(Room* room, Pedestrian* ped) const; }; class DirectionGeneral : public DirectionStrategy { public: - virtual bool PreSim(Building* building) {(void) building; return true;}; virtual Point GetTarget(Room* room, Pedestrian* ped) const; }; @@ -88,7 +80,6 @@ class DirectionFloorfield : public DirectionStrategy { public: DirectionFloorfield(); void Init(Building* building, double stepsize, double threshold, bool useDistancMap); - virtual bool PreSim(Building* building) {(void) building; return true;}; ~DirectionFloorfield(); //void Init(); virtual Point GetTarget(Room* room, Pedestrian* ped) const; @@ -105,7 +96,6 @@ public: DirectionLocalFloorfield(); void Init(Building* building, double stepsize, double threshold, bool useDistancMap); - virtual bool PreSim(Building* building); ~DirectionLocalFloorfield(); //void Init(); virtual Point GetTarget(Room* room, Pedestrian* ped) const; @@ -132,7 +122,6 @@ public: DirectionSubLocalFloorfield(); void Init(Building* building, double stepsize, double threshold, bool useDistancMap); - virtual bool PreSim(Building* building) {(void) building; return true;}; ~DirectionSubLocalFloorfield(); //void Init(); virtual Point GetTarget(Room* room, Pedestrian* ped) const; diff --git a/routing/ff_router/UnivFFviaFM.cpp b/routing/ff_router/UnivFFviaFM.cpp new file mode 100644 index 0000000000000000000000000000000000000000..222c2cbcf429f98925b53555f69459f7c4832d3b --- /dev/null +++ b/routing/ff_router/UnivFFviaFM.cpp @@ -0,0 +1,624 @@ +// +// Created by arne on 5/9/17. +// + +#include "UnivFFviaFM.h" +#include "../../geometry/Line.h" +#include "../../geometry/Building.h" +#include "../../geometry/Room.h" +#include "../../geometry/SubRoom.h" +#include "mesh/RectGrid.h" + + +UnivFFviaFM::UnivFFviaFM(Room* a, Building* b, double hx, double hy, double wallAvoid, bool useWallAvoid) { + _building = b; + const Configuration* conf = b->GetConfig(); + UnivFFviaFM(a, conf, hx, hy, wallAvoid, useWallAvoid); +} + +UnivFFviaFM::UnivFFviaFM(SubRoom* a, Building* b, double hx, double hy, double wallAvoid, bool useWallAvoid) { + _building = b; + const Configuration* conf = b->GetConfig(); + UnivFFviaFM(a, conf, hx, hy, wallAvoid, useWallAvoid); +} + +UnivFFviaFM::UnivFFviaFM(Room *a, const Configuration *b, double hx, double hy, double wallAvoid, bool useWallAvoid) { + //build the vector with walls(wall or obstacle), the map with <UID, Door(Cross or Trans)>, the vector with targets(UIDs) + //then call other constructor including the mode + _wallAvoidDistance = wallAvoid; + _useWallAvoidance = useWallAvoid; + + std::vector<Line> lines; + std::map<int, Line> tmpDoors; + + for (auto& subroomMap : a->GetAllSubRooms()) { + SubRoom* subRoomPtr = subroomMap.second.get(); + std::vector<Wall> walls = std::vector<Wall>(subRoomPtr->GetAllWalls()); + for (auto& wall : walls) { + lines.emplace_back((Line)wall); + } + + std::vector<Obstacle*> tmpObsPtrVec = subRoomPtr->GetAllObstacles(); + for (Obstacle* ptrObs : tmpObsPtrVec) { + const std::vector<Wall> obsWalls = ptrObs->GetAllWalls(); + for (auto& owall : obsWalls) { + lines.emplace_back((Line)owall); + } + } + + const std::vector<Crossing*> tmpCross = subRoomPtr->GetAllCrossings(); + const std::vector<Transition*> tmpTrans = subRoomPtr->GetAllTransitions(); + + for (auto& cross : tmpCross) { + tmpDoors.emplace(std::make_pair(cross->GetUniqueID(), (Line) *cross)); + } + for (auto& trans : tmpTrans) { + tmpDoors.emplace(std::make_pair(trans->GetUniqueID(), (Line) *trans)); + } + } + + std::vector<int> noDoors; + UnivFFviaFM(lines, tmpDoors, noDoors, FF_HOMO_SPEED, hx); +} + +UnivFFviaFM::UnivFFviaFM(SubRoom* a, const Configuration* b, double hx, double hy, double wallAvoid, bool useWallAvoid) { + //build the vector with walls(wall or obstacle), the map with <UID, Door(Cross or Trans)>, the vector with targets(UIDs) + //then call other constructor including the mode + _wallAvoidDistance = wallAvoid; + _useWallAvoidance = useWallAvoid; + + std::vector<Wall> walls = std::vector<Wall> (a->GetAllWalls()); + std::vector<Line> lines; + for (auto& wall : walls) { + lines.emplace_back((Line)wall); + } + + std::vector<Obstacle*> tmpObsPtrVec = a->GetAllObstacles(); + for (Obstacle* ptrObs : tmpObsPtrVec) { + const std::vector<Wall> obsWalls = ptrObs->GetAllWalls(); + for (auto& owall : obsWalls) { + lines.emplace_back((Line)owall); + } + } + + std::map<int, Line> tmpDoors; + const std::vector<Crossing*> tmpCross = a->GetAllCrossings(); + const std::vector<Transition*> tmpTrans = a->GetAllTransitions(); + + for (auto& cross : tmpCross) { + tmpDoors.emplace(std::make_pair(cross->GetUniqueID(), (Line) *cross)); + } + for (auto& trans : tmpTrans) { + tmpDoors.emplace(std::make_pair(trans->GetUniqueID(), (Line) *trans)); + } + + std::vector<int> noDoors; + UnivFFviaFM(lines, tmpDoors, noDoors, FF_HOMO_SPEED, hx); +} + +UnivFFviaFM::UnivFFviaFM(std::vector<Line>& walls, std::map<int, Line>& doors, std::vector<int> targetUIDs, int mode, double spacing) { + //find circumscribing rectangle (x_min/max, y_min/max) //create RectGrid + createRectGrid(walls, doors, spacing); + _nPoints = _grid->GetnPoints(); + + //allocate _gridCode and _speedFieldSelector and initialize them ("draw" walls and doors) + _gridCode = new int[_nPoints]; + processGeometry(walls, doors); + + _speedFieldSelector[INITIAL_SPEED] = new double[_nPoints]; + std::fill(_speedFieldSelector[INITIAL_SPEED], _speedFieldSelector[INITIAL_SPEED]+_nPoints, 1.0); + + //allocate _initalSpeed and maybe _modifiedSpeed + if (mode == FF_WALL_AVOID) { + double* cost_alias_walldistance = new double[_nPoints]; + _costFieldWithKey[0] = cost_alias_walldistance; + Point* gradient_alias_walldirection = new Point[_nPoints]; + _directionFieldWithKey[0] = gradient_alias_walldirection; + + //create wall distance field + drawLinesOnGrid(walls, cost_alias_walldistance, magicnum(TARGET_REGION)); + calcFF(cost_alias_walldistance, gradient_alias_walldirection, _speedFieldSelector[INITIAL_SPEED]); + + double* temp_reduWallSpeed = new double[_nPoints]; + if (_speedFieldSelector[REDU_WALL_SPEED]) { //free memory before overwriting + delete[] _speedFieldSelector[REDU_WALL_SPEED]; + } + _speedFieldSelector[REDU_WALL_SPEED] = temp_reduWallSpeed; + //init _reducedWallSpeed by using distance field + //@todo: @ar.graf @newFF + } + + for (auto targetUID : targetUIDs ) { + Line tempTargetLine = Line(doors[targetUID]); + Point tempCenterPoint = Point(tempTargetLine.GetCentre()); + + //this allocation must be on shared heap! to be accessable by any thread later (head should be shared in openmp) + double* newArrayDBL = new double[_nPoints]; + Point* newArrayPt = nullptr; + if (_user == DISTANCE_AND_DIRECTIONS_USED) { + newArrayPt = new Point[_nPoints]; + } + + if (_costFieldWithKey[targetUID]) + delete[] _costFieldWithKey[targetUID]; + _costFieldWithKey[targetUID] = newArrayDBL; + + //init costarray + for (int i = 0; i < _nPoints; ++i) { + if (_gridCode[i] == WALL) { + newArrayDBL[i] = magicnum(WALL_ON_COSTARRAY); + } else { + newArrayDBL[i] = magicnum(UNKNOWN_COST); + } + } + + if (_directionFieldWithKey[targetUID]) + delete[] _directionFieldWithKey[targetUID]; + _directionFieldWithKey[targetUID] = newArrayPt; + + //initialize start area + if (_mode == LINESEGMENT) { + drawLinesOnGrid(tempTargetLine, newArrayDBL, magicnum(TARGET_REGION)); + } + if (_mode == CENTERPOINT) { + newArrayDBL[_grid->getKeyAtPoint(tempCenterPoint)] = magicnum(TARGET_REGION); + } + + if (mode == FF_WALL_AVOID) { + calcFF(newArrayDBL, newArrayPt, _speedFieldSelector[REDU_WALL_SPEED]); + } else if (mode == FF_HOMO_SPEED) { + calcFF(newArrayDBL, newArrayPt, _speedFieldSelector[INITIAL_SPEED]); + } + _uids.emplace_back(targetUID); + } //loop over targets + + + +} + +void UnivFFviaFM::createRectGrid(std::vector<Line>& walls, std::map<int, Line>& doors, double spacing) { + double x_min = DBL_MAX; double x_max = DBL_MIN; + double y_min = DBL_MAX; double y_max = DBL_MIN; + + for(auto& wall : walls) { + if (wall.GetPoint1()._x < x_min) x_min = wall.GetPoint1()._x; + if (wall.GetPoint1()._y < y_min) y_min = wall.GetPoint1()._y; + if (wall.GetPoint2()._x < x_min) x_min = wall.GetPoint2()._x; + if (wall.GetPoint2()._y < y_min) y_min = wall.GetPoint2()._y; + + if (wall.GetPoint1()._x > x_max) x_max = wall.GetPoint1()._x; + if (wall.GetPoint1()._y > y_max) y_max = wall.GetPoint1()._y; + if (wall.GetPoint2()._x > x_max) x_max = wall.GetPoint2()._x; + if (wall.GetPoint2()._y > y_max) y_max = wall.GetPoint2()._y; + } + + for(auto& doorPair:doors) { + Line& door = doorPair.second; + if (door.GetPoint1()._x < x_min) x_min = door.GetPoint1()._x; + if (door.GetPoint1()._y < y_min) y_min = door.GetPoint1()._y; + if (door.GetPoint2()._x < x_min) x_min = door.GetPoint2()._x; + if (door.GetPoint2()._y < y_min) y_min = door.GetPoint2()._y; + + if (door.GetPoint1()._x > x_max) x_max = door.GetPoint1()._x; + if (door.GetPoint1()._y > y_max) y_max = door.GetPoint1()._y; + if (door.GetPoint2()._x > x_max) x_max = door.GetPoint2()._x; + if (door.GetPoint2()._y > y_max) y_max = door.GetPoint2()._y; + } + + //create Rect Grid + _grid = new RectGrid(); + _grid->setBoundaries(x_min, y_min, x_max, y_max); + _grid->setSpacing(spacing, spacing); + _grid->createGrid(); +} + +void UnivFFviaFM::processGeometry(std::vector<Line>&walls, std::map<int, Line>& doors) { + for (int i = 0; i < _nPoints; ++i) { + _gridCode[i] = OUTSIDE; + } + + _doors = doors; + + drawLinesOnGrid<int>(walls, _gridCode, WALL); + drawLinesOnGrid(doors, _gridCode); //UIDs of doors will be drawn on _gridCode +} + +void UnivFFviaFM::drawLinesOnGrid(std::map<int, Line>& doors, int *const grid) { + for (auto&& doorPair : doors) { + int tempUID = doorPair.first; + Line tempDoorLine = Line(doorPair.second); + drawLinesOnGrid(tempDoorLine, grid, tempUID); + } +} + +template <typename T> +void UnivFFviaFM::drawLinesOnGrid(std::vector<Line>& wallArg, T* const target, const T value) { //no init, plz init elsewhere + + for (auto& line : wallArg) { + drawLinesOnGrid(line, target, value); + } //loop over all walls + +} //drawLinesOnGrid + +template <typename T> +void UnivFFviaFM::drawLinesOnGrid(Line& line, T* const target, const T value) { //no init, plz init elsewhere +// i~x; j~y; +//http://stackoverflow.com/questions/10060046/drawing-lines-with-bresenhams-line-algorithm +//src in answer of "Avi"; adapted to fit this application + + //grid handeling local vars: + long int iMax = _grid->GetiMax(); + + long int iStart, iEnd; + long int jStart, jEnd; + long int iDot, jDot; + long int key; + long int deltaX, deltaY, deltaX1, deltaY1, px, py, xe, ye, i; //Bresenham Algorithm + + + key = _grid->getKeyAtPoint(line.GetPoint1()); + iStart = (long) _grid->get_i_fromKey(key); + jStart = (long) _grid->get_j_fromKey(key); + + key = _grid->getKeyAtPoint(line.GetPoint2()); + iEnd = (long) _grid->get_i_fromKey(key); + jEnd = (long) _grid->get_j_fromKey(key); + + deltaX = (int) (iEnd - iStart); + deltaY = (int) (jEnd - jStart); + deltaX1 = abs( (int) (iEnd - iStart)); + deltaY1 = abs( (int) (jEnd - jStart)); + + px = 2*deltaY1 - deltaX1; + py = 2*deltaX1 - deltaY1; + + if(deltaY1<=deltaX1) { + if(deltaX>=0) { + iDot = iStart; + jDot = jStart; + xe = iEnd; + } else { + iDot = iEnd; + jDot = jEnd; + xe = iStart; + } + if ((_gridCode[jDot*iMax + iDot] != WALL) && (_gridCode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gridCode[jDot*iMax + iDot] != CLOSED_TRANSITION)) { + target[jDot * iMax + iDot] = value; + } + for (i=0; iDot < xe; ++i) { + ++iDot; + if(px<0) { + px+=2*deltaY1; + } else { + if((deltaX<0 && deltaY<0) || (deltaX>0 && deltaY>0)) { + ++jDot; + } else { + --jDot; + } + px+=2*(deltaY1-deltaX1); + } + if ((_gridCode[jDot*iMax + iDot] != WALL) && (_gridCode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gridCode[jDot*iMax + iDot] != CLOSED_TRANSITION)) { + target[jDot * iMax + iDot] = value; + } + } + } else { + if(deltaY>=0) { + iDot = iStart; + jDot = jStart; + ye = jEnd; + } else { + iDot = iEnd; + jDot = jEnd; + ye = jStart; + } + if ((_gridCode[jDot*iMax + iDot] != WALL) && (_gridCode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gridCode[jDot*iMax + iDot] != CLOSED_TRANSITION)) { + target[jDot * iMax + iDot] = value; + } + for(i=0; jDot<ye; ++i) { + ++jDot; + if (py<=0) { + py+=2*deltaX1; + } else { + if((deltaX<0 && deltaY<0) || (deltaX>0 && deltaY>0)) { + ++iDot; + } else { + --iDot; + } + py+=2*(deltaX1-deltaY1); + } + if ((_gridCode[jDot*iMax + iDot] != WALL) && (_gridCode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gridCode[jDot*iMax + iDot] != CLOSED_TRANSITION)) { + target[jDot * iMax + iDot] = value; + } + } + } +} //drawLinesOnGrid + +void UnivFFviaFM::calcFF(double* costOutput, Point* directionOutput, const double *const speed) { + CompareCost comp = CompareCost(costOutput); + std::priority_queue<long int, std::vector<long int>, CompareCost> trialfield(costOutput); //pass the argument for the constr of CompareCost + std::priority_queue<long int, std::vector<long int>, CompareCost> trialfield2(comp); //pass the CompareCost object directly + + directNeighbor local_neighbor = _grid->getNeighbors(0); + long int aux = 0; + //init trial field + for (long int i = 0; i < _nPoints; ++i) { + if (costOutput[i] == 0.0) { + //check for negative neighbours, calc that ones and add to queue trialfield + local_neighbor = _grid->getNeighbors(i); + + //check for valid neigh + aux = local_neighbor.key[0]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[1]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[2]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[3]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + } + } + + while(!trialfield.empty()) { + local_neighbor = _grid->getNeighbors(trialfield.top()); + trialfield.pop(); + + //check for valid neigh + aux = local_neighbor.key[0]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[1]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[2]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + aux = local_neighbor.key[3]; + if ((aux != -2) && (_gridCode[aux] != WALL) && (costOutput[aux] < 0.0)) { + calcCost(aux, costOutput, directionOutput, speed); + trialfield.emplace(aux); + trialfield2.emplace(aux); + } + } +} + +void UnivFFviaFM::calcCost(const long int key, double* cost, Point* dir, const double* const speed) { + //adapt from calcFloorfield + double row = DBL_MAX; + double col = DBL_MAX; + long int aux = -1; //will be set below + bool pointsUp = false; + bool pointsRight = false; + + directNeighbor dNeigh = _grid->getNeighbors(key); + + aux = dNeigh.key[0]; + //hint: trialfield[i].cost = dist2Wall + i; <<< set in resetGoalAndCosts + if ((aux != -2) && //neighbor is a gridpoint + (cost[aux] != magicnum(UNKNOWN_COST)) && (cost[aux] != magicnum(UNKNOWN_DISTANCE)) && //gridpoint holds a calculated value + (_gridCode[aux] != WALL)) //gridpoint holds a calculated value + { + row = cost[aux]; + pointsRight = true; + if (row < 0) { + std::cerr << "hier ist was schief " << row << " " << aux << " " << std::endl; + row = DBL_MAX; + } + } + aux = dNeigh.key[2]; + if ((aux != -2) && //neighbor is a gridpoint + (cost[aux] != magicnum(UNKNOWN_COST)) && (cost[aux] != magicnum(UNKNOWN_DISTANCE)) && //gridpoint holds a calculated value + (_gridCode[aux] != WALL) && + (cost[aux] < row)) //calculated value promises smaller cost + { + row = cost[aux]; + pointsRight = false; + } + + aux = dNeigh.key[1]; + //hint: trialfield[i].cost = dist2Wall + i; <<< set in parseBuilding after linescan call + if ((aux != -2) && //neighbor is a gridpoint + (cost[aux] != magicnum(UNKNOWN_COST)) && (cost[aux] != magicnum(UNKNOWN_DISTANCE)) && //gridpoint holds a calculated value + (_gridCode[aux] != WALL)) + { + col = cost[aux]; + pointsUp = true; + if (col < 0) { + std::cerr << "hier ist was schief " << col << " " << aux << " " << std::endl; + col = DBL_MAX; + } + } + aux = dNeigh.key[3]; + if ((aux != -2) && //neighbor is a gridpoint + (cost[aux] != magicnum(UNKNOWN_COST)) && (cost[aux] != magicnum(UNKNOWN_DISTANCE)) && //gridpoint holds a calculated value + (_gridCode[aux] != WALL) && + (cost[aux] < col)) //calculated value promises smaller cost + { + col = cost[aux]; + pointsUp = false; + } + if (col == DBL_MAX) { //one sided update with row + cost[key] = onesidedCalc(row, _grid->Gethx()/speed[key]); + //flag[key] = FM_SINGLE; + if (pointsRight) { + dir[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx()); + dir[key]._y = (0.); + } else { + dir[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx()); + dir[key]._y = (0.); + } + dir[key] = dir[key].Normalized(); //@todo: ar.graf: what yields better performance? scale every point here or scale each read value? more points or more calls to any element of dir2Wall + return; + } + + if (row == DBL_MAX) { //one sided update with col + cost[key] = onesidedCalc(col, _grid->Gethy()/speed[key]); + //flag[key] = FM_SINGLE; + if (pointsUp) { + dir[key]._x = (0.); + dir[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy()); + } else { + dir[key]._x = (0.); + dir[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy()); + } + dir[key] = dir[key].Normalized(); + return; + } + + //two sided update + double precheck = twosidedCalc(row, col, _grid->Gethx()/speed[key]); + if (precheck >= 0) { + cost[key] = precheck; + //flag[key] = FM_DOUBLE; + if (pointsUp && pointsRight) { + dir[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx()); + dir[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy()); + } + if (pointsUp && !pointsRight) { + dir[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx()); + dir[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy()); + } + if (!pointsUp && pointsRight) { + dir[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx()); + dir[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy()); + } + if (!pointsUp && !pointsRight) { + dir[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx()); + dir[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy()); + } + } else { + std::cerr << "else in twosided Dist " << std::endl; + } + dir[key] = dir[key].Normalized(); +} + +inline double UnivFFviaFM::onesidedCalc(double xy, double hDivF) { + //if ( (xy+hDivF) > 10000) std::cerr << "error in onesided " << xy << std::endl; + return xy + hDivF; +} + +inline double UnivFFviaFM::twosidedCalc(double x, double y, double hDivF) { //on error return -2 + double determinante = (2*hDivF*hDivF - (x-y)*(x-y)); + if (determinante >= 0) { + return (x + y + sqrt(determinante))/2; + } else { + return (x < y) ? (x + hDivF) : (y + hDivF); + } + std::cerr << "error in two-sided 2!!!!!!!!!!!!!!!!!!!!!!! o_O??" << std::endl; + return -2.; //this line should never execute +} //twosidedCalc + +void UnivFFviaFM::addTarget(const int uid, Line* door) { + + +} +std::vector<int> UnivFFviaFM::getKnownDoorUIDs(){ + return _uids; +} + +void UnivFFviaFM::writeFF(const std::string& filename, std::vector<int> targetID) { + Log->Write("INFO: \tWrite Floorfield to file"); + Log->Write(filename); + std::ofstream file; + + Log->Write("FloorfieldViaFM::writeFF(): writing to file %s: There are %d targets.", filename.c_str(), targetID.size()); + + int numX = (int) ((_grid->GetxMax()-_grid->GetxMin())/_grid->Gethx()); + int numY = (int) ((_grid->GetyMax()-_grid->GetyMin())/_grid->Gethy()); + int numTotal = numX * numY; + //std::cerr << numTotal << " numTotal" << std::endl; + //std::cerr << grid->GetnPoints() << " grid" << std::endl; + file.open(filename); + + file << "# vtk DataFile Version 3.0" << std::endl; + file << "Testdata: Fast Marching: Test: " << std::endl; + file << "ASCII" << std::endl; + file << "DATASET STRUCTURED_POINTS" << std::endl; + file << "DIMENSIONS " << + std::to_string(_grid->GetiMax()) << + " " << + std::to_string(_grid->GetjMax()) << + " 1" << std::endl; + file << "ORIGIN " << _grid->GetxMin() << " " << _grid->GetyMin() << " 0" << std::endl; + file << "SPACING " << std::to_string(_grid->Gethx()) << " " << std::to_string(_grid->Gethy()) << " 1" << std::endl; + file << "POINT_DATA " << std::to_string(numTotal) << std::endl; + file << "SCALARS GCode float 1" << std::endl; + file << "LOOKUP_TABLE default" << std::endl; + for (long int i = 0; i < _grid->GetnPoints(); ++i) { + file << _gridCode[i] << std::endl; + } + + if (_directionFieldWithKey[0]) { + file << "VECTORS Dir2Wall float" << std::endl; + for (long int i = 0; i < _grid->GetnPoints(); ++i) { + file << _directionFieldWithKey[0][i]._x << " " << _directionFieldWithKey[0][i]._y << " 0.0" << std::endl; + } + + file << "SCALARS Dist2Wall float 1" << std::endl; + file << "LOOKUP_TABLE default" << std::endl; + for (long int i = 0; i < _grid->GetnPoints(); ++i) { + file << _costFieldWithKey[0][i] << std::endl; //@todo: change target to all dist2wall + } + } + +// file << "SCALARS SubroomPtr float 1" << std::endl; +// file << "LOOKUP_TABLE default" << std::endl; +// for (long int i = 0; i < _grid->GetnPoints(); ++i) { +// if (_subrooms[i]) { +// file << _subrooms[i]->GetUID() << std::endl; +// } else { +// file << 0.0 << std::endl; +// } +// } + + for (unsigned int iTarget = 0; iTarget < targetID.size(); ++iTarget) { + Log->Write("%s: target number %d: UID %d", filename.c_str(), iTarget, targetID[iTarget]); + if (_directionFieldWithKey.count(targetID[iTarget]) == 0) { + continue; + } + + Point *gradarray = _directionFieldWithKey[targetID[iTarget]]; + if (gradarray == nullptr) { + continue; + } + + std::string name = _building->GetTransOrCrossByUID(targetID[iTarget])->GetCaption() + "-" + std::to_string(targetID[iTarget]); + std::replace(name.begin(), name.end(), ' ', '_'); + file << "VECTORS GradientTarget" << name << " float" << std::endl; + for (int i = 0; i < _grid->GetnPoints(); ++i) { + file << gradarray[i]._x << " " << gradarray[i]._y << " 0.0" << std::endl; + } + + double *costarray = _costFieldWithKey[targetID[iTarget]]; + file << "SCALARS CostTarget" << name << " float 1" << std::endl; + file << "LOOKUP_TABLE default" << std::endl; + for (long int i = 0; i < _grid->GetnPoints(); ++i) { + file << costarray[i] << std::endl; + } + } + file.close(); +} \ No newline at end of file diff --git a/routing/ff_router/UnivFFviaFM.h b/routing/ff_router/UnivFFviaFM.h new file mode 100644 index 0000000000000000000000000000000000000000..4f046d2d4e09d45392e9b30335d1f074fb1a18d8 --- /dev/null +++ b/routing/ff_router/UnivFFviaFM.h @@ -0,0 +1,136 @@ +// +// Created by arne on 5/9/17. +// +/** + * \file UnivFFviaFM.h + * \date May 09, 2017 + * \version N/A (v0.8.x) + * \copyright <2017-2020> Forschungszentrum Jülich GmbH. All rights reserved. + * + * \section License + * This file is part of JuPedSim. + * + * JuPedSim is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * JuPedSim is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with JuPedSim. If not, see <http://www.gnu.org/licenses/>. + * + * \section Description + * Implementation of classes for a reworked floorfield. A floorfield in general + * yields a cost field to a specific goal and a correlated vectorfield for the + * optimal path in terms of the cost value. + * + * Rework focused on a cleaner structure and less inheritance (no diamond) and + * less workarounds. + * + * + **/ +#ifndef JPSCORE_UNIVFFVIAFM_H +#define JPSCORE_UNIVFFVIAFM_H + +#include <string> +#include <vector> +#include <map> +#include <float.h> + +class Room; +class SubRoom; +class Building; +class Configuration; +class Point; +class RectGrid; +class Line; + +enum SPEEDFIELD { //this enum is used as index in _speedFieldSelector + INITIAL_SPEED=0, //homogen speed in walkable area, nealy zero in walls + REDU_WALL_SPEED=1, //reduced wall speed + PED_SPEED=2 //standing agents reduce speed, so that jams will be considered in ff +}; + +enum TARGETMODE { + LINESEGMENT=0, + CENTERPOINT +}; + +enum USERMODE { + DISTANCE_MEASUREMENTS_ONLY, + DISTANCE_AND_DIRECTIONS_USED +}; + +class CompareCost { //this class is used in std::priority_queue in UnivFFviaFM::calcFF +public: + CompareCost(double* costarray) : _costarray(costarray) {} + bool operator() (const int a, const int b) const { + return _costarray[a] > _costarray[b]; + } + +private: + double* _costarray = nullptr; +}; + +class UnivFFviaFM { +public: + UnivFFviaFM(Room* a, Building* b, double c, double d, double e, bool f); + UnivFFviaFM(SubRoom* a, Building* b, double c, double d, double e, bool f); + UnivFFviaFM(Room *a, const Configuration *b, double c, double d, double e, bool f); + UnivFFviaFM(SubRoom *a, const Configuration *b, double c, double d, double e, bool f); + UnivFFviaFM(std::vector<Line>& walls, std::map<int, Line>& doors, std::vector<int> targetUIDs, int mode, double spacing); + UnivFFviaFM() {}; + UnivFFviaFM(UnivFFviaFM&){}; + ~UnivFFviaFM(){}; + + void addTarget(const int uid, Line* door); + std::vector<int> getKnownDoorUIDs(); + + double getCostToDestination(const int destID, const Point& position, int mode) {return 0.;}; + double getCostToDestination(const int destID, const Point& position) {return 0.;}; + RectGrid* getGrid(){return nullptr;}; + virtual void getDirectionToUID(int destID, const long int key, Point& direction, int mode){}; + void getDirectionToUID(int destID, const long int key, Point& direction){}; + void writeFF(const std::string&, std::vector<int> targetID); + + void createRectGrid(std::vector<Line>& walls, std::map<int, Line>& doors, double spacing); + void processGeometry(std::vector<Line>&walls, std::map<int, Line>& doors); + + void drawLinesOnGrid(std::map<int, Line>& doors, int *const grid); + template <typename T> + void drawLinesOnGrid(std::vector<Line>& wallArg, T* const target, const T value); + template <typename T> + void drawLinesOnGrid(Line& line, T* const target, const T value); + + void calcFF(double*, Point*, const double* const); + void calcCost(const long int key, double* cost, Point* dir, const double* const speed); + inline double onesidedCalc(double xy, double hDivF); + inline double twosidedCalc(double x, double y, double hDivF); + +private: + Building* _building = nullptr; + Configuration* _configuration = nullptr; + int _mode = LINESEGMENT; //default + int _user = DISTANCE_AND_DIRECTIONS_USED; //default + RectGrid* _grid = nullptr; + long int _nPoints = 0; + std::vector<double*> _speedFieldSelector; + int* _gridCode = nullptr; + + double _wallAvoidDistance = 0.; + bool _useWallAvoidance = false; + + //the following maps are responsible for dealloc the arrays + std::map<int, double*> _costFieldWithKey; + std::map<int, Point*> _directionFieldWithKey; + std::vector<int> _uids; + std::map<int, Line> _doors; + +}; + + +#endif //JPSCORE_UNIVFFVIAFM_H diff --git a/routing/ff_router/ffRouter.cpp b/routing/ff_router/ffRouter.cpp index 8b3c27138ef38fdb342d60d11e854d778b487cb0..6d6c5f3d645f70c4c04ea23cc75801e2771685bf 100644 --- a/routing/ff_router/ffRouter.cpp +++ b/routing/ff_router/ffRouter.cpp @@ -87,7 +87,7 @@ FFRouter::~FFRouter() delete _globalFF; } //delete localffs - std::map<int, LocalFloorfieldViaFM*>::reverse_iterator delIter; + std::map<int, UnivFFviaFM*>::reverse_iterator delIter; for (delIter = _locffviafm.rbegin(); delIter != _locffviafm.rend(); ++delIter) { @@ -142,8 +142,8 @@ bool FFRouter::Init(Building* building) if (room1) roomAndCroTrVector.emplace_back(std::make_pair(room1->GetID(), pair.second->GetUniqueID())); } } - //make unique // because of the way how this vector is constructed, the entries are already unique. Besides, std::unique would need a sorted vector. - //_allDoorUIDs.erase( std::unique(_allDoorUIDs.begin(),_allDoorUIDs.end()), _allDoorUIDs.end()); + //make unique + _allDoorUIDs.erase( std::unique(_allDoorUIDs.begin(),_allDoorUIDs.end()), _allDoorUIDs.end()); //cleanse maps _distMatrix.clear(); @@ -179,13 +179,14 @@ bool FFRouter::Init(Building* building) auto pairRoomIt = allRooms.begin(); std::advance(pairRoomIt, i); - LocalFloorfieldViaFM *locffptr = nullptr; - Log->Write("INFO: \tusing %s in ffRouter::Init", _useCentrePointDistance ? "CentrePointLocalFFViaFm" : "LocalFloorfieldViaFM"); - if (_useCentrePointDistance) { - locffptr = new CentrePointLocalFFViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false); - } else { - locffptr = new LocalFloorfieldViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false); - } + UnivFFviaFM *locffptr = nullptr; + locffptr = new UnivFFviaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false); +// Log->Write("INFO: \tusing %s in ffRouter::Init", _useCentrePointDistance ? "CentrePointLocalFFViaFm" : "LocalFloorfieldViaFM"); +// if (_useCentrePointDistance) { +// locffptr = new CentrePointLocalFFViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false); +// } else { +// locffptr = new LocalFloorfieldViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false); +// } Log->Write("INFO: \tAdding distances in Room %d to matrix", (*pairRoomIt).first); #pragma omp critical(_locffviafm) @@ -236,7 +237,7 @@ bool FFRouter::Init(Building* building) //question: if (a to c) > (a to b) + (b to c), then FloyedWarshall will favour intermediate goal b // as a precessor to c. This might be very important, if there are edges among lines, that // are not adjacent. - LocalFloorfieldViaFM* locffptr = _locffviafm[rctIt->first]; + UnivFFviaFM* locffptr = _locffviafm[rctIt->first]; double tempDistance = locffptr->getCostToDestination(rctIt->second, _CroTrByUID.at(otherDoor.second)->GetCentre()); @@ -310,7 +311,6 @@ bool FFRouter::Init(Building* building) } // omp parallel FloydWarshall(); - AvoidDoorHopping(); //debug output in file // _locffviafm[4]->writeFF("ffTreppe.vtk", _allDoorUIDs); @@ -346,229 +346,215 @@ bool FFRouter::Init(Building* building) bool FFRouter::ReInit() { - if (_hasSpecificGoals) { - //get global field to manage goals (which are not in a subroom) - if (_globalFF) delete _globalFF; - _globalFF = new FloorfieldViaFM(_building, 0.25, 0.25, 0.0, false, true); - for (auto &itrGoal : _building->GetAllGoals()) { - _globalFF->createMapEntryInLineToGoalID(itrGoal.first); - } - _goalToLineUIDmap = _globalFF->getGoalToLineUIDmap(); //@todo: ar.graf: will this create mem-leak? - _goalToLineUIDmap2 = _globalFF->getGoalToLineUIDmap2(); - _goalToLineUIDmap3 = _globalFF->getGoalToLineUIDmap3(); - } - //get all door UIDs - _allDoorUIDs.clear(); - _TransByUID.clear(); - _ExitsByUID.clear(); - _CroTrByUID.clear(); - auto& allTrans = _building->GetAllTransitions(); - auto& allCross = _building->GetAllCrossings(); - for (auto& pair:allTrans) { - if (pair.second->IsOpen()) { - _allDoorUIDs.emplace_back(pair.second->GetUniqueID()); - _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), (Crossing *) pair.second)); - if (pair.second->IsExit()) { - _ExitsByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second)); - } - } - } - for (auto& pair:allCross) { - if (pair.second->IsOpen()) { - _allDoorUIDs.emplace_back(pair.second->GetUniqueID()); - _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second)); - } - } - //make unique - _allDoorUIDs.erase( std::unique(_allDoorUIDs.begin(),_allDoorUIDs.end()), _allDoorUIDs.end()); - - std::map< std::pair<int, int> , double > tmpdistMatrix; - std::map< std::pair<int, int> , int > tmppathsMatrix; - - tmpdistMatrix.clear(); - tmppathsMatrix.clear(); - tmpdistMatrix = std::move(_distMatrix); - tmppathsMatrix = std::move(_pathsMatrix); - - //cleanse maps - _distMatrix.clear(); - _pathsMatrix.clear(); - - //init, yet no distances, only create map entries - for(auto& id1 : _allDoorUIDs) { - for(auto& id2 : _allDoorUIDs){ - std::pair<int, int> key = std::make_pair(id1, id2); - double value = (id1 == id2)? 0.0 : DBL_MAX; - //distMatrix[i][j] = 0, if i==j - //distMatrix[i][j] = max, else - _distMatrix.insert(std::make_pair( key , value)); - //pathsMatrix[i][j] = i or j ? (follow wiki:path_reconstruction, it should be j) - _pathsMatrix.insert(std::make_pair( key , id2 )); - } - } - - for (auto ptr : _locffviafm) { - delete ptr.second; - } - //prepare all room-floor-fields-objects (one room = one instance) - _locffviafm.clear(); - //type of allRooms: const std::map<int, std::unique_ptr<Room> >& - const std::map<int, std::shared_ptr<Room> >& allRooms = _building->GetAllRooms(); -#pragma omp parallel for - //for (auto &pairRoom : allRooms) { - for (unsigned int i = 0; i < allRooms.size(); ++i) { - -#ifdef DEBUG - std::cerr << "Creating Floorfield for Room: " << pair.first << std::endl; -#endif - auto pairRoomIt = allRooms.begin(); - std::advance(pairRoomIt, i); - LocalFloorfieldViaFM* ptrToNew = nullptr; - double tempDistance = 0.; - if (_useCentrePointDistance) { - ptrToNew = new CentrePointLocalFFViaFM((*pairRoomIt).second.get(), _building, 0.125, 0.125, 0.0, false); - } else { - ptrToNew = new LocalFloorfieldViaFM((*pairRoomIt).second.get(), _building, 0.125, 0.125, 0.0, false); - } - //for (long int i = 0; i < ptrToNew) - //Log->Write("INFO: \tAdding distances in Room %d to matrix", (*pairRoomIt).first); -#pragma omp critical(_locffviafm) - _locffviafm.insert(std::make_pair((*pairRoomIt).first, ptrToNew)); - - if (_mode == quickest) { - ptrToNew->setSpeedThruPeds(_building->GetAllPedestrians().data(), _building->GetAllPedestrians().size(), _mode, 0.5); - } - //SetDistances - vector<int> doorUIDs; - doorUIDs.clear(); - for (int transI: (*pairRoomIt).second->GetAllTransitionsIDs()) { - if ( (_CroTrByUID.count(transI) != 0) && (_CroTrByUID[transI]->IsOpen()) ) { - doorUIDs.emplace_back(transI); - //Log->Write("Door UID: %d", transI); - //Log->Write(_CroTrByUID[transI]->GetDescription()); - } - } - - for (auto &subI : (*pairRoomIt).second->GetAllSubRooms()) { - for (auto &crossI : subI.second->GetAllCrossings()) { //if clause checks so that only new doors get added - if ((crossI->IsOpen()) && - (std::find(doorUIDs.begin(), doorUIDs.end(), crossI->GetUniqueID()) == doorUIDs.end())) { - doorUIDs.emplace_back(crossI->GetUniqueID()); - //Log->Write("Crossing: %d", crossI->GetUniqueID()); - //Log->Write(crossI->GetDescription()); - } - } - } - //loop over upper triangular matrice (i,j) and write to (j,i) as well - std::vector<int>::const_iterator outerPtr; - std::vector<int>::const_iterator innerPtr; - //Log->Write("INFO: \tFound %d Doors (Cross + Trans) in room %d", doorUIDs.size(), (*pairRoomIt).first); - for (outerPtr = doorUIDs.begin(); outerPtr != doorUIDs.end(); ++outerPtr) { - //if the door is closed, then dont calc distances - if (!_CroTrByUID.at(*outerPtr)->IsOpen()) { - continue; - } - // @todo: ar.graf: this following loop and the one directly wrapping this "for (outerPtr = ...)" could be - // moved out of the parallel for loop into a follow up part. There we could parallelize the most inner loop - // to achieve a better load balancing. You can have a look at DirectionStrategy.cpp at the DirectionLocalFloorfield::Init - // and take that scheme. - for (innerPtr = outerPtr; innerPtr != doorUIDs.end(); ++innerPtr) { - //if outerdoor == innerdoor or the inner door is closed - if ((*outerPtr == *innerPtr) || (!_CroTrByUID.at(*innerPtr)->IsOpen())) { - continue; - } - - //if the two doors are not within the same subroom, do not consider (ar.graf) - //should fix problems of oscillation caused by doorgaps in the distancegraph - int innerUID1 = (_CroTrByUID.at(*innerPtr)->GetSubRoom1()) ? _CroTrByUID.at(*innerPtr)->GetSubRoom1()->GetUID() : -1 ; - int innerUID2 = (_CroTrByUID.at(*innerPtr)->GetSubRoom2()) ? _CroTrByUID.at(*innerPtr)->GetSubRoom2()->GetUID() : -2 ; - int outerUID1 = (_CroTrByUID.at(*outerPtr)->GetSubRoom1()) ? _CroTrByUID.at(*outerPtr)->GetSubRoom1()->GetUID() : -3 ; - int outerUID2 = (_CroTrByUID.at(*outerPtr)->GetSubRoom2()) ? _CroTrByUID.at(*outerPtr)->GetSubRoom2()->GetUID() : -4 ; - - if ( - (innerUID1 != outerUID1) && - (innerUID1 != outerUID2) && - (innerUID2 != outerUID1) && - (innerUID2 != outerUID2) ) { - continue; - } - - //The distance is checked by reading the timecost of a wave starting at the line(!) to reach a point(!) - //That will have the following implications: - //distance (a to b) can be different than distance (b ta a) - // for this reason, we calc only (a to b) and set (b to a) to the same value - //distance (line to center) can be larger than (line to endpoint). to get closer to the min-distance - //we did take the minimum of three shots: center, and a point close to each endpoint BUT not anymore - // - //note: we can not assume: (a to c) = (a to b) + (b to c) for the reasons above. - //question: if (a to c) > (a to b) + (b to c), then FloyedWarshall will favour intermediate goal b - // as a precessor to c. This might be very important, if there are edges among lines, that - // are not adjacent. - std::pair<int, int> key_ij = std::make_pair(*outerPtr, *innerPtr); - std::pair<int, int> key_ji = std::make_pair(*innerPtr, *outerPtr); - if ((!(_mode == quickest)) && (tmpdistMatrix.count(key_ij) > 0)) { //only take old value if ffields do not change during sim (quickest do change) - tempDistance = tmpdistMatrix.at(key_ij); - } else { - tempDistance = ptrToNew->getCostToDestination(*outerPtr, - _CroTrByUID.at(*innerPtr)->GetCentre(), _mode); - } - - if (tempDistance < ptrToNew->getGrid()->Gethx()) { - //Log->Write("WARNING:\tDistance of doors %d and %d is too small: %f",*outerPtr, *innerPtr, tempDistance); - //Log->Write("^^^^^^^^\tIf there are scattered subrooms, which are not connected, this is ok."); - continue; - } -// tempDistance = ptrToNew->getCostToDestination(*outerPtr, _CroTrByUID[*innerPtr]->GetCentre()); - _distMatrix.erase(key_ij); - _distMatrix.erase(key_ji); - _distMatrix.insert(std::make_pair(key_ij, tempDistance)); - _distMatrix.insert(std::make_pair(key_ji, tempDistance)); - } - } - } - FloydWarshall(); - - //debug output in file - std::string ffname = "MasterFF" + std::to_string(++_cnt) + ".vtk"; - //_locffviafm[0]->writeFF(ffname, _allDoorUIDs); - - //int roomTest = (*(_locffviafm.begin())).first; - //int transTest = (building->GetRoom(roomTest)->GetAllTransitionsIDs())[0]; -// for (unsigned int i = 0; i < _locffviafm.size(); ++i) { -// auto iter = _locffviafm.begin(); -// std::advance(iter, i); -// int roomNr = iter->first; -// iter->second->writeFF("testFF" + std::to_string(roomNr) + ".vtk", _allDoorUIDs); +// if (_hasSpecificGoals) { +// //get global field to manage goals (which are not in a subroom) +// if (_globalFF) delete _globalFF; +// _globalFF = new FloorfieldViaFM(_building, 0.25, 0.25, 0.0, false, true); +// for (auto &itrGoal : _building->GetAllGoals()) { +// _globalFF->createMapEntryInLineToGoalID(itrGoal.first); +// } +// _goalToLineUIDmap = _globalFF->getGoalToLineUIDmap(); //@todo: ar.graf: will this create mem-leak? +// _goalToLineUIDmap2 = _globalFF->getGoalToLineUIDmap2(); +// _goalToLineUIDmap3 = _globalFF->getGoalToLineUIDmap3(); +// } +// //get all door UIDs +// _allDoorUIDs.clear(); +// _TransByUID.clear(); +// _ExitsByUID.clear(); +// _CroTrByUID.clear(); +// auto& allTrans = _building->GetAllTransitions(); +// auto& allCross = _building->GetAllCrossings(); +// for (auto& pair:allTrans) { +// if (pair.second->IsOpen()) { +// _allDoorUIDs.emplace_back(pair.second->GetUniqueID()); +// _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), (Crossing *) pair.second)); +// if (pair.second->IsExit()) { +// _ExitsByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second)); +// } +// } // } +// for (auto& pair:allCross) { +// if (pair.second->IsOpen()) { +// _allDoorUIDs.emplace_back(pair.second->GetUniqueID()); +// _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second)); +// } +// } +// //make unique +// _allDoorUIDs.erase( std::unique(_allDoorUIDs.begin(),_allDoorUIDs.end()), _allDoorUIDs.end()); // - std::ofstream matrixfile; - matrixfile.open("Matrix.txt"); - - for (auto mapItem : _distMatrix) { - matrixfile << mapItem.first.first << " to " << mapItem.first.second << " : " << mapItem.second << "\t via \t" << _pathsMatrix[mapItem.first]; - matrixfile << "\t" << _CroTrByUID.at(mapItem.first.first)->GetID() << " to " << _CroTrByUID.at(mapItem.first.second)->GetID() << "\t via \t"; - matrixfile << _CroTrByUID.at(_pathsMatrix[mapItem.first])->GetID() << std::endl; - } - matrixfile.close(); - Log->Write("INFO: \tFF Router Init done."); - return true; +// std::map< std::pair<int, int> , double > tmpdistMatrix; +// std::map< std::pair<int, int> , int > tmppathsMatrix; +// +// tmpdistMatrix.clear(); +// tmppathsMatrix.clear(); +// tmpdistMatrix = std::move(_distMatrix); +// tmppathsMatrix = std::move(_pathsMatrix); +// +// //cleanse maps +// _distMatrix.clear(); +// _pathsMatrix.clear(); +// +// //init, yet no distances, only create map entries +// for(auto& id1 : _allDoorUIDs) { +// for(auto& id2 : _allDoorUIDs){ +// std::pair<int, int> key = std::make_pair(id1, id2); +// double value = (id1 == id2)? 0.0 : DBL_MAX; +// //distMatrix[i][j] = 0, if i==j +// //distMatrix[i][j] = max, else +// _distMatrix.insert(std::make_pair( key , value)); +// //pathsMatrix[i][j] = i or j ? (follow wiki:path_reconstruction, it should be j) +// _pathsMatrix.insert(std::make_pair( key , id2 )); +// } +// } +// +// for (auto ptr : _locffviafm) { +// delete ptr.second; +// } +// //prepare all room-floor-fields-objects (one room = one instance) +// _locffviafm.clear(); +// //type of allRooms: const std::map<int, std::unique_ptr<Room> >& +// const std::map<int, std::shared_ptr<Room> >& allRooms = _building->GetAllRooms(); +//#pragma omp parallel for +// //for (auto &pairRoom : allRooms) { +// for (unsigned int i = 0; i < allRooms.size(); ++i) { +// +//#ifdef DEBUG +// std::cerr << "Creating Floorfield for Room: " << pair.first << std::endl; +//#endif +// auto pairRoomIt = allRooms.begin(); +// std::advance(pairRoomIt, i); +// LocalFloorfieldViaFM* ptrToNew = nullptr; +// double tempDistance = 0.; +// if (_useCentrePointDistance) { +// ptrToNew = new CentrePointLocalFFViaFM((*pairRoomIt).second.get(), _building, 0.125, 0.125, 0.0, false); +// } else { +// ptrToNew = new LocalFloorfieldViaFM((*pairRoomIt).second.get(), _building, 0.125, 0.125, 0.0, false); +// } +// //for (long int i = 0; i < ptrToNew) +// //Log->Write("INFO: \tAdding distances in Room %d to matrix", (*pairRoomIt).first); +//#pragma omp critical(_locffviafm) +// _locffviafm.insert(std::make_pair((*pairRoomIt).first, ptrToNew)); +// +// if (_mode == quickest) { +// ptrToNew->setSpeedThruPeds(_building->GetAllPedestrians().data(), _building->GetAllPedestrians().size(), _mode, 0.5); +// } +// //SetDistances +// vector<int> doorUIDs; +// doorUIDs.clear(); +// for (int transI: (*pairRoomIt).second->GetAllTransitionsIDs()) { +// if ( (_CroTrByUID.count(transI) != 0) && (_CroTrByUID[transI]->IsOpen()) ) { +// doorUIDs.emplace_back(transI); +// //Log->Write("Door UID: %d", transI); +// //Log->Write(_CroTrByUID[transI]->GetDescription()); +// } +// } +// +// for (auto &subI : (*pairRoomIt).second->GetAllSubRooms()) { +// for (auto &crossI : subI.second->GetAllCrossings()) { //if clause checks so that only new doors get added +// if ((crossI->IsOpen()) && +// (std::find(doorUIDs.begin(), doorUIDs.end(), crossI->GetUniqueID()) == doorUIDs.end())) { +// doorUIDs.emplace_back(crossI->GetUniqueID()); +// //Log->Write("Crossing: %d", crossI->GetUniqueID()); +// //Log->Write(crossI->GetDescription()); +// } +// } +// } +// //loop over upper triangular matrice (i,j) and write to (j,i) as well +// std::vector<int>::const_iterator outerPtr; +// std::vector<int>::const_iterator innerPtr; +// //Log->Write("INFO: \tFound %d Doors (Cross + Trans) in room %d", doorUIDs.size(), (*pairRoomIt).first); +// for (outerPtr = doorUIDs.begin(); outerPtr != doorUIDs.end(); ++outerPtr) { +// //if the door is closed, then dont calc distances +// if (!_CroTrByUID.at(*outerPtr)->IsOpen()) { +// continue; +// } +// // @todo: ar.graf: this following loop and the one directly wrapping this "for (outerPtr = ...)" could be +// // moved out of the parallel for loop into a follow up part. There we could parallelize the most inner loop +// // to achieve a better load balancing. You can have a look at DirectionStrategy.cpp at the DirectionLocalFloorfield::Init +// // and take that scheme. +// for (innerPtr = outerPtr; innerPtr != doorUIDs.end(); ++innerPtr) { +// //if outerdoor == innerdoor or the inner door is closed +// if ((*outerPtr == *innerPtr) || (!_CroTrByUID.at(*innerPtr)->IsOpen())) { +// continue; +// } +// +// //if the two doors are not within the same subroom, do not consider (ar.graf) +// //should fix problems of oscillation caused by doorgaps in the distancegraph +// int innerUID1 = (_CroTrByUID.at(*innerPtr)->GetSubRoom1()) ? _CroTrByUID.at(*innerPtr)->GetSubRoom1()->GetUID() : -1 ; +// int innerUID2 = (_CroTrByUID.at(*innerPtr)->GetSubRoom2()) ? _CroTrByUID.at(*innerPtr)->GetSubRoom2()->GetUID() : -2 ; +// int outerUID1 = (_CroTrByUID.at(*outerPtr)->GetSubRoom1()) ? _CroTrByUID.at(*outerPtr)->GetSubRoom1()->GetUID() : -3 ; +// int outerUID2 = (_CroTrByUID.at(*outerPtr)->GetSubRoom2()) ? _CroTrByUID.at(*outerPtr)->GetSubRoom2()->GetUID() : -4 ; +// +// if ( +// (innerUID1 != outerUID1) && +// (innerUID1 != outerUID2) && +// (innerUID2 != outerUID1) && +// (innerUID2 != outerUID2) ) { +// continue; +// } +// +// //The distance is checked by reading the timecost of a wave starting at the line(!) to reach a point(!) +// //That will have the following implications: +// //distance (a to b) can be different than distance (b ta a) +// // for this reason, we calc only (a to b) and set (b to a) to the same value +// //distance (line to center) can be larger than (line to endpoint). to get closer to the min-distance +// //we did take the minimum of three shots: center, and a point close to each endpoint BUT not anymore +// // +// //note: we can not assume: (a to c) = (a to b) + (b to c) for the reasons above. +// //question: if (a to c) > (a to b) + (b to c), then FloyedWarshall will favour intermediate goal b +// // as a precessor to c. This might be very important, if there are edges among lines, that +// // are not adjacent. +// std::pair<int, int> key_ij = std::make_pair(*outerPtr, *innerPtr); +// std::pair<int, int> key_ji = std::make_pair(*innerPtr, *outerPtr); +// if ((!(_mode == quickest)) && (tmpdistMatrix.count(key_ij) > 0)) { //only take old value if ffields do not change during sim (quickest do change) +// tempDistance = tmpdistMatrix.at(key_ij); +// } else { +// tempDistance = ptrToNew->getCostToDestination(*outerPtr, +// _CroTrByUID.at(*innerPtr)->GetCentre(), _mode); +// } +// +// if (tempDistance < ptrToNew->getGrid()->Gethx()) { +// //Log->Write("WARNING:\tDistance of doors %d and %d is too small: %f",*outerPtr, *innerPtr, tempDistance); +// //Log->Write("^^^^^^^^\tIf there are scattered subrooms, which are not connected, this is ok."); +// continue; +// } +//// tempDistance = ptrToNew->getCostToDestination(*outerPtr, _CroTrByUID[*innerPtr]->GetCentre()); +// _distMatrix.erase(key_ij); +// _distMatrix.erase(key_ji); +// _distMatrix.insert(std::make_pair(key_ij, tempDistance)); +// _distMatrix.insert(std::make_pair(key_ji, tempDistance)); +// } +// } +// } +// FloydWarshall(); +// +// //debug output in file +// std::string ffname = "MasterFF" + std::to_string(++_cnt) + ".vtk"; +// //_locffviafm[0]->writeFF(ffname, _allDoorUIDs); +// +// //int roomTest = (*(_locffviafm.begin())).first; +// //int transTest = (building->GetRoom(roomTest)->GetAllTransitionsIDs())[0]; +//// for (unsigned int i = 0; i < _locffviafm.size(); ++i) { +//// auto iter = _locffviafm.begin(); +//// std::advance(iter, i); +//// int roomNr = iter->first; +//// iter->second->writeFF("testFF" + std::to_string(roomNr) + ".vtk", _allDoorUIDs); +//// } +//// +// std::ofstream matrixfile; +// matrixfile.open("Matrix.txt"); +// +// for (auto mapItem : _distMatrix) { +// matrixfile << mapItem.first.first << " to " << mapItem.first.second << " : " << mapItem.second << "\t via \t" << _pathsMatrix[mapItem.first]; +// matrixfile << "\t" << _CroTrByUID.at(mapItem.first.first)->GetID() << " to " << _CroTrByUID.at(mapItem.first.second)->GetID() << "\t via \t"; +// matrixfile << _CroTrByUID.at(_pathsMatrix[mapItem.first])->GetID() << std::endl; +// } +// matrixfile.close(); +// Log->Write("INFO: \tFF Router Init done."); +// return true; } -std::set<std::pair<SubRoom*, int>> FFRouter::GetPresumableExitRoute(Pedestrian* p) { - std::set<std::pair<SubRoom*, int>> subroomsDoorsSet; - subroomsDoorsSet.clear(); - int finalDoor = _finalDoors.at(p->GetID()); - SubRoom* subroom = _building->GetRoom(p->GetRoomID())->GetSubRoom(p->GetSubRoomID()); - int doorUID = p->GetNextDestination(); - - while (doorUID != finalDoor) { - subroomsDoorsSet.insert(std::make_pair(subroom, doorUID)); - subroom = _CroTrByUID[doorUID]->GetOtherSubRoom(subroom->GetRoomID(), subroom->GetSubRoomID()); - doorUID = _pathsMatrix.at(std::make_pair(doorUID, finalDoor)); - } - subroomsDoorsSet.insert(std::make_pair(subroom, doorUID)); - return subroomsDoorsSet; -} + int FFRouter::FindExit(Pedestrian* p) { @@ -782,19 +768,6 @@ int FFRouter::FindExit(Pedestrian* p) return bestDoor; //-1 if no way was found, doorUID of best, if path found } -void FFRouter::Reset() -{ - for(auto& pair : _distMatrix) { - //distMatrix[i][j] = 0, if i==j - //distMatrix[i][j] = max, else - pair.second = (pair.second == 0.0) ? 0.0 : DBL_MAX; - } - for(auto& pair : _pathsMatrix) { - //pathsMatrix[i][j] = i - pair.second = pair.first.first; - } -} - void FFRouter::FloydWarshall() { int totalnum = _allDoorUIDs.size(); diff --git a/routing/ff_router/ffRouter.h b/routing/ff_router/ffRouter.h index c7878eb4c9b3b09ff4d859a4b77ee10bbf1f40bc..b0b866460286e89819ada94c38aa2f168dba07dc 100644 --- a/routing/ff_router/ffRouter.h +++ b/routing/ff_router/ffRouter.h @@ -64,6 +64,7 @@ #include "../../general/Macros.h" #include "../../geometry/Building.h" #include "LocalFloorfieldViaFM.h" +#include "UnivFFviaFM.h" class Building; class Pedestrian; @@ -181,13 +182,6 @@ public: */ void SetMode(std::string s); - /*! - * \brief Get the route the pedestrian p wants to take (according to _pathsMatrix) - * @param p The pedestrian in question - * @return A set containing (subroom*, doorUID) pairs. The floorfields needed are inside the subroom, originating from the door. - */ - std::set<std::pair<SubRoom*, int>> GetPresumableExitRoute(Pedestrian* p); - private: protected: @@ -198,7 +192,7 @@ protected: std::vector<int> _allDoorUIDs; std::vector<int> _localShortestSafedPeds; const Building* _building; - std::map<int, LocalFloorfieldViaFM*> _locffviafm; // the actual type might be CentrePointLocalFFViaFM + std::map<int, UnivFFviaFM*> _locffviafm; // the actual type might be CentrePointLocalFFViaFM FloorfieldViaFM* _globalFF; std::map<int, Transition*> _TransByUID; std::map<int, Transition*> _ExitsByUID;