/**/ if (abs(dAlpha) >= M_PI) //разница между новым углом и предыдущим не нормальная!
{//необходимо скорректировать текущую alpha
/**/ if (dAlpha < 0.0)
{
while (abs(dAlpha) > M_PI)
{
alpha += 2.0 * M_PI;
dAlpha += 2.0 * M_PI;
}
}else
{
while (dAlpha >= M_PI)
{
alpha -= 2.0 * M_PI;
dAlpha -= 2.0 * M_PI;
}
}
}
_tmpDotFing.alpha = alpha; //запоминание направления из точки А//
vecDotS.push_front(_tmpDotFing);
///////////////////////////////////////////////////////////////////////
///////проверяем два соседних длинных вектора при условии что//////////
///////пройдено достаточно точек, чтоб сравнивать длнинные вектора/////
if(vecDotS.size() < KOL_S) continue;
//Вычисление среднего направления LEN_L коротких векторов//
//запись данных по длинному вектору////////////////////////
double sumAlpha = 0.0;
iter = vecDotS.begin();
vecDotL.clear(); //пересчитаем длинные вектора
for(int i = 0; i < KOL_S; i++)
{
sumAlpha += iter->alpha;
if ((i+1) % LEN_L == 0)
{
_tmpDotFing = *iter;
_tmpDotFing.alpha = sumAlpha / LEN_L;
vecDotL.push_back(_tmpDotFing);
sumAlpha = 0.0;
}
iter++;
}
if (abs(vecDotL.begin()->alpha) > 3*2*M_PI)
{//слишком много оборотов//
CString s;
s.Format("alpha = %.2f", vecDotL.begin()->alpha*180);
if(MESSAGEOUT)MessageBox(0, "слишком много оборотов\n"+s, "", MB_OK);
return changeN;
}
//проверяем два соседних длинных вектора//
dAlpha = vecDotL.begin()->alpha - (++vecDotL.begin())->alpha;
if (abs(dAlpha) > (TEST_ALPHA / 180.0 * M_PI)) //сильный изгиб//
{
if (historyDotL.empty())
{ //сохранение состояния//
resetDot = vecDotL.back();
bestDot.alpha = 0.0;
}
if (dAlpha > 0) //раздвоение
alpha = (vecDotL.front().alpha - M_PI + (vecDotL.back().alpha)) / 2.0;
else //окончание
alpha = (vecDotL.front().alpha + M_PI + (vecDotL.back().alpha)) / 2.0;
_tmpDotFing = vecDotL.front();
_tmpDotFing.alpha = alpha; //направление в СТ (специфичная точка)//
_tmpDotFing.type = dAlpha<0; //тип СТ//
historyDotL.push_front(_tmpDotFing);
if(bestDot.alpha <= abs(dAlpha))
{
bestDot.coord = _tmpDotFing.coord;
bestDot.alpha = abs(dAlpha);
}
}
else //сильный изгиб//
{
if (!historyDotL.empty()) //был _пройден_ сильный изгиб
{
alpha = 0.0;
for(iter = historyDotL.begin(); iter != historyDotL.end(); iter++)
alpha += iter->alpha;
alpha /= historyDotL.size(); //среднее значение в пройденной СТ
iter = historyDotL.begin();
for(unsigned int i = 0; i<(historyDotL.size()/2); i++) iter++;
CPoint wdot = bestDot.coord; //наиболее вероятная точка для СТ
CPoint dotForAccept = FindAcceptDot(wdot, alpha, iter->type);
if (dotForAccept.x != -1)
{ //точка имеет продолжение//
COLORREF cl;
cl = (historyDotL.begin()->type)?0x000000:0xffffff;
//здесь можно поиграть с разной толщиной линии//
pic->Line(wdot, dotForAccept, 4, cl);
_dot->pr1 = true; //эту линию необходио еще раз проанализировать
changeN++;
stopKol += (stopKol-kol < 200)?200:0;
//stopKol += (kol*1.5 > stopKol)?500:0;
//загрузить начальное состояние
if(!historyDotL.begin()->type)
{ //если ликвидировано слипание то необходимо добавить новую точку на карту
_map.push_back(TMapElDot(dot));
}
//пройдена начальная точка, продлим анализ
//очень возможно, что начальную точку мы больше не попадем
if(ret-KOL_S*LEN_S < 0)
{
ret = 0;
homeOver = false;
stopKol = 500;
}
A = B = dot = resetDot.coord;
vecDotS.clear();
vecDotL.clear();
//------------------------------
}
historyDotL.clear();
}
}
}
if (dot.x == _dot->coord.x && dot.y == _dot->coord.y)
{//вероятно обход линии завершен
if (kol <= 2)
{//Линия подозрительно короткая
CString s;
s.Format("%d", kol);
if(MESSAGEOUT)MessageBox(0, "kol<=2 kol = " + s, "", MB_OK);
return changeN;
}else
{
homeOver = true; //пройти необходимо дальше начала
stopKol = kol + KOL_L*LEN_L*LEN_S;
}
}
if (homeOver) ret++;
}while(ret < (LEN_L*LEN_S*KOL_L) && ret < stopKol && kol <= stopKol);
_dot->pr2 = false;
return changeN;
}
inline double TAnalysePicture::GetAlpha(const CPoint A, const CPoint B)
//Направлени из точки А в В [-pi,pi)
{
if(A == B) return 0.0;
double alpha;
if (A.x - B.x == 0)
{
if (A.y > B.y) alpha = M_PI_2;
else alpha = -M_PI_2;
}else
{
double a = ((double)A.y-B.y)/((double)B.x-A.x);
alpha = atan(a);
if (A.x > B.x)
{
if (alpha < 0) alpha += M_PI;
else alpha -= M_PI;
if (A.y == B.y) alpha = -M_PI;
}
}
return alpha;
}
bool TAnalysePicture::TestFindDot(int _x, int _y)
//тест точки: Разность направлений вперед и назад должно быть меньше 110 градусов
{
const int len = 7;
CPoint A(_x, _y), B, C;
//первый вектор
B = A;
int vec = 0;
for(int i = 1; i<=len; i++)
B = tmpPic->NextDotCW(B, vec);
//------расчет угла-------//
double alpha1 = GetAlpha(A, B);
//второй вектор
C = B;
B = A;
vec = 0;
for(int i = 1; i<=len; i++)
{
B = tmpPic->NextDotCCW(B, vec);
if(abs(B.x-C.x) < 3 && abs(B.y-C.y) < 3) return true;
}
//------расчет угла-------//
double alpha2 = GetAlpha(A, B);
//-----alpha1, alpha2------//
alpha1 = abs(alpha2 - alpha1);
if (alpha1 > M_PI) alpha1 = 2.0*M_PI - alpha1;
return alpha1 < (110.0/180.0 * M_PI);
}
CPoint TAnalysePicture::FindAcceptDot(CPoint dot, double alpha, bool type)
//Поиск продолжения из окончания/раздвоения
{
const int maxL = 11;
const int minL = 3;
COLORREF color;
color = (type)?0x000000:0xffffff;
//окончание - ищем черную точку
//раздвоение - ищем белую точку
int i = 0;
while (i<=6) //разброс поиска в указанном направлении alpha
{
int l = minL;
int k = (i+1) / 2;
if (i % 2 == 1) k = -k;
while (l<=maxL)
{
double arg = alpha + k * M_PI * 5.0/180.0;
int x = dot.x + (int)(l*cos(arg)+0.5);
int y = dot.y - (int)(l*sin(arg)+0.5);
if (tmpPic->GetPixel(x, y) == color) //важное условие цвета точки!!!
{
if(TestFindDot(x,y)) //проверка найденной точки (на "вшивость" :) )
return CPoint(x, y); //найденная точка
else
break;
}
l++; //увеличение дальности поиска
}
i++;
}
return CPoint(-1, -1); //точка не найдена
}
bool TAnalysePicture::Show(int x, int y, int xt, int yt)
{
if(xt!=-1) pic2->Show(xt, yt);
return pic->Show(x, y);
}
TFingPicture *TAnalysePicture::GetPic1()
{
return pic;
}
TFingPicture *TAnalysePicture::GetPic2()
{
return pic2;
}
double TAnalysePicture::ChangeAlphaInterval(double _alpha)
//Приведение итрервала к [-pi,pi)
{
double ret = abs(_alpha);
while(ret >= 2.0*M_PI) ret -= 2.0*M_PI;
if(ret > M_PI) ret = 2.0*M_PI - ret;
else ret = -ret;
if(_alpha > 0) ret = -ret;
return ret;
}
/*Фильтрование полученных точек
отсеиваются близкостоящие направленные в противоположные строки
а так же точки слева и справа от которых нет линий*/
int TAnalysePicture::DotsFilter(TAbsFing &_dots)
{
int leftDots = 0;
TAbsFing::iterator iter1;
TAbsFing::iterator iter2;
for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++)
{
if(!iter1->show) continue;
//отсев точек сложным условием (условие окружения)
iter1->show = LeftDot(iter1);
}
for(iter1 = _dots.begin(); iter1 != _dots.end(); iter1++)
{
if(!iter1->show) continue;
//отсев близкостоящих точек
for(iter2 = iter1, ++iter2; iter2 != _dots.end(); iter2++)
{
if(!iter2->show) continue;
double difL = GetS(iter1->coord,iter2->coord);
if( //условия отсева
(
//на близком растоянии (15) находятся два окончания/раздвоения направленных друг на друга
(difL < 15)&&
((abs(iter2->alpha - iter1->alpha) > (165.0/180.0*M_PI))&&(abs(iter2->alpha - iter1->alpha)<(195.0/180.0*M_PI)))
)
||
(
//или просто очень близкие точки (<5..10)
(difL < 10)&&(iter1->type == iter2->type)
)
)
{
iter1->show = false;
iter2->show = false;
}
}
}
return leftDots;
}
inline double TAnalysePicture::GetS(CPoint A, CPoint B)
//растояние между точками
{
return sqrt( (double)((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)) );
}
/*Если точка является окончанием, то слева и справа от нее должны быть линии
если это не так, то точку нужно исключить из дальнейшего анализа*/
bool TAnalysePicture::LeftDot(TAbsFing::iterator &iter)
{
COLORREF color = 0x000000; //ищем черную точку для окончаний
if(!iter->type) color = 0xffffff;; //ищем белую точку для раздвоений
int l, k = 35;
const int minL = 4, maxL = 12;
bool find = false;
while(k <= 55)
{
l = minL;
while(l <= maxL)
{
int x = iter->coord.x + (int)(l*cos(iter->alpha + k/180.0*M_PI)+0.5);
int y = iter->coord.y - (int)(l*sin(iter->alpha + k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y) == color) // важное условие!!!
{ find = true; break;} //нашли точку слева
l++;
}
if(find) break;
k += 10; //Поиск с шагом 10гр
}
if(!find) return false;
k = 35;
while(k <= 55)
{
l= minL;
while(l <= maxL)
{
int x = iter->coord.x + (int)(l*cos(iter->alpha - k/180.0*M_PI)+0.5);
int y = iter->coord.y - (int)(l*sin(iter->alpha - k/180.0*M_PI)+0.5);
if(pic->GetPixel(x,y) == color) // важное условие!!!
return true; //нашли точку справа
l++;
}
k += 10;
}
return false;
}
П.1.10. ТЕКСТ МОДУЛЯ TFingPicture.h
#pragma once
#include "Fing.h"
///////////////////////////////////////////////////////////////////////////////
//Класс изображения.
//Хранение изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
class TFingPicture
{
private:
CDC pic; //указатель на изображение
BITMAP bmp; //изображение
bool IsLoad; //изображение загружено
CDC *Screen; //указатель на окно программы
public:
TFingPicture(CDC *_Screen); //_Screen - указатель на окно
~TFingPicture(void);
bool Load(const CString src); //загрузить изображение из файла src
bool Show(int X, int Y); //отобразить изображение на окне в координатах (X,Y)
bool SetPixel(CPoint dot, COLORREF color); //установка цвета пикселя dot
bool SetPixel(int x, int y, COLORREF color); //установка цвета пикселя (x,y)
COLORREF GetPixel(CPoint dot); //взятие цвета пикселя dot
COLORREF GetPixel(int x, int y); //взятие цвета пикселя (x,y)
bool FloodFill(CPoint dot, COLORREF color=0xffffff); //заливка области (по умолчанию черным цветом)
bool FloodFill(int x, int y, COLORREF color=0xffffff); //заливка области (по умолчанию черным цветом)
bool Line(CPoint from, CPoint to, int width, COLORREF color); //рисование линии
bool Rectangle(CPoint from, CPoint to, int width=2, COLORREF color=0xffffff); //рисование прямоугольника
bool Copy(TFingPicture &from); //копирование изображения
CPoint NextDotCW(const CPoint dot, int &vec); //Поиск следующей точки "_по часовой_ стрелке"
CPoint NextDotCCW(const CPoint dot, int &vec); //Поиск следующей точки "_против часовой_ стрелке"
CPoint GetSize(); //получение размера изображения
};
П.1.11. ТЕКСТ МОДУЛЯ TFingPicture.cpp
#include "StdAfx.h"
#include "TFingPicture.h"
///////////////////////////////////////////////////////////////////////////////
//Класс изображения.
//Хранение изображения, выполнение простейших операции над ним
///////////////////////////////////////////////////////////////////////////////
//координаты окружающих точек
const CPoint incXY[8]=
{
CPoint(-1, -1),
CPoint(0, -1),
CPoint(1, -1),
CPoint(1, 0),
CPoint(1, 1),
CPoint(0, 1),
CPoint(-1, 1),
CPoint(-1, 0)};
TFingPicture::TFingPicture(CDC *_Screen)
{
Screen = _Screen;
pic.CreateCompatibleDC(Screen);
IsLoad = false;
}
TFingPicture::~TFingPicture(void){}
//отобразить изображение на окне в координатах (X,Y)
bool TFingPicture::Show(int X, int Y)
{
if (!IsLoad) return false;
int kx = bmp.bmWidth;
int ky = bmp.bmHeight;
return Screen->StretchBlt(X, Y, bmp.bmWidth, bmp.bmHeight, &pic, 0, 0, kx, ky, SRCCOPY)>0;
}
//загрузить изображение из файла src
bool TFingPicture::Load(const CString src)
{
IsLoad = false;
CBitmap bm;
bm.Detach();
IsLoad = bm.Attach(LoadImage(0, src, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE))>0;
bm.GetObject(sizeof(BITMAP), &bmp);
pic.SelectObject(&bm);
return IsLoad;
}
// color = BGR;
bool TFingPicture::SetPixel(CPoint dot, COLORREF color)
{
if (!IsLoad) return false;
pic.SetPixel(dot.x, dot.y, color);
return true;
}
bool TFingPicture::SetPixel(int x, int y, COLORREF color)
{
if (!IsLoad) return false;
pic.SetPixel(x, y, color);
return true;