C实现简易运动轨迹检测的程序
2011-4-25
这几天,XXX的项目让我做了一个运动轨迹检测的程序,主要用来检测汽车和给定路线的偏移问题,和定位汽车主要在什么路段上。
如下图
下面是一些算法和资料:
首先,要确定移动的点,也就是汽车和线段之间的距离,不能直接理解成点到直线的距离,因为当出现下面的情况的时候,点P到BC和到A的距离都是一样
的,这样就区分不点到底靠近哪条线上了。很显然,点固然靠近的应该是线段AB,所以我对这种情况进行了一些改进,如果遇到这种情况,那么直接计算P点到B之间的距离。其实这个程序的关键都是算点到线段的距离,而不是点到线段的高,这些要分清楚。
点到线段距离的计算:
点到直线的距离可以直接做垂线求取,但线段是有首尾点的,若要求距离则要考虑首尾点。
点和线段的关系大致可以有下面几种:
有特殊情况,是P点和A或B重合,否则,根据∠PAB或∠PBA的角度可以有图1、图2、图4三种情况(包括点在AB之间,算是零度角)。
我做的算法可以快速、简洁地判断角度是钝角还是锐角。
在求垂线距离时,用海伦公式取代三角函数,使得程序看起来很简洁。
1. double GetPointDistance(CPoint p1, CPoint p2)
2. {
3. return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
4. }
5. float GetNearestDistance(CPoint PA, CPoint PB, CPoint P3)
6. {
7.
8. //----------图2--------------------
9. float a,b,c;
10. a=GetPointDistance(PB,P3);
11. if(a<=0.00001)
12. return 0.0f;
13. b=GetPointDistance(PA,P3);
14. if(b<=0.00001)
15. return 0.0f;
16. c=GetPointDistance(PA,PB);
17. if(c<=0.00001)
18. return a;//如果PA和PB坐标相同,则退出函数,并返回距离
19. //------------------------------
20.
21. if(a*a>=b*b+c*c)//--------图3--------
22. return b; //如果是钝角返回b
23. if(b*b>=a*a+c*c)//--------图4-------
24. return a; //如果是钝角返回a
25.
26. //图1
27. float l=(a+b+c)/2; //周长的一半
28. float s=sqrt(l*(l-a)*(l-b)*(l-c)); //海伦公式求面积,也可以用矢量求
29. return 2*s/c;
30. }
下面的程序虽然没用上,还是用经纬度来判断偏移的,不过也贴上,怕以后用到哈。
根据经纬度坐标计算实际距离
double hypot(double x, double y) {
return sqrt(x * x + y * y);
}
double distance(double wd1, double jd1, double wd2, double jd2) {// 根据经纬度坐标计算实际距离
double x, y, out;
double PI = 3.1415926535898;
double R = 6.371229 * 1e6;
x = (jd2 - jd1) * PI * R * cos( ( (wd1 + wd2) / 2) * PI / 180) / 180;
y = (wd2 - wd1) * PI * R / 180;
out = hypot(x, y);
return out;
}
判断汽车轨迹是否偏离的算法其实不难,因为通过计算点到每个线段的距离,找出最小的距离,判断是否小于门限0.0001度(就是50米)就好了。然后返回一个0或者1。嘿嘿,简单吧。
举个例子,比如有8个点,必然有7个线段,依次计算7个线段的长度,然后计算点到7个线段的距离,找出最小的距离,再拿来和门限比较就OK了。
最近我程序构架思想大改,虽然是C语言,但是我引入C++的面向对象思想,运用封装和抽象的思想,大量使用指针和结构体。我用结构体封装了私有变量和函数,同时也提供公共变量和函数。我尽量给用户最简单的和最傻瓜的使用方法,也方便以后自己。
测试平台:Eclipse CDT
三个文件,.h .c 还有个test.c(主要用来演示)
下面是程序:
//Track_Detect.h
#ifndef TRACK_DETECT_H_
#define TRACK_DETECT_H_
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#define THRESHOLD_MILES 50
#define THRESHOLD_DEGREE 0.0001
struct Road_coordinate
{
double x;
double y;
};
struct GetNearestDistance_Private
{
double TempA,TempB,TempC;
double perimeter;
double area;
double (*GetPointDistance)(struct Road_coordinate p1, struct Road_coordinate p2);
};
struct MinDistance_Of_Roads_Private
{
uint32_t Data_Size;
uint32_t Data_Resolution;
double *Temp_Data;
double minTemp;
};
struct GPS_Track_Detect_Private
{
//struct Road_coordinate *RXY;
double (*GetNearestDistance)(struct Road_coordinate PA, struct Road_coordinate PB, struct Road_coordinate PC);
struct MinDistance_Of_Roads_Private MinDistance_Of_Roads;
};
struct GPS_Track_Detect_Public
{
struct Road_coordinate *set_p;
uint32_t num;
struct Road_coordinate *move_p;
uint8_t MinNum;
double (*MinDistance_Of_Roads)(struct Road_coordinate *set_p, uint32_t num, struct Road_coordinate *move_p, uint8_t *MinNum);
};
//外部函数
extern double MinDistance_Of_Roads(struct Road_coordinate *set_p, uint32_t num, struct Road_coordinate *move_p, uint8_t *MinNum);
extern uint32_t GPS_Track_Detect(uint32_t *deviate_flag, double *minValue, struct GPS_Track_Detect_Public *p);
//注意set_p和move_p是指针
#define GPS_Track_Detect_MinDistance(set_p, num, move_p, MinNum) MinDistance_Of_Roads(set_p, num, move_p, MinNum)
#endif
//Track_Detect.c
//门限是0.0001度,就是50米
#include "Track_Detect.h"
//私有函数声明区
static double GetPointDistance(struct Road_coordinate p1, struct Road_coordinate p2);
static double GetNearestDistance(struct Road_coordinate PA, struct Road_coordinate PB, struct Road_coordinate PC);
static double GetPointDistance(struct Road_coordinate p1, struct Road_coordinate p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
static double GetNearestDistance(struct Road_coordinate PA, struct Road_coordinate PB, struct Road_coordinate PC)
{
struct GetNearestDistance_Private *this = (struct GetNearestDistance_Private *) malloc(sizeof(struct GetNearestDistance_Private));
this->GetPointDistance = GetPointDistance;
this->TempA = this->GetPointDistance(PB,PC);
double return_value = 0.0;
if(this->TempA <= 0.00001)
{
free(this);
return 0.0f;
}
this->TempB = this->GetPointDistance(PA,PC);
if(this->TempB <=0.00001 )
{
//return_value = this->TempB;
free(this);
return 0.0f;
}
this->TempC = this->GetPointDistance(PA,PB);
if(this->TempC <= 0.00001)
{
return_value = this->TempA;
free(this);
return return_value;//如果PA和PB坐标相同,则退出函数,并返回距离
}
if(this->TempA * this->TempA >= this->TempB * this->TempB + this->TempC * this->TempC)
{
return_value = this->TempB; //如果是钝角返回TempB
free(this);
return return_value;
}
if(this->TempB * this->TempB >= this->TempA * this->TempA + this->TempC * this->TempC)
{
return_value = this->TempA;
free(this);
return return_value; //如果是钝角返回TempA
}
this->perimeter = (this->TempA + this->TempB + this->TempC) / 2; //周长的一半
this->area = sqrt(this->perimeter * (this->perimeter - this->TempA) * (this->perimeter - this->TempB) * (this->perimeter - this->TempC)); //海伦公式求面积,也可以用矢量求
return_value = 2 * this->area / this->TempC;
free(this);
return return_value;
}
double MinDistance_Of_Roads(struct Road_coordinate *set_p, uint32_t num, struct Road_coordinate *move_p, uint8_t *MinNum)
{
uint32_t i = 0;
double return_value = 0.0;
struct GPS_Track_Detect_Private *this = (struct GPS_Track_Detect_Private *) malloc(sizeof(struct GPS_Track_Detect_Private));
this->GetNearestDistance = GetNearestDistance;
this->MinDistance_Of_Roads.Data_Resolution = sizeof(set_p[0]);
this->MinDistance_Of_Roads.Data_Size = this->MinDistance_Of_Roads.Data_Resolution * num;//动态分配数据空间
this->MinDistance_Of_Roads.Temp_Data = (double *)malloc(this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n", this->MinDistance_Of_Roads.Data_Size);
//printf("%d\n", this->MinDistance_Of_Roads.Data_Resolution);
for(i = 0; i < (this->MinDistance_Of_Roads.Data_Size / this->MinDistance_Of_Roads.Data_Resolution - 1 ); i++)
{
*(this->MinDistance_Of_Roads.Temp_Data + i) = this->GetNearestDistance(set_p[i], set_p[i + 1], *move_p);
//printf("%f\n",*(this->MinDistance_Of_Roads.Temp_Data + i));
}
this->MinDistance_Of_Roads.minTemp = *(this->MinDistance_Of_Roads.Temp_Data + 0);
for(i = 1; i < (this->MinDistance_Of_Roads.Data_Size / this->MinDistance_Of_Roads.Data_Resolution - 1 ); i++)
{
if(*(this->MinDistance_Of_Roads.Temp_Data + i) < this->MinDistance_Of_Roads.minTemp)
{
this->MinDistance_Of_Roads.minTemp = *(this->MinDistance_Of_Roads.Temp_Data + i);
if(MinNum != NULL)
*MinNum = i;
}
}
free(this->MinDistance_Of_Roads.Temp_Data);
return_value = this->MinDistance_Of_Roads.minTemp;
free(this);
//printf("\n\n\n");
return return_value;
}
//deviate_flag中 0 表示不偏移 1表示偏移
uint32_t GPS_Track_Detect(uint32_t *deviate_flag, double *minValue, struct GPS_Track_Detect_Public *p)
{
p->MinDistance_Of_Roads = MinDistance_Of_Roads;
*minValue = p->MinDistance_Of_Roads(p->set_p, p->num, p->move_p, &p->MinNum);
*deviate_flag = THRESHOLD_DEGREE >= *minValue ? 0 : 1;
return 0;
}
// 测试文件,使用范例Track_Detect_test.c
#include "Track_Detect.h"
struct Road_coordinate RoadXY[] = {
{25.037936,98.431538},
{25.035104,98.429070},
{25.046580,98.411377},
{25.049696,98.409866},
{25.050273,98.407812},
{25.053200,98.406574},
{25.056470,98.406300},
{25.056452,98.404327}
};
int main(void) {
struct Road_coordinate test_dat = {.x = 25.050273, .y = 98.407712};
struct GPS_Track_Detect_Public GTDtest_dat;
GTDtest_dat.move_p = &test_dat;
GTDtest_dat.num = 8;
GTDtest_dat.set_p = RoadXY;
double minValue;
uint32_t deviate_flag;
GPS_Track_Detect(&deviate_flag, &minValue, >Dtest_dat);
printf("%d\n",GTDtest_dat.MinNum);
printf("\n\n");
printf("%f\n",minValue);
printf("%d\n",deviate_flag);
printf("\n\n");
uint8_t num;
printf("%f\n", GPS_Track_Detect_MinDistance(RoadXY, 8, &test_dat, &num));
printf("%d\n",num);
return EXIT_SUCCESS;
}