From 3d913f772c309291bbf61b7949dd55376e1c5807 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20Schr=C3=B6dter?= <t.schroedter@fz-juelich.de>
Date: Wed, 30 Jan 2019 09:11:18 +0100
Subject: [PATCH] FF now navigates ped to subroom, which contains a waiting
 area

---
 geometry/Building.cpp                         |    1 +
 .../ff_router_trips/FloorfieldViaFMTrips.cpp  | 1821 ++++++++++++++++
 .../ff_router_trips/FloorfieldViaFMTrips.h    |  226 ++
 routing/ff_router_trips/UnivFFviaFMTrips.cpp  | 1916 +++++++++++++++++
 routing/ff_router_trips/UnivFFviaFMTrips.h    |  165 ++
 routing/ff_router_trips/ffRouterTrips.cpp     |   38 +-
 routing/trips_router/TripsRouter.cpp          |    9 +-
 7 files changed, 4165 insertions(+), 11 deletions(-)
 create mode 100644 routing/ff_router_trips/FloorfieldViaFMTrips.cpp
 create mode 100644 routing/ff_router_trips/FloorfieldViaFMTrips.h
 create mode 100644 routing/ff_router_trips/UnivFFviaFMTrips.cpp
 create mode 100644 routing/ff_router_trips/UnivFFviaFMTrips.h

diff --git a/geometry/Building.cpp b/geometry/Building.cpp
index 5a975e94..3d819302 100644
--- a/geometry/Building.cpp
+++ b/geometry/Building.cpp
@@ -363,6 +363,7 @@ bool Building::InitGeometry()
           if (s2) s2->AddNeighbor(s1);
      }
 
+
      Log->Write("INFO: \tInit Geometry successful!!!\n");
 
      return true;
diff --git a/routing/ff_router_trips/FloorfieldViaFMTrips.cpp b/routing/ff_router_trips/FloorfieldViaFMTrips.cpp
new file mode 100644
index 00000000..2ab078e1
--- /dev/null
+++ b/routing/ff_router_trips/FloorfieldViaFMTrips.cpp
@@ -0,0 +1,1821 @@
+/**
+ * \file        FloorfieldViaFMTrips.cpp
+ * \date        Mar 05, 2015
+ * \version     N/A (v0.6)
+ * \copyright   <2009-2014> 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 ...
+ *
+ *
+ **/
+#define TESTING
+#define GEO_UP_SCALE 1
+#include "FloorfieldViaFMTrips.h"
+
+#ifdef _OPENMP
+#else
+#define omp_get_thread_num() 0
+#define omp_get_max_threads()  1
+#endif
+
+FloorfieldViaFMTrips::FloorfieldViaFMTrips()
+{
+    //ctor (very ugly)
+    //std::cerr << "The defaultconsturctor FloorfieldViaFMTrips should not be called!" << std::endl;
+}
+
+FloorfieldViaFMTrips::~FloorfieldViaFMTrips()
+{
+    //dtor
+    delete _grid;
+    if (_gcode) delete[] _gcode;
+    if (_subrooms) delete[] _subrooms;
+    if (_dist2Wall) delete[] _dist2Wall;
+    if (_speedInitial) delete[] _speedInitial;
+    if (_modifiedspeed) delete[] _modifiedspeed;
+    if (_densityspeed) delete[] _densityspeed;
+    //if (cost) delete[] cost;
+    //if (neggrad) delete[] neggrad;
+    if (_dirToWall) delete[] _dirToWall;
+    //if (trialfield) delete[] trialfield;
+    for ( const auto& goalid : _goalcostmap) {
+        if (goalid.second) delete[] goalid.second;
+    }
+    for ( const auto& id : _costmap) {
+        //if (id.first == -1) continue;
+        if (id.second) delete[] id.second;
+        if (_neggradmap.at(id.first)) delete[] _neggradmap.at(id.first);
+        //map will be deleted by itself
+    }
+
+}
+
+FloorfieldViaFMTrips::FloorfieldViaFMTrips(const Building* const buildingArg, const double hxArg, const double hyArg,
+                                 const double wallAvoidDistance, const bool useDistancefield, const bool onlyRoomsWithExits) {
+     Log->Write("FloorfieldViaFMTrips::FloorfieldViaFMTrips(...)");
+    //ctor
+    //_threshold = -1; //negative value means: ignore threshold
+    _threshold = wallAvoidDistance;
+    _building = buildingArg;
+    _useDistanceToWall = useDistancefield;
+
+    if (hxArg != hyArg) {
+        //std::cerr << "ERROR: hx != hy <=========";
+        Log->Write("WARNING: \tFloor field: stepsize hx differs from hy! Taking hx = %d for both.", hxArg);
+    }
+    //parse building and create list of walls/obstacles (find xmin xmax, ymin, ymax, and add border?)
+    //Log->Write("INFO: \tStart Parsing: Building");
+    if (onlyRoomsWithExits) {
+        parseBuildingForExits(buildingArg, hxArg, hyArg);
+    } else {
+        parseBuilding(buildingArg, hxArg, hyArg);
+    }
+    //Log->Write("INFO: \tFinished Parsing: Building");
+    //testoutput("AALineScan.vtk", "AALineScan.txt", dist2Wall);
+
+    prepareForDistanceFieldCalculation(onlyRoomsWithExits);
+    //Log->Write("INFO: \tGrid initialized: Walls");
+
+    calculateDistanceField(-1.); //negative threshold is ignored, so all distances get calculated. this is important since distances is used for slowdown/redirect
+    //Log->Write("INFO: \tGrid initialized: Walldistances");
+
+    setSpeed(useDistancefield); //use distance2Wall
+    //Log->Write("INFO: \tGrid initialized: Speed");
+
+    calculateFloorfield(_exitsFromScope, _cost, _neggrad);
+    //writing FF-file disabled, we will not revive it ( @todo: argraf )
+}
+
+FloorfieldViaFMTrips::FloorfieldViaFMTrips(const FloorfieldViaFMTrips &other) :
+_building(other._building)
+
+{
+    _grid = other.getGrid();
+    long int otherNumOfPoints = _grid->GetnPoints();
+
+    _wall.clear();
+    _wall.reserve(other._wall.size());
+    std::copy(other._wall.begin(), other._wall.end(), _wall.begin());
+
+    _exitsFromScope.clear();
+    _exitsFromScope.reserve(other._exitsFromScope.size());
+    std::copy(other._exitsFromScope.begin(), other._exitsFromScope.end(), _exitsFromScope.begin());
+
+    _numOfExits = other._numOfExits;
+
+    _gcode = new int[otherNumOfPoints];
+    std::copy(other._gcode, other._gcode + otherNumOfPoints, _gcode);
+
+    _dist2Wall = new double[otherNumOfPoints];
+    std::copy(other._dist2Wall, other._dist2Wall + otherNumOfPoints, _dist2Wall);
+
+    _speedInitial = new double[otherNumOfPoints];
+    std::copy(other._speedInitial, other._speedInitial + otherNumOfPoints, _speedInitial);
+
+    _modifiedspeed = new double[otherNumOfPoints];
+    std::copy(other._modifiedspeed, other._modifiedspeed + otherNumOfPoints, _modifiedspeed);
+
+    _densityspeed = new double[otherNumOfPoints];
+    std::copy(other._densityspeed, other._densityspeed + otherNumOfPoints, _densityspeed);
+
+    _cost = new double[otherNumOfPoints];
+    std::copy(other._cost, other._cost + otherNumOfPoints, _cost);
+
+    _neggrad = new Point[otherNumOfPoints]; //gradients
+    std::copy(other._neggrad, other._neggrad + otherNumOfPoints, _neggrad);
+
+    _dirToWall = new Point[otherNumOfPoints];
+    std::copy(other._dirToWall, other._dirToWall + otherNumOfPoints, _dirToWall);
+
+    _threshold = other._threshold;
+    _useDistanceToWall = other._useDistanceToWall;
+}
+
+FloorfieldViaFMTrips::FloorfieldViaFMTrips(const std::string& filename) {
+
+
+    Log->Write("ERROR: \tReading  FF from file not supported!!");
+    Log->Write(filename);
+
+}
+
+//void FloorfieldViaFMTrips::getDirectionAt(const Point& position, Point& direction){
+//    long int key = grid->getKeyAtPoint(position);
+//    direction._x = (neggrad[key]._x);
+//    direction._y = (neggrad[key]._y);
+//}
+
+void FloorfieldViaFMTrips::getDirectionToDestination(Pedestrian* ped, Point& direction){
+    const Point& position = ped->GetPos();
+    int destID = ped->GetExitIndex();
+    long int key = _grid->getKeyAtPoint(position);
+    getDirectionToUID(destID, key, direction);
+    if (direction._x == DBL_MAX && direction._y == DBL_MAX) {
+        // This can be interpreted differently by the different operational models.
+        // The inaccuracy introduced by this is negligible. --f.mack
+         direction._x = 0;
+         direction._y = 0;
+    }
+}
+
+void FloorfieldViaFMTrips::getDirectionToUID(int destID, const long int key, Point &direction) {
+    getDirectionToUID(destID, key, direction, global_shortest);
+}
+
+void FloorfieldViaFMTrips::getDirectionToUID(int destID, const long int key, Point& direction, int mode) {
+    //what if goal == -1, meaning closest exit... is GetExitIndex then -1? NO... ExitIndex is UID, given by router
+    //if (ped->GetFinalDestination() == -1) /*go to closest exit*/ destID != -1;
+
+    if ((key < 0) || (key >= _grid->GetnPoints())) { // @todo: ar.graf: this check in a #ifdef-block?
+        Log->Write("ERROR: \t Floorfield tried to access a key out of grid!");
+        direction._x = 0.;
+        direction._y = 0.;
+        return;
+    }
+    Point* localneggradptr = nullptr;
+    double* localcostptr = nullptr;
+    {
+        if (_neggradmap.count(destID) == 0) {
+            //Log->Write("FF for destID %d does not exist (key is %d)", destID, key);
+            //check, if distID is in this grid
+            Hline* destLine = _building->GetTransOrCrossByUID(destID);
+            Point A = destLine->GetPoint1();
+            Point B = destLine->GetPoint2();
+            if (!(_grid->includesPoint(A)) || !(_grid->includesPoint(B))) {
+                Log->Write("ERROR: \t Destination ID %d is not in grid!", destID);
+                direction._x = direction._y = 0.;
+                //return;
+            }
+        }
+        localneggradptr = (_neggradmap.count(destID) == 0) ? nullptr : _neggradmap.at(destID);
+        localcostptr = (_costmap.count(destID) == 0) ? nullptr : _costmap.at(destID);
+        if (localneggradptr == nullptr) {
+            bool isBeingCalculated;
+#pragma omp critical(floorfieldsBeingCalculated)
+            {
+                if (!(isBeingCalculated = _floorfieldsBeingCalculated.count(destID) > 0)) {
+                    _floorfieldsBeingCalculated.insert(destID);
+                }
+            }
+            if (isBeingCalculated) {
+                // we do not want to wait until the other calculation has finished, so we return immediately
+                // the values are corrected in getDirectionToDestination(), and getCostToDestination doesn't care about the direction
+                direction._x = DBL_MAX;
+                direction._y = DBL_MAX;
+                return;
+            }
+
+            //create floorfield (remove mapentry with nullptr, allocate memory, add mapentry, create ff)
+            localcostptr =    new double[_grid->GetnPoints()];
+            localneggradptr = new Point[_grid->GetnPoints()];
+#pragma omp critical(neggradmap)
+            _neggradmap.erase(destID);
+#pragma omp critical(neggradmap)
+            _neggradmap.emplace(destID, localneggradptr);
+#pragma omp critical(costmap)
+            _costmap.erase(destID);
+#pragma omp critical(costmap)
+            _costmap.emplace(destID, localcostptr);
+
+                //create ff (prepare Trial-mechanic, then calc)
+//                for (long int i = 0; i < grid->GetnPoints(); ++i) {
+//                    //set TrialPTripstr to fieldelements
+//                    trialfield[i].cost = localcostptr + i;
+//                    trialfield[i].neggrad = localneggradptr + i;
+//                    trialfield[i].father = nullptr;
+//                    trialfield[i].child = nullptr;
+//                }
+//                clearAndPrepareForFloorfieldReCalc(localcostptr);
+            std::vector<Line> localline = {Line((Line) *(_building->GetTransOrCrossByUID(destID)))};
+//                setNewGoalAfterTheClear(localcostptr, localline);
+                //Log->Write("Starting FF for UID %d (ID %d)", destID, dynamic_cast<Crossing*>(building->GetTransOrCrossByUID(destID))->GetID());
+                //std::cerr << "\rW\tO\tR\tK\tI\tN\tG";
+            if (mode == quickest) {
+                calculateFloorfield(localline, localcostptr, localneggradptr, _densityspeed);
+            } else {
+                calculateFloorfield(localline, localcostptr, localneggradptr, _modifiedspeed);
+            }
+#pragma omp critical(floorfieldsBeingCalculated)
+            {
+                if (_floorfieldsBeingCalculated.count(destID) != 1) {
+                    Log->Write("ERROR: FloorfieldViaFMTrips::getDirectionToUID: key %d was calculating FF for destID %d, but it was removed from floorfieldsBeingCalculated meanwhile", key, destID);
+                }
+                _floorfieldsBeingCalculated.erase(destID);
+            }
+                //Log->Write("Ending   FF for UID %d", destID);
+                //std::cerr << "\r W\t O\t R\t K\t I\t N\t G";
+        }
+    }
+    direction._x = (localneggradptr[key]._x);
+    direction._y = (localneggradptr[key]._y);
+}
+
+void FloorfieldViaFMTrips::createMapEntryInLineToGoalID(const int goalID, bool isInside)
+{
+    Point* localneggradptr;
+    double* localcostptr;
+    if (goalID < 0) {
+        Log->Write("WARNING: \t goalID was negative in FloorfieldViaFMTrips::createMapEntryInLineToGoalID");
+        return;
+    }
+    if (!_building->GetFinalGoal(goalID)) {
+        Log->Write("WARNING: \t goalID was unknown in FloorfieldViaFMTrips::createMapEntryInLineToGoalID");
+        return;
+    }
+
+    // The scope of this critical section can probably be reduced (maybe use a GoalsBeingCalculated similar to FloorfieldViaFMTrips::getDirectionToUID)
+#pragma omp critical(FloorfieldViaFMTrips_maps)
+    {
+        if (_goalcostmap.count(goalID) == 0) { //no entry for goalcostmap, so we need to calc FF
+            _goalcostmap.emplace(goalID, nullptr);
+            _goalneggradmap.emplace(goalID, nullptr);
+            _goalToLineUIDmap.emplace(goalID, -1);
+            _goalToLineUIDmap2.emplace(goalID, -1);
+            _goalToLineUIDmap3.emplace(goalID, -1);
+        }
+        localneggradptr = _goalneggradmap.at(goalID);
+        localcostptr = _goalcostmap.at(goalID);
+        if (localneggradptr == nullptr) {
+            //create floorfield (remove mapentry with nullptr, allocate memory, add mapentry, create ff)
+            localcostptr = new double[_grid->GetnPoints()];
+            localneggradptr = new Point[_grid->GetnPoints()];
+            _goalneggradmap.erase(goalID);
+            //goalneggradmap.emplace(goalID, localneggradptr);
+            _goalcostmap.erase(goalID);
+            //goalcostmap.emplace(goalID, localcostptr);
+            //create ff (prepare Trial-mechanic, then calc)
+//            for (long int i = 0; i < grid->GetnPoints(); ++i) {
+//                //set TrialPTripstr to fieldelements
+//                trialfield[i].cost = localcostptr + i;
+//                trialfield[i].neggrad = localneggradptr + i;
+//                trialfield[i].father = nullptr;
+//                trialfield[i].child = nullptr;
+//            }
+//            clearAndPrepareForFloorfieldReCalc(localcostptr);
+
+            //get all lines/walls of goalID
+            vector<Line> localline;
+            const std::map<int, Goal*>& allgoals = _building->GetAllGoals();
+            vector<Wall> localwalls = allgoals.at(goalID)->GetAllWalls();
+
+            double xMin = _grid->GetxMin();
+            double xMax = _grid->GetxMax();
+
+            double yMin = _grid->GetyMin();
+            double yMax = _grid->GetyMax();
+
+            for (const auto& iwall:localwalls) {
+                const Point& a = iwall.GetPoint1();
+                const Point& b = iwall.GetPoint2();
+                if (
+                          (a._x>=xMin) && (a._x<=xMax)
+                                    && (a._y>=yMin) && (a._y<=yMax)
+                                    && (b._x>=xMin) && (b._x<=xMax)
+                                    && (b._y>=yMin) && (b._y<=yMax)
+                          ) {
+                    localline.emplace_back(Line((Line) iwall));
+                    std::cout << "(Line) iwall : " << ((Line) iwall).toString() << std::endl;
+
+                }
+                else {
+                    std::cerr << "GOAL " << goalID << " includes point out of grid!" << std::endl;
+                    std::cerr << "Point: " << a._x << ", " << a._y << std::endl;
+                    std::cerr << "Point: " << b._x << ", " << b._y << std::endl;
+                }
+            }
+
+//            setNewGoalAfterTheClear(localcostptr, localline);
+
+            //performance-measurement:
+            //auto start = std::chrono::steady_clock::now();
+            calculateFloorfield(localline, localcostptr, localneggradptr);
+
+            //performance-measurement:
+            //auto end = std::chrono::steady_clock::now();
+            //auto diff = end - start;
+            //std::cerr << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << std::endl;
+            //std::cerr << "new GOALfield " << goalID << "   :    " << localline[0].GetPoint1().GetX() << " " << localline[0].GetPoint1().GetY() << " " << localline[0].GetPoint2().GetX() << " " << localline[0].GetPoint2().GetY() << std::endl;
+            //Log->Write("new GOALfield " + std::to_string(goalID) + "  :   " + std::to_string(localline[0].GetPoint1().GetX()));
+            //Log->Write("new GOALfield " + std::to_string(goalID) + "  :   " + std::to_string( std::chrono::duration_cast<std::chrono::seconds>(end - start).count() ) + " " + std::to_string(localline.size()) );
+            //find closest door and add to cheatmap "goalToLineUID" map
+
+            const std::map<int, Transition*>& transitions = _building->GetAllTransitions();
+            const std::map<int, Crossing*>& crossings = _building->GetAllCrossings();
+
+            int UID_of_MIN = -1;
+            int UID_of_MIN2 = -1;
+            int UID_of_MIN3 = -1;
+            double cost_of_MIN = DBL_MAX;
+            double cost_of_MIN2 = DBL_MAX;
+            double cost_of_MIN3 = DBL_MAX;
+            long int dummykey;
+
+            if (isInside) {
+                for (const auto& loccross : crossings) {
+                    std::cout << "Check crossing ID " << loccross.second->GetID() << " " << loccross.second->toString() << std::endl;
+                    if ( !loccross.second->IsOpen()) {
+                        continue;
+                    }
+                    dummykey = _grid->getKeyAtPoint(loccross.second->GetCentre());
+                    if ((cost_of_MIN>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = UID_of_MIN2;
+                        cost_of_MIN3 = cost_of_MIN2;
+
+                        UID_of_MIN2 = UID_of_MIN;
+                        cost_of_MIN2 = cost_of_MIN;
+
+                        UID_of_MIN = loccross.second->GetUniqueID();
+                        cost_of_MIN = localcostptr[dummykey];
+                        std::cout << "Closer Line found: " << UID_of_MIN << std::endl;
+                        continue;
+                    }
+                    if ((cost_of_MIN2>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = UID_of_MIN2;
+                        cost_of_MIN3 = cost_of_MIN2;
+
+                        UID_of_MIN2 = loccross.second->GetUniqueID();
+                        cost_of_MIN2 = localcostptr[dummykey];
+                        continue;
+                    }
+                    if ((cost_of_MIN3>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = loccross.second->GetUniqueID();
+                        cost_of_MIN3 = localcostptr[dummykey];
+                        continue;
+                    }
+                }
+            }
+            else {
+                for (const auto& loctrans : transitions) {
+                    if (!loctrans.second->IsExit() || !loctrans.second->IsOpen()) {
+                        continue;
+                    }
+                    dummykey = _grid->getKeyAtPoint(loctrans.second->GetCentre());
+                    if ((cost_of_MIN>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = UID_of_MIN2;
+                        cost_of_MIN3 = cost_of_MIN2;
+
+                        UID_of_MIN2 = UID_of_MIN;
+                        cost_of_MIN2 = cost_of_MIN;
+
+                        UID_of_MIN = loctrans.second->GetUniqueID();
+                        cost_of_MIN = localcostptr[dummykey];
+                        //std::cerr << std::endl << "Closer Line found: " << UID_of_MIN ;
+                        continue;
+                    }
+                    if ((cost_of_MIN2>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = UID_of_MIN2;
+                        cost_of_MIN3 = cost_of_MIN2;
+
+                        UID_of_MIN2 = loctrans.second->GetUniqueID();
+                        cost_of_MIN2 = localcostptr[dummykey];
+                        continue;
+                    }
+                    if ((cost_of_MIN3>localcostptr[dummykey]) && (localcostptr[dummykey]>=0.)) {
+                        UID_of_MIN3 = loctrans.second->GetUniqueID();
+                        cost_of_MIN3 = localcostptr[dummykey];
+                        continue;
+                    }
+                }
+            }
+
+            _goalToLineUIDmap.erase(goalID);
+            _goalToLineUIDmap.emplace(goalID, UID_of_MIN);
+            _goalToLineUIDmap2.erase(goalID);
+            _goalToLineUIDmap2.emplace(goalID, UID_of_MIN2);
+            _goalToLineUIDmap3.erase(goalID);
+            _goalToLineUIDmap3.emplace(goalID, UID_of_MIN3);
+            delete[] localcostptr;
+            delete[] localneggradptr;
+        }
+    }
+}
+
+double FloorfieldViaFMTrips::getCostToDestination(const int destID, const Point& position) {
+    return getCostToDestination(destID, position, global_shortest);
+}
+
+double FloorfieldViaFMTrips::getCostToDestination(const int destID, const Point& position, int mode) {
+    if ((_costmap.count(destID) == 0) || (_costmap.at(destID) == nullptr)) {
+        Point dummy;
+        getDirectionToUID(destID, 0, dummy, mode);         //this call induces the floorfieldcalculation
+    }
+    if ((_costmap.count(destID) == 0) || (_costmap.at(destID) == nullptr)) {
+        Log->Write("ERROR: \tDestinationUID %d is invalid / out of grid.", destID);
+        return DBL_MAX;
+    }
+    if (_grid->getKeyAtPoint(position) == -1) {  //position is out of grid
+        return -7;
+    }
+    return (_costmap.at(destID))[_grid->getKeyAtPoint(position)];
+}
+
+void FloorfieldViaFMTrips::getDir2WallAt(const Point& position, Point& direction){
+    long int key = _grid->getKeyAtPoint(position);
+    //debug assert
+    if (key < 0) {
+        Log->Write("ERROR: \tgetDir2WallAt error");
+    } else {
+        direction._x = (_dirToWall[key]._x);
+        direction._y = (_dirToWall[key]._y);
+    }
+}
+
+double FloorfieldViaFMTrips::getDistance2WallAt(const Point& position) {
+    long int key = _grid->getKeyAtPoint(position);
+    //debug assert
+    if (key < 0) {
+        Log->Write("ERROR: \tgetDistance2WallAt error");
+        return 1.;
+    } else {
+        return _dist2Wall[key];
+    }
+}
+
+//int  FloorfieldViaFMTrips::getSubroomUIDAt(const Point &position) {
+//    long int key = grid->getKeyAtPoint(position);
+//    return subroomUID[key];
+//}
+
+/*!
+ * \brief Parsing geo-info but conflicts in multi-floor-buildings OBSOLETE
+ *
+ * When parsing a building with multiple floors, the projection of all floors onto the x-/y- plane leads to wrong
+ * results.
+ *
+ * \param[in] buildingArg provides the handle to all information
+ * \param[out] stepSizeX/-Y discretization of the grid, which will be created here
+ * \return member attributes of FloorfieldViaFMTrips class are allocated and initialized
+ * \sa Macros.h, RectGrid.h
+ * \note
+ * \warning
+ */
+void FloorfieldViaFMTrips::parseBuilding(const Building* const buildingArg, const double stepSizeX, const double stepSizeY) {
+    _building = buildingArg;
+    //init min/max before parsing
+    double xMin = DBL_MAX;
+    double xMax = -DBL_MAX;
+    double yMin = xMin;
+    double yMax = xMax;
+
+    if (stepSizeX != stepSizeY) Log->Write("ERROR: \tStepsizes in x- and y-direction must be identical!");
+
+    _costmap.clear();
+    _neggradmap.clear();
+    _wall.clear();
+    _exitsFromScope.clear();
+
+    //create a list of walls
+    const std::map<int, Transition*>& allTransitions = buildingArg->GetAllTransitions();
+    for (auto& trans : allTransitions) {
+        if (
+            trans.second->IsExit() && trans.second->IsOpen()
+           )
+        {
+            _exitsFromScope.emplace_back(Line ( (Line) *(trans.second)));
+        }
+        //populate both maps: costmap, neggradmap. These are the lookup maps for floorfields to specific transitions
+        _costmap.emplace(trans.second->GetUniqueID(), nullptr);
+        _neggradmap.emplace(trans.second->GetUniqueID(), nullptr);
+    }
+    _numOfExits = (unsigned int) _exitsFromScope.size();
+    for (auto& trans : allTransitions) {
+        if (!trans.second->IsOpen()) {
+            _wall.emplace_back(Line ( (Line) *(trans.second)));
+        }
+
+    }
+    for (const auto& itRoom : buildingArg->GetAllRooms()) {
+        for (const auto& itSubroom : itRoom.second->GetAllSubRooms()) {
+            std::vector<Obstacle*> allObstacles = itSubroom.second->GetAllObstacles();
+            for (std::vector<Obstacle*>::iterator itObstacles = allObstacles.begin(); itObstacles != allObstacles.end(); ++itObstacles) {
+
+                std::vector<Wall> allObsWalls = (*itObstacles)->GetAllWalls();
+                for (std::vector<Wall>::iterator itObsWall = allObsWalls.begin(); itObsWall != allObsWalls.end(); ++itObsWall) {
+                    _wall.emplace_back(Line( (Line) *itObsWall));
+                    // xMin xMax
+                    if ((*itObsWall).GetPoint1()._x < xMin) xMin = (*itObsWall).GetPoint1()._x;
+                    if ((*itObsWall).GetPoint2()._x < xMin) xMin = (*itObsWall).GetPoint2()._x;
+                    if ((*itObsWall).GetPoint1()._x > xMax) xMax = (*itObsWall).GetPoint1()._x;
+                    if ((*itObsWall).GetPoint2()._x > xMax) xMax = (*itObsWall).GetPoint2()._x;
+
+                    // yMin yMax
+                    if ((*itObsWall).GetPoint1()._y < yMin) yMin = (*itObsWall).GetPoint1()._y;
+                    if ((*itObsWall).GetPoint2()._y < yMin) yMin = (*itObsWall).GetPoint2()._y;
+                    if ((*itObsWall).GetPoint1()._y > yMax) yMax = (*itObsWall).GetPoint1()._y;
+                    if ((*itObsWall).GetPoint2()._y > yMax) yMax = (*itObsWall).GetPoint2()._y;
+                }
+            }
+
+            std::vector<Wall> allWalls = itSubroom.second->GetAllWalls();
+            for (std::vector<Wall>::iterator itWall = allWalls.begin(); itWall != allWalls.end(); ++itWall) {
+                _wall.emplace_back( Line( (Line) *itWall));
+
+                // xMin xMax
+                if ((*itWall).GetPoint1()._x < xMin) xMin = (*itWall).GetPoint1()._x;
+                if ((*itWall).GetPoint2()._x < xMin) xMin = (*itWall).GetPoint2()._x;
+                if ((*itWall).GetPoint1()._x > xMax) xMax = (*itWall).GetPoint1()._x;
+                if ((*itWall).GetPoint2()._x > xMax) xMax = (*itWall).GetPoint2()._x;
+
+                // yMin yMax
+                if ((*itWall).GetPoint1()._y < yMin) yMin = (*itWall).GetPoint1()._y;
+                if ((*itWall).GetPoint2()._y < yMin) yMin = (*itWall).GetPoint2()._y;
+                if ((*itWall).GetPoint1()._y > yMax) yMax = (*itWall).GetPoint1()._y;
+                if ((*itWall).GetPoint2()._y > yMax) yMax = (*itWall).GetPoint2()._y;
+            }
+
+            const vector<Crossing*>& allCrossings = itSubroom.second->GetAllCrossings();
+            for (Crossing* crossPtr : allCrossings) {
+                if (!crossPtr->IsOpen()) {
+                    _wall.emplace_back( Line( (Line) *crossPtr));
+
+                    if (crossPtr->GetPoint1()._x < xMin) xMin = crossPtr->GetPoint1()._x;
+                    if (crossPtr->GetPoint2()._x < xMin) xMin = crossPtr->GetPoint2()._x;
+                    if (crossPtr->GetPoint1()._x > xMax) xMax = crossPtr->GetPoint1()._x;
+                    if (crossPtr->GetPoint2()._x > xMax) xMax = crossPtr->GetPoint2()._x;
+
+                    if (crossPtr->GetPoint1()._y < yMin) yMin = crossPtr->GetPoint1()._y;
+                    if (crossPtr->GetPoint2()._y < yMin) yMin = crossPtr->GetPoint2()._y;
+                    if (crossPtr->GetPoint1()._y > yMax) yMax = crossPtr->GetPoint1()._y;
+                    if (crossPtr->GetPoint2()._y > yMax) yMax = crossPtr->GetPoint2()._y;
+                }
+            }
+        }
+    }
+
+    //all goals
+    const std::map<int, Goal*>& allgoals = buildingArg->GetAllGoals();
+    for (auto eachgoal:allgoals) {
+        for (auto& eachwall:eachgoal.second->GetAllWalls() ) {
+            if (eachwall.GetPoint1()._x < xMin) xMin = eachwall.GetPoint1()._x;
+            if (eachwall.GetPoint2()._x < xMin) xMin = eachwall.GetPoint2()._x;
+            if (eachwall.GetPoint1()._x > xMax) xMax = eachwall.GetPoint1()._x;
+            if (eachwall.GetPoint2()._x > xMax) xMax = eachwall.GetPoint2()._x;
+
+            if (eachwall.GetPoint1()._y < yMin) yMin = eachwall.GetPoint1()._y;
+            if (eachwall.GetPoint2()._y < yMin) yMin = eachwall.GetPoint2()._y;
+            if (eachwall.GetPoint1()._y > yMax) yMax = eachwall.GetPoint1()._y;
+            if (eachwall.GetPoint2()._y > yMax) yMax = eachwall.GetPoint2()._y;
+        }
+        _goalcostmap.emplace(eachgoal.second->GetId(), nullptr);
+        _goalneggradmap.emplace(eachgoal.second->GetId(), nullptr);
+    }
+
+    //create Rect Grid
+    _grid = new RectGrid();
+    _grid->setBoundaries(xMin, yMin, xMax, yMax);
+    _grid->setSpacing(stepSizeX, stepSizeX);
+    _grid->createGrid();
+
+    //create arrays
+    _subrooms = new SubRoom*[_grid->GetnPoints()]();
+    _gcode = new int[_grid->GetnPoints()];                  //gcode:
+                                                            //    enum GridCode { //used in floor fields
+                                                            //         WALL = 0,
+                                                            //         INSIDE,
+                                                            //         OUTSIDE,
+                                                            //         OPEN_CROSSING,
+                                                            //         OPEN_TRANSITION,
+                                                            //         CLOSED_CROSSING,
+                                                            //         CLOSED_TRANSITION
+                                                            //    };
+    _dist2Wall = new double[_grid->GetnPoints()];
+    _speedInitial = new double[_grid->GetnPoints()];
+    _modifiedspeed = new double[_grid->GetnPoints()];
+    _densityspeed = new double[_grid->GetnPoints()];
+    _cost = new double[_grid->GetnPoints()];
+    _neggrad = new Point[_grid->GetnPoints()];
+    _dirToWall = new Point[_grid->GetnPoints()];
+
+    _costmap.emplace(-1 , _cost);                         // enable default ff (closest exit)
+    _neggradmap.emplace(-1, _neggrad);
+
+    //init grid with -3 as unknown distance to any wall
+    for(long int i = 0; i < _grid->GetnPoints(); ++i) {
+        _dist2Wall[i]    = -3.;
+        _cost[i]         = -2.;
+        _gcode[i]        = OUTSIDE;
+        //flag[i] = FM_UNKNOWN;            //unknown
+    }
+    drawLinesOnGrid<double>(_wall, _dist2Wall, 0.);
+    drawLinesOnGrid<double>(_wall, _cost, -7.);
+    drawLinesOnGrid<int>(_wall, _gcode, WALL);
+    drawLinesOnGrid<int>(_exitsFromScope, _gcode, OPEN_TRANSITION);
+}
+
+/*!
+ * \brief Parsing geo-info ONLY considering rooms with EXITS to the outside to avoid conflicts in multi-floor-buildings
+ *
+ * When parsing a building with multiple floors, the projection of all floors onto the x-/y- plane leads to wrong
+ * results. We then decided, to consider each floor separately and each staircase separately.
+ * We still need to match the ouside goals to an exit (transition), so that the router can guide agents to that goals.
+ * Next problem was in buildings, where exits to the outside would now be on different rooms. This is why we create this
+ * function. We want to create one floorfield for all rooms, that lead outside. Reason: We want the router to lead agents
+ * to the maybe second or third best exit-door, which might be in a different room.
+ *
+ * \param[in] buildingArg provides the handle to all information
+ * \param[out] stepSizeX/-Y discretization of the grid, which will be created here
+ * \return member attributes of FloorfieldViaFMTrips class are allocated and initialized
+ * \sa Macros.h, RectGrid.h
+ * \note
+ * \warning
+ */
+void FloorfieldViaFMTrips::parseBuildingForExits(const Building* const buildingArg, const double stepSizeX, const double stepSizeY) {
+    _building = buildingArg;
+    //init min/max before parsing
+    double xMin = DBL_MAX;
+    double xMax = -DBL_MAX;
+    double yMin = xMin;
+    double yMax = xMax;
+
+    if (stepSizeX != stepSizeY) Log->Write("ERROR: \tStepsizes in x- and y-direction must be identical!");
+
+    _costmap.clear();
+    _neggradmap.clear();
+    _wall.clear();
+    _exitsFromScope.clear();
+
+    std::vector<int> exitRoomIDs;
+    exitRoomIDs.clear();
+
+    //create a list of walls
+    const std::map<int, Transition*>& allTransitions = buildingArg->GetAllTransitions();
+    for (auto& trans : allTransitions) {
+        if (
+                  trans.second->IsExit() && trans.second->IsOpen()
+                  )
+        {
+            _exitsFromScope.emplace_back(Line ( (Line) *(trans.second)));
+            int roomID = -1;
+            if (trans.second->GetRoom1()) {
+                roomID = trans.second->GetRoom1()->GetID();
+            }
+            if (trans.second->GetRoom2()) {
+                roomID = trans.second->GetRoom2()->GetID();
+            }
+            if (std::find(exitRoomIDs.begin(), exitRoomIDs.end(), roomID) == exitRoomIDs.end()) {
+                exitRoomIDs.emplace_back(roomID);
+            }
+        }
+        //populate both maps: costmap, neggradmap. These are the lookup maps for floorfields to specific transitions
+        _costmap.emplace(trans.second->GetUniqueID(), nullptr);
+        _neggradmap.emplace(trans.second->GetUniqueID(), nullptr);
+    }
+    _numOfExits = (unsigned int) _exitsFromScope.size();
+    for (auto& trans : allTransitions) {
+        if (!trans.second->IsOpen()) {
+            _wall.emplace_back(Line ( (Line) *(trans.second)));
+        }
+
+    }
+    for (const auto& itRoom : buildingArg->GetAllRooms()) {
+        if (std::find(exitRoomIDs.begin(), exitRoomIDs.end(), itRoom.second->GetID()) == exitRoomIDs.end()) { //room with no exit
+            continue;
+        }
+        for (const auto& itSubroom : itRoom.second->GetAllSubRooms()) {
+            std::vector<Obstacle*> allObstacles = itSubroom.second->GetAllObstacles();
+            for (std::vector<Obstacle*>::iterator itObstacles = allObstacles.begin(); itObstacles != allObstacles.end(); ++itObstacles) {
+
+                std::vector<Wall> allObsWalls = (*itObstacles)->GetAllWalls();
+                for (std::vector<Wall>::iterator itObsWall = allObsWalls.begin(); itObsWall != allObsWalls.end(); ++itObsWall) {
+                    _wall.emplace_back(Line( (Line) *itObsWall));
+                    // xMin xMax
+                    if ((*itObsWall).GetPoint1()._x < xMin) xMin = (*itObsWall).GetPoint1()._x;
+                    if ((*itObsWall).GetPoint2()._x < xMin) xMin = (*itObsWall).GetPoint2()._x;
+                    if ((*itObsWall).GetPoint1()._x > xMax) xMax = (*itObsWall).GetPoint1()._x;
+                    if ((*itObsWall).GetPoint2()._x > xMax) xMax = (*itObsWall).GetPoint2()._x;
+
+                    // yMin yMax
+                    if ((*itObsWall).GetPoint1()._y < yMin) yMin = (*itObsWall).GetPoint1()._y;
+                    if ((*itObsWall).GetPoint2()._y < yMin) yMin = (*itObsWall).GetPoint2()._y;
+                    if ((*itObsWall).GetPoint1()._y > yMax) yMax = (*itObsWall).GetPoint1()._y;
+                    if ((*itObsWall).GetPoint2()._y > yMax) yMax = (*itObsWall).GetPoint2()._y;
+                }
+            }
+
+            std::vector<Wall> allWalls = itSubroom.second->GetAllWalls();
+            for (std::vector<Wall>::iterator itWall = allWalls.begin(); itWall != allWalls.end(); ++itWall) {
+                _wall.emplace_back( Line( (Line) *itWall));
+
+                // xMin xMax
+                if ((*itWall).GetPoint1()._x < xMin) xMin = (*itWall).GetPoint1()._x;
+                if ((*itWall).GetPoint2()._x < xMin) xMin = (*itWall).GetPoint2()._x;
+                if ((*itWall).GetPoint1()._x > xMax) xMax = (*itWall).GetPoint1()._x;
+                if ((*itWall).GetPoint2()._x > xMax) xMax = (*itWall).GetPoint2()._x;
+
+                // yMin yMax
+                if ((*itWall).GetPoint1()._y < yMin) yMin = (*itWall).GetPoint1()._y;
+                if ((*itWall).GetPoint2()._y < yMin) yMin = (*itWall).GetPoint2()._y;
+                if ((*itWall).GetPoint1()._y > yMax) yMax = (*itWall).GetPoint1()._y;
+                if ((*itWall).GetPoint2()._y > yMax) yMax = (*itWall).GetPoint2()._y;
+            }
+            const vector<Crossing*>& allCrossings = itSubroom.second->GetAllCrossings();
+            for (Crossing* crossPtr : allCrossings) {
+                if (!crossPtr->IsOpen()) {
+                    _wall.emplace_back( Line( (Line) *crossPtr));
+
+                    if (crossPtr->GetPoint1()._x < xMin) xMin = crossPtr->GetPoint1()._x;
+                    if (crossPtr->GetPoint2()._x < xMin) xMin = crossPtr->GetPoint2()._x;
+                    if (crossPtr->GetPoint1()._x > xMax) xMax = crossPtr->GetPoint1()._x;
+                    if (crossPtr->GetPoint2()._x > xMax) xMax = crossPtr->GetPoint2()._x;
+
+                    if (crossPtr->GetPoint1()._y < yMin) yMin = crossPtr->GetPoint1()._y;
+                    if (crossPtr->GetPoint2()._y < yMin) yMin = crossPtr->GetPoint2()._y;
+                    if (crossPtr->GetPoint1()._y > yMax) yMax = crossPtr->GetPoint1()._y;
+                    if (crossPtr->GetPoint2()._y > yMax) yMax = crossPtr->GetPoint2()._y;
+                }
+            }
+        }
+    }
+
+    //all goals
+    const std::map<int, Goal*>& allgoals = buildingArg->GetAllGoals();
+    for (auto eachgoal:allgoals) {
+        for (auto& eachwall:eachgoal.second->GetAllWalls() ) {
+            if (eachwall.GetPoint1()._x < xMin) xMin = eachwall.GetPoint1()._x;
+            if (eachwall.GetPoint2()._x < xMin) xMin = eachwall.GetPoint2()._x;
+            if (eachwall.GetPoint1()._x > xMax) xMax = eachwall.GetPoint1()._x;
+            if (eachwall.GetPoint2()._x > xMax) xMax = eachwall.GetPoint2()._x;
+
+            if (eachwall.GetPoint1()._y < yMin) yMin = eachwall.GetPoint1()._y;
+            if (eachwall.GetPoint2()._y < yMin) yMin = eachwall.GetPoint2()._y;
+            if (eachwall.GetPoint1()._y > yMax) yMax = eachwall.GetPoint1()._y;
+            if (eachwall.GetPoint2()._y > yMax) yMax = eachwall.GetPoint2()._y;
+        }
+        //goalcostmap.emplace(eachgoal.second->GetId(), nullptr);
+        //goalneggradmap.emplace(eachgoal.second->GetId(), nullptr);
+    }
+
+    //create Rect Grid
+    _grid = new RectGrid();
+    _grid->setBoundaries(xMin, yMin, xMax, yMax);
+    _grid->setSpacing(stepSizeX, stepSizeX);
+    _grid->createGrid();
+
+    //create arrays
+    _gcode = new int[_grid->GetnPoints()];                  //see Macros.h: enum GridCode {...}
+    _subrooms = new SubRoom*[_grid->GetnPoints()]();
+    _dist2Wall = new double[_grid->GetnPoints()];
+    _speedInitial = new double[_grid->GetnPoints()];
+    _modifiedspeed = new double[_grid->GetnPoints()];
+    _cost = new double[_grid->GetnPoints()];
+    _neggrad = new Point[_grid->GetnPoints()];
+    _dirToWall = new Point[_grid->GetnPoints()];
+
+    _costmap.emplace(-1 , _cost);                         // enable default ff (closest exit)
+    _neggradmap.emplace(-1, _neggrad);
+
+    //init grid with -3 as unknown distance to any wall
+    for(long int i = 0; i < _grid->GetnPoints(); ++i) {
+        _dist2Wall[i] = -3.;
+        _cost[i] = -2.;
+        _gcode[i] = OUTSIDE;            //unknown
+        _subrooms[i] = nullptr;
+    }
+    drawLinesOnGrid<double>(_wall, _dist2Wall, 0.);
+    drawLinesOnGrid<double>(_wall, _cost, -7.);
+    drawLinesOnGrid<int>(_wall, _gcode, WALL);
+    drawLinesOnGrid<int>(_exitsFromScope, _gcode, OPEN_TRANSITION);
+}
+
+//this function must only be used BEFORE calculateDistanceField(), because we set trialfield[].cost = dist2Wall AND we init dist2Wall with "-3"
+void FloorfieldViaFMTrips::prepareForDistanceFieldCalculation(const bool onlyRoomsWithExits) { //onlyRoomsWithExits means, outside points must be considered
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+
+        switch (_gcode[i]) {
+            //wall, closed_cross/_trans are all coded with "WALL" after prasing building
+            case WALL:
+                _speedInitial[i] = .001;
+                _cost[i]         = -7.;
+                _dist2Wall[i]    = 0.;
+                break;
+            case CLOSED_CROSSING:
+                _speedInitial[i] = .001;
+                _cost[i]         = -7.;
+                _dist2Wall[i]    = 0.;
+                break;
+            case CLOSED_TRANSITION:
+                _speedInitial[i] = .001;
+                _cost[i]         = -7.;
+                _dist2Wall[i]    = 0.;
+                break;
+            //open transitions are marked
+            case OPEN_TRANSITION:
+                _speedInitial[i] = 1.;
+                _cost[i]         = 0.;
+                _neggrad[i]._x = (0.);        //must be changed to costarray/neggradarray?
+                _neggrad[i]._y = (0.);        //we can leave it, if we agree on cost/neggrad being
+                _dirToWall[i]._x = (0.);      //default floorfield using all exits and have the
+                _dirToWall[i]._y = (0.);      //array mechanic on top
+                break;
+            //open crossings are not marked at all after parsing building
+            case OPEN_CROSSING:
+                _speedInitial[i] = 1.;
+                _cost[i]         = -2.;
+                break;
+            //after parsing, none is INSIDE, but for style reasons, I want switch cases to show all values
+            case INSIDE:
+                _speedInitial[i] = 1.;
+                _cost[i]         = -2.;
+                break;
+            //this is the main thing in this loop, we want to find and mark inside points (and it is costly!!)
+            case OUTSIDE:
+            {
+                SubRoom* subroom = isInside(i);
+                if (subroom || onlyRoomsWithExits) {
+                    _speedInitial[i] = 1.;
+                    _cost[i] = -2.;
+                    _gcode[i] = INSIDE;
+                    _subrooms[i] = subroom;
+                }
+                break;
+            }
+        } //switch
+    } //for loop (points)
+    // drawLinesOnGrid(exits, cost, 0.); //already mark targets/exits in cost array (for floorfieldcalc and crossout (LocalFF))
+}
+
+void FloorfieldViaFMTrips::deleteAllFFs() {
+    for (size_t i = 0; i < _costmap.size(); ++i) {
+        auto costIter = _costmap.begin();
+        auto negIter  = _neggradmap.begin();
+        std::advance(costIter, (_costmap.size() - (i+1)));
+        std::advance(negIter,  (_neggradmap.size() - (i+1)));
+
+        if (costIter->second) delete[] costIter->second;
+        if (negIter->second) delete[] negIter->second;
+
+        costIter->second = nullptr;
+        negIter->second = nullptr;
+    }
+}
+
+template <typename T>
+void FloorfieldViaFMTrips::drawLinesOnGrid(std::vector<Line>& wallArg, 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
+
+//    //init with inside value:
+//    long int indexMax = grid->GetnPoints();
+//    for (long int i = 0; i < indexMax; ++i) {
+//        target[i] = inside;
+//    }
+
+    //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
+
+    for (auto& line : wallArg) {
+        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 ((_gcode[jDot*iMax + iDot] != WALL) && (_gcode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gcode[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 ((_gcode[jDot*iMax + iDot] != WALL) && (_gcode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gcode[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 ((_gcode[jDot*iMax + iDot] != WALL) && (_gcode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gcode[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 ((_gcode[jDot*iMax + iDot] != WALL) && (_gcode[jDot*iMax + iDot] != CLOSED_CROSSING) && (_gcode[jDot*iMax + iDot] != CLOSED_TRANSITION)) {
+                    target[jDot * iMax + iDot] = value;
+                }
+            }
+        }
+    } //loop over all walls
+
+} //drawLinesOnGrid
+
+void FloorfieldViaFMTrips::setSpeed(bool useDistance2WallArg) {
+    if (useDistance2WallArg && (_threshold > 0)) {
+        double temp;            //needed to only slowdown band of threshold. outside of band modifiedspeed should be 1
+        for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+            temp = (_dist2Wall[i] < _threshold) ? _dist2Wall[i] : _threshold;
+            _modifiedspeed[i] = 0.001 + 0.999 * (temp/_threshold); //linear ramp from wall (0.001) to thresholddistance (1.000)
+        }
+    } else {
+        if (useDistance2WallArg) {     //favor middle of hallways/rooms
+            for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+                if (_threshold == 0.) {  //special case if user set (use_wall_avoidance = true, wall_avoid_distance = 0.0) and thus wants a plain floorfield
+                    _modifiedspeed[i] = _speedInitial[i];
+                } else {                //this is the regular case for "favor middle of hallways/rooms
+                    _modifiedspeed[i] = 0.001 + 0.999 * (_dist2Wall[i]/10); // @todo: ar.graf  (10 ist ein hardgecodeter wert.. sollte ggf. angepasst werden)
+                }
+            }
+        } else {                    //do not use Distance2Wall
+            for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+                _modifiedspeed[i] = _speedInitial[i];
+            }
+        }
+    }
+    if (_densityspeed) {
+        std::copy(_modifiedspeed, _modifiedspeed + _grid->GetnPoints(), _densityspeed);
+    }
+}
+
+void FloorfieldViaFMTrips::setSpeedThruPeds(Pedestrian* const * pedsArg, int nsize, int modechoice, double radius) {
+
+    long int delta = radius / _grid->Gethx();
+    long int posIndex = 0;
+    long int pos_i = 0;
+    long int pos_j = 0;
+    long int i_start = 0;
+    long int j_start = 0;
+    long int i_end = 0;
+    long int j_end = 0;
+    double indexDistance = 0.0;
+
+    if (nsize == 0) {
+        Log->Write("WARNING: \tSetSpeedThruPeds: nsize is ZERO");
+    } else {
+        Log->Write("INFO: \t\tNumber of Peds used in setSpeedThruPeds: %d",nsize);
+    }
+
+    if ((modechoice == quickest) && (!_densityspeed)) {
+        _densityspeed = new double[_grid->GetnPoints()];
+    }
+    //std::copy(modifiedspeed, modifiedspeed+(grid->GetnPoints()), densityspeed);
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        _densityspeed[i] = _speedInitial[i];
+    }
+
+    for (int i = 0; i < nsize; ++i) {
+        //the following check is not 3D proof, we require the caller of this function to provide a list with "valid"
+        //pedestrian-pointer
+        if (!_grid->includesPoint(pedsArg[i]->GetPos())) {
+            continue;
+        }
+                                                    /*this value defines the jam-speed threshold*/
+//        if (pedsArg[i]->GetEllipse().GetV().Norm() >  0.8*pedsArg[i]->GetEllipse().GetV0()) {
+//            continue;
+//        }
+        posIndex = _grid->getKeyAtPoint(pedsArg[i]->GetPos());
+        pos_i = _grid->get_i_fromKey(posIndex);
+        pos_j = _grid->get_j_fromKey(posIndex);
+
+        i_start = ((pos_i - delta) < 0)               ? 0               : (pos_i - delta);
+        i_end   = ((pos_i + delta) >= _grid->GetiMax()) ? _grid->GetiMax()-1 : (pos_i + delta);
+
+        j_start = ((pos_j - delta) < 0)               ? 0               : (pos_j - delta);
+        j_end   = ((pos_j + delta) >= _grid->GetjMax()) ? _grid->GetjMax()-1 : (pos_j + delta);
+
+        for     (long int curr_i = i_start; curr_i < i_end; ++curr_i) {
+            for (long int curr_j = j_start; curr_j < j_end; ++curr_j) {
+                //indexDistance holds the square
+                indexDistance = ( (curr_i - pos_i)*(curr_i - pos_i) + (curr_j - pos_j)*(curr_j - pos_j) );
+                //now using indexDistance to store the (speed) reduction value
+                //indexDistance = (delta*delta) - (indexDistance);
+                //if (indexDistance < 0) { indexDistance = 0.;}
+                //scale to [0 .. 1]
+                //indexDistance = indexDistance/(delta*delta);
+
+                //densityspeed[curr_j*grid->GetiMax() + curr_i] = (indexDistance > (delta*delta)) ? densityspeed[curr_j*grid->GetiMax() + curr_i] : .001;
+                if (indexDistance < (delta*delta)) {
+                    //std::cout << "c h a n g i n g   ";
+                    _densityspeed[curr_j*_grid->GetiMax() + curr_i] = 0.07;
+                }
+            }
+        }
+    }
+
+}
+
+void FloorfieldViaFMTrips::calculateFloorfield(std::vector<Line>& targetlines, double* costarray, Point* neggradarray) {
+    calculateFloorfield(targetlines, costarray, neggradarray, _modifiedspeed);
+}
+
+void FloorfieldViaFMTrips::calculateFloorfield(std::vector<Line>& targetlines, double* costarray, Point* neggradarray, double* speedarray) {
+
+    std::priority_queue<TrialPTrips, std::vector<TrialPTrips>, std::greater<TrialPTrips>> trialqueue;
+    int* flag = new int[_grid->GetnPoints()];
+
+    //re-init memory
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        if ((_gcode[i] == INSIDE) || (_gcode[i] == OPEN_TRANSITION) || (_gcode[i] == OPEN_CROSSING)) {
+            flag[i]         = FM_UNKNOWN;   //inside
+        } else {
+            flag[i]         = FM_OUTSIDE;  //wall, outside or closed
+        }
+
+        costarray[i] = -7.;
+    }
+    drawLinesOnGrid<double>(targetlines, costarray, 0.);
+    drawLinesOnGrid<int>(targetlines, flag, FM_FINAL);
+
+    //init narrowband
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        if (flag[i] == FM_FINAL) {
+            TrialPTrips newTrialPTrips = TrialPTrips(i, costarray, speedarray, flag, neggradarray);
+            checkNeighborsAndAddToNarrowband(trialqueue, newTrialPTrips,
+                                             [&] (TrialPTrips TrialPTripsArg) {this->calcFloorfield(TrialPTripsArg);});
+        }
+    }
+
+    // initial narrowband done, now loop (while not empty: remove smallest, add neighbors of removed)
+    while (!trialqueue.empty()) {
+        long int keyOfSmallest = trialqueue.top().key;
+        flag[keyOfSmallest] = FM_FINAL;
+        trialqueue.pop();
+        TrialPTrips newTrialPTrips = TrialPTrips(keyOfSmallest, costarray, speedarray, flag, neggradarray);
+        checkNeighborsAndAddToNarrowband(trialqueue,  newTrialPTrips,
+                                         [&] (TrialPTrips TrialPTripsArg) { this->calcFloorfield(TrialPTripsArg);});
+    }
+    delete[] flag;
+}
+
+void FloorfieldViaFMTrips::calculateDistanceField(const double thresholdArg) {  //if threshold negative, then ignore it
+
+    std::priority_queue<TrialPTrips, std::vector<TrialPTrips>, std::greater<TrialPTrips>> trialqueue;
+    int* flag = new int[_grid->GetnPoints()];
+#ifdef TESTING
+    //sanity check (fields <> 0)
+    if (flag == nullptr) return;
+    if (_dist2Wall == 0) return;
+    if (_speedInitial == 0) return;
+    if (_cost == 0) return;
+    if (_neggrad == 0) return;
+#endif //TESTING
+
+    //re-init memory
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        if ((_gcode[i] == INSIDE) || (_gcode[i] == OPEN_TRANSITION) || (_gcode[i] == OPEN_CROSSING)) {
+            flag[i]         = FM_UNKNOWN;   //inside
+        } else if (_gcode[i] == OUTSIDE) {
+            flag[i]         = FM_OUTSIDE;  //outside
+        } else {
+            flag[i]         = FM_FINAL;   //wall or closed
+        }
+    }
+
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        //if ((dist2Wall[i] == 0.) && (flag[i] == -7.)) {
+        if ((_gcode[i] == WALL) || (_gcode[i] == CLOSED_TRANSITION) || (_gcode[i] == CLOSED_CROSSING)) {
+            TrialPTrips newP = TrialPTrips(i, _dist2Wall, _speedInitial, flag, _dirToWall);
+            checkNeighborsAndAddToNarrowband(trialqueue, newP,
+                                             [&] (TrialPTrips TrialPTripsArg) { this->calcDist2Wall(TrialPTripsArg);} );
+        }
+    }
+
+    while (!trialqueue.empty()) {
+        long int keyOfSmallest = trialqueue.top().key;
+        flag[keyOfSmallest] = FM_FINAL;
+        trialqueue.pop();
+        if ((thresholdArg > 0) && (_dist2Wall[keyOfSmallest] > thresholdArg)) {    //set rest of nearfield and rest of unknown to this max value:
+
+            //rest of nearfield
+            while (!trialqueue.empty()) {
+                long int currKey = trialqueue.top().key;
+                _dist2Wall[currKey] = _dist2Wall[keyOfSmallest];
+                flag[currKey] = FM_FINAL;
+                _dirToWall[currKey]._x = (0.);
+                _dirToWall[currKey]._y = (0.);
+                trialqueue.pop();
+            }
+
+            //rest of unknown
+            for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+                if (flag[i] == FM_UNKNOWN) {
+                    flag[i] = FM_FINAL;
+                    _dist2Wall[i] = _dist2Wall[keyOfSmallest];
+                    _dirToWall[i]._x = (0.);
+                    _dirToWall[i]._y = (0.);
+                }
+            }
+        } else {
+            //Log->Write(std::to_string(debugcounter++) + " " + std::to_string(grid->GetnPoints()));
+            TrialPTrips smallestP = TrialPTrips(keyOfSmallest, _dist2Wall, _speedInitial, flag, _dirToWall);
+            checkNeighborsAndAddToNarrowband(trialqueue, smallestP,
+                                             [&] (TrialPTrips TrialPTripsArg) { this->calcDist2Wall(TrialPTripsArg);} );
+        }
+    }
+    delete[] flag;
+} //calculateDistancField
+
+void FloorfieldViaFMTrips::checkNeighborsAndAddToNarrowband(std::priority_queue<TrialPTrips, std::vector<TrialPTrips>, std::greater<TrialPTrips>>& trialqueue, TrialPTrips keyP,
+                                                       std::function<void (TrialPTrips)> calc) {
+    int* flag = keyP.flag;
+
+    directNeighbor dNeigh = _grid->getNeighbors(keyP.key);
+
+    //check for valid neigh
+    long int aux = dNeigh.key[0];
+    //hint: trialfield[i].cost = dist2Wall + i; <<< set in prepareForDistanceFieldCalc
+    if ((aux != -2) && (flag[aux] == FM_UNKNOWN)) {
+        flag[aux] = FM_ADDED;      // added to trial but not calculated
+        TrialPTrips currNeighP = TrialPTrips(aux, keyP.cost, keyP.speed, flag, keyP.neggrad);
+        calc(currNeighP);
+        trialqueue.emplace(currNeighP);
+    }
+    aux = dNeigh.key[1];
+    if ((aux != -2) && (flag[aux] == FM_UNKNOWN)) {
+        flag[aux] = FM_ADDED;      // added to trial but not calculated
+        TrialPTrips currNeighP = TrialPTrips(aux, keyP.cost, keyP.speed, flag, keyP.neggrad);
+        calc(currNeighP);
+        trialqueue.emplace(currNeighP);
+    }
+    aux = dNeigh.key[2];
+    if ((aux != -2) && (flag[aux] == FM_UNKNOWN)) {
+        flag[aux] = FM_ADDED;      // added to trial but not calculated
+        TrialPTrips currNeighP = TrialPTrips(aux, keyP.cost, keyP.speed, flag, keyP.neggrad);
+        calc(currNeighP);
+        trialqueue.emplace(currNeighP);
+    }
+    aux = dNeigh.key[3];
+    if ((aux != -2) && (flag[aux] == FM_UNKNOWN)) {
+        flag[aux] = FM_ADDED;      // added to trial but not calculated
+        TrialPTrips currNeighP = TrialPTrips(aux, keyP.cost, keyP.speed, flag, keyP.neggrad);
+        calc(currNeighP);
+        trialqueue.emplace(currNeighP);
+    }
+}
+
+void FloorfieldViaFMTrips::calcDist2Wall(TrialPTrips newPoint) {
+    double row;
+    double col;
+    long int aux;
+    bool pointsUp;
+    bool pointsRight;
+
+    int* flag = newPoint.flag;
+    double* cost = newPoint.cost;
+    long int key = newPoint.key;
+
+    row = 100000.;
+    col = 100000.;
+    //aux = -1;
+
+    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
+         (flag[aux] != FM_UNKNOWN) &&                                                    //gridpoint holds a calculated value
+         (_gcode[aux] != OUTSIDE))                                                     //gridpoint holds a calculated value
+    {
+        row = cost[aux];
+        pointsRight = true;
+        if (row < 0) {
+            std::cerr << "hier ist was schief " << row << " " << aux << " " << flag[aux] << std::endl;
+            row = 100000;
+        }
+    }
+    aux = dNeigh.key[2];
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&                                                    //gridpoint holds a calculated value
+         (_gcode[aux] != OUTSIDE) &&
+         (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
+         (flag[aux] != FM_UNKNOWN) &&                                                    //gridpoint holds a calculated value
+         (_gcode[aux] != OUTSIDE))
+    {
+        col = cost[aux];
+        pointsUp = true;
+        if (col < 0) {
+            std::cerr << "hier ist was schief " << col << " " << aux << " " << flag[aux] << std::endl;
+            col = 100000;
+        }
+    }
+    aux = dNeigh.key[3];
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&                                                    //gridpoint holds a calculated value
+         (_gcode[aux] != OUTSIDE) &&
+         (cost[aux] < col))                                       //calculated value promises smaller cost
+    {
+        col = cost[aux];
+        pointsUp = false;
+    }
+    if (col == 100000.) { //one sided update with row
+        cost[key] = onesidedCalc(row, _grid->Gethx());
+        flag[key] = FM_SINGLE;
+        if (pointsRight) {
+            _dirToWall[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            _dirToWall[key]._y = (0.);
+        } else {
+            _dirToWall[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            _dirToWall[key]._y = (0.);
+        }
+        _dirToWall[key] = _dirToWall[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 == 100000.) { //one sided update with col
+        cost[key] = onesidedCalc(col, _grid->Gethy());
+        flag[key] = FM_SINGLE;
+        if (pointsUp) {
+            _dirToWall[key]._x = (0.);
+            _dirToWall[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        } else {
+            _dirToWall[key]._x = (0.);
+            _dirToWall[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+        _dirToWall[key] = _dirToWall[key].Normalized();
+        return;
+    }
+
+    //two sided update
+    double precheck = twosidedCalc(row, col, _grid->Gethx());
+    if (precheck >= 0) {
+        cost[key] = precheck;
+        flag[key] = FM_DOUBLE;
+        if (pointsUp && pointsRight) {
+            _dirToWall[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            _dirToWall[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        }
+        if (pointsUp && !pointsRight) {
+            _dirToWall[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            _dirToWall[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        }
+        if (!pointsUp && pointsRight) {
+            _dirToWall[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            _dirToWall[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+        if (!pointsUp && !pointsRight) {
+            _dirToWall[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            _dirToWall[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+    } else {
+        std::cerr << "else in twosided Dist " << std::endl;
+    }
+    _dirToWall[key] = _dirToWall[key].Normalized();
+}
+
+void FloorfieldViaFMTrips::calcFloorfield(TrialPTrips newPoint) {
+    double row;
+    double col;
+    long int aux;
+    bool pointsUp = false;
+    bool pointsRight = false;
+
+    int* flag = newPoint.flag;
+    double* cost = newPoint.cost;
+    long int key = newPoint.key;
+    double* speed = newPoint.speed;
+    Point* neggrad = newPoint.neggrad;
+
+    row = DBL_MAX;
+    col = DBL_MAX;
+    //aux = -1;
+
+    directNeighbor dNeigh = _grid->getNeighbors(key);
+
+    aux = dNeigh.key[0];
+    //hint: trialfield[i].cost = costarray + i; <<< set in calculateFloorfield
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&
+         //((gcode[aux] == INSIDE) || (gcode[aux] == OPEN_CROSSING) || (gcode[aux] == OPEN_TRANSITION)) )    //gridpoint holds a calculated value
+         (flag[aux] != FM_OUTSIDE))
+    {
+        row = cost[aux];
+        pointsRight = true;
+    }
+    aux = dNeigh.key[2];
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&
+         (flag[aux] != FM_OUTSIDE) &&                                                 //gridpoint holds a calculated value
+         (cost[aux] < row))                                       //calculated value promises smaller cost
+    {
+        row = cost[aux];
+        pointsRight = false;
+    }
+
+    aux = dNeigh.key[1];
+    //hint: trialfield[i].cost = cost + i; <<< set in calculateFloorfield
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&
+         (flag[aux] != FM_OUTSIDE))                                                      //gridpoint holds a calculated value
+    {
+        col = cost[aux];
+        pointsUp = true;
+    }
+    aux = dNeigh.key[3];
+    if  ((aux != -2) &&                                                         //neighbor is a gridpoint
+         (flag[aux] != FM_UNKNOWN) &&
+         (flag[aux] != FM_OUTSIDE) &&                                                  //gridpoint holds a calculated value
+         (cost[aux] < col))                                       //calculated value promises smaller cost
+    {
+        col = cost[aux];
+        pointsUp = false;
+    }
+    if ((col == DBL_MAX) && (row == DBL_MAX)) {
+        std::cerr << "Issue 175 in FloorfieldViaFMTrips: invalid combination of row,col (both on max)" <<std::endl;
+        return;
+    }
+    if (col == DBL_MAX) { //one sided update with row
+        cost[key] = onesidedCalc(row, _grid->Gethx()/speed[key]);
+        flag[key] = FM_SINGLE;
+        if (pointsRight && (dNeigh.key[0] != -2)) {
+            neggrad[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            neggrad[key]._y = (0.);
+        } else if (dNeigh.key[2] != -2) {
+            neggrad[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            neggrad[key]._y = (0.);
+        }
+        return;
+    }
+
+    if (row == DBL_MAX) { //one sided update with col
+        cost[key] = onesidedCalc(col, _grid->Gethy()/speed[key]);
+        flag[key] = FM_SINGLE;
+        if ((pointsUp) && (dNeigh.key[1] != -2)) {
+            neggrad[key]._x = (0.);
+            neggrad[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        } else if (dNeigh.key[3] != -2){
+            neggrad[key]._x = (0.);
+            neggrad[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+        return;
+    }
+
+    //two sided update
+    double precheck = twosidedCalc(row, col, _grid->Gethx()/speed[key]);
+//    if (precheck > 10000) {
+//        Log->Write("ERROR \t\t\t is in twosided");
+//    }
+    if (precheck >= 0) {
+        cost[key] = precheck;
+        flag[key] = FM_DOUBLE;
+        if (pointsUp && pointsRight) {
+            neggrad[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            neggrad[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        }
+        if (pointsUp && !pointsRight) {
+            neggrad[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            neggrad[key]._y = (-(cost[key+(_grid->GetiMax())]-cost[key])/_grid->Gethy());
+        }
+        if (!pointsUp && pointsRight) {
+            neggrad[key]._x = (-(cost[key+1]-cost[key])/_grid->Gethx());
+            neggrad[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+        if (!pointsUp && !pointsRight) {
+            neggrad[key]._x = (-(cost[key]-cost[key-1])/_grid->Gethx());
+            neggrad[key]._y = (-(cost[key]-cost[key-(_grid->GetiMax())])/_grid->Gethy());
+        }
+    } else {
+        std::cerr << "else in twosided Floor " << precheck << " " << row << " " << col << std::endl;
+    }
+}
+
+inline double FloorfieldViaFMTrips::onesidedCalc(double xy, double hDivF) {
+    //if ( (xy+hDivF) > 10000) std::cerr << "error in onesided " << xy << std::endl;
+    return xy + hDivF;
+}
+
+inline double FloorfieldViaFMTrips::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 FloorfieldViaFMTrips::testoutput(const char* filename1, const char* filename2, const double* target) {
+//security debug check
+    std::ofstream file;
+    std::ofstream file2;
+    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(filename1);
+    file2.open(filename2);
+    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 Cost float 1" << std::endl;
+    file << "LOOKUP_TABLE default" << std::endl;
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        file << target[i] << std::endl;
+        Point iPoint = _grid->getPointFromKey(i);
+        file2 << iPoint._x /*- grid->GetxMin()*/ << " " << iPoint._y /*- grid->GetyMin()*/ << " " << target[i] << std::endl;
+    }
+
+    if (target == _cost) {
+        file << "VECTORS Gradient float" << std::endl;
+        for (int i = 0; i < _grid->GetnPoints(); ++i) {
+            file << _neggrad[i]._x << " " << _neggrad[i]._y << " 0.0" << std::endl;
+        }
+    }
+
+    file.close();
+    file2.close();
+
+    //std::cerr << "INFO: \tFile closed: " << filename1 << std::endl;
+}
+
+void FloorfieldViaFMTrips::writeFF(const std::string& filename, std::vector<int> targetID) {
+    Log->Write("INFO: \tWrite Floorfield to file");
+    Log->Write(filename);
+    std::ofstream file;
+
+    Log->Write("FloorfieldViaFMTrips::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 Dist2Wall float 1" << std::endl;
+    file << "LOOKUP_TABLE default" << std::endl;
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        file << _dist2Wall[i] << std::endl; //@todo: change target to all dist2wall
+        //Point iPoint = grid->getPointFromKey(i);
+        //file2 << iPoint._x /*- grid->GetxMin()*/ << " " << iPoint._y /*- grid->GetyMin()*/ << " " << target[i] << std::endl;
+    }
+
+    file << "VECTORS Dir2Wall float" << std::endl;
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        file << _dirToWall[i]._x << " " << _dirToWall[i]._y << " 0.0" << std::endl;
+    }
+
+    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 (_neggradmap.count(targetID[iTarget]) == 0) {
+            continue;
+        }
+
+        Point *gradarray = _neggradmap[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 = _costmap[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 << "SCALARS GCode float 1" << std::endl;
+    file << "LOOKUP_TABLE default" << std::endl;
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        file << _gcode[i] << std::endl;
+    }
+    file.close();
+}
+
+void FloorfieldViaFMTrips::writeGoalFF(const std::string& filename, std::vector<int> targetID) {
+    Log->Write("INFO: \tWrite Floorfield to file");
+    Log->Write(filename);
+    std::ofstream file;
+
+    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 Dist2Wall float 1" << std::endl;
+    //file << "LOOKUP_TABLE default" << std::endl;
+    //for (long int i = 0; i < grid->GetnPoints(); ++i) {
+    //    file << dist2Wall[i] << std::endl; //@todo: change target to all dist2wall
+        //Point iPoint = grid->getPointFromKey(i);
+        //file2 << iPoint._x /*- grid->GetxMin()*/ << " " << iPoint._y /*- grid->GetyMin()*/ << " " << target[i] << std::endl;
+    //}
+
+    //file << "VECTORS Dir2Wall float" << std::endl;
+    //for (long int i = 0; i < grid->GetnPoints(); ++i) {
+    //    file << dirToWall[i]._x << " " << dirToWall[i]._y << " 0.0" << std::endl;
+    //}
+
+    for (unsigned int iTarget = 0; iTarget < targetID.size(); ++iTarget) {
+        if (_goalneggradmap.count(targetID[iTarget]) == 0) {
+            continue;
+        }
+
+        Point *gradarray = _goalneggradmap[targetID[iTarget]];
+        if (gradarray == nullptr) {
+            continue;
+        }
+
+        file << "VECTORS GradientTarget" << targetID[iTarget] << " float" << std::endl;
+        for (int i = 0; i < _grid->GetnPoints(); ++i) {
+            file << gradarray[i]._x << " " << gradarray[i]._y << " 0.0" << std::endl;
+        }
+
+        double *costarray = _goalcostmap[targetID[iTarget]];
+        file << "SCALARS CostTarget" << targetID[iTarget] << " 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 << "SCALARS GCode float 1" << std::endl;
+    file << "LOOKUP_TABLE default" << std::endl;
+    for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+        file << _gcode[i] << std::endl;
+    }
+    file.close();
+}
+
+SubRoom* FloorfieldViaFMTrips::isInside(const long int key) {
+//    Point probe = _grid->getPointFromKey(key);
+
+//    const std::map<int, std::shared_ptr<Room>>& roomMap = _building->GetAllRooms();
+//
+//    for (auto& roomPair : roomMap) {
+//
+//        Room* roomPtr = roomPair.second.get();
+//        const std::map<int, std::shared_ptr<SubRoom>>& subRoomMap = roomPtr->GetAllSubRooms();
+//
+//        for (auto& subRoomPair : subRoomMap) {
+//
+//            SubRoom* subRoomPtr = subRoomPair.second.get();
+//
+//            if (subRoomPtr->IsInSubRoom(probe)) {
+//                return subRoomPtr;
+//            }
+//        }
+
+    //FloorfieldViaFMTrips does not support isInside because of unresolved problem of ambiguous projection of xy plane in multi-
+    //storage buildings
+
+    return nullptr;
+}
+
+void CentrePointFFViaFMTrips::getDirectionToUID(int destID, const long int key, Point& direction, int mode) {
+    //what if goal == -1, meaning closest exit... is GetExitIndex then -1? NO... ExitIndex is UID, given by router
+    //if (ped->GetFinalDestination() == -1) /*go to closest exit*/ destID != -1;
+
+    if ((key < 0) || (key >= _grid->GetnPoints())) { // @todo: ar.graf: this check in a #ifdef-block?
+        Log->Write("ERROR: \t Floorfield tried to access a key out of grid!");
+        direction._x = 0.;
+        direction._y = 0.;
+        return;
+    }
+    Point* localneggradptr = nullptr;
+    double* localcostptr = nullptr;
+    {
+        if (_neggradmap.count(destID) == 0) {
+            //Log->Write("FF for destID %d does not exist (key is %d)", destID, key);
+            //check, if distID is in this grid
+            Hline* destLine = _building->GetTransOrCrossByUID(destID);
+            Point A = destLine->GetCentre();
+            //Point B = destLine->GetPoint2();
+            if (!(_grid->includesPoint(A))) {
+                Log->Write("ERROR: \t Destination ID %d is not in grid!", destID);
+                direction._x = direction._y = 0.;
+                //return;
+            }
+        }
+        localneggradptr = (_neggradmap.count(destID) == 0) ? nullptr : _neggradmap.at(destID);
+        localcostptr = (_costmap.count(destID) == 0) ? nullptr : _costmap.at(destID);
+        if (localneggradptr == nullptr) {
+            bool isBeingCalculated;
+#pragma omp critical(floorfieldsBeingCalculated)
+            {
+                if (!(isBeingCalculated = _floorfieldsBeingCalculated.count(destID) > 0)) {
+                    _floorfieldsBeingCalculated.insert(destID);
+                }
+            }
+            if (isBeingCalculated) {
+                // we do not want to wait until the other calculation has finished, so we return immediately
+                // the values are corrected in getDirectionToDestination(), and getCostToDestination doesn't care about the direction
+                direction._x = DBL_MAX;
+                direction._y = DBL_MAX;
+                return;
+            }
+
+            //create floorfield (remove mapentry with nullptr, allocate memory, add mapentry, create ff)
+            localcostptr =    new double[_grid->GetnPoints()];
+            localneggradptr = new Point[_grid->GetnPoints()];
+#pragma omp critical(neggradmap)
+            _neggradmap.erase(destID);
+#pragma omp critical(neggradmap)
+            _neggradmap.emplace(destID, localneggradptr);
+#pragma omp critical(costmap)
+            _costmap.erase(destID);
+#pragma omp critical(costmap)
+            _costmap.emplace(destID, localcostptr);
+
+
+            //create ff (prepare Trial-mechanic, then calc)
+//                for (long int i = 0; i < grid->GetnPoints(); ++i) {
+//                    //set TrialPTripstr to fieldelements
+//                    trialfield[i].cost = localcostptr + i;
+//                    trialfield[i].neggrad = localneggradptr + i;
+//                    trialfield[i].father = nullptr;
+//                    trialfield[i].child = nullptr;
+//                }
+//                clearAndPrepareForFloorfieldReCalc(localcostptr);
+            //std::vector<Line> localline = {Line((Line) *(building->GetTransOrCrossByUID(destID)))};
+            Point centre = _building->GetTransOrCrossByUID(destID)->GetCentre();
+            std::vector<Line> localline = {Line(centre, centre, 0)}; // only one point
+//                setNewGoalAfterTheClear(localcostptr, localline);
+            //Log->Write("Starting FF for UID %d (ID %d)", destID, dynamic_cast<Crossing*>(building->GetTransOrCrossByUID(destID))->GetID());
+            //std::cerr << "\rW\tO\tR\tK\tI\tN\tG";
+            if (mode == quickest) {
+                calculateFloorfield(localline, localcostptr, localneggradptr, _densityspeed);
+            } else {
+                calculateFloorfield(localline, localcostptr, localneggradptr, _modifiedspeed);
+            }
+             //when using CentralPoint, the rest of destID Line would not be calculated. We set that line to zero in the lines below.
+             //this way, the ffrouter understands, if a pedestrian reached the line, but is next to central point.
+             Point a = _building->GetTransOrCrossByUID(destID)->GetPoint1();
+             Point b = _building->GetTransOrCrossByUID(destID)->GetPoint2();
+             localline.emplace_back(Line(a, b, 0));
+             drawLinesOnGrid<double>(localline, localcostptr, 0.);
+#pragma omp critical(floorfieldsBeingCalculated)
+            {
+                if (_floorfieldsBeingCalculated.count(destID) != 1) {
+                    Log->Write("ERROR: FloorfieldViaFMTrips::getDirectionToUID: key %d was calculating FF for destID %d, but it was removed from floorfieldsBeingCalculated meanwhile", key, destID);
+                }
+                _floorfieldsBeingCalculated.erase(destID);
+            }
+            //Log->Write("Ending   FF for UID %d", destID);
+            //std::cerr << "\r W\t O\t R\t K\t I\t N\t G";
+        }
+    }
+    direction._x = (localneggradptr[key]._x);
+    direction._y = (localneggradptr[key]._y);
+}
+
+SubRoom* FloorfieldViaFMTrips::GetSubroom(Pedestrian* ped) {
+    long int key = _grid->getKeyAtPoint(ped->GetPos());
+    assert(key >= 0 && key <= _grid->GetnPoints());
+    return _subrooms[key];
+}
\ No newline at end of file
diff --git a/routing/ff_router_trips/FloorfieldViaFMTrips.h b/routing/ff_router_trips/FloorfieldViaFMTrips.h
new file mode 100644
index 00000000..cd39fdf7
--- /dev/null
+++ b/routing/ff_router_trips/FloorfieldViaFMTrips.h
@@ -0,0 +1,226 @@
+/**
+ * \file        FloorfieldViaFMTrips.h
+ * \date        Mar 05, 2015
+ * \version     N/A (v0.6)
+ * \copyright   <2009-2014> 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 ...
+ *
+ *
+ **/
+
+ //remark:
+ //refac the code to use enums instead of integer values where integer values code sth
+ //was considered, but enum classes do not implicitly cast to int
+ //rather use makros/masks like in plain C? or just makros (defines)?
+ //this would make it easier to read
+
+#ifndef FloorfieldViaFMTrips_H
+#define FloorfieldViaFMTrips_H
+
+#include <vector>
+#include <unordered_set>
+#include <cmath>
+#include <functional>
+#include "mesh/RectGrid.h"
+#include "../../geometry/Wall.h"
+#include "../../geometry/Point.h"
+#include "../../geometry/Building.h"
+#include "../../geometry/SubRoom.h" //check: should Room.h include SubRoom.h??
+#include "./mesh/Trial.h"
+#include "../../pedestrian/Pedestrian.h"
+
+//maybe put following in macros.h
+#define LOWSPEED 0.001
+
+class TrialPTrips
+{
+public:
+     long int key;
+     int* flag;
+     double* cost;
+     double* speed;
+     Point* neggrad;
+
+     TrialPTrips() {
+          key = 0;
+          flag = nullptr;
+          cost = nullptr;
+          speed = nullptr;
+          neggrad = nullptr;
+     }
+
+     TrialPTrips(long int keyArg, double* t, double* f, int* flagArg, Point* neggradArg) {
+          key = keyArg;
+          cost = t;
+          speed = f;
+          flag = flagArg;
+          neggrad = neggradArg;
+     }
+
+     ~TrialPTrips(){}
+
+     bool operator <(const TrialPTrips& rhs) const
+     {
+          return this->cost[this->key] < rhs.cost[rhs.key];
+     }
+
+     bool operator >(const TrialPTrips& rhs) const
+     {
+          return this->cost[this->key] > rhs.cost[rhs.key];
+     }
+
+     bool operator ==(const TrialPTrips& rhs) const
+     {
+          return this->cost[this->key] == rhs.cost[rhs.key];
+     }
+};
+
+class FloorfieldViaFMTrips
+{
+public:
+     FloorfieldViaFMTrips();
+     FloorfieldViaFMTrips(const std::string&);
+     FloorfieldViaFMTrips(const Building* const buildingArg, const double hxArg, const double hyArg,
+                     const double wallAvoidDistance, const bool useDistancefield, const bool onlyRoomsWithExits);
+     //FloorfieldViaFMTrips(const FloorfieldViaFMTrips* const refFM);
+     virtual ~FloorfieldViaFMTrips();
+     FloorfieldViaFMTrips(const FloorfieldViaFMTrips& other); //will not make a copy; only takes geometry info
+     //FloorfieldViaFMTrips& operator=(const FloorfieldViaFMTrips& other);
+
+     //void getDirectionAt(const Point& position, Point& direction);                                   //obsolete
+     //void getDirectionToDestination (const int destID, const Point& position, Point& direction);     //obsolete
+     void getDirectionToUID(int destID, const long int key, Point& direction); // shall not be used any more, therefore not virtual
+     virtual void getDirectionToUID(int destID, const long int key, Point& direction, int mode);
+     //void getDirectionToUIDParallel(int destID, const long int key, Point& direction);
+     virtual void getDirectionToDestination (Pedestrian* ped, Point& direction);
+     //void getDirectionToFinalDestination(Pedestrian* ped, Point& direction); //this is router buissness! problem in multi-storage buildings
+
+     void createMapEntryInLineToGoalID(const int goalID, bool isInside);
+
+     double getCostToDestination(const int destID, const Point& position);
+     double getCostToDestination(const int destID, const Point& position, int mode);
+     //double getCostToDestinationParallel(const int destID, const Point& position);
+
+     void getDir2WallAt(const Point& position, Point& direction);
+     double getDistance2WallAt(const Point& position);
+
+     int getSubroomUIDAt(const Point& position);
+
+     void parseBuilding(const Building* const buildingArg, const double stepSizeX, const double stepSizeY);
+     void parseBuildingForExits(const Building* const buildingArg, const double stepSizeX, const double stepSizeY);
+     void prepareForDistanceFieldCalculation(const bool withExits);
+     template <typename T>
+     void drawLinesOnGrid(std::vector<Line>& wallArg, T* const target, const T value);
+     void setSpeed(bool useDistance2WallArg);
+     void setSpeedThruPeds(Pedestrian* const* pedsArg, int nPeds, int modechoice, double radius);
+     void deleteAllFFs();
+     void clearAndPrepareForFloorfieldReCalc(double* costarray);
+     void setNewGoalAfterTheClear(double* costarray, std::vector<Line>& GoalWallArg);
+     void calculateFloorfield(std::vector<Line>& wallArg, double* costarray, Point* neggradarray);   //make private
+     void calculateFloorfield(std::vector<Line>& wallArg, double* costarray, Point* neggradarray, double* speedarray);
+     void calculateDistanceField(const double thresholdArg);             //make private
+
+     void checkNeighborsAndAddToNarrowband(std::priority_queue<TrialPTrips, std::vector<TrialPTrips>, std::greater<TrialPTrips> >& trialfield, TrialPTrips key,
+                                           std::function<void (TrialPTrips)> calc);
+
+     void calcDist2Wall(TrialPTrips);
+     void calcFloorfield(TrialPTrips);
+     //void (*checkNeighborsAndCalc)(const long int key);
+
+     inline double onesidedCalc(double xy, double hDivF);
+     inline double twosidedCalc(double x, double y, double hDivF);
+
+     void testoutput(const char*, const char*, const double*);
+     void writeFF(const std::string&, std::vector<int> targetID);
+     void writeGoalFF(const std::string&, std::vector<int> targetID);
+
+     virtual SubRoom* isInside(const long int key);
+     SubRoom* GetSubroom(Pedestrian* p);
+
+     std::map<int, int> getGoalToLineUIDmap() const
+     {
+          return _goalToLineUIDmap;
+     }
+
+     std::map<int, int> getGoalToLineUIDmap2() const
+     {
+          return _goalToLineUIDmap2;
+     }
+
+     std::map<int, int> getGoalToLineUIDmap3() const
+     {
+          return _goalToLineUIDmap3;
+     }
+
+     RectGrid* getGrid() const
+     {
+          return _grid;
+     }
+
+#ifdef TESTING
+     void setGrid(RectGrid* gridArg) {_grid = gridArg;}
+#endif //TESTING
+
+protected:
+     RectGrid* _grid = nullptr;
+     std::vector<Line> _wall;
+     std::vector<Line> _exitsFromScope;
+     unsigned int _numOfExits;
+
+     const Building* _building;
+
+     //GridPoint Data in independant arrays (shared primary key)
+     // changed to threadsafe creation when needed: int* flag;
+     int* _gcode = nullptr;                 //gridcode (see Macros.h)
+     SubRoom* * _subrooms = nullptr; // this is an array (first asterisk) of pointers (second asterisk)
+     double* _dist2Wall = nullptr;
+     double* _speedInitial = nullptr;
+     double* _modifiedspeed = nullptr;
+     double* _densityspeed = nullptr;
+     double* _cost = nullptr;
+     //long int* secKey;  //secondary key to address ... not used yet
+     Point* _neggrad = nullptr; //gradients
+     Point* _dirToWall = nullptr;
+     // changed to threadsafe creation when needed: Trial* trialfield;
+
+     std::map<int, double*> _goalcostmap;
+     std::map<int, int>     _goalToLineUIDmap; //key is the goalID and value is the UID of closest transition -> it maps goal to LineUID
+     std::map<int, int>     _goalToLineUIDmap2;
+     std::map<int, int>     _goalToLineUIDmap3;
+     std::map<int, Point*>  _goalneggradmap;
+     std::map<int, double*> _costmap;
+     std::map<int, Point*>  _neggradmap;
+     // use an unordered_set for faster access (it is accessed within a critical region)
+     std::unordered_set<int>  _floorfieldsBeingCalculated;
+     bool maps_deleted = false; // @todo f.mack remove
+
+     double _threshold;
+     bool _useDistanceToWall;
+};
+
+// very similar to FloorfieldViaFMTrips, but the calculation of floorfields starts at the center of the door only, not on the whole line
+// this happens in order to avoid "door hopping" (for a pedestrian, it is shorter to go to a nearby door and skip half the door width)
+class CentrePointFFViaFMTrips : public virtual FloorfieldViaFMTrips {
+public:
+     virtual void getDirectionToUID(int destID, const long int key, Point& direction, int mode);
+};
+
+#endif // FloorfieldViaFMTrips_H
diff --git a/routing/ff_router_trips/UnivFFviaFMTrips.cpp b/routing/ff_router_trips/UnivFFviaFMTrips.cpp
new file mode 100644
index 00000000..7a99aec6
--- /dev/null
+++ b/routing/ff_router_trips/UnivFFviaFMTrips.cpp
@@ -0,0 +1,1916 @@
+//
+// Created by arne on 5/9/17.
+//
+#define NOMINMAX
+#include <unordered_set>
+#include "UnivFFviaFMTrips.h"
+#include "../../geometry/Line.h"
+#include "../../geometry/Building.h"
+#include "../../geometry/SubRoom.h"
+#include "../../pedestrian/Pedestrian.h"
+#include "mesh/RectGrid.h"
+#include "../../geometry/Goal.h"
+#include "../../geometry/WaitingArea.h"
+
+UnivFFviaFMTrips::~UnivFFviaFMTrips() {
+     if (_grid) delete _grid;
+     //size_t speedsize = _speedFieldSelector.size();
+     for (auto speedPtr : _speedFieldSelector) {
+          if (speedPtr) delete[] speedPtr;
+     }
+     if (_gridCode) delete[] _gridCode;
+     if (_subrooms) delete[] _subrooms;
+
+     std::map<int, double*>::reverse_iterator delIterCost;
+
+     for (delIterCost = _costFieldWithKey.rbegin();
+          delIterCost != _costFieldWithKey.rend();
+          ++delIterCost) {
+          delete[] delIterCost->second;
+     }
+     std::map<int, Point*>::reverse_iterator delIterDir;
+     for (delIterDir = _directionFieldWithKey.rbegin();
+          delIterDir != _directionFieldWithKey.rend();
+          ++delIterDir) {
+          delete[] delIterDir->second;
+     }
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(Room* r, Building* b, double hx, double wallAvoid, bool useWallDistances)
+          : UnivFFviaFMTrips(r, b->GetConfig(), hx, wallAvoid, useWallDistances, b->GetAllGoals()) {
+     _building = b;
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(SubRoom* sr, Building* b, double hx, double wallAvoid, bool useWallDistances)
+          : UnivFFviaFMTrips(sr, b->GetConfig(), hx, wallAvoid, useWallDistances, b->GetAllGoals()) {
+     _building = b;
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(Room* r, Configuration* const conf, double hx, double wallAvoid, bool useWallDistances, std::map<int, Goal*> goals)
+          : UnivFFviaFMTrips(r, conf, hx, wallAvoid, useWallDistances, std::vector<int>(), goals){
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(Room* roomArg, Configuration* const confArg, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors, std::map<int, Goal*> goals) {
+     //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
+     Log->Write("UnivFFviaFMTrips::UnivFFviaFMTrips(Room* roomArg, Configuration* const confArg, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors)\n");
+     _configuration = confArg;
+     _scope = FF_ROOM_SCALE;
+     _room = roomArg->GetID();
+     std::vector<Line> lines;
+     std::map<int, Line> tmpDoors;
+     Line anyDoor = Line{};
+
+     // Loop over all subrooms of roomArg
+     for (auto& subroomMap : roomArg->GetAllSubRooms()) {
+          SubRoom* subRoomPtr = subroomMap.second.get();
+
+          // Save all walls of subroom in lines
+          std::vector<Wall> walls = std::vector<Wall>(subRoomPtr->GetAllWalls());
+          for (auto& wall : walls) {
+               lines.emplace_back((Line)wall);
+          }
+
+          // save all obstacles of subroom in lines
+          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);
+               }
+          }
+
+          // save all transisitions/crossings in tmpDoor
+          const std::vector<Crossing*> tmpCross = subRoomPtr->GetAllCrossings();
+          const std::vector<Transition*> tmpTrans = subRoomPtr->GetAllTransitions();
+
+          int uidNotConst = 0;
+          bool isOpen = false;
+          for (auto& cross : tmpCross) {
+               uidNotConst = cross->GetUniqueID();
+               isOpen = cross->IsOpen();
+               if (!isOpen) {
+                    //will be added twice! is it a problem?
+                    lines.emplace_back((Line)*cross);
+               } else {
+                   anyDoor = Line{*cross};
+                   if (tmpDoors.count(uidNotConst) == 0) {
+                       tmpDoors.emplace(std::make_pair(uidNotConst, (Line) *cross));
+                   }
+               }
+          }
+          for (auto& trans : tmpTrans) {
+               uidNotConst = trans->GetUniqueID();
+               isOpen = trans->IsOpen();
+               if (!isOpen) {
+                    //will be added twice! is it a problem?
+                    lines.emplace_back((Line)*trans);
+               } else {
+                   anyDoor = Line{*trans};
+                   if (tmpDoors.count(uidNotConst) == 0) {
+                       tmpDoors.emplace(std::make_pair(uidNotConst, (Line) *trans));
+                   }
+               }
+          }
+
+//          //save all waiting area walls in tmpdoors
+          for (auto& goalMap : goals){
+               Goal* goal = goalMap.second;
+               if(WaitingArea* wa = dynamic_cast<WaitingArea*>(goal)) {
+                    std::cout << "Testing for subroom " << subRoomPtr->GetSubRoomID() << std::endl;
+                    if ((subRoomPtr->IsInSubRoom(wa->GetCentroid())) && (wa->isOpen())){
+                         for (const Wall wall : wa->GetAllWalls()){
+                              int uid = wall.GetUniqueID();
+                              if (tmpDoors.count(uid) == 0) {
+                                   tmpDoors.emplace(std::make_pair(uid, (Line) wall));
+                              }
+                         }
+                    }
+               }
+          }
+
+          for (auto& door : tmpDoors){
+               std::cout << "uid: " << door.first << " door: " << door.second.toString() << std::endl;
+          }
+
+          //find insidePoint and save it, together with UID
+          Point normalVec = anyDoor.NormalVec();
+          double length = normalVec.Norm();
+          Point midPoint = anyDoor.GetCentre();
+          Point candidate01 = midPoint + (normalVec * 0.25);
+          Point candidate02 = midPoint - (normalVec * 0.25);
+          if (subRoomPtr->IsInSubRoom(candidate01)) {
+               _subRoomPtrTOinsidePoint.emplace(std::make_pair(subRoomPtr, candidate01));
+          } else {
+               //candidate = candidate - (normalVec * 0.25);
+               if (subRoomPtr->IsInSubRoom(candidate02)) {
+                    _subRoomPtrTOinsidePoint.emplace(std::make_pair(subRoomPtr, candidate02));
+               } else {
+                    Log->Write("ERROR:\t In UnivFF InsidePoint Analysis");
+                    bool a = subRoomPtr->IsInSubRoom(candidate01);
+                    bool b = subRoomPtr->IsInSubRoom(candidate02);
+                    a = b && a; //ignore this line. only to have a codeline after initialization of bools (to place a breakpoint)
+               }
+          }
+          //_subroomUIDtoSubRoomPtr.emplace(std::make_pair(subRoomPtr->GetUID(), subRoomPtr));
+     }
+     //this will interpret "useWallDistances" as best as possible. Users should clearify with "setSpeedMode" before calling "AddTarget"
+     if (useWallDistances) {
+          create(lines, tmpDoors, wantedDoors, FF_WALL_AVOID, hx, wallAvoid, useWallDistances);
+     } else {
+          create(lines, tmpDoors, wantedDoors, FF_HOMO_SPEED, hx, wallAvoid, useWallDistances);
+     }
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(SubRoom* sr, Configuration* const conf, double hx, double wallAvoid, bool useWallDistances, std::map<int, Goal*> goals)
+          : UnivFFviaFMTrips(sr, conf, hx, wallAvoid, useWallDistances, std::vector<int>(), goals){
+}
+
+UnivFFviaFMTrips::UnivFFviaFMTrips(SubRoom* subRoomArg, Configuration* const confArg, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors, std::map<int, Goal*> goals) {
+     //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
+
+     Log->Write("UnivFFviaFMTrips::UnivFFviaFMTrips(SubRoom* subRoomArg, Configuration* const confArg, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors))");
+
+     _configuration = confArg;
+     _scope = FF_SUBROOM_SCALE;
+     _room = subRoomArg->GetRoomID();
+     std::vector<Line> lines;
+     std::map<int, Line> tmpDoors;
+
+     std::vector<Wall> walls = std::vector<Wall> (subRoomArg->GetAllWalls());
+     for (auto& wall : walls) {
+          lines.emplace_back((Line)wall);
+     }
+
+     std::vector<Obstacle*> tmpObsPtrVec = subRoomArg->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 = subRoomArg->GetAllCrossings();
+     const std::vector<Transition*> tmpTrans = subRoomArg->GetAllTransitions();
+
+     int uidNotConst = 0;
+     bool isOpen = false;
+     for (auto& cross : tmpCross) {
+          uidNotConst = cross->GetUniqueID();
+          isOpen = cross->IsOpen();
+          if (!isOpen) {
+               lines.emplace_back((Line)*cross);
+          } else {
+               tmpDoors.emplace(std::make_pair(uidNotConst, (Line) *cross));
+          }
+     }
+     for (auto& trans : tmpTrans) {
+          uidNotConst = trans->GetUniqueID();
+          isOpen = trans->IsOpen();
+          if (!isOpen) {
+               lines.emplace_back((Line)*trans);
+          } else {
+               tmpDoors.emplace(std::make_pair(uidNotConst, (Line) *trans));
+          }
+     }
+
+     _building->GetAllGoals();
+     //find insidePoint and save it, together with UID
+    Line anyDoor = Line{(--tmpDoors.end())->second};
+    Point normalVec = anyDoor.NormalVec();
+    double length = normalVec.Norm();
+    Point midPoint = anyDoor.GetCentre();
+    Point candidate01 = midPoint + (normalVec * 0.25);
+    Point candidate02 = midPoint - (normalVec * 0.25);
+    if (subRoomArg->IsInSubRoom(candidate01)) {
+        _subRoomPtrTOinsidePoint.emplace(std::make_pair(subRoomArg, candidate01));
+    } else {
+        //candidate = candidate - (normalVec * 0.25);
+        if (subRoomArg->IsInSubRoom(candidate02)) {
+            _subRoomPtrTOinsidePoint.emplace(std::make_pair(subRoomArg, candidate02));
+        } else {
+            Log->Write("ERROR:\t In UnivFF InsidePoint Analysis");
+            bool a = subRoomArg->IsInSubRoom(candidate01);
+            bool b = subRoomArg->IsInSubRoom(candidate02);
+            a = b && a;
+        }
+    }
+
+     //_subroomUIDtoSubRoomPtr.emplace(std::make_pair(subRoomArg->GetUID(), subRoomArg));
+
+     //this will interpret "useWallDistances" as best as possible. Users should clearify with "setSpeedMode" before calling "AddTarget"
+     if (useWallDistances) {
+          create(lines, tmpDoors, wantedDoors, FF_WALL_AVOID, hx, wallAvoid, useWallDistances);
+     } else {
+          create(lines, tmpDoors, wantedDoors, FF_HOMO_SPEED, hx, wallAvoid, useWallDistances);
+     }
+}
+
+void UnivFFviaFMTrips::create(std::vector<Line>& walls, std::map<int, Line>& doors, std::vector<int> targetUIDs, int mode,
+                         double spacing, double wallAvoid, bool useWallDistances) {
+
+     _wallAvoidDistance = wallAvoid;
+     _useWallDistances = useWallDistances;
+     _speedmode = mode;
+
+     //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.emplace(_speedFieldSelector.begin()+INITIAL_SPEED, new double[_nPoints]);
+     std::fill(_speedFieldSelector[INITIAL_SPEED], _speedFieldSelector[INITIAL_SPEED]+_nPoints, 1.0);
+
+     _speedFieldSelector.emplace(_speedFieldSelector.begin()+REDU_WALL_SPEED, nullptr);
+     _speedFieldSelector.emplace(_speedFieldSelector.begin()+PED_SPEED, nullptr);
+
+     //mark Inside areas (dont write outside areas)
+     for (auto subRoomPointPair : _subRoomPtrTOinsidePoint) {
+          markSubroom(subRoomPointPair.second, subRoomPointPair.first);
+     }
+
+     //allocate _modifiedSpeed
+     if ((_speedmode == FF_WALL_AVOID) || (useWallDistances)) {
+          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
+          //init costarray
+          for (int i = 0; i < _nPoints; ++i) {
+               if (_gridCode[i] == WALL) {
+                    cost_alias_walldistance[i] = magicnum(WALL_ON_COSTARRAY);
+               } else {
+                    cost_alias_walldistance[i] = magicnum(UNKNOWN_COST);
+               }
+          }
+          drawLinesOnWall(walls, cost_alias_walldistance, magicnum(TARGET_REGION));
+          calcDF(cost_alias_walldistance, gradient_alias_walldirection, _speedFieldSelector[INITIAL_SPEED]);
+          //_uids.emplace_back(0);
+
+          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
+          createReduWallSpeed(temp_reduWallSpeed);
+     }
+
+     // parallel call
+     if (!targetUIDs.empty()) {
+          addTargetsParallel(targetUIDs);
+     }
+}
+
+void UnivFFviaFMTrips::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 UnivFFviaFMTrips::processGeometry(std::vector<Line>&walls, std::map<int, Line>& doors) {
+     for (int i = 0; i < _nPoints; ++i) {
+          _gridCode[i] = OUTSIDE;
+     }
+
+     for (auto mapentry : doors) {
+          _doors.insert(mapentry);
+     }
+     //_doors = doors;
+
+     drawLinesOnGrid<int>(walls, _gridCode, WALL);
+     drawLinesOnGrid(doors, _gridCode); //UIDs of doors will be drawn on _gridCode
+}
+
+void UnivFFviaFMTrips::markSubroom(const Point& insidePoint, SubRoom* const value) {
+     //value must not be nullptr. it would lead to infinite loop
+     if (!value) return;
+
+     if(!_grid->includesPoint(insidePoint)) return;
+
+     //alloc mem if needed
+     if (!_subrooms) {
+          _subrooms = new SubRoom*[_nPoints];
+          for (long i = 0; i < _nPoints; ++i) {
+               _subrooms[i] = nullptr;
+          }
+     }
+
+     //init start
+     _subrooms[_grid->getKeyAtPoint(insidePoint)] = value;
+     _gridCode[_grid->getKeyAtPoint(insidePoint)] = INSIDE;
+
+     std::unordered_set<long> wavefront;
+     wavefront.reserve(_nPoints);
+
+     directNeighbor _neigh = _grid->getNeighbors(_grid->getKeyAtPoint(insidePoint));
+     long aux = _neigh.key[0];
+     if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE)) {
+          wavefront.insert(aux);
+          _subrooms[aux] = value;
+     }
+
+     aux = _neigh.key[1];
+     if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE)) {
+          wavefront.insert(aux);
+          _subrooms[aux] = value;
+     }
+
+     aux = _neigh.key[2];
+     if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE)) {
+          wavefront.insert(aux);
+          _subrooms[aux] = value;
+     }
+
+     aux = _neigh.key[3];
+     if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE)) {
+          wavefront.insert(aux);
+          _subrooms[aux] = value;
+     }
+
+     while(!wavefront.empty()) {
+          long current = *(wavefront.begin());
+          wavefront.erase(current);
+          _gridCode[current] = INSIDE;
+
+          _neigh = _grid->getNeighbors(current);
+          aux = _neigh.key[0];
+          if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE) && _subrooms[aux] == nullptr) {
+               wavefront.insert(aux);
+               _subrooms[aux] = value;
+          }
+
+          aux = _neigh.key[1];
+          if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE) && _subrooms[aux] == nullptr) {
+               wavefront.insert(aux);
+               _subrooms[aux] = value;
+          }
+
+          aux = _neigh.key[2];
+          if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE) && _subrooms[aux] == nullptr) {
+               wavefront.insert(aux);
+               _subrooms[aux] = value;
+          }
+
+          aux = _neigh.key[3];
+          if ((aux != -2) && (_gridCode[aux] == INSIDE || _gridCode[aux] == OUTSIDE) && _subrooms[aux] == nullptr) {
+               wavefront.insert(aux);
+               _subrooms[aux] = value;
+          }
+     }
+}
+
+void UnivFFviaFMTrips::createReduWallSpeed(double* reduWallSpeed){
+     double factor = 1/_wallAvoidDistance;
+     double* wallDstAlias = _costFieldWithKey[0];
+
+     for (long int i = 0; i < _nPoints; ++i) {
+          if (wallDstAlias[i] > 0.) {
+               reduWallSpeed[i] = (wallDstAlias[i] > _wallAvoidDistance) ? 1.0 : (factor * wallDstAlias[i]);
+          }
+     }
+}
+
+void UnivFFviaFMTrips::recreateAllForQuickest() {
+     //allocate if neccessary (should not be!)
+     for (int doorUID : _uids) {
+          if (!_costFieldWithKey[doorUID]) {
+               _costFieldWithKey[doorUID] = new double[_nPoints];
+          }
+          if (_user == DISTANCE_MEASUREMENTS_ONLY) {
+               if (_directionFieldWithKey.count(doorUID) != 0 && _directionFieldWithKey[doorUID]){
+                    delete[] _directionFieldWithKey[doorUID];
+               }
+               _directionFieldWithKey[doorUID] = nullptr;
+          }
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               //check if not in map OR (in map but) nullptr)
+               if ((_directionFieldWithKey.count(doorUID) == 0) || (!_directionFieldWithKey[doorUID])) {
+                    _directionFieldWithKey[doorUID] = new Point[_nPoints];
+               }
+          }
+     }
+
+     //parallel region
+#pragma omp parallel
+     {
+#pragma omp for
+          for (signed int i = 0; i < _doors.size(); ++i) {
+               auto doorPair = _doors.begin();
+               std::advance(doorPair, i);
+               addTarget(doorPair->first, _costFieldWithKey[doorPair->first], _directionFieldWithKey[doorPair->first]);
+          }
+     };
+}
+
+void UnivFFviaFMTrips::createPedSpeed(Pedestrian *const *pedsArg, int nsize, int modechoice, double radius) {
+     long int delta = radius / _grid->Gethx();
+     long int posIndex = 0;
+     long int pos_i = 0;
+     long int pos_j = 0;
+     long int i_start = 0;
+     long int j_start = 0;
+     long int i_end = 0;
+     long int j_end = 0;
+     long int iStride = _grid->GetiMax();
+     double indexDistance = 0.0;
+     double newWaveSpeed = 0.0;
+
+//     if (nsize == 0) {
+//          Log->Write("WARNING: \tcreatePedSpeed: nsize is ZERO");
+//     } else {
+//          Log->Write("INFO: \t\tNumber of Peds used in createPedSpeed: %d",nsize);
+//     }
+
+     if ((modechoice == quickest) && (!_speedFieldSelector[PED_SPEED])) {
+          _speedFieldSelector[PED_SPEED] = new double[_grid->GetnPoints()];
+     }
+
+     //we assume, that this function is only used by router and is not using REDU_WALL_SPEED
+     for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+          _speedFieldSelector[PED_SPEED][i] = _speedFieldSelector[INITIAL_SPEED][i];
+     }
+     if (_speedFieldSelector[REDU_WALL_SPEED] && _mode == LINESEGMENT) { //indicates, that the direction strat is using it
+          for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+               _speedFieldSelector[PED_SPEED][i] = _speedFieldSelector[REDU_WALL_SPEED][i];
+          }
+     }
+
+     for (int i = 0; i < nsize; ++i) {
+          //the following check is not 3D proof, we require the caller of this function to provide a list with "valid"
+          //pedestrian-pointer
+          if (!_grid->includesPoint(pedsArg[i]->GetPos())) {
+               continue;
+          }
+
+          newWaveSpeed = pedsArg[i]->GetEllipse().GetV().Norm()/pedsArg[i]->GetEllipse().GetV0(); //   (current speed)/(desired speed)
+          newWaveSpeed *= 0.8;
+          if (newWaveSpeed < 0.1) {
+               newWaveSpeed = 0.1;
+          }
+          posIndex = _grid->getKeyAtPoint(pedsArg[i]->GetPos());
+          pos_i = _grid->get_i_fromKey(posIndex);
+          pos_j = _grid->get_j_fromKey(posIndex);
+
+          i_start = ((pos_i - delta) < 0)               ? 0               : (pos_i - delta);
+          i_end   = ((pos_i + delta) >= iStride) ? iStride-1 : (pos_i + delta);
+
+          j_start = ((pos_j - delta) < 0)               ? 0               : (pos_j - delta);
+          j_end   = ((pos_j + delta) >= _grid->GetjMax()) ? _grid->GetjMax()-1 : (pos_j + delta);
+
+          for     (long int curr_i = i_start; curr_i < i_end; ++curr_i) {
+               for (long int curr_j = j_start; curr_j < j_end; ++curr_j) {
+                    //indexDistance holds the square
+                    indexDistance = ( (curr_i - pos_i)*(curr_i - pos_i) + (curr_j - pos_j)*(curr_j - pos_j) );
+
+                    if (indexDistance < (delta*delta)) {
+                         //_speedFieldSelector[PED_SPEED][curr_j*iStride + curr_i] = 0.2;
+                         _speedFieldSelector[PED_SPEED][curr_j*iStride + curr_i] = std::min(newWaveSpeed, _speedFieldSelector[PED_SPEED][curr_j*iStride + curr_i]);
+                    }
+               }
+          }
+     }
+}
+
+void UnivFFviaFMTrips::finalizeTargetLine(const int uid, const Line& line, Point* target, Point& value) {
+    // 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
+
+    long int goodneighbor;
+    directNeighbor neigh;
+
+
+    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] == uid) {
+            /* //find a good neighborvalue
+             neigh = _grid->getNeighbors(jDot*iMax + iDot);
+             if ((neigh.key[0] >= 0) && (_gridCode[neigh.key[0]] == INSIDE)) {
+                 goodneighbor = neigh.key[0];
+             } else if ((neigh.key[1] >= 0) && (_gridCode[neigh.key[1]] == INSIDE)) {
+                 goodneighbor = neigh.key[1];
+             } else if ((neigh.key[2] >= 0) && (_gridCode[neigh.key[2]] == INSIDE)) {
+                 goodneighbor = neigh.key[2];
+             } else if ((neigh.key[3] >= 0) && (_gridCode[neigh.key[3]] == INSIDE)) {
+                 goodneighbor = neigh.key[3];
+             } else {
+                 //ERROR - should have an inside neighbor
+                 Log->Write("ERROR:\t In finalizeTargetLine");
+             }
+             //write the value on targetline
+             if ((target[goodneighbor]._x == 0.) && (target[goodneighbor]._y == 0.)) {
+                 //ERROR - should have a true vector
+                 Log->Write("ERROR:\t (0;0) In finalizeTargetLine");
+             }*/
+            target[jDot * iMax + iDot] = value;
+        } else if (_gridCode[jDot*iMax + iDot] == WALL) {
+            //do nothing
+        } else {
+            target[jDot * iMax + iDot] = value;
+            //Log->Write("ERROR:\t in finalizingTargetLine");
+        }
+        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] == uid) {
+                /*//find a good neighborvalue
+                neigh = _grid->getNeighbors(jDot*iMax + iDot);
+                if ((neigh.key[0] >= 0) && (_gridCode[neigh.key[0]] == INSIDE)) {
+                    goodneighbor = neigh.key[0];
+                } else if ((neigh.key[1] >= 0) && (_gridCode[neigh.key[1]] == INSIDE)) {
+                    goodneighbor = neigh.key[1];
+                } else if ((neigh.key[2] >= 0) && (_gridCode[neigh.key[2]] == INSIDE)) {
+                    goodneighbor = neigh.key[2];
+                } else if ((neigh.key[3] >= 0) && (_gridCode[neigh.key[3]] == INSIDE)) {
+                    goodneighbor = neigh.key[3];
+                } else {
+                    //ERROR - should have an inside neighbor
+                    Log->Write("ERROR:\t In finalizeTargetLine");
+                }
+                //write the value on targetline
+                if ((target[goodneighbor]._x == 0.) && (target[goodneighbor]._y == 0.)) {
+                    //ERROR - should have a true vector
+                    Log->Write("ERROR:\t (0;0) In finalizeTargetLine");
+                }*/
+                target[jDot * iMax + iDot] = value;
+            } else if (_gridCode[jDot*iMax + iDot] == WALL) {
+                //do nothing
+            } else {
+                target[jDot * iMax + iDot] = value;
+                //Log->Write("ERROR:\t in finalizingTargetLine");
+            }
+        }
+    } else {
+        if(deltaY>=0) {
+            iDot = iStart;
+            jDot = jStart;
+            ye = jEnd;
+        } else {
+            iDot = iEnd;
+            jDot = jEnd;
+            ye = jStart;
+        }
+        if (_gridCode[jDot*iMax + iDot] == uid) {
+            /*//find a good neighborvalue
+            neigh = _grid->getNeighbors(jDot*iMax + iDot);
+            if ((neigh.key[0] >= 0) && (_gridCode[neigh.key[0]] == INSIDE)) {
+                goodneighbor = neigh.key[0];
+            } else if ((neigh.key[1] >= 0) && (_gridCode[neigh.key[1]] == INSIDE)) {
+                goodneighbor = neigh.key[1];
+            } else if ((neigh.key[2] >= 0) && (_gridCode[neigh.key[2]] == INSIDE)) {
+                goodneighbor = neigh.key[2];
+            } else if ((neigh.key[3] >= 0) && (_gridCode[neigh.key[3]] == INSIDE)) {
+                goodneighbor = neigh.key[3];
+            } else {
+                //ERROR - should have an inside neighbor
+                Log->Write("ERROR:\t In finalizeTargetLine");
+            }
+            //write the value on targetline
+            if ((target[goodneighbor]._x == 0.) && (target[goodneighbor]._y == 0.)) {
+                //ERROR - should have a true vector
+                Log->Write("ERROR:\t (0;0) In finalizeTargetLine");
+            }*/
+            target[jDot * iMax + iDot] = value;
+        } else if (_gridCode[jDot*iMax + iDot] == WALL) {
+            //do nothing
+        }  else {
+            target[jDot * iMax + iDot] = value;
+            //Log->Write("ERROR:\t in finalizingTargetLine");
+        }
+        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] == uid) {
+                /*//find a good neighborvalue
+                neigh = _grid->getNeighbors(jDot*iMax + iDot);
+                if ((neigh.key[0] >= 0) && (_gridCode[neigh.key[0]] == INSIDE)) {
+                    goodneighbor = neigh.key[0];
+                } else if ((neigh.key[1] >= 0) && (_gridCode[neigh.key[1]] == INSIDE)) {
+                    goodneighbor = neigh.key[1];
+                } else if ((neigh.key[2] >= 0) && (_gridCode[neigh.key[2]] == INSIDE)) {
+                    goodneighbor = neigh.key[2];
+                } else if ((neigh.key[3] >= 0) && (_gridCode[neigh.key[3]] == INSIDE)) {
+                    goodneighbor = neigh.key[3];
+                } else {
+                    //ERROR - should have an inside neighbor
+                    Log->Write("ERROR:\t In finalizeTargetLine");
+                }
+                //write the value on targetline
+                if ((target[goodneighbor]._x == 0.) && (target[goodneighbor]._y == 0.)) {
+                    //ERROR - should have a true vector
+                    Log->Write("ERROR:\t (0;0) In finalizeTargetLine");
+                }*/
+                target[jDot * iMax + iDot] = value;
+            } else if (_gridCode[jDot*iMax + iDot] == WALL) {
+                //do nothing
+            } else {
+                target[jDot * iMax + iDot] = value;
+                //Log->Write("ERROR:\t in finalizingTargetLine");
+            }
+        }
+    }
+}
+
+void UnivFFviaFMTrips::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 UnivFFviaFMTrips::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 UnivFFviaFMTrips::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
+
+template <typename T>
+void UnivFFviaFMTrips::drawLinesOnWall(std::vector<Line>& wallArg, T* const target, const T value) { //no init, plz init elsewhere
+
+     for (auto& line : wallArg) {
+          drawLinesOnWall(line, target, value);
+     } //loop over all walls
+
+} //drawLinesOnWall
+
+template <typename T>
+void UnivFFviaFMTrips::drawLinesOnWall(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] != 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] != 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] != 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] != CLOSED_CROSSING) && (_gridCode[jDot*iMax + iDot] != CLOSED_TRANSITION)) {
+                    target[jDot * iMax + iDot] = value;
+               }
+          }
+     }
+} //drawLinesOnWall
+
+void UnivFFviaFMTrips::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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (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) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+               calcCost(aux, costOutput, directionOutput, speed);
+               trialfield.emplace(aux);
+               //trialfield2.emplace(aux);
+          }
+     }
+}
+
+void UnivFFviaFMTrips::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 (!dir) {
+               return;
+          }
+          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();
+          return;
+     }
+
+     if (row == DBL_MAX) { //one sided update with col
+          cost[key] = onesidedCalc(col, _grid->Gethy()/speed[key]);
+          //flag[key] = FM_SINGLE;
+          if (!dir) {
+               return;
+          }
+          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 (!dir) {
+               return;
+          }
+          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();
+}
+
+void UnivFFviaFMTrips::calcDF(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) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+                    calcDist(aux, costOutput, directionOutput, speed);
+                    trialfield.emplace(aux);
+                    //trialfield2.emplace(aux);
+               }
+               aux = local_neighbor.key[1];
+               if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+                    calcDist(aux, costOutput, directionOutput, speed);
+                    trialfield.emplace(aux);
+                    //trialfield2.emplace(aux);
+               }
+               aux = local_neighbor.key[2];
+               if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+                    calcDist(aux, costOutput, directionOutput, speed);
+                    trialfield.emplace(aux);
+                    //trialfield2.emplace(aux);
+               }
+               aux = local_neighbor.key[3];
+               if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+                    calcDist(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) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+               calcDist(aux, costOutput, directionOutput, speed);
+               trialfield.emplace(aux);
+               //trialfield2.emplace(aux);
+          }
+          aux = local_neighbor.key[1];
+          if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+               calcDist(aux, costOutput, directionOutput, speed);
+               trialfield.emplace(aux);
+               //trialfield2.emplace(aux);
+          }
+          aux = local_neighbor.key[2];
+          if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+               calcDist(aux, costOutput, directionOutput, speed);
+               trialfield.emplace(aux);
+               //trialfield2.emplace(aux);
+          }
+          aux = local_neighbor.key[3];
+          if ((aux != -2) && (_gridCode[aux] != WALL) && (_gridCode[aux] != OUTSIDE) && (costOutput[aux] < 0.0)) {
+               calcDist(aux, costOutput, directionOutput, speed);
+               trialfield.emplace(aux);
+               //trialfield2.emplace(aux);
+          }
+     }
+}
+
+void UnivFFviaFMTrips::calcDist(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
+          )                                                              //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
+           &&
+          (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
+          )
+     {
+          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
+
+          (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 (!dir) {
+               return;
+          }
+          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();
+          return;
+     }
+
+     if (row == DBL_MAX) { //one sided update with col
+          cost[key] = onesidedCalc(col, _grid->Gethy()/speed[key]);
+          //flag[key] = FM_SINGLE;
+          if (!dir) {
+               return;
+          }
+          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 (!dir) {
+               return;
+          }
+          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 UnivFFviaFMTrips::onesidedCalc(double xy, double hDivF) {
+     //if ( (xy+hDivF) > 10000) std::cerr << "error in onesided " << xy << std::endl;
+     return xy + hDivF;
+}
+
+inline double UnivFFviaFMTrips::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 UnivFFviaFMTrips::addTarget(const int uid, double* costarrayDBL, Point* gradarrayPt) {
+     if (_doors.count(uid) == 0) {
+          Log->Write("ERROR: \tCould not find door with uid %d in Room %d", uid, _room);
+          return;
+     }
+     Line tempTargetLine = Line(_doors[uid]);
+     Point tempCenterPoint = Point(tempTargetLine.GetCentre());
+     if (_mode == LINESEGMENT) {
+          if (tempTargetLine.GetLength() > 0.6) { //shorten line from both Points to avoid targeting edges of real door
+               const Point &p1 = tempTargetLine.GetPoint1();
+               const Point &p2 = tempTargetLine.GetPoint2();
+               double length = tempTargetLine.GetLength();
+               double u = 0.2 / length;
+               tempTargetLine = Line(p1 + (p2 - p1) * u, p1 + (p2 - p1) * (1 - u), 0);
+          } else if (tempTargetLine.GetLength() > 0.2) {
+               const Point &p1 = tempTargetLine.GetPoint1();
+               const Point &p2 = tempTargetLine.GetPoint2();
+               double length = tempTargetLine.GetLength();
+               double u = 0.05 / length;
+               tempTargetLine = Line(p1 + (p2 - p1) * u, p1 + (p2 - p1) * (1 - u), 0);
+          }
+     }
+
+     //this allocation must be on shared heap! to be accessible by any thread later (should be shared in openmp)
+     double* newArrayDBL = (costarrayDBL)? costarrayDBL : new double[_nPoints];
+     Point* newArrayPt = nullptr;
+     if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+          newArrayPt = (gradarrayPt)? gradarrayPt : new Point[_nPoints];
+     }
+
+     if ((_costFieldWithKey[uid]) && (_costFieldWithKey[uid] != costarrayDBL))
+          delete[] _costFieldWithKey[uid];
+     _costFieldWithKey[uid] = 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[uid]) && (_directionFieldWithKey[uid] != gradarrayPt))
+          delete[] _directionFieldWithKey[uid];
+     if (newArrayPt)
+          _directionFieldWithKey[uid] = newArrayPt;
+
+     //initialize start area
+     if (_mode == LINESEGMENT) {
+          drawLinesOnGrid(tempTargetLine, newArrayDBL, magicnum(TARGET_REGION));
+     }
+     if (_mode == CENTERPOINT) {
+          newArrayDBL[_grid->getKeyAtPoint(tempCenterPoint)] = magicnum(TARGET_REGION);
+     }
+
+     if (_speedmode == FF_WALL_AVOID) {
+          calcFF(newArrayDBL, newArrayPt, _speedFieldSelector[REDU_WALL_SPEED]);
+     } else if (_speedmode == FF_HOMO_SPEED) {
+          calcFF(newArrayDBL, newArrayPt, _speedFieldSelector[INITIAL_SPEED]);
+     } else if (_speedmode == FF_PED_SPEED) {
+          calcFF(newArrayDBL, newArrayPt, _speedFieldSelector[PED_SPEED]);
+     }
+
+     //the rest of the door must be initialized if centerpoint was used. else ff_router will have probs getting localDist
+     if (_mode == CENTERPOINT) {
+         drawLinesOnGrid(tempTargetLine, newArrayDBL, magicnum(TARGET_REGION));
+     }
+     //the directional field is yet undefined on the target line itself. we will use neighboring vector to help agents
+     //to cross the line
+     if (newArrayPt) {
+         Point passvector = tempTargetLine.NormalVec();
+         Point trial = tempTargetLine.GetCentre() - passvector * 0.25;
+         Point trial2 = tempTargetLine.GetCentre() + passvector * 0.25;
+         if ((_grid->includesPoint(trial)) && (_gridCode[_grid->getKeyAtPoint(trial)] == INSIDE)) {
+             finalizeTargetLine(uid, _doors[uid], newArrayPt, passvector);
+             finalizeTargetLine(uid, tempTargetLine, newArrayPt, passvector);
+         } else if ((_grid->includesPoint(trial2)) && (_gridCode[_grid->getKeyAtPoint(trial2)] == INSIDE)) {
+             passvector = passvector * -1.0;
+             finalizeTargetLine(uid, _doors[uid], newArrayPt, passvector);
+             finalizeTargetLine(uid, tempTargetLine, newArrayPt, passvector);
+
+         } else {
+             Log->Write("ERROR:\t in addTarget: calling finalizeTargetLine");
+         }
+//         for (long int i = 0; i < _grid->GetnPoints(); ++i) {
+//             if ((_gridCode[i] != OUTSIDE) && (_gridCode[i] != WALL) && (newArrayPt[i] == Point(0.0, 0.0) )) {
+//                 Log->Write("Mist");
+//             }
+//         }
+     }
+#pragma omp critical(_uids)
+     _uids.emplace_back(uid);
+}
+
+void UnivFFviaFMTrips::addTarget(const int uid, Line* door, double* costarray, Point* gradarray){
+     if (_doors.count(uid) == 0) {
+          _doors.emplace(std::make_pair(uid, *door));
+     }
+     addTarget(uid, costarray, gradarray);
+}
+
+void UnivFFviaFMTrips::addAllTargets() {
+     for (auto uidmap : _doors) {
+          addTarget(uidmap.first);
+     }
+}
+
+void UnivFFviaFMTrips::addAllTargetsParallel() {
+     //Reason: freeing and reallocating takes time. We do not use already allocated memory, because we do not know if it
+     //        is shared memory. Maybe this is not neccessary - maybe reconsider. This way, it is safe. If this function
+     //        is called from a parallel region, we all go to hell.
+     //free old memory
+     for (auto memoryDBL : _costFieldWithKey) {
+          if (memoryDBL.first == 0) continue;          //do not free distancemap
+          if (memoryDBL.second) delete[](memoryDBL.second);
+     }
+     for (auto memoryPt : _directionFieldWithKey) {
+          if (memoryPt.first == 0) continue;           //do not free walldirectionmap
+          if (memoryPt.second) delete[](memoryPt.second);
+     }
+     //allocate new memory
+     for (auto uidmap : _doors) {
+          _costFieldWithKey[uidmap.first] = new double[_nPoints];
+          if (_user == DISTANCE_MEASUREMENTS_ONLY) {
+               _directionFieldWithKey[uidmap.first] = nullptr;
+          }
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[uidmap.first] = new Point[_nPoints];
+          }
+     }
+
+     //parallel region
+#pragma omp parallel
+     {
+#pragma omp for
+          for (signed int i = 0; i < _doors.size(); ++i) {
+               auto doorPair = _doors.begin();
+               std::advance(doorPair, i);
+               addTarget(doorPair->first, _costFieldWithKey[doorPair->first], _directionFieldWithKey[doorPair->first]);
+          }
+     };
+}
+
+void UnivFFviaFMTrips::addTargetsParallel(std::vector<int> wantedDoors) {
+     //free old memory (but not the distancemap with key == 0)
+     for (int targetUID : wantedDoors) {
+          if ((targetUID != 0) && _costFieldWithKey.count(targetUID) && _costFieldWithKey[targetUID]) {
+               delete[] _costFieldWithKey[targetUID];
+          }
+          if ((targetUID != 0) && _directionFieldWithKey.count(targetUID) && _directionFieldWithKey[targetUID]) {
+               delete[] _directionFieldWithKey[targetUID];
+          }
+     }
+     //allocate new memory
+     for (int targetUID : wantedDoors) {
+          _costFieldWithKey[targetUID] = new double[_nPoints];
+          if (_user == DISTANCE_MEASUREMENTS_ONLY) {
+               _directionFieldWithKey[targetUID] = nullptr;
+          }
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[targetUID] = new Point[_nPoints];
+          }
+     }
+
+     //parallel region
+#pragma omp parallel
+     {
+#pragma omp for
+          for (signed int i = 0; i < wantedDoors.size(); ++i) {
+               auto doorUID = wantedDoors.begin();
+               std::advance(doorUID, i);
+               addTarget(*doorUID, _costFieldWithKey[*doorUID], _directionFieldWithKey[*doorUID]);
+          }
+     };
+}
+
+SubRoom** UnivFFviaFMTrips::getSubRoomFF(){
+     return _subrooms;
+}
+
+SubRoom* UnivFFviaFMTrips::getSubRoom(const Point& pos){
+     if (!_subrooms) return nullptr;
+     if (!_grid->includesPoint(pos)) return nullptr;
+
+     long key = _grid->getKeyAtPoint(pos);
+     return _subrooms[key];
+}
+
+std::vector<int> UnivFFviaFMTrips::getKnownDoorUIDs(){
+     return _uids;
+}
+
+void UnivFFviaFMTrips::setUser(int userArg) {
+     _user=userArg;
+}
+
+void UnivFFviaFMTrips::setMode(int modeArg) {
+     _mode=modeArg;
+}
+
+void UnivFFviaFMTrips::setSpeedMode(int speedModeArg) {
+     _speedmode = speedModeArg;
+     if (_speedmode == FF_PED_SPEED && !_speedFieldSelector[PED_SPEED]) {
+          _speedFieldSelector[PED_SPEED] = new double[_nPoints];
+     }
+}
+
+
+void UnivFFviaFMTrips::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(_configuration->GetProjectRootDir()+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(_grid->GetnPoints()) << std::endl;
+    file << "SCALARS GCode float 1" << std::endl;
+    file << "LOOKUP_TABLE default" << std::endl;
+    if (!_gridCode) {
+         return;
+    }
+    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
+         }
+    }
+
+    if (_subrooms) {
+         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;
+              }
+         }
+    }
+
+    if (!targetID.empty()) {
+         for (unsigned int iTarget = 0; iTarget < targetID.size(); ++iTarget) {
+              if (_costFieldWithKey.count(targetID[iTarget]) == 0) {
+                   continue;
+              }
+              double *costarray = _costFieldWithKey[targetID[iTarget]];
+
+              Log->Write("%s: target number %d: UID %d", filename.c_str(), iTarget, targetID[iTarget]);
+
+//              std::string name = _building->GetTransOrCrossByUID(targetID[iTarget])->GetCaption() + "-" +
+//                                                                                          std::to_string(targetID[iTarget]);
+
+              std::string name = std::to_string(targetID[iTarget]);
+
+              std::replace(name.begin(), name.end(), ' ', '_');
+
+              if (!costarray) {
+                   continue;
+              }
+
+              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;
+              }
+
+              if (_directionFieldWithKey.count(targetID[iTarget]) == 0) {
+                   continue;
+              }
+
+              Point *gradarray = _directionFieldWithKey[targetID[iTarget]];
+              if (gradarray == nullptr) {
+                   continue;
+              }
+
+
+              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;
+              }
+
+
+         }
+    }
+    file.close();
+}
+
+//mode is argument, which should not be needed, the info is stored in members like speedmode, ...
+double UnivFFviaFMTrips::getCostToDestination(const int destID, const Point& position, int mode) {
+    assert(_grid->includesPoint(position));
+    long int key = _grid->getKeyAtPoint(position);
+    if ((_gridCode[key] == OUTSIDE) || (_gridCode[key] == WALL)) {
+        //bresenham line (treppenstruktur) at middle and calculated centre of line are on different gridpoints
+        //find a key that belongs domain (must be one left or right and second one below or above)
+        if ((key+1 <= _grid->GetnPoints()) && (_gridCode[key+1] != OUTSIDE) && (_gridCode[key+1] != WALL)) {
+            key = key+1;
+        } else if ((key-1 >= 0) && (_gridCode[key-1] != OUTSIDE) && (_gridCode[key-1] != WALL)) {
+            key = key - 1;
+        } else if ((key >= _grid->GetiMax()) && (_gridCode[key-_grid->GetiMax()] != OUTSIDE) && (_gridCode[key-_grid->GetiMax()] != WALL)) {
+            key = key - _grid->GetiMax();
+        } else if ((key < _grid->GetnPoints()-_grid->GetiMax()) && (_gridCode[key+_grid->GetiMax()] != OUTSIDE) && (_gridCode[key+_grid->GetiMax()] != WALL)) {
+            key = key + _grid->GetiMax();
+        } else {
+            Log->Write("ERROR:\t In getCostToDestination(3 args)");
+        }
+    }
+     if (_costFieldWithKey.count(destID)==1 && _costFieldWithKey[destID]) {
+          return _costFieldWithKey[destID][key];
+     } else if (_directCalculation && _doors.count(destID) > 0) {
+          _costFieldWithKey[destID] = new double[_nPoints];
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[destID] = new Point[_nPoints];
+          } else {
+               _directionFieldWithKey[destID] = nullptr;
+          }
+
+          addTarget(destID, _costFieldWithKey[destID], _directionFieldWithKey[destID]);
+          return getCostToDestination(destID, position, mode);
+     } else if (!_directCalculation && _doors.count(destID) > 0) {
+          //omp critical
+#pragma omp critical(UnivFFviaFMTrips_toDo)
+          _toDo.emplace_back(destID);
+     }
+     return DBL_MAX;
+}
+
+double UnivFFviaFMTrips::getCostToDestination(const int destID, const Point& position) {
+     assert(_grid->includesPoint(position));
+    long int key = _grid->getKeyAtPoint(position);
+    if ((_gridCode[key] == OUTSIDE) || (_gridCode[key] == WALL)) {
+        //bresenham line (treppenstruktur) getKeyAtPoint yields gridpoint next to edge, although position is on edge
+        //find a key that belongs domain (must be one left or right and second one below or above)
+        if ((key+1 <= _grid->GetnPoints()) && (_gridCode[key+1] != OUTSIDE) && (_gridCode[key+1] != WALL)) {
+            key = key+1;
+        } else if ((key-1 >= 0) && (_gridCode[key-1] != OUTSIDE) && (_gridCode[key-1] != WALL)) {
+            key = key - 1;
+        } else if ((key >= _grid->GetiMax()) && (_gridCode[key-_grid->GetiMax()] != OUTSIDE) && (_gridCode[key-_grid->GetiMax()] != WALL)) {
+            key = key - _grid->GetiMax();
+        } else if ((key < _grid->GetnPoints()-_grid->GetiMax()) && (_gridCode[key+_grid->GetiMax()] != OUTSIDE) && (_gridCode[key+_grid->GetiMax()] != WALL)) {
+            key = key + _grid->GetiMax();
+        } else {
+            Log->Write("ERROR:\t In getCostToDestination(2 args)");
+        }
+    }
+     if (_costFieldWithKey.count(destID)==1 && _costFieldWithKey[destID]) {
+          return _costFieldWithKey[destID][key];
+     } else if (_directCalculation && _doors.count(destID) > 0) {
+          _costFieldWithKey[destID] = new double[_nPoints];
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[destID] = new Point[_nPoints];
+          } else {
+               _directionFieldWithKey[destID] = nullptr;
+          }
+
+          addTarget(destID, _costFieldWithKey[destID], _directionFieldWithKey[destID]);
+          return getCostToDestination(destID, position);
+     } else if (!_directCalculation && _doors.count(destID) > 0) {
+//omp critical
+#pragma omp critical(UnivFFviaFMTrips_toDo)
+          _toDo.emplace_back(destID);
+     }
+     return DBL_MAX;
+}
+
+double UnivFFviaFMTrips::getDistanceBetweenDoors(const int door1_ID, const int door2_ID) {
+    assert(_doors.count(door1_ID) != 0);
+    assert(_doors.count(door2_ID) != 0);
+
+    if (_costFieldWithKey.count(door1_ID)==1 && _costFieldWithKey[door1_ID]) {
+        long int key = _grid->getKeyAtPoint(_doors.at(door2_ID).GetCentre());
+        if (_gridCode[key] != door2_ID) {
+            //bresenham line (treppenstruktur) getKeyAtPoint yields gridpoint next to edge, although position is on edge
+            //find a key that belongs to door (must be one left or right and second one below or above)
+            if (_gridCode[key+1] == door2_ID) {
+                key = key+1;
+            } else if (_gridCode[key-1] == door2_ID){
+                key = key-1;
+            } else {
+                Log->Write("ERROR:\t In DistanceBetweenDoors");
+            }
+        }
+        return _costFieldWithKey[door1_ID][key];
+    } else if (_directCalculation && _doors.count(door1_ID) > 0) {
+        _costFieldWithKey[door1_ID] = new double[_nPoints];
+        if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+            _directionFieldWithKey[door1_ID] = new Point[_nPoints];
+        } else {
+            _directionFieldWithKey[door1_ID] = nullptr;
+        }
+
+        addTarget(door1_ID, _costFieldWithKey[door1_ID], _directionFieldWithKey[door1_ID]);
+        return getDistanceBetweenDoors(door1_ID, door2_ID);
+    } else if (!_directCalculation && _doors.count(door1_ID) > 0) {
+//omp critical
+#pragma omp critical(UnivFFviaFMTrips_toDo)
+        _toDo.emplace_back(door1_ID);
+    }
+    return DBL_MAX;
+}
+
+RectGrid* UnivFFviaFMTrips::getGrid(){
+     return _grid;
+}
+
+void UnivFFviaFMTrips::getDirectionToUID(int destID, long int key, Point& direction, int mode){
+     assert(key > 0 && key < _nPoints);
+    if ((_gridCode[key] == OUTSIDE) || (_gridCode[key] == WALL)) {
+        //bresenham line (treppenstruktur) getKeyAtPoint yields gridpoint next to edge, although position is on edge
+        //find a key that belongs domain (must be one left or right and second one below or above)
+        if ((key+1 <= _grid->GetnPoints()) && (_gridCode[key+1] != OUTSIDE) && (_gridCode[key+1] != WALL)) {
+            key = key+1;
+        } else if ((key-1 >= 0) && (_gridCode[key-1] != OUTSIDE) && (_gridCode[key-1] != WALL)) {
+            key = key - 1;
+        } else if ((key >= _grid->GetiMax()) && (_gridCode[key-_grid->GetiMax()] != OUTSIDE) && (_gridCode[key-_grid->GetiMax()] != WALL)) {
+            key = key - _grid->GetiMax();
+        } else if ((key < _grid->GetnPoints()-_grid->GetiMax()) && (_gridCode[key+_grid->GetiMax()] != OUTSIDE) && (_gridCode[key+_grid->GetiMax()] != WALL)) {
+            key = key + _grid->GetiMax();
+        } else {
+            Log->Write("ERROR:\t In getDirectionToUID (4 args)");
+        }
+    }
+     if (_directionFieldWithKey.count(destID)==1 && _directionFieldWithKey[destID]) {
+          direction = _directionFieldWithKey[destID][key];
+     } else if (_directCalculation && _doors.count(destID) > 0) {
+          //free memory if needed
+          if (_costFieldWithKey.count(destID) == 1 && _costFieldWithKey[destID]) {
+               delete[] _costFieldWithKey[destID];
+          }
+          //allocate memory
+          _costFieldWithKey[destID] = new double[_nPoints];
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[destID] = new Point[_nPoints];
+          } else {
+               _directionFieldWithKey[destID] = nullptr;
+          }
+
+          //calculate destID's fields and call function
+          addTarget(destID, _costFieldWithKey[destID], _directionFieldWithKey[destID]);
+          getDirectionToUID(destID, key, direction, mode);
+     } else if (!_directCalculation && _doors.count(destID) > 0) {
+//omp critical
+#pragma omp critical(UnivFFviaFMTrips_toDo)
+          _toDo.emplace_back(destID);
+          direction._x = 0.;
+          direction._y = 0.;
+     }
+     return;
+}
+
+void UnivFFviaFMTrips::getDirectionToUID(int destID, long int key, Point& direction){
+     //assert(key > 0 && key < _nPoints);
+     if(key <=0 || key>=_nPoints)
+     {
+          direction._x = 0.;
+          direction._y = 0.;
+          return;
+     }
+    if ((_gridCode[key] == OUTSIDE) || (_gridCode[key] == WALL)) {
+        //bresenham line (treppenstruktur) getKeyAtPoint yields gridpoint next to edge, although position is on edge
+        //find a key that belongs domain (must be one left or right and second one below or above)
+        if ((key+1 <= _grid->GetnPoints()) && (_gridCode[key+1] != OUTSIDE) && (_gridCode[key+1] != WALL)) {
+            key = key+1;
+        } else if ((key-1 >= 0) && (_gridCode[key-1] != OUTSIDE) && (_gridCode[key-1] != WALL)) {
+            key = key - 1;
+        } else if ((key >= _grid->GetiMax()) && (_gridCode[key-_grid->GetiMax()] != OUTSIDE) && (_gridCode[key-_grid->GetiMax()] != WALL)) {
+            key = key - _grid->GetiMax();
+        } else if ((key < _grid->GetnPoints()-_grid->GetiMax()) && (_gridCode[key+_grid->GetiMax()] != OUTSIDE) && (_gridCode[key+_grid->GetiMax()] != WALL)) {
+            key = key + _grid->GetiMax();
+        } else {
+            Log->Write("ERROR:\t In getDirectionToUID (3 args)");
+        }
+    }
+     if (_directionFieldWithKey.count(destID)==1 && _directionFieldWithKey[destID]) {
+          direction = _directionFieldWithKey[destID][key];
+     } else if (_directCalculation && _doors.count(destID) > 0) {
+          //free memory if needed
+          if (_costFieldWithKey.count(destID) == 1 && _costFieldWithKey[destID]) {
+               delete[] _costFieldWithKey[destID];
+          }
+          //allocate memory
+          _costFieldWithKey[destID] = new double[_nPoints];
+          if (_user == DISTANCE_AND_DIRECTIONS_USED) {
+               _directionFieldWithKey[destID] = new Point[_nPoints];
+          } else {
+               _directionFieldWithKey[destID] = nullptr;
+          }
+
+          //calculate destID's fields and call function
+          addTarget(destID, _costFieldWithKey[destID], _directionFieldWithKey[destID]);
+          getDirectionToUID(destID, key, direction);
+     } else if (!_directCalculation && _doors.count(destID) > 0) {
+//omp critical
+#pragma omp critical(UnivFFviaFMTrips_toDo)
+          _toDo.emplace_back(destID);
+          direction._x = 0.;
+          direction._y = 0.;
+     }
+     return;
+}
+
+void UnivFFviaFMTrips::getDirectionToUID(int destID, const Point& pos, Point& direction, int mode) {
+     getDirectionToUID(destID, _grid->getKeyAtPoint(pos), direction, mode);
+}
+
+void UnivFFviaFMTrips::getDirectionToUID(int destID, const Point& pos,Point& direction) {
+     getDirectionToUID(destID, _grid->getKeyAtPoint(pos), direction);
+}
+
+double UnivFFviaFMTrips::getDistance2WallAt(const Point &pos) {
+     if (_useWallDistances || (_speedmode == FF_WALL_AVOID)) {
+          if (_costFieldWithKey[0]) {
+               return _costFieldWithKey[0][_grid->getKeyAtPoint(pos)];
+          }
+     }
+     return DBL_MAX;
+}
+
+void UnivFFviaFMTrips::getDir2WallAt(const Point &pos, Point &p) {
+     if (_useWallDistances || (_speedmode == FF_WALL_AVOID)) {
+          if (_directionFieldWithKey[0]) {
+               p = _directionFieldWithKey[0][_grid->getKeyAtPoint(pos)];
+          }
+     } else {
+          p = Point(0.0, 0.0);
+     }
+}
+
+/* Log:
+ * todo:
+ *   - implement error treatment: extend fctns to throw errors and handle them
+ *   - error treatment will be advantageous, if calculation of FFs can be postponed
+ *                                           to be done in Simulation::RunBody, where
+ *                                           all cores are available
+ *   - (WIP) fill subroom* array with correct values
+ *   */
diff --git a/routing/ff_router_trips/UnivFFviaFMTrips.h b/routing/ff_router_trips/UnivFFviaFMTrips.h
new file mode 100644
index 00000000..069e92b9
--- /dev/null
+++ b/routing/ff_router_trips/UnivFFviaFMTrips.h
@@ -0,0 +1,165 @@
+//
+// Created by arne on 5/9/17.
+//
+/**
+ * \file        UnivFFviaFMTrips.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_UnivFFviaFMTrips_H
+#define JPSCORE_UnivFFviaFMTrips_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <float.h>
+#include "../../general/Macros.h"
+
+class Pedestrian;
+class Room;
+class SubRoom;
+class Building;
+class Configuration;
+class Point;
+class RectGrid;
+class Line;
+class Goal;
+
+
+class CompareCost {      //this class is used in std::priority_queue in UnivFFviaFMTrips::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 UnivFFviaFMTrips {
+public:
+     UnivFFviaFMTrips(Room* a, Building* b, double c, double e, bool f);
+     UnivFFviaFMTrips(SubRoom* a, Building* b, double c, double e, bool f);
+     UnivFFviaFMTrips(Room* a, Configuration* const b, double hx, double wallAvoid, bool useWallDistances, std::map<int, Goal*> goals);
+     UnivFFviaFMTrips(Room* a, Configuration* const b, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors, std::map<int, Goal*> goals);
+     UnivFFviaFMTrips(SubRoom* sr, Configuration* const conf, double hx, double wallAvoid, bool useWallDistances, std::map<int, Goal*> goals);
+     UnivFFviaFMTrips(SubRoom* subRoomArg, Configuration* const confArg, double hx, double wallAvoid, bool useWallDistances, std::vector<int> wantedDoors, std::map<int, Goal*> goals);
+     void create(std::vector<Line>& walls, std::map<int, Line>& doors, std::vector<int> targetUIDs, int mode,
+                 double spacing, double wallAvoidDist, bool useWallDistances);
+     void recreateAllForQuickest();
+     UnivFFviaFMTrips() {};
+     UnivFFviaFMTrips(UnivFFviaFMTrips&){};
+     virtual ~UnivFFviaFMTrips();
+
+     void addTarget(const int uid, Line* door, double* costarray = nullptr, Point* gradarray = nullptr);
+     void addTarget(const int uid, double* costarray = nullptr, Point* gradarray = nullptr);
+     void addAllTargets();
+     void addAllTargetsParallel();
+     void addTargetsParallel(std::vector<int> wantedDoors);
+     std::vector<int> getKnownDoorUIDs();
+     void setUser(int userArg);
+     void setMode(int modeArg);
+     void setSpeedMode(int speedModeArg);
+     SubRoom** getSubRoomFF();
+     SubRoom* getSubRoom(const Point& pos);
+
+     double getCostToDestination(const int destID, const Point& position, int mode);
+     double getCostToDestination(const int destID, const Point& position);
+     double getDistanceBetweenDoors(const int door1_ID, const int door2_ID);
+     RectGrid* getGrid();
+     virtual void getDirectionToUID(int destID, long int key, Point& direction, int mode);
+     void getDirectionToUID(int destID, long int key, Point& direction);
+     virtual void getDirectionToUID(int destID, const Point& pos, Point& direction, int mode);
+     void getDirectionToUID(int destID, const Point& pos, Point& direction);
+     double getDistance2WallAt(const Point& pos);
+     void getDir2WallAt(const Point& pos, Point& p);
+
+     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 markSubroom(const Point& insidePoint, SubRoom* const value);
+     void createReduWallSpeed(double* reduWallSpeed);
+     void createPedSpeed(Pedestrian* const * pedsArg, int nsize, int modechoice, double radius);
+     void finalizeTargetLine(const int uid, const Line& tempTargetLine, Point* newArrayPt, Point& passvector);
+
+     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);
+
+     template <typename T>
+     void drawLinesOnWall(std::vector<Line>& wallArg, T* const target, const T value);
+     template <typename T>
+     void drawLinesOnWall(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);
+     void calcDF(double*, Point*, const double* const);
+     void calcDist(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 _room = -1;                              //not set
+     int _mode = LINESEGMENT;                     //default
+     int _user = DISTANCE_AND_DIRECTIONS_USED;    //default
+     int _speedmode = FF_HOMO_SPEED;              //default
+     int _scope = 0;                              //not set / unknown
+     bool _directCalculation = true;
+     RectGrid* _grid = nullptr;
+     long int _nPoints = 0;
+     std::vector<double*> _speedFieldSelector;
+     int* _gridCode = nullptr;
+     SubRoom* * _subrooms = nullptr; // this is an array (first asterisk) of pointers (second asterisk)
+
+     double _wallAvoidDistance = 0.;
+     bool _useWallDistances = false;    //could be used in DirectionStrategy even if mode _speedmode is FF_HOMO_SPEED
+
+     //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;
+     std::vector<int> _toDo;
+
+     std::map<int, Point> _subroomUIDtoInsidePoint;
+     std::map<int, SubRoom*> _subroomUIDtoSubRoomPtr;
+     std::map<SubRoom*, Point> _subRoomPtrTOinsidePoint;
+
+};
+
+
+#endif //JPSCORE_UnivFFviaFMTrips_H
diff --git a/routing/ff_router_trips/ffRouterTrips.cpp b/routing/ff_router_trips/ffRouterTrips.cpp
index 36faf374..e16e4eb1 100644
--- a/routing/ff_router_trips/ffRouterTrips.cpp
+++ b/routing/ff_router_trips/ffRouterTrips.cpp
@@ -108,7 +108,11 @@ bool FFRouterTrips::Init(Building* building)
           std::cout << std::endl;
           for (auto &itrGoal : building->GetAllGoals()) {
                std::cout << "Goal ID: " << itrGoal.second->GetId() << std::endl;
-               _globalFF->createMapEntryInLineToGoalID(itrGoal.first);
+               if(WaitingArea* wa = dynamic_cast<WaitingArea*>(itrGoal.second)) {
+                    _globalFF->createMapEntryInLineToGoalID(itrGoal.first, true);
+               }else{
+                    _globalFF->createMapEntryInLineToGoalID(itrGoal.first, false);
+               }
                goalIDs.emplace_back(itrGoal.first);
           }
           _goalToLineUIDmap = _globalFF->getGoalToLineUIDmap();
@@ -470,10 +474,27 @@ int FFRouterTrips::FindExit(Pedestrian* ped)
 //     std::cout << "ExitLine: "  << ped->GetExitLine() << std::endl;
      std::cout << "ExitIndex: "  << ped->GetExitIndex() << std::endl << std::endl;
 
+     for (auto& goal : _goalToLineUIDmap){
+          std::cout << goal.first << " -> " << goal.second << std::endl;
+     }
+
+     SubRoom* subroom = _building->GetSubRoomByUID(ped->GetSubRoomUID());
+     Goal* goal = _building->GetFinalGoal(ped->GetFinalDestination());
+
+     int ret;
 
      // Check if current position is already waiting area
      // yes: set next goal and return findExit(p)
-     int ret = FindExit1(ped);
+     if (subroom->IsInSubRoom(goal->GetCentroid())){
+          std::cout << "Ped and Goal in same subroom: " << subroom->IsInSubRoom(goal->GetCentroid()) << std::endl;
+          int bestDoor = 31;
+          ped->SetExitIndex(bestDoor);
+          ped->SetExitLine(_CroTrByUID.at(bestDoor));
+
+     }else{
+          ret = FindExit1(ped);
+     }
+
 
      std::cout << "Ped[" << ped->GetID() << "] in (" << ped->GetRoomID() << ", " << ped->GetSubRoomID()
                << "/" << ped->GetSubRoomUID() << "): " << std::endl;
@@ -527,6 +548,7 @@ int FFRouterTrips::FindExit1(Pedestrian* p)
           }
      }
 
+
      std::vector<int> DoorUIDsOfRoom;
      DoorUIDsOfRoom.clear();
      if (_building->GetRoom(p->GetRoomID())->GetSubRoom(p->GetSubRoomID())->IsInSubRoom(p->GetPos())) {
@@ -624,12 +646,12 @@ int FFRouterTrips::FindExit1(Pedestrian* p)
      }
 
      //at this point, bestDoor is either a crossing or a transition
-     if ((!_targetWithinSubroom) && (_CroTrByUID.count(bestDoor) != 0)) {
-          while (!_CroTrByUID[bestDoor]->IsTransition()) {
-               std::pair<int, int> key = std::make_pair(bestDoor, bestFinalDoor);
-               bestDoor = _pathsMatrix[key];
-          }
-     }
+//     if ((!_targetWithinSubroom) && (_CroTrByUID.count(bestDoor) != 0)) {
+//          while (!_CroTrByUID[bestDoor]->IsTransition()) {
+//               std::pair<int, int> key = std::make_pair(bestDoor, bestFinalDoor);
+//               bestDoor = _pathsMatrix[key];
+//          }
+//     }
 
 //#pragma omp critical(finalDoors)
 //     _finalDoors.emplace(std::make_pair(p->GetID(), bestFinalDoor));
diff --git a/routing/trips_router/TripsRouter.cpp b/routing/trips_router/TripsRouter.cpp
index 776f3da0..f28b0aff 100644
--- a/routing/trips_router/TripsRouter.cpp
+++ b/routing/trips_router/TripsRouter.cpp
@@ -23,6 +23,11 @@ TripsRouter::~TripsRouter()
 
 bool TripsRouter::Init(Building* building)
 {
+     Log->Write("TripsRouter::Init");
+
+
+     // Create Floorfield for each subroom
+          // If goal inside room, start wave from each edge to the outside
      return true;
 }
 
@@ -36,8 +41,6 @@ int TripsRouter::FindExit(Pedestrian* p)
      // Check if current position is already waiting area
      // yes: set next goal and return findExit(p)
 
-     p->SetExitIndex(17);
-     p->SetExitLine(0);
 
-     return 17;
+     return 0;
 }
-- 
GitLab