Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • devel
  • paper_resubmission_20230816
  • paper_resubmission_20230630
  • paper_submission_20220921
  • before_elimination_of_duplicates_20220722
  • before_dlr_20220429
7 results

correct_and_smooth.py

  • Analysis.cpp 23.39 KiB
    /**
     * \file        Analysis.cpp
     * \date        Oct 10, 2014
     * \version     v0.7
     * \copyright   <2009-2016> Forschungszentrum Juelich 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
     * The Analysis class represents a process of analyzing groups of pedestrian
     * trajectories from experiment or simulation. Different measurement methods
     * can be used and are defined by various parameters and functions.
     *
     *
     **/
    
    #include "Analysis.h"
    #include "geometry/Room.h"
    #include "geometry/SubRoom.h"
    
    #include "methods/VoronoiDiagram.h"
    #include "methods/Method_A.h"
    #include "methods/Method_B.h"
    #include "methods/Method_C.h"
    #include "methods/Method_D.h"
    #include "methods/Method_I.h"
    #include "methods/PedData.h"
    
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <cfloat>
    #include <stdlib.h>
    #include <algorithm>    // std::min_element, std::max_element
    
    #ifdef __linux__
    #include <sys/stat.h>
    #include <dirent.h>
    #elif   __APPLE__
    #include <sys/stat.h>
    #include <dirent.h>
    #else
    #include <direct.h>
    #endif
    
    
    using boost::geometry::dsv;
    using namespace std;
    OutputHandler* Log = new STDIOHandler();
    
    /************************************************
     // Konstruktoren
     ************************************************/
    
    Analysis::Analysis()
    {
         _building = NULL;
         _projectRootDir="";
         _deltaF=5;   // half of the time interval that used to calculate instantaneous velocity of ped i. Here v_i = (X(t+deltaF) - X(t+deltaF))/(2*deltaF).   X is location.
         _DoesUseMethodA = false;                                           // Method A (Zhang2011a)
         _DoesUseMethodB = false;                   // Method B (Zhang2011a)
         _DoesUseMethodC = false;                                   // Method C //calculate and save results of classic in separate file
         _DoesUseMethodD = false;                                   // Method D--Voronoi method
         _cutByCircle = false;  //Adjust whether cut each original voronoi cell by a circle
         _getProfile = false;   // Whether make field analysis or not
         _outputGraph = false;   // Whether output the data for plot the fundamental diagram each frame
         _calcIndividualFD = false; //Adjust whether analyze the individual density and velocity of each pedestrian in stationary state (ALWAYS VORONOI-BASED)
         _vComponent = "B"; // to mark whether x, y or x and y coordinate are used when calculating the velocity
         _IgnoreBackwardMovement = false;
         _grid_size_X = 0.10;   // the size of the grid
         _grid_size_Y = 0.10;
         _lowVertexX = 0;// LOWest vertex of the geometry (x coordinate)
         _lowVertexY = 0; //  LOWest vertex of the geometry (y coordinate)
         _highVertexX = 10; // Highest vertex of the geometry
         _highVertexY = 10;
    
         _cutRadius=1.0;
         _circleEdges=6;
         _trajFormat=FileFormat::FORMAT_PLAIN;
         _isOneDimensional=false;
         _plotGraph=false;
    }
    
    Analysis::~Analysis()
    {
         delete _building;
    }
    
    // file.txt ---> file
    std::string Analysis::GetBasename (const std::string& str)
    {
         std::cout << "Splitting: " << str << '\n';
         unsigned found = str.find_last_of(".");
         return  str.substr(0,found);
    }
    // c:\\windows\\winhelp.exe ---> winhelp.exe
    std::string Analysis::GetFilename (const std::string& str)
    {
         std::cout << "GetFilename: " << str << '\n';
         unsigned found = str.find_last_of("/\\");
         return   str.substr(found+1);
    }
    
    void Analysis::InitArgs(ArgumentParser* args)
    {
         string s = "Parameter:\n";
         _building = new Building();
         _building->LoadGeometry(args->GetGeometryFilename());
         // create the polygons
         _building->InitGeometry();
         // _building->AddSurroundingRoom();
    
         if(args->GetIsMethodA()) {
              _DoesUseMethodA = true;
              vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodA();
              for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++)
              {
                   _areaForMethod_A.push_back(dynamic_cast<MeasurementArea_L*>( args->GetMeasurementArea(Measurement_Area_IDs[i])));
              }
              _deltaT = args->GetTimeIntervalA();
              _plotTimeseriesA=args->GetIsPlotTimeSeriesA();
         }
    
         if(args->GetIsMethodB()) {
              _DoesUseMethodB = true;
              vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodB();
              for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++)
              {
                   _areaForMethod_B.push_back(dynamic_cast<MeasurementArea_B*>( args->GetMeasurementArea(Measurement_Area_IDs[i])));
              }
         }
    
         if(args->GetIsMethodC()) {
              _DoesUseMethodC = true;
              vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodC();
              for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++)
              {
                   _areaForMethod_C.push_back(dynamic_cast<MeasurementArea_B*>( args->GetMeasurementArea(Measurement_Area_IDs[i])));
              }
              _plotTimeseriesC=args->GetIsPlotTimeSeriesC();
         }
    
         if(args->GetIsMethodD()) {
              _DoesUseMethodD = true;
              vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodD();
              for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++)
              {
                   _areaForMethod_D.push_back(dynamic_cast<MeasurementArea_B*>( args->GetMeasurementArea(Measurement_Area_IDs[i])));
              }
              _StartFramesMethodD = args->GetStartFramesMethodD();
              _StopFramesMethodD = args->GetStopFramesMethodD();
              _IndividualFDFlags = args->GetIndividualFDFlags();
              _plotTimeseriesD=args->GetIsPlotTimeSeriesD();
              _geoPolyMethodD = ReadGeometry(args->GetGeometryFilename(), _areaForMethod_D);
    
         }
         if(args->GetIsMethodI()) {
              _DoesUseMethodI = true;
              vector<int> Measurement_Area_IDs = args->GetAreaIDforMethodI();
              for(unsigned int i=0; i<Measurement_Area_IDs.size(); i++)
              {
                   _areaForMethod_I.push_back(dynamic_cast<MeasurementArea_B*>( args->GetMeasurementArea(Measurement_Area_IDs[i])));
              }
              _StartFramesMethodI = args->GetStartFramesMethodI();
              _StopFramesMethodI = args->GetStopFramesMethodI();
              _IndividualFDFlags = args->GetIndividualFDFlags();
              _plotTimeseriesI=args->GetIsPlotTimeSeriesI();
              _geoPolyMethodI = ReadGeometry(args->GetGeometryFilename(), _areaForMethod_I);
         }
    
    // ToDo: obsolete ?
    
    //     if( _DoesUseMethodD &&  _DoesUseMethodI)
    //     {
    //          Log->Write("Warning:\t Using both method D and I is not safe!");
    //          // because ReadGeometry() may be called twice (line 169 and 182)
    //          // overwrite _geoPoly -> new value for each Method
    //          Log->Write("Info:\t Using both method D and I is safe! :-)");
    //     }
    
         _deltaF = args->GetDelatT_Vins();
         _cutByCircle = args->GetIsCutByCircle();
         _getProfile = args->GetIsGetProfile();
         _outputGraph = args->GetIsOutputGraph();
         _plotGraph = args->GetIsPlotGraph();
         _plotIndex = args->GetIsPlotIndex();
         _isOneDimensional=args->GetIsOneDimensional();
         _vComponent = args->GetVComponent();
         _IgnoreBackwardMovement =args->GetIgnoreBackwardMovement();
         _grid_size_X = int(args->GetGridSizeX());
         _grid_size_Y = int(args->GetGridSizeY());
         _geometryFileName=args->GetGeometryFilename();
         _projectRootDir=args->GetProjectRootDir();
         _trajFormat=args->GetFileFormat();
         _cutRadius=args->GetCutRadius();
         _circleEdges=args->GetCircleEdges();
         _scriptsLocation=args->GetScriptsLocation();
         _outputLocation=args->GetOutputLocation();
    }
    
    
    std::map<int, polygon_2d> Analysis::ReadGeometry(const fs::path& geometryFile, const std::vector<MeasurementArea_B*>& areas)
    {
         Log->Write("INFO:\tReadGeometry with %s", geometryFile.string().c_str());
         double geo_minX  = FLT_MAX;
         double geo_minY  = FLT_MAX;
         double geo_maxX  = -FLT_MAX;
         double geo_maxY  = -FLT_MAX;
    
         std::map<int, polygon_2d> geoPoly;
    
         //loop over all areas
         for(auto&& area: areas)
         {
              //search for the subroom that contains that area
              for (auto&& it_room : _building->GetAllRooms())
              {
                   for (auto&& it_sub : it_room.second->GetAllSubRooms())
                   {
                        SubRoom* subroom = it_sub.second.get();
                        point_2d point(0,0);
                        boost::geometry::centroid(area->_poly,point);
                        //check if the area is contained in the obstacle
                        if(subroom->IsInSubRoom(Point(point.x()/M2CM,point.y()/M2CM)))
                        {
                             for (auto&& tmp_point : subroom->GetPolygon())
                             {
                                  append(geoPoly[area->_id], make<point_2d>(tmp_point._x*M2CM, tmp_point._y*M2CM));
                                  geo_minX = (tmp_point._x*M2CM<=geo_minX) ? (tmp_point._x*M2CM) : geo_minX;
                                  geo_minY = (tmp_point._y*M2CM<=geo_minY) ? (tmp_point._y*M2CM) : geo_minY;
                                  geo_maxX = (tmp_point._x*M2CM>=geo_maxX) ? (tmp_point._x*M2CM) : geo_maxX;
                                  geo_maxY = (tmp_point._y*M2CM>=geo_maxY) ? (tmp_point._y*M2CM) : geo_maxY;
                             }
                             correct(geoPoly[area->_id]);
                             //cout<<"this is:\t"<<subroom->GetAllObstacles().size()<<endl;
                             //appen the holes/obstacles if any
                             int k=1;
                             for(auto&& obst: subroom->GetAllObstacles())
                             {
                                  geoPoly[area->_id].inners().resize(k++);
                                  geoPoly[area->_id].inners().back();
                                  model::ring<point_2d>& inner = geoPoly[area->_id].inners().back();
                                  for(auto&& tmp_point:obst->GetPolygon())
                                  {
                                       append(inner, make<point_2d>(tmp_point._x*M2CM, tmp_point._y*M2CM));
                                  }
                                  correct(geoPoly[area->_id]);
                             }
                        }
                   }
              }//room
    
              if(geoPoly.count(area->_id)==0)
              {
                   Log->Write("ERROR: \t No polygon containing the measurement id [%d]", area->_id);
                   geoPoly[area->_id] = area->_poly;
              }
         }
    
         _highVertexX = geo_maxX;
         _highVertexY = geo_maxY;
         _lowVertexX = geo_minX;
         _lowVertexY = geo_minY;
         return geoPoly;
    }
    
    
    int Analysis::RunAnalysis(const fs::path& filename, const fs::path& path)
    {
         PedData data;
         if(data.ReadData(_projectRootDir, _outputLocation, path, filename, _trajFormat, _deltaF, _vComponent, _IgnoreBackwardMovement)==false)
         {
              Log->Write("ERROR:\tCould not parse the file %d", filename.c_str());
              return -1;
         }
    
         //-----------------------------check whether there is pedestrian outside the whole geometry--------------------------------------------
         std::map<int , std::vector<int> > _peds_t=data.GetPedsFrame();
         for(int frameNr = 0; frameNr < data.GetNumFrames(); frameNr++ )
         {
              vector<int> ids=_peds_t[frameNr];
              vector<int> IdInFrame = data.GetIdInFrame(frameNr, ids);
              vector<double> XInFrame = data.GetXInFrame(frameNr, ids);
              vector<double> YInFrame = data.GetYInFrame(frameNr, ids);
              for( unsigned int i=0;i<IdInFrame.size();i++)
              {
                   bool IsInBuilding=false;
                   for (auto&& it_room : _building->GetAllRooms())
                   {
                        for (auto&& it_sub : it_room.second->GetAllSubRooms())
                        {
                             SubRoom* subroom = it_sub.second.get();
                             if(subroom->IsInSubRoom(Point(XInFrame[i]*CMtoM,YInFrame[i]*CMtoM)))
                             {
                                  IsInBuilding=true;
                                  break;
                             }
                        }
                        if(IsInBuilding)
                        {
                             break;
                        }
                   }
                   if(false==IsInBuilding)
                   {
                        Log->Write("Warning:\tAt %dth frame pedestrian at <x=%.4f, y=%.4f> is not in geometry!", frameNr+data.GetMinFrame(), XInFrame[i]*CMtoM, YInFrame[i]*CMtoM );
                   }
              }
         }
         //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
    
         if(_DoesUseMethodA) //Method A
         {
              if(_areaForMethod_A.empty())
              {
                   Log->Write("ERROR: Method A selected with no measurement area!");
                   exit(EXIT_FAILURE);
              }
    #pragma omp parallel for
              for(long unsigned int i=0; i < _areaForMethod_A.size(); i++)
              {
                   Method_A method_A ;
                   method_A.SetMeasurementArea(_areaForMethod_A[i]);
                   method_A.SetTimeInterval(_deltaT[i]);
                   method_A.SetPlotTimeSeries(_plotTimeseriesA[i]);
                   bool result_A=method_A.Process(data,_scriptsLocation,_areaForMethod_A[i]->_zPos);
                   if(result_A)
                   {
                        Log->Write("INFO:\tSuccess with Method A using measurement area id %d!\n",_areaForMethod_A[i]->_id);
                        std::cout << "INFO:\tSuccess with Method A using measurement area id "<< _areaForMethod_A[i]->_id << "\n";
                   }
                   else
                   {
                        Log->Write("INFO:\tFailed with Method A using measurement area id %d!\n",_areaForMethod_A[i]->_id);
                   }
              }
         }
    
         if(_DoesUseMethodB) //Method_B
         {
              if(_areaForMethod_B.empty())
              {
                   Log->Write("ERROR: Method B selected with no measurement area!");
                   exit(EXIT_FAILURE);
              }
    
    #pragma omp parallel for
              for(long unsigned int i=0; i < _areaForMethod_B.size(); i++)
              {
                   Method_B method_B;
                   method_B.SetMeasurementArea(_areaForMethod_B[i]);
                   bool result_B = method_B.Process(data);
                   if(result_B)
                   {
                        Log->Write("INFO:\tSuccess with Method B using measurement area id %d!\n",_areaForMethod_B[i]->_id);
                        std::cout << "INFO:\tSuccess with Method B using measurement area id "<< _areaForMethod_B[i]->_id << "\n";
                   }
                   else
                   {
                        Log->Write("INFO:\tFailed with Method B using measurement area id %d!\n",_areaForMethod_B[i]->_id);
                   }
              }
         }
    
         if(_DoesUseMethodC) //Method C
         {
              if(_areaForMethod_C.empty())
              {
                   Log->Write("ERROR: Method C selected with no measurement area!");
                   exit(EXIT_FAILURE);
              }
    #pragma omp parallel for
              for(long unsigned int i=0; i < _areaForMethod_C.size(); i++)
              {
                   Method_C method_C;
                   method_C.SetMeasurementArea(_areaForMethod_C[i]);
                   bool result_C =method_C.Process(data,_areaForMethod_C[i]->_zPos);
                   if(result_C)
                   {
                        Log->Write("INFO:\tSuccess with Method C using measurement area id %d!\n",_areaForMethod_C[i]->_id);
                        std::cout << "INFO:\tSuccess with Method C using measurement area id "<< _areaForMethod_C[i]->_id << "\n";
                        if(_plotTimeseriesC[i])
                        {
                             string parameters_Timeseries=" " + _scriptsLocation.string()+
                                  "/_Plot_timeseries_rho_v.py -p "+ _projectRootDir.string()+VORO_LOCATION + " -n "+filename.string()+
                                  " -f "+boost::lexical_cast<std::string>(data.GetFps());
                             parameters_Timeseries = PYTHON + parameters_Timeseries;
                             int res=system(parameters_Timeseries.c_str());
                             Log->Write("INFO:\t time series result: %d ",res);
                        }
                   }
                   else
                   {
                        Log->Write("INFO:\tFailed with Method C using measurement area id %d!\n",_areaForMethod_C[i]->_id);
                   }
              }
         }
    
         if(_DoesUseMethodD) //method_D
         {
              if(_areaForMethod_D.empty())
              {
                   Log->Write("ERROR: Method D selected with no measurement area!");
                   exit(EXIT_FAILURE);
              }
    
    #pragma omp parallel for
              for(long unsigned int i=0; i<_areaForMethod_D.size(); i++)
              {
                   Method_D method_D;
                   method_D.SetStartFrame(_StartFramesMethodD[i]);
                   method_D.SetStopFrame(_StopFramesMethodD[i]);
                   method_D.SetCalculateIndividualFD(_IndividualFDFlags[i]);
                   method_D.SetGeometryPolygon(_geoPolyMethodD[_areaForMethod_D[i]->_id]);
                   method_D.SetGeometryFileName(_geometryFileName);
                   method_D.SetGeometryBoundaries(_lowVertexX, _lowVertexY, _highVertexX, _highVertexY);
                   method_D.SetGridSize(_grid_size_X, _grid_size_Y);
                   method_D.SetOutputVoronoiCellData(_outputGraph);
                   method_D.SetPlotVoronoiGraph(_plotGraph);
                   method_D.SetPlotVoronoiIndex(_plotIndex);
                   method_D.SetDimensional(_isOneDimensional);
                   method_D.SetCalculateProfiles(_getProfile);
                   method_D.SetTrajectoriesLocation(path);
                   if(_cutByCircle)
                   {
                        method_D.Setcutbycircle(_cutRadius, _circleEdges);
                   }
                   method_D.SetMeasurementArea(_areaForMethod_D[i]);
                   bool result_D = method_D.Process(data,_scriptsLocation, _areaForMethod_D[i]->_zPos);
                   if(result_D)
                   {
                        Log->Write("INFO:\tSuccess with Method D using measurement area id %d!\n",_areaForMethod_D[i]->_id);
                        std::cout << "INFO:\tSuccess with Method D using measurement area id "<< _areaForMethod_D[i]->_id << "\n";
                        if(_plotTimeseriesD[i])
                        {
                             string parameters_Timeseries= " " +_scriptsLocation.string()+"/_Plot_timeseries_rho_v.py -p "+ _projectRootDir.string()+VORO_LOCATION + " -n "+filename.string()+
                                  " -f "+boost::lexical_cast<std::string>(data.GetFps());
                             parameters_Timeseries = PYTHON + parameters_Timeseries;
                             std::cout << parameters_Timeseries << "\n;";
    
                             int res=system(parameters_Timeseries.c_str());
                             Log->Write("INFO:\t time series result: %d ",res);
                        }
                   }
                   else
                   {
                        Log->Write("INFO:\tFailed with Method D using measurement area id %d!\n",_areaForMethod_D[i]->_id);
                   }
              }
         }
    
         if(_DoesUseMethodI) //method_I
         {
              if(_areaForMethod_I.empty())
              {
                   Log->Write("ERROR: Method I selected with no measurement area!");
                   exit(EXIT_FAILURE);
              }
    
    #pragma omp parallel for
              for(long unsigned int i=0; i<_areaForMethod_I.size(); i++)
              {
                   Method_I method_I;
                   method_I.SetStartFrame(_StartFramesMethodI[i]);
                   method_I.SetStopFrame(_StopFramesMethodI[i]);
                   method_I.SetCalculateIndividualFD(_IndividualFDFlags[i]);
                   method_I.SetGeometryPolygon(_geoPolyMethodI[_areaForMethod_I[i]->_id]);
                   method_I.SetGeometryFileName(_geometryFileName);
                   method_I.SetGeometryBoundaries(_lowVertexX, _lowVertexY, _highVertexX, _highVertexY);
                   method_I.SetGridSize(_grid_size_X, _grid_size_Y);
                   method_I.SetOutputVoronoiCellData(_outputGraph);
                   // method_I.SetPlotVoronoiGraph(_plotGraph);
                   method_I.SetPlotVoronoiIndex(_plotIndex);
                   method_I.SetDimensional(_isOneDimensional);
                   // method_I.SetCalculateProfiles(_getProfile);
                   method_I.SetTrajectoriesLocation(path);
                   if(_cutByCircle)
                   {
                        method_I.Setcutbycircle(_cutRadius, _circleEdges);
                   }
                   method_I.SetMeasurementArea(_areaForMethod_I[i]);
                   bool result_I = method_I.Process(data,_scriptsLocation, _areaForMethod_I[i]->_zPos);
                   if(result_I)
                   {
                        Log->Write("INFO:\tSuccess with Method I using measurement area id %d!\n",_areaForMethod_I[i]->_id);
                        std::cout << "INFO:\tSuccess with Method I using measurement area id "<< _areaForMethod_I[i]->_id << "\n";
                        if(_plotTimeseriesI[i])
                        {
                             string parameters_Timeseries= " " +_scriptsLocation.string()+"/_Plot_timeseries_rho_v.py -p "+ _projectRootDir.string()+VORO_LOCATION + " -n "+filename.string()+
                                  " -f "+boost::lexical_cast<std::string>(data.GetFps());
                             parameters_Timeseries = PYTHON + parameters_Timeseries;
                             std::cout << parameters_Timeseries << "\n;";
    
                             int res=system(parameters_Timeseries.c_str());
                             Log->Write("INFO:\t time series result: %d ",res);
                        }
                   }
                   else
                   {
                        Log->Write("INFO:\tFailed with Method I using measurement area id %d!\n",_areaForMethod_I[i]->_id);
                   }
              }
         }
    
    
         return 0;
    }
    
    FILE* Analysis::CreateFile(const string& filename)
    {
         //first try to create the file
         FILE* fHandle= fopen(filename.c_str(),"w");
         if(fHandle) return fHandle;
    
         unsigned int found=filename.find_last_of("/\\");
         string dir = filename.substr(0,found)+"/";
         //string file= filename.substr(found+1);
    
         // the directories are probably missing, create it
         if (mkpath((char*)dir.c_str())==-1) {
              Log->Write("ERROR:\tcannot create the directory <%s>",dir.c_str());
              return NULL;
         }
         //second and last attempt
         return fopen(filename.c_str(),"w");
    }
    
    #if defined(_WIN32)
    // @todo: rewrite using boost
    int Analysis::mkpath(char* file_path)
    {
         assert(file_path && *file_path);
         char* p;
         for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) {
              *p='\0';
    
              if (_mkdir(file_path)==-1) {
    
                   if (errno!=EEXIST) {
                        *p='/';
                        return -1;
                   }
              }
              *p='/';
         }
         return 0;
    }
    
    #else
    
    // @todo: rewrite using boost
    int Analysis::mkpath(char* file_path, mode_t mode)
    {
         assert(file_path && *file_path);
         char* p;
         for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) {
              *p='\0';
    
              if (mkdir(file_path, mode)==-1) {
    
                   if (errno!=EEXIST) {
                        *p='/';
                        return -1;
                   }
              }
              *p='/';
         }
         return 0;
    }
    // delete
    #endif