Библиотека PolyMap — различия между версиями
=DeaD= (обсуждение | вклад) (Новая: {{InfoBlock|Теоретические выкладки по этой теме можно найти на странице [[Перемещение робота в нужную точк...) |
=DeaD= (обсуждение | вклад) (→Функции (описание)) |
||
| Строка 7: | Строка 7: | ||
== Функции (описание)== | == Функции (описание)== | ||
| + | === saveToFile === | ||
| + | Сохранить карту в файл. | ||
| + | |||
| + | |||
| + | === loadFromFile === | ||
| + | Загрузить карту из файла. | ||
| + | |||
| + | === addObstacle === | ||
| + | Добавить на карту информацию о препятствии в переданном многоугольнике. | ||
| + | |||
| + | === addFreeSpace === | ||
| + | Добавить на карту информацию о свободном пространстве в переданном многоугольнике. | ||
| + | |||
| + | === prepareWayFindingMap === | ||
| + | Подготовить информацию для поиска пути. Параметры - дистанция безопасности, количество вершин в скруглении и требуется ли поиск только путей в разведанной области. | ||
| + | |||
| + | === findShortestWay === | ||
| + | Найти самый короткий путь между переданными точками. Вызывать только при подготовленной информации для поиска пути. | ||
== Файлы библиотеки == | == Файлы библиотеки == | ||
Версия 18:10, 25 января 2008
| Теория | |
Теоретические выкладки по этой теме можно найти на странице Перемещение робота в нужную точку векторной карты | |
Содержание
Назначение библиотеки
Решение задачи поиска пути на векторной карте с отступом от препятствий на требуемое расстояние.
Функции (описание)
saveToFile
Сохранить карту в файл.
loadFromFile
Загрузить карту из файла.
addObstacle
Добавить на карту информацию о препятствии в переданном многоугольнике.
addFreeSpace
Добавить на карту информацию о свободном пространстве в переданном многоугольнике.
prepareWayFindingMap
Подготовить информацию для поиска пути. Параметры - дистанция безопасности, количество вершин в скруглении и требуется ли поиск только путей в разведанной области.
findShortestWay
Найти самый короткий путь между переданными точками. Вызывать только при подготовленной информации для поиска пути.
Файлы библиотеки
Пока выложена альфа-версия библиотеки без работы с файлами, ограниченная по количеству вершин в графе - 1000 и с доступным количеством вершин на скруглениях - только 2.
PolyMap.h
<source lang="cpp">
- ifndef PolyMapH
- define PolyMapH
//---------------------------------------------------------------------------
- include "myPolyBool.h"
- include <dstring.h>
- include <StdCtrls.hpp>
struct pmPoint{
int x,y; pmPoint* next;
};
class pmMap{ public:
//Сама карта PAREA* revealed; PAREA* obstacles;
//Карта запретных зон для поиска пути PAREA* restricted; PAREA* safe_distanced;
TMemo* tm;
//Структуры данных для хранения графа double vert_x[1000]; double vert_y[1000]; int vert_qty; int graph_ready; double graph[1000][1000];
//Структуры данных для дейкстры int vert_queue[1000]; int vert_from[1000]; int vert_flag[1000]; double vert_dist[1000];
PLINE2* getAroundLine(int x1, int y1, int x2, int y2, int safe_distance, int rounding_size); int intersectLine2Lines(int x1, int y1, int x2, int y2, int xp, int yp, int xc, int yc, int xn, int yn); int intersectLinePAREA(int x1, int y1, int x2, int y2, PAREA* p); void stepBackSafeDistance(int safe_distance, int rounding_size); void getRestricted(int only_revealed); void generateVertexList(); void generateGraph();
public:
pmMap(); ~pmMap(); void saveToFile(const char* filename); void loadFromFile(const char* filename); void addObstacle(pmPoint* poly); void addFreeSpace(pmPoint* poly); void prepareWayFindingMap(int safe_distance, int rounding_size, int only_revealed); pmPoint* findShortestWay(pmPoint* start, pmPoint* finish);
};
//---------------------------------------------------------------------------
- endif
</source>
PolyMap.cpp
<source lang="cpp">
- pragma hdrstop
- include "PolyMap.h"
- include <Math.h>
- include "myBasicGeometry.h"
//---------------------------------------------------------------------------
- pragma package(smart_init)
void pmMap::saveToFile(const char* filename){
//Save
};
void pmMap::loadFromFile(const char* filename){
PAREA::Del(&revealed); PAREA::Del(&obstacles); PAREA::Del(&restricted); //Load
};
PLINE2* pmMap::getAroundLine(int x1, int y1, int x2, int y2, int safe_distance, int rounding_size){
double dx=x2-x1; double dy=y2-y1; double dd=sqrt(dx*dx+dy*dy); double du_x=dx/dd*safe_distance; //Сонаправленный вектор длиной safe_distance double du_y=dy/dd*safe_distance; //Сонаправленный вектор длиной safe_distance double dv_x=du_y; //Перпендикулярный вектор длиной safe_distance double dv_y=-du_x; //Перпендикулярный вектор длиной safe_distance
PLINE2* p=NULL; GRID2 g;
//пока будем всё тупо обводить прямоугольниками
if( rounding_size>2 ){ rounding_size=2; };
if( rounding_size<3 ){
g.x=x2+dv_x+du_x;
g.y=y2+dv_y+du_y;
PLINE2::Incl(&p, g);
g.x=x2-dv_x+du_x;
g.y=y2-dv_y+du_y;
PLINE2::Incl(&p, g);
g.x=x1-dv_x-du_x;
g.y=y1-dv_y-du_y;
PLINE2::Incl(&p, g);
g.x=x1+dv_x-du_x;
g.y=y1+dv_y-du_y;
PLINE2::Incl(&p, g);
}else{
//Тут будем по хитрому отступать на safe_distance, а пока упростим задачу
};
p->Prepare();
if (not p->IsOuter()) // make sure the contour is outer
p->Invert();
return p;
};
void pmMap::getRestricted(int only_revealed){
if(only_revealed==1){
//Подготовим область перекрывающую всё поле
PAREA* r=NULL;
PLINE2* pline = NULL;
GRID2 gr;
gr.x=500000;
gr.y=500000;
PLINE2::Incl(&pline, gr);
gr.x=-500000;
gr.y=500000;
PLINE2::Incl(&pline, gr);
gr.x=-500000;
gr.y=-500000;
PLINE2::Incl(&pline, gr);
gr.x=500000;
gr.y=-500000;
PLINE2::Incl(&pline, gr);
pline->Prepare();
if (not pline->IsOuter()) // make sure the contour is outer
pline->Invert();
PAREA::InclPline(&r, pline);
// Запретная зона - всё неразведанное и препятствия PAREA* r1=NULL;
//Неразведанное int err = PAREA::Boolean(r, revealed, &r1, PAREA::SB);
//Препятствия PAREA::Del(&restricted); restricted=NULL; err = PAREA::Boolean(r1, obstacles, &restricted, PAREA::UN);
}else{
//Запретная зона - только препятствия restricted=obstacles->Copy();
};
};
void pmMap::stepBackSafeDistance(int safe_distance, int rounding_size){
//Начнем с области restricted PAREA* r0=restricted->Copy(); PAREA* r1=NULL;
PAREA* curl=restricted;
while( curl!=NULL ){
//Будем добавлять к ней по очереди контуры вокруг её ребер
PLINE2* cur;
cur=curl->cntr;
while(cur!=NULL){
VNODE2* nc;
nc=cur->head;
while(nc!=NULL){
PLINE2* x=getAroundLine(nc->g.x,nc->g.y,nc->next->g.x,nc->next->g.y,safe_distance,rounding_size);
x->Prepare();
if (not x->IsOuter()) // make sure the contour is outer
x->Invert();
//Добавим полученный контур к уже имеющейся области
PAREA* b=NULL;
PAREA::InclPline(&b, x);
int err = PAREA::Boolean(r0, b, &r1, PAREA::UN); //Будем избегать на расстоянии Safe_Distance
PAREA::Del(&r0);
PAREA::Del(&b);
r0=r1;
r1=NULL;
nc=nc->next;
if(nc==cur->head){nc=NULL;};
};
cur=cur->next;
if(cur==curl->cntr){cur=NULL;};
};
curl=curl->f;
if(curl==restricted){ curl=NULL; };
};
//сохраним полученную область в safe_distanced PAREA::Del(&safe_distanced); safe_distanced=r0; r0=NULL;
};
int pmMap::intersectLinePAREA(int x1, int y1, int x2, int y2, PAREA* p){
PAREA* curl=p;
while( curl!=NULL ){
PLINE2* cur=curl->cntr;
while(cur != NULL){
VNODE2* vcur=cur->head;
while(vcur != NULL){
int xp=vcur->prev->g.x;
int yp=vcur->prev->g.y;
int xc=vcur->g.x;
int yc=vcur->g.y;
int xn=vcur->next->g.x;
int yn=vcur->next->g.y;
int rs=rfwLineAndPolygonSectionCrossing(x1,y1,x2,y2,xp,yp,xc,yc,xn,yn);
if(rs==1){ return 1; };
vcur=vcur->next;
if(vcur==cur->head){ vcur=NULL; };
};
cur=cur->next;
if(cur==curl->cntr){ cur=NULL; };
};
curl=curl->f;
if(curl==p){ curl=NULL; };
};
return 0;
};
void pmMap::generateGraph(){
for(int i=0; i<vert_qty; i++){
for(int j=i+1; j<vert_qty; j++){
if(intersectLinePAREA(vert_x[i],vert_y[i],vert_x[j],vert_y[j],safe_distanced)==0){
graph[i][j]=sqrt((vert_x[i]-vert_x[j])*(vert_x[i]-vert_x[j])+(vert_y[i]-vert_y[j])*(vert_y[i]-vert_y[j]));
graph[j][i]=graph[i][j];
}else{
graph[i][j]=-1;
graph[j][i]=graph[i][j];
};
};};
};
void pmMap::generateVertexList(){
vert_qty=0;
PAREA* curl=safe_distanced;
while( curl!=NULL ){
//Выделим вершины на которых будем строить граф
PLINE2* cur=curl->cntr;
while(cur != NULL){
VNODE2* vcur=cur->head;
while(vcur != NULL){
int dx1=vcur->g.x-vcur->prev->g.x;
int dy1=vcur->g.y-vcur->prev->g.y;
int dx2=vcur->next->g.x-vcur->g.x;
int dy2=vcur->next->g.y-vcur->g.y;
if(dx1*dy2>dy1*dx2){
vert_x[vert_qty]=vcur->g.x;
vert_y[vert_qty]=vcur->g.y;
vert_qty++;
if(vert_qty>998){vert_qty=1/0;};
};
vcur=vcur->next;
if(vcur==cur->head){ vcur=NULL; };
};
cur=cur->next;
if(cur==curl->cntr){ cur=NULL; };
};
curl=curl->f;
if(curl==safe_distanced){ curl=NULL; };
};
};
void pmMap::prepareWayFindingMap(int safe_distance, int rounding_size, int only_revealed){
//Сначала получим что будем объезжать - препятствия или еще неразведанное getRestricted(only_revealed);
//Затем отступим от всех препятствий на SAFE_DISTANCE stepBackSafeDistance(safe_distance, rounding_size);
//Выделим вершины generateVertexList();
//Построим граф generateGraph();
};
pmPoint* pmMap::findShortestWay(pmPoint* start, pmPoint* finish) {
//Добавим стартовую и финишную вершины int v_qty=vert_qty+2; vert_x[vert_qty]=start->x; vert_y[vert_qty]=start->y; vert_x[vert_qty+1]=finish->x; vert_y[vert_qty+1]=finish->y;
//Достроим граф для них
for(int i=0; i<v_qty; i++){
for(int j=vert_qty; j<v_qty; j++){
if(intersectLinePAREA(vert_x[i],vert_y[i],vert_x[j],vert_y[j],safe_distanced)==0){
graph[i][j]=sqrt((vert_x[i]-vert_x[j])*(vert_x[i]-vert_x[j])+(vert_y[i]-vert_y[j])*(vert_y[i]-vert_y[j]));
graph[j][i]=graph[i][j];
}else{
graph[i][j]=-1;
graph[j][i]=graph[i][j];
};
};};
//Подготовим всё для Дейкстры, начнем с финишной вершины for(int i=0; i<v_qty; i++) vert_flag[i]=0; int queue_start=0; int queue_end=1; vert_dist[vert_qty+1]=0; vert_queue[0]=vert_qty+1; vert_flag[vert_qty+1]=1; vert_from[vert_qty+1]=-1;
//Основной цикл Дейкстры
while(queue_start<queue_end){
int cur=vert_queue[queue_start];
if( cur==vert_qty ){
queue_start=queue_end;
}else{
for(int i=0; i<v_qty; i++) if(i!=cur){
if(graph[cur][i]>=0){
if( vert_flag[i]==0 ){
vert_flag[i]=1;
int j=queue_end;
vert_queue[queue_end++]=i;
vert_dist[i]=vert_dist[cur]+graph[cur][i];
vert_from[i]=cur;
while(vert_dist[vert_queue[j]]<vert_dist[vert_queue[j-1]]){
int k=vert_queue[j];
vert_queue[j]=vert_queue[j-1];
vert_queue[j-1]=k;
j--;
};
}else{
if( vert_dist[i]>vert_dist[cur]+graph[cur][i] ){
vert_dist[i]=vert_dist[cur]+graph[cur][i];
vert_from[i]=cur;
};
};
};
}; }; queue_start++; };
//Если смогли дойти до стартовой вершины, тогда
if(vert_flag[vert_qty]==0){
return NULL;
}else{
//Заполним структуру показывающую найденный путь и вернём её.
pmPoint* p=new pmPoint();
pmPoint* x=p;
int cur=vert_qty;
while(cur!=-1){
p->x=vert_x[cur];
p->y=vert_y[cur];
cur=vert_from[cur];
if(cur!=-1){ p->next=new pmPoint(); p=p->next; }else{ p->next=NULL; };
};
return x;
};
};
void pmMap::addObstacle(pmPoint* poly){
pmPoint* cur=poly;
PAREA* p=NULL;
PLINE2 * pline = NULL;
while(cur!=NULL){
GRID2 gr;
gr.x=cur->x;
gr.y=cur->y;
PLINE2::Incl(&pline, gr);
cur=cur->next;
if(cur==poly){cur=NULL;};
};
pline->Prepare();
if (not pline->IsOuter()) // make sure the contour is outer
pline->Invert();
PAREA::InclPline(&p, pline);
// Добавим к разведанной области PAREA * R = NULL; int err = PAREA::Boolean(revealed, p, &R, PAREA::UN); PAREA::Del(&revealed); revealed=R;
// Добавим к препятствиям R = NULL; err = PAREA::Boolean(obstacles, p, &R, PAREA::UN); PAREA::Del(&obstacles); obstacles=R;
};
void pmMap::addFreeSpace(pmPoint* poly){
pmPoint* cur=poly;
PAREA* p=NULL;
PLINE2 * pline = NULL;
while(cur!=NULL){
GRID2 gr;
gr.x=cur->x;
gr.y=cur->y;
PLINE2::Incl(&pline, gr);
cur=cur->next;
if(cur==poly){cur=NULL;};
};
pline->Prepare();
if (not pline->IsOuter()) // make sure the contour is outer
pline->Invert();
PAREA::InclPline(&p, pline);
// Добавим к разведанной области PAREA * R = NULL; int err = PAREA::Boolean(revealed, p, &R, PAREA::UN); PAREA::Del(&revealed); revealed=R;
};
pmMap::pmMap(){
revealed=NULL; obstacles=NULL; restricted=NULL; safe_distanced=NULL; graph_ready=0; vert_qty=0;
};
pmMap::~pmMap(){
PAREA::Del(&revealed); PAREA::Del(&obstacles); PAREA::Del(&restricted); PAREA::Del(&safe_distanced);
};
</source>