#ifndef RRT

#define RRT

 

#include <stdio.h>

#include "iostream.h"

#include <stdlib.h>

#include <math.h>

#include "collide.h"

 

#define pi 3.1416

#define Null -1

#define Reach 0

#define Advance 1

#define Trapped 3

#define free 1

#define collide 0

#define pass 1

#define fail 0

#define forward 1

#define sharepath 1

#define freepath 0

#define newRobot 3

struct Nodes{

      float x, y, theta;

      int parent;

      int level;

      int status;

      int shareRegion;

  };

 Nodes path[2][1000];

 Nodes node[2][20000];

 Nodes dualnode[2][20000];

  float goal[2][3];

int halfWidth,halfLength,startpt,endpt;

int reach[2],finalStatus[2],numRegion;

Collision obstacle;

int finalLevel[2],numNodes[2],zone[2];

class Build{

public:

 

 

  float rand[3],  phi,alpha;

  float minDistance[2];

  int numNode[2], currentNode[2], nearestNode[2];

  int  state,direction;

  float minGoalDistance[2];

 

  void build(){}

  int build(float, float) ;

  init();

  rrt(); 

  extend(  float, float, float,int);

  pathsearch();

  sharezone();

  private:

  float value[3]; 

};

 

Build::build(float x,  float y){

    value[0]=x;

    value[1]=y;

}

 

Build::init(){

   node[0][0].x=10.0;

   node[0][0].y=50.0;

   node[0][0].theta=0;

   node[0][0].parent=Null;

   node[0][0].level=0;

   goal[0][0]=410;

   goal[0][1]=50.0;

   goal[0][2]=1.57;

 

   node[1][0].x=50.0;

   node[1][0].y=450.0;

   node[1][0].theta=0;

   node[1][0].parent=Null;

   node[1][0].level=0;

   goal[1][0]=430.0;

   goal[1][1]=50.0;

   goal[1][2]=4.71;

   halfWidth=15;

   halfLength=8;

   minGoalDistance[2]=1000;

   phi=10;

   numNode[0]=1;

   currentNode[0]=1;

   nearestNode[0]=0;

   obstacle.polygon();

  

}

Build::rrt(){

 

int loopNum=10;

int signs;

 

   for (int i=0;i<loopNum;i++){

       rand[0]=random()%470;

       rand[1]=random()%570;

       rand[2]=random()%30;

       signs=random()%2;

       direction=random()%2;

       if(signs==0) rand[2]=-1*rand[2];

       rand[2]=rand[2]*pi/180;       

       state=extend(rand[0], rand[1], rand[2],direction);

       if(state==Reach) {

       loopNum=i;

      

       printf("Reach\n");

       }

       else loopNum++;

 

     }

 

    return 0;

}

 

Build::extend( float x, float y,  float theta, int direct){

 

float distance, goalDistance[2],dx,dy,dtheta,temptheta,orienttheta;

float length,width,zero,rangle;

int status,constraintStatus,angle,heading,goalBias;

 

for(int j=startpt;j<endpt;j++){

 

  minDistance[j]=1000;   

  finalStatus[j]=1;

  goalBias=random()%100;

    for (int i=0;i<numNode[j];i++){

      distance=sqrt((x-node[j][i].x)*(x-node[j][i].x)+(y-node[j][i].y)*(y-                      node[j][i].y));

      if(distance<minDistance[j]){

         nearestNode[j]=i;

         minDistance[j]=distance;

         }

     }

    goalDistance[j]=sqrt((goal[j][0]-node[j][nearestNode[j]].x)*(goal[j][0]-  node[j][nearestNode[j]].x)+ goal[j][1]-      node[j][nearestNode[j]].y)*(goal[j][1]-node[j][nearestNode[j]].y));

    if(goalDistance[j]<50) zone[j]=1;

    if(zone[j]==1 && goalDistance[j]>50) return Trapped;

    if(goalDistance[j]<phi+50) heading=direct;

    else heading=forward;

    dtheta=(phi*tan(theta))/(2*halfLength);

 

    temptheta=node[j][nearestNode[j]].theta+dtheta;

    if (temptheta>2*pi) temptheta-=2*pi;

    if(temptheta<0) temptheta=2*pi+temptheta;

 

    if(heading==forward){

    dx=phi*cos(temptheta);

    dy=phi*sin(temptheta);

    }

    else {

    dx=phi*cos(temptheta+pi);

    dy=phi*sin(temptheta+pi);

 

   }

    zero=-dx*sin(temptheta)+dy*cos(temptheta);

    if(fabs(zero)<.05){

     constraintStatus=pass;

   

    }

  

 //-- upper right corner coordinate

    car.x[0]=node[j][nearestNode[j]].x+dx+(halfWidth*cos(temptheta)+halfLength*sin(temptheta));

    car.y[0]=node[j][nearestNode[j]].y+dy+(-halfWidth*sin(temptheta)+halfLength*cos(temptheta));

//-- lower right corner

    car.x[1]=node[j][nearestNode[j]].x+dx+(halfWidth*cos(temptheta)-halfLength*sin(temptheta));

    car.y[1]=node[j][nearestNode[j]].y+dy+(-halfWidth*sin(temptheta)-halfLength*cos(temptheta));

//-- lower left corner

    car.x[2]=node[j][nearestNode[j]].x+dx+(-halfWidth*cos(temptheta)-halfLength*sin(temptheta));

    car.y[2]=node[j][nearestNode[j]].y+dy+(halfWidth*sin(temptheta)-halfLength*cos(temptheta));

//-- upper left corner

    car.x[3]=node[j][nearestNode[j]].x+dx+(-halfWidth*cos(temptheta)+halfLength*sin(temptheta));

    car.y[3]=node[j][nearestNode[j]].y+dy+(halfWidth*sin(temptheta)+halfLength*cos(temptheta));

    for (i=0;i<4;i++){

    // Checking for collision

       status=obstacle.coll(car.x[i],car.y[i]);

       finalStatus[j]*=status;

    }

// Limit the world coordinates

  if( node[j][nearestNode[j]].x<470 && node[j][nearestNode[j]].y<570 &&

      node[j][nearestNode[j]].x>0 && node[j][nearestNode[j]].y>0)

    {

     finalStatus[j]*=free;}

  else finalStatus[j]*=collide;

 

  if (finalStatus[j]==free){

   

    numNodes[j]++;

    node[j][currentNode[j]].x=node[j][nearestNode[j]].x+dx;

    node[j][currentNode[j]].y=node[j][nearestNode[j]].y+dy;

    node[j][currentNode[j]].theta=temptheta;

    node[j][currentNode[j]].parent=nearestNode[j];

    node[j][currentNode[j]].level=node[j][nearestNode[j]].level+1;

    goalDistance[j]=sqrt((goal[j][0]-node[j][currentNode[j]].x)*(goal[j][0]-node[j][currentNode[j]].x)+

                  (goal[j][1]-node[j][currentNode[j]].y)*(goal[j][1]-node[j][currentNode[j]].y));

 

// orientation is not a concern in this case

//if(goalDistance[j]<=phi ){

 

// orientation takes into account       

if(goalDistance[j]<=phi &&( temptheta>goal[j][2]-.1&& temptheta<goal[j][2]+.1)){

   

     reach[j]=1;

        if(reach[0]==1) startpt=1,endpt=2;     

      else if(reach[1]==1) startpt=0,endpt=1;

        else startpt=0,endpt=2;

      node[j][currentNode[j]].x=goal[j][0];

      node[j][currentNode[j]].y=goal[j][1];

      node[j][currentNode[j]].theta=temptheta;

      node[j][currentNode[j]].parent=nearestNode[j];

      //node[j][currentNode[j]].level=node[j][nearestNode[j]].level+1;

   

       

    }

    else{

    reach[j]=0;

    currentNode[j]++;

    numNode[j]++;

    }

   }

  }

 if(reach[1]==1&&reach[0]==1){

         pathsearch(); 

         return Reach;

     }

   else

  return Trapped;

 

}

 

Build::pathsearch(){  // Search for the final paths

int control[2];

int count[2];

control[0]=1;

control[1]=1;

count[0]=node[0][currentNode[0]].level;

count[1]=node[1][currentNode[1]].level;

printf("count[0]=%d/n",count[0]);

for(int i=0;i<2;i++){

    while(control[i]==1){

 

      path[i][count[i]].x=node[i][currentNode[i]].x;

      path[i][count[i]].y=node[i][currentNode[i]].y;

      path[i][count[i]].theta=node[i][currentNode[i]].theta*180/pi;

      currentNode[i]=node[i][currentNode[i]].parent;

      printf("path[%d][%d]=%f\n",i,count[i],path[i][count[i]].theta);

     if(count[i]==0) control[i]=0;

      else{ control[i]=1;

     

      count[i]--;

      finalLevel[i]++;

      }

   }

}

 

}

 

Build::sharezone(){ // Defining sharezones

float distance;

 

for (int i =1;i<finalLevel[0];i++){

     for(int j=1;j<finalLevel[1];j++){

      distance=sqrt((path[0][i].x-path[1][j].x)*(path[0][i].x-path[1][j].x)+

                  (path[0][i].y-path[1][j].y)*(path[0][i].y-path[1][j].y));

        if(distance<2*halfLength){

              path[0][i].status=sharepath;

       path[1][j].status=sharepath;

 

         if(path[0][i].status==sharepath && path[0][i-1].status!=sharepath){

             numRegion++;

           path[0][i].shareRegion=numRegion;

          path[1][j].shareRegion=numRegion;

           }

           if(path[0][i].status==sharepath && path[0][i-1].status==sharepath){

             path[0][i].shareRegion=numRegion;

           path[1][j].shareRegion=numRegion;

        }

             }

     }

}

printf("numShareRegion=%d\n",numRegion);

}

#endif