#include "gpsr_neighbor.h"
#define PI 3.141593
#define MAX(a, b) (a>=b?a:b)
#define MIN(a, b) (a>=b?b:a)
初始化当前节点:my_id_、my_x_、my_y_分别代表当前节点的id标识以及地理位置信息,初始化阶段节点尚不存在。
初始化邻居列表:首、尾指针均指向空,并将邻居列表中表项数量归零。
关于构造函数参照此文章 click here
关于结构体指针参照此文章click here
GPSRNeighbors::GPSRNeighbors(){
my_id_ = -1;
my_x_ = 0.0;
my_y_ = 0.0;
head_ = tail_ = NULL;
nbSize_ = 0;
}
关于析构函数参照此文章click here
GPSRNeighbors::~GPSRNeighbors(){
struct gpsr_neighbor *temp = head_;
while(temp){
temp = temp->next_;
free(head_);
head_ = temp;
}
}
double
GPSRNeighbors::getdis(double ax, double ay, double bx, double by){
double tempx = ax - bx;
double tempy = ay - by;
tempx = tempx * tempx;
tempy = tempy * tempy;
double result = sqrt(tempx + tempy);
return result;
}
int
GPSRNeighbors::nbsize(){
return nbSize_;
}
void
GPSRNeighbors::myinfo(nsaddr_t mid, double mx, double my){
my_id_ = mid;
my_x_ = mx;
my_y_ = my;
}
作用是根据所给出的id来返回对应的邻居节点。从邻居列表的第一项开始遍历邻居表,通过比较得到与所给id相符合的表项并返回,若表中不存在符合要求的表项,返回NULL。
struct gpsr_neighbor*
GPSRNeighbors::getnb(nsaddr_t nid){
struct gpsr_neighbor *temp = head_;
while(temp){
if(temp->id_ == nid){
if((GPSR_CURRENT - temp->ts_) < DEFAULT_GPSR_TIMEOUT)
return temp;
else {
delnb(temp); //if this entry expire, delete it and return NULL
return NULL;
}
return temp;
}
temp = temp->next_; //遍历邻居表
}
return NULL;
}
根据getnb()的返回结果判断邻居列表中是否已经存在id为 nid 的表项:
void
GPSRNeighbors::newNB(nsaddr_t nid, double nx, double ny){
struct gpsr_neighbor *temp = getnb(nid); //temp指向id为nid的节点
if(temp==NULL){ //it is a new neighbor
temp=(struct gpsr_neighbor*)malloc(sizeof(struct gpsr_neighbor));
temp->id_ = nid;
temp->x_ = nx;
temp->y_ = ny;
temp->ts_ = GPSR_CURRENT;
temp->next_ = temp->prev_ = NULL;
if(tail_ == NULL){ //the list now is empty
head_ = tail_ = temp;
nbSize_ = 1;
}
else { //now the neighbors list is not empty
tail_->next_ = temp;
temp->prev_ = tail_;
tail_ = temp;
nbSize_++;
}
}
else { //it is a already known neighbor
temp->ts_ = GPSR_CURRENT;
temp->x_ = nx; //the updating of location is allowed
temp->y_ = ny;
}
}
判断该id对应的表项在邻居列表中是否已存在,若不存在,则什么也不做;若存在,调用delnb(struct gpsr_neighbor *)给这个表项删掉。
void
GPSRNeighbors::delnb(nsaddr_t nid){
struct gpsr_neighbor *temp = getnb(nid);
if(temp==NULL) return;
else delnb(temp);
}
首先是根据该链表结点O是否为头结点(它的前指针是否指向NULL)来判断其是否为链表的头结点。
void
GPSRNeighbors::delnb(struct gpsr_neighbor *nb){
struct gpsr_neighbor *preffix = nb->prev_;
if(preffix == NULL){
head_ = nb->next_;
nb->next_ = NULL;
if(head_ == NULL)
tail_ = NULL;
else
head_->prev_ = NULL;
free(nb);
}
else {
preffix->next_ = nb->next_;
nb->prev_ = NULL;
if(preffix->next_ == NULL)
tail_ = preffix;
else
(preffix->next_)->prev_ = preffix;
free(nb);
}
nbSize_--;
}
比较邻居列表中节点的停留时间(当前时间与上次接收到hello消息的时间差)与生存时间,若已经超出规定的生存时间,则将该节点在邻居列表中删去(这里就不管前向指针了吗?不太清楚),若未超出,则继续检查下一节点。
void
GPSRNeighbors::delalltimeout(){
struct gpsr_neighbor *temp = head_;
struct gpsr_neighbor *dd;
while(temp){
if((GPSR_CURRENT - temp->ts_) >= DEFAULT_GPSR_TIMEOUT){
dd = temp;
temp = temp->next_;
delnb(dd);
}
else temp = temp->next_;
}
}
首先调用函数getdis()获取当前节点与目的节点的距离mindis,然后遍历邻居列表,依次比较列表中每个节点和目的节点的距离,并用更小的distance去更新mindis。直到最后便得到邻居列表中距离目的节点距离最小的节点。(这时候应该是若收到的返回值nexthop=-1,就代表要开始周边转发了?)
nsaddr_t
GPSRNeighbors::gf_nexthop(double dx, double dy){
struct gpsr_neighbor *temp = head_;
//initializing the minimal distance as my distance to sink
double mindis =getdis(my_x_, my_y_, dx, dy);
nsaddr_t nexthop = -1; //the nexthop result
while(temp){
double tempdis = getdis(temp->x_, temp->y_, dx, dy);
if(tempdis < mindis){
mindis = tempdis;
nexthop = temp->id_;
}
temp = temp->next_;
}
return nexthop;
}
RNG平面图click here
对处在已知节点 O 的邻居列表中的所有节点 N ,都分别计算他们之间的距离dis(ON),然后对每一对节点O,N分别计算他们各自与邻居列表中其他节点 M 之间的距离dis(OM) 和 dis(NM)。根据RNG平面图的定义,把所有满足dis(ON) <= max[dis(OM), dis(NM)]的节点N计入新链表。
struct gpsr_neighbor *
GPSRNeighbors::rng_planarize()
{
struct gpsr_neighbor *temp, *result, *index;
index = head_;
result = NULL;
while(index)
{
double mdis = getdis(my_x_, my_y_, index->x_, index->y_); //当前节点和其邻居节点的距离
temp = head_;
while(temp) //判断是否有节点,使得其到my和index的最大距离小于my和index的距离(有的话代表这个邻居节点不好使)
{
if(temp->id_ != index->id_)
{
double tempdis1 = getdis(my_x_, my_y_, temp->x_, temp->y_);
double tempdis2 = getdis(index->x_, index->y_, temp->x_, temp->y_);
if(tempdis1 < mdis && tempdis2 < mdis)
break;
}
temp=temp->next_;
}
if(temp==NULL) //将该邻居节点记录
{
temp = (struct gpsr_neighbor*)malloc(sizeof(struct gpsr_neighbor));
temp->id_ = index->id_;
temp->x_ = index->x_;
temp->y_ = index->y_;
temp->next_ = result; //头插
temp->prev_ = NULL;
if(result) //前向指针
result->prev_ = temp;
result = temp;
}
index=index->next_; //遍历邻居表
}
return result;
}
struct gpsr_neighbor *
GPSRNeighbors::gg_planarize(){
struct gpsr_neighbor *temp, *result, *index;
index = head_;
result = NULL;
while(index)
{
double midpx = my_x_ + (index->x_ - my_x_)/2.0;
double midpy = my_y_ + (index->y_ - my_y_)/2.0;
double mdis = getdis(my_x_, my_y_, midpx, midpy); //按图形来理解,为圆半径长度
temp = head_;
while(temp) //判断邻居表中所有节点是否在圆的范围内
{
if(temp->id_ != index->id_)
{
double tempdis = getdis(midpx, midpy, temp->x_, temp->y_);
if(tempdis < mdis)
break;
}
temp=temp->next_;
}
if(temp==NULL) //在圆范围内不存在节点,则可以选择index点
{
temp = (struct gpsr_neighbor*)malloc(sizeof(struct gpsr_neighbor));
temp->id_ = index->id_;
temp->x_ = index->x_;
temp->y_ = index->y_;
temp->next_ = result; //前插
temp->prev_ = NULL;
if(result)
result->prev_ = temp;
result = temp;
}
index=index->next_;
}
return result;
}
首先计算两点R1(x1,y1)和R2(x2,y2)之间的距离,再计算出两点连线与坐标轴的正弦值和余弦值。这时候要判断sin的符号,若sin>0,代表R2在R1的y正方向,计算arccos(cos)即可求出角度。否则代表R2在R1的y负方向,用2π减去所求值采薇实际角度。
double
GPSRNeighbors::angle(double x1, double y1, double x2, double y2){
double line_len = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
double sin_theta, cos_theta;
double theta;
if(line_len == 0.0){
printf("2 nodes are the same\n");
return -1.0;
}
sin_theta = (y2-y1)/line_len;
cos_theta = (x2-x1)/line_len;
theta = acos(cos_theta);
if(sin_theta<0){
theta = 2*PI - theta;
}
return theta;
}
只搞懂了判断平行(abtan(x) == a*tan(x)*b),对交叉那部分还是不怎么懂。
/* To check the line from me to theother, and the line from source
* and destination is intersecting each other or not
* Note: 2 line segments intersects each other if they have a common
* point, BUT here, if the common point is the end point,
* we don't count it.
*/
int
GPSRNeighbors::intersect(nsaddr_t theother, double sx, double sy,
double dx, double dy){
//line 1 (x1,y1)--(x2,y2) is the segment
//line 2 (x3,y3)--(x4,y4) is the xD
struct gpsr_neighbor *other = getnb(theother); //根据id获取该邻居节点
if(other==NULL){
printf("Wrong the other node\n");
exit(1);
}
double x1 = my_x_;
double y1 = my_y_;
double x2 = other->x_;
double y2 = other->y_;
double x3 = sx;
double y3 = sy;
double x4 = dx;
double y4 = dy;
double a1 = y2 - y1;
double b1 = x1 - x2;
double c1 = x2*y1 - x1*y2;
double a2 = y4 - y3;
double b2 = x3 - x4;
double c2 = x4*y3 - x3*y4;
double denom = a1*b2 - a2*b1;
double x, y; //the result;
if(denom == 0) {
return 0; //parallel lines;
}
x = (b1*c2 - b2*c1)/denom;
y = (a2*c1 - a1*c2)/denom;
if(x > MIN(x1, x2) && x < MAX(x1, x2) &&
x > MIN(x3, x4) && x < MAX(x3, x4))
return 1;
else return 0;
}
int
GPSRNeighbors::num_of_neighbors(struct gpsr_neighbor *nblist){
struct gpsr_neighbor *temp = nblist;
int counter = 0;
while(temp){
counter++;
temp = temp->next_;
}
return counter;
}
void
GPSRNeighbors::free_neighbors(struct gpsr_neighbor *nblist){
struct gpsr_neighbor *temp, *head;
head = nblist;
while(head){
temp = head;
head = head->next_;
free(temp);
}
}
首先根据type来确定是GG平面化或者RNG平面化,得到平面化后的邻居列表。
nsaddr_t
GPSRNeighbors::peri_nexthop(int type_, nsaddr_t last,
double sx, double sy,
double dx, double dy)
{
struct gpsr_neighbor *planar_neighbors, *temp;
double alpha, minangle;
nsaddr_t nexthop=-1;
if(type_) //GG 平面化
{
planar_neighbors = gg_planarize(); //得到GG平面化后的邻居列表
}
else //RNG 平面化
{
planar_neighbors = rng_planarize(); //得到RNG平面化后的邻居列表
}
if(last>-1)
{
struct gpsr_neighbor *lastnb = getnb(last);
if(lastnb == NULL)
{
printf("Wrong last nb %d->%d\n", last, my_id_);
exit(1);
}
alpha = angle(my_x_, my_y_, lastnb->x_, lastnb->y_); //计算当前节点与上一跳节点连线的夹角
}
else
alpha = angle(my_x_, my_y_, dx, dy); //计算当前节点与目的节点连线的夹角
temp = planar_neighbors;
while(temp) //遍历平面化后的邻居列表
{
if(temp->id_ != last)
{
double delta;
delta = angle(my_x_, my_y_, temp->x_, temp->y_); //计算当前节点与邻居节点连线的夹角
delta = delta - alpha;
//得到“当前节点与邻居节点连线” 与 “当前节点与目的节点连线”或“当前节点与上一跳节点连线”的夹角
if(delta < 0.0) //这就规定了逆时针方向。
{
delta = 2*PI + delta;
}
if(delta < minangle)
{
minangle = delta;
nexthop = temp->id_;
}
}
temp = temp->next_;
}
if(num_of_neighbors(planar_neighbors) > 1 && intersect(nexthop, sx, sy, dx, dy))
{
free_neighbors(planar_neighbors);
return peri_nexthop(type_, nexthop, sx, sy, dx, dy);
}
return nexthop;
}
将当前节点id写入到文件中,然后指针temp指向链表头部,遍历链表,获取每个节点的id并写入到文件中。从而完成邻居列表的转储工作。
void
GPSRNeighbors::dump(){
delalltimeout(); //删除超时邻居节点
FILE *fp = fopen(NB_TRACE_FILE, "a+");
struct gpsr_neighbor *temp = head_;
fprintf(fp, "%d:\t", my_id_);
while(temp){ //遍历邻居表
fprintf(fp, "%d ", temp->id_);
temp = temp->next_;
}
fprintf(fp,"\n");
fclose(fp);
}