Robot's source code

Dependencies:   mbed

Map/Map.cpp

Committer:
Jagang
Date:
2015-05-06
Revision:
117:f8c147141a0c
Parent:
109:53918ba98306
Child:
119:c45efcd706d9

File content as of revision 117:f8c147141a0c:

#include "Map.h"

#include "mbed.h"
#include "Obs_circle.h"
#include "Obs_rect.h"

extern Serial logger;

Map::Map()
{
    
}

Map::~Map()
{
    for(unsigned int i=0;i<obstacles.size();i++)
        delete obstacles[i];
}

void Map::build()
{
    //obstacles.push_back(new Obs_circle(ROBOTRADIUS,2,2,1));
    obstacles.push_back(new Obs_rect(ROBOTRADIUS,-100,-100,2100,0)); // MG
    
    
    obstacles.push_back(new Obs_rect(ROBOTRADIUS,778,0,800,400)); // M1
    obstacles.push_back(new Obs_rect(ROBOTRADIUS,1200,0,1222,400)); // M2
    obstacles.push_back(new Obs_rect(ROBOTRADIUS,800,0,1200,70)); // M3
    
}

int Map::getHeight(float x, float y)
{
    int height = 0;
    for(unsigned int i=0;i<obstacles.size();i++)
        height += obstacles[i]->height(x,y);
    return height;
}

float dist(Point *p1,Point *p2)
{
    int dx = p1->getx()-p2->getx();
    if(dx<0) dx=-dx;
    int dy = p1->gety()-p2->gety();
    if(dy<0) dy=-dy;
    return sqrt((float)dx*dx+dy*dy);
}

char Map::AStar(float x, float y, float goal_x, float goal_y, float mpc)
{
    /*! http://www.gamedev.net/page/resources/_/technical/artificial-intelligence/a-pathfinding-for-beginners-r2003 !*/
    //float dx,dy; // Permet de diminuer l'erreur par rapport au centre des cases
    //dx = ((((int)(x/mpc))*mpc-mpc/2)+(((int)(goal_x/mpc))*mpc-mpc/2))/2;
    
    Point goal(goal_x/mpc,goal_y/mpc);
    if(getHeight(goal_x,goal_y) >= 32000)
    {
        #if LOG_LEVEL >= 2
            logger.printf("[warning - pathfinder] Unreachable point (%.3f,%.3f)\r\n",goal_x,goal_y);
        #endif
        return 4;
    }
    
    if(getHeight(x,y) >= 32000)
    {
        #if LOG_LEVEL >= 2
            logger.printf("[warning - pathfinder] Unstartable point (%.3f,%.3f)\r\n",x,y);
        #endif
        return 5;
    }
    
    
    unsigned int i=0;
    unsigned int instanceDePoint=0;
    
    std::vector<Point*> openList;
    openList.push_back(new Point(x/mpc,y/mpc));
    openList[0]->setG(0);
    openList[0]->setH(dist(openList[0],&goal));
    openList[0]->setParent();
    
    std::vector<Point*> closeList;
    
    Point* current;
    do
    {
        
        // On cherche le plus petit F dans la liste ouverte
        current = openList[0];
        
        unsigned int pos = 0;
        for(i=0;i<openList.size();i++)
            if(openList[i]->getF() < current->getF())
            {
                current = openList[i];
                pos = i;
            }
        
        // On le place dans la liste fermé
        closeList.push_back(current);
        openList.erase(openList.begin()+pos);
        
        #if LOG_LEVEL >= 4 && LOG_ASTAR
            logger.printf("[info - pathfinder] Adding (%d,%d) in the closed list\r\n",current->getx(),current->gety());
            logger.printf("[info - pathfinder] Closed list : %d elements\r\n[info - pathfinder] Opened list : %d elements\r\n",openList.size(),closeList.size());
        #endif
        
        // On ajoute tous ses voisins viable das la liste ouverte
        for(int dx=-1;dx<=1;dx++)
        {
            for(int dy=-1;dy<=1;dy++)
            {
                if(dx==0 && dy==0) continue;
                
                Point *p = new Point(current->getx()+dx,current->gety()+dy);
                instanceDePoint++;
                if(p == 0 || instanceDePoint >= MAXPOINT) // Overload !!!
                {
                    for(unsigned int i=0;i<openList.size();i++)
                        delete openList[i];
                    for(unsigned int i=0;i<closeList.size();i++)
                        delete closeList[i];
                    
                    path.clear();
                        
                    #if LOG_LEVEL >= 1
                        logger.printf("[error - pathfinder] Overload (%d,%d)\r\n",openList.size(),closeList.size());
                    #endif
                    
                    return 3;
                }
                
                if(p->in(closeList)) // On ignore le point si il est déjà dans la liste fermé
                {
                    delete p;
                    continue; 
                }
                
                int height = getHeight((current->getx()+dx)*mpc,(current->gety()+dy)*mpc);
                if(height>=32000)  // On ignore le point, il n'est pas accessible
                {
                    delete p;
                    continue; // On ignore le point si il est déjà dans la liste fermé
                }
                
                if(p->in(openList,pos))
                {
                    if(dx == 0 || dy == 0) // Mouvement non diagonnal
                    {
                        if(current->getG() + NDIAG_COST < openList[pos]->getG())
                        {
                            openList[pos]->setG(current->getG() + NDIAG_COST);
                            openList[pos]->setParent(current);
                        }
                    }
                    else
                    {
                        if(current->getG() + DIAG_COST < openList[pos]->getG())
                        {
                            openList[pos]->setG(current->getG() + DIAG_COST);
                            openList[pos]->setParent(current);
                        }
                    }
                    
                    delete p;
                }
                else
                {
                    openList.push_back(p);
                    if(dx == 0 || dy == 0) // Mouvement non diagonnal
                        p->setG(current->getG() + NDIAG_COST);
                    else
                        p->setG(current->getG() + DIAG_COST);
                    p->setH(height + dist(p,&goal));
                    p->setParent(current);
                }
            }
        }
    }
    while(dist(closeList.back(),&goal) && !openList.empty()); // Tant qu'on a pas atteint la case et qu'on a des choix
    
    
    #if LOG_LEVEL >= 3
        logger.printf("[info - pathfinder] Closed list : %d elements\r\n[info - pathfinder] Opened list : %d elements\r\n",openList.size(),closeList.size());
    #endif
    
    if(!openList.empty())
    {
        for(i=0;i<openList.size();i++)
            delete openList[i];
        
        // On reconstruit le chemin
        #if LOG_LEVEL >= 3
            logger.printf("[info - pathfinder] Recontruction du chemin ... ");
        #endif
        path.clear();
        Point* c = closeList.back();
        while(c != 0)
        {
            path.insert(path.begin(),SimplePoint(c->getx()*mpc,c->gety()*mpc));
            c = c->getParent();
        }
        
        for(i=0;i<closeList.size();i++)
            delete closeList[i];
        
        #if LOG_LEVEL >= 3
            logger.printf("[done] %d elements\r\n",path.size());
            logger.printf("[info - pathfinder] Tendage du chemin ... ");
        #endif
        
        
        // Algo de 'tendage' du chemin
        bool continuer = true;
        std::vector<SimplePoint> tempPath;
        while(continuer)
        {
            for(i=1;i<path.size();i+=2)
            {
                tempPath.push_back(path[i-1]);
                int height = (getHeight(path[i-1].x*mpc,path[i-1].y*mpc)+getHeight(path[i+1].x*mpc,path[i+1].y*mpc))/2;
                
                #if LOG_LEVEL >= 4 & LOG_TENDEUR
                    logger.printf("[info - tendeur] Testing (%.3f,%.3f) %d\r\n",path[i].x,path[i].y,height);
                #endif
                
                if(path[i-1].x!=path[i+1].x)
                {
                    // y=a*x+b
                    float a = (path[i-1].y-path[i+1].y)/(path[i-1].x-path[i+1].x);
                    float b = path[i-1].y - a*path[i-1].x;
                    
                    float step = (mpc*0.1f)*cos(atan(a));
                    
                    #if LOG_LEVEL >= 4 & LOG_TENDEUR
                        logger.printf("[info - tendeur] X: a=%.2f b=%.2f\r\n",a,b);
                        logger.printf("[info - tendeur] x [%.3f,%.3f] step=%.6f\r\n",path[i-1].x,path[i+1].x,step);
                    #endif
                    float x;
                    for(x=min(path[i-1].x,path[i+1].x);x<max(path[i-1].x,path[i+1].x);x+=step)
                    {
                        #if LOG_LEVEL >= 4 & LOG_TENDEUR
                            logger.printf("%.3f\t%.3f\t%.3f\r\n",getHeight(x,(a*x+b)),x,(a*x+b));
                        #endif
                        if(getHeight(x,(a*x+b)) > height) // Ca ne passe pas sans ce point
                        {
                            tempPath.push_back(path[i]);
                            
                            #if LOG_LEVEL >= 4 & LOG_TENDEUR
                                logger.printf("[info - tendeur] Adding (%.3f,%.3f) to the path\r\n",path[i].x,path[i].y);
                            #endif
                            break;
                        }
                    }
                    #if LOG_LEVEL >= 4 & LOG_TENDEUR
                        if(x >= max(path[i-1].x,path[i+1].x))
                        {
                            logger.printf("[info - tendeur] Skipping (%.3f,%.3f) to the path\r\n",path[i].x,path[i].y);
                        }
                    #endif
                }
                else if(path[i-1].y!=path[i+1].y)
                {
                    // x=a*y+b
                    float a = (path[i-1].x-path[i+1].x)/(path[i-1].y-path[i+1].y);
                    float b = path[i-1].x - a*path[i-1].y;
                    
                    float step = (mpc*0.1f)*cos(atan(a));
                    
                    #if LOG_LEVEL >= 4 & LOG_TENDEUR
                        logger.printf("[info - tendeur] Y: a=%.2f b=%.2f\r\n",a,b);
                        logger.printf("[info - tendeur] y [%.3f,%.3f] step=%.6f\r\n",path[i-1].y,path[i+1].y,step);
                    #endif
                    float y;
                    for(y=min(path[i-1].y,path[i+1].y);y<max(path[i-1].y,path[i+1].y);y+=step)
                    {
                        #if LOG_LEVEL >= 4 & LOG_TENDEUR
                            logger.printf("%.3f\t%.3f\t%.3f\t%.3f\r\n",getHeight((a*y+b),y),height,(a*y+b),y);
                        #endif
                        if(getHeight((a*y+b),y) > height) // Ca ne passe pas sans ce point
                        {
                            tempPath.push_back(path[i]);
                            
                            #if LOG_LEVEL >= 4 & LOG_TENDEUR
                                logger.printf("[info - tendeur] Adding (%.3f,%.3f) to the path\r\n",path[i].x,path[i].y);
                            #endif
                            break;
                        }
                    }
                    #if LOG_LEVEL >= 4 & LOG_TENDEUR
                        if(y >= max(path[i-1].y,path[i+1].y))
                        {
                            logger.printf("[info - tendeur] Skipping (%.3f,%.3f) to the path\r\n",path[i].x,path[i].y);
                        }
                    #endif
                }
            }
            if(path.back() != tempPath.back())
                tempPath.push_back(path.back());
            
            if(tempPath.size() < path.size()) // On a réussit a enlever un point
            {
                path.clear();
                for(i=0;i<tempPath.size();i++)
                    path.push_back(tempPath[i]);
                continuer = true;
            }
            else
                continuer = false;
            
            tempPath.clear();
        }
        
        #if LOG_LEVEL >= 3
            logger.printf("[done] %d elements\r\n",path.size());
        #endif
        
        return 1;
    }
    else
    {
        for(i=0;i<openList.size();i++)
            delete openList[i];
        for(i=0;i<closeList.size();i++)
            delete closeList[i];
        
        path.clear();
        
        return 2;
    }
}