# MapDrawer.cpp
### MapDrawer::GetCurrentOpenGLCameraMatrix()
將相機姿態mCameraPose由Mat類型轉化為OpenGlMatrix類型
在[Viewer::Run()](#Viewer::Run())中引用
#### 函式流程
1. 取得相機的姿態
2. 將姿態變成轉換矩陣
#### 流程詳解
1. 取得相機的姿態
```
if(!mCameraPose.empty())
{
cv::Mat Rwc(3,3,CV_32F);
cv::Mat twc(3,1,CV_32F);
{
unique_lock<mutex> lock(mMutexCamera);
Rwc = mCameraPose.rowRange(0,3).colRange(0,3).t();
twc = -Rwc*mCameraPose.rowRange(0,3).col(3);
}
```
2. 將姿態變成轉換矩陣
```
M.m[0] = Rwc.at<float>(0,0);
M.m[1] = Rwc.at<float>(1,0);
M.m[2] = Rwc.at<float>(2,0);
M.m[3] = 0.0;
M.m[4] = Rwc.at<float>(0,1);
M.m[5] = Rwc.at<float>(1,1);
M.m[6] = Rwc.at<float>(2,1);
M.m[7] = 0.0;
M.m[8] = Rwc.at<float>(0,2);
M.m[9] = Rwc.at<float>(1,2);
M.m[10] = Rwc.at<float>(2,2);
M.m[11] = 0.0;
M.m[12] = twc.at<float>(0);
M.m[13] = twc.at<float>(1);
M.m[14] = twc.at<float>(2);
M.m[15] = 1.0;
}
else
M.SetIdentity();
```
### MapDrawer::DrawCurrentCamera()
繪製當前相機
在[Viewer::Run()](#Viewer::Run())
#### 定義
```
void MapDrawer::DrawCurrentCamera(pangolin::OpenGlMatrix &Twc) //輸入轉換矩陣
```
#### 函式流程
1. 計算相機在世界座標的位置
2. 根據相機姿態畫出當前相機姿態對應的綠色方框
#### 流程詳解
1. 計算相機在世界座標的位置
```
//相機模型大小:寬度佔總寬度比例為0.08
const float &w = mCameraSize;
const float h = w*0.75;
const float z = w*0.6;
//儲存當前姿態
glPushMatrix();
//將4*4的矩陣Twc.m右乘一個當前矩陣
//(由於使用了glPushMatrix函數,因此當前幀矩陣為世界坐標系下的單位矩陣)
//因為OpenGL中的矩陣為列優先存儲,因此實際為Tcw,即相機在世界坐標下的位姿
#ifdef HAVE_GLES
glMultMatrixf(Twc.m);
#else
glMultMatrixd(Twc.m);
#endif
```
2. 根據相機姿態畫出當前相機姿態對應的綠色方框
```
//設置繪製圖形時線的寬度
glLineWidth(mCameraLineWidth);
//設置當前顏色為綠色(相機圖標顯示為綠色)
glColor3f(0.0f,1.0f,0.0f);
//用線將下面的頂點兩兩相連
glBegin(GL_LINES);
glVertex3f(0,0,0);
glVertex3f(w,h,z);
glVertex3f(0,0,0);
glVertex3f(w,-h,z);
glVertex3f(0,0,0);
glVertex3f(-w,-h,z);
glVertex3f(0,0,0);
glVertex3f(-w,h,z);
glVertex3f(w,h,z);
glVertex3f(w,-h,z);
glVertex3f(-w,h,z);
glVertex3f(-w,-h,z);
glVertex3f(-w,h,z);
glVertex3f(w,h,z);
glVertex3f(-w,-h,z);
glVertex3f(w,-h,z);
glEnd();
glPopMatrix();
```
### MapDrawer::DrawKeyFrames()
繪製當前關鍵幀
在[Viewer::Run()](#Viewer::Run())
#### 函式流程
1. 取出所有的關鍵幀
2. 顯示所有關鍵幀
3. 顯示本質圖(Essential Graph)
#### 流程詳解
1. 取出所有的關鍵幀
```
//歷史關鍵幀圖標:寬度佔總寬度比例為0.05
const float &w = mKeyFrameSize;
const float h = w*0.75;
const float z = w*0.6;
//取出 vector<KeyFrame*>(mspKeyFrames.begin(),mspKeyFrames.end());
const vector<KeyFrame*> vpKFs = mpMap->GetAllKeyFrames();
```
2. 顯示所有關鍵幀
```
//通過顯示界面選擇是否顯示歷史關鍵幀圖標
if(bDrawKF)
{
for(size_t i=0; i<vpKFs.size(); i++)
{
KeyFrame* pKF = vpKFs[i];
//轉置, OpenGL中的矩陣為列優先存儲
cv::Mat Twc = pKF->GetPoseInverse().t();
glPushMatrix();
//(由於使用了glPushMatrix函數,因此當前幀矩陣為世界坐標系下的單位矩陣)
//因為OpenGL中的矩陣為列優先存儲,因此實際為Tcw,即相機在世界坐標下的位姿
glMultMatrixf(Twc.ptr<GLfloat>(0));
//設置繪製圖形時線的寬度
glLineWidth(mKeyFrameLineWidth);
//設置當前顏色為藍色(關鍵幀圖標顯示為藍色)
glColor3f(0.0f,0.0f,1.0f);
//用線將下面的頂點兩兩相連
glBegin(GL_LINES);
glVertex3f(0,0,0);
glVertex3f(w,h,z);
glVertex3f(0,0,0);
glVertex3f(w,-h,z);
glVertex3f(0,0,0);
glVertex3f(-w,-h,z);
glVertex3f(0,0,0);
glVertex3f(-w,h,z);
glVertex3f(w,h,z);
glVertex3f(w,-h,z);
glVertex3f(-w,h,z);
glVertex3f(-w,-h,z);
glVertex3f(-w,h,z);
glVertex3f(w,h,z);
glVertex3f(-w,-h,z);
glVertex3f(w,-h,z);
glEnd();
glPopMatrix();
}
}
```
3. 顯示本質圖(Essential Graph)
```
/**已知共視圖中存儲了所有關鍵幀的共視關係,本徵圖中對邊進行了優化,
保存了所有節點,只存儲了具有較多共視點的邊,用於進行優化,而生成樹則進一步進行了優化,
保存了所有節點,但是值保存具有最多共視地圖點的關鍵幀的邊**/
//通過顯示界面選擇是否顯示關鍵幀連接關係
if(bDrawGraph)
{
//設置繪製圖形時線的寬度
glLineWidth(mGraphLineWidth);
//設置共視圖連接線為綠色,透明度為0.6f
glColor4f(0.0f,1.0f,0.0f,0.6f);
glBegin(GL_LINES);
//遍歷關鍵幀
for(size_t i=0; i<vpKFs.size(); i++)
{
// Covisibility Graph
//3.1. 共視程度比較高的共視關鍵幀用線連接
//遍歷每一個關鍵幀,得到它們共視程度比較高的關鍵幀
const vector<KeyFrame*> vCovKFs = vpKFs[i]->GetCovisiblesByWeight(100);
//遍歷每一個關鍵幀,得到它在世界坐標系下的相機坐標
cv::Mat Ow = vpKFs[i]->GetCameraCenter();
if(!vCovKFs.empty())
{
for(vector<KeyFrame*>::const_iterator vit=vCovKFs.begin(), vend=vCovKFs.end(); vit!=vend; vit++)
{
if((*vit)->mnId<vpKFs[i]->mnId)
continue;
cv::Mat Ow2 = (*vit)->GetCameraCenter();
glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
glVertex3f(Ow2.at<float>(0),Ow2.at<float>(1),Ow2.at<float>(2));
}
}
// Spanning tree
//3.2. 連接最小生成樹
KeyFrame* pParent = vpKFs[i]->GetParent();
if(pParent)
{
cv::Mat Owp = pParent->GetCameraCenter();
glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
glVertex3f(Owp.at<float>(0),Owp.at<float>(1),Owp.at<float>(2));
}
// Loops
//3.3 連接閉環時形成的連接關係
set<KeyFrame*> sLoopKFs = vpKFs[i]->GetLoopEdges();
for(set<KeyFrame*>::iterator sit=sLoopKFs.begin(), send=sLoopKFs.end(); sit!=send; sit++)
{
if((*sit)->mnId<vpKFs[i]->mnId)
continue;
cv::Mat Owl = (*sit)->GetCameraCenter();
glVertex3f(Ow.at<float>(0),Ow.at<float>(1),Ow.at<float>(2));
glVertex3f(Owl.at<float>(0),Owl.at<float>(1),Owl.at<float>(2));
}
}
glEnd();
}
```
### MapDrawer::DrawMapPoints()
繪製當前地圖點
在[Viewer::Run()](#Viewer::Run())
#### 函式流程
1. 取出所有的地圖點
2. 繪製不包含局部地圖點地圖點(黑色)
3. 繪製局部地圖點(紅色)
#### 流程詳解
1. 取出所有的地圖點
```
const vector<MapPoint*> &vpMPs = mpMap->GetAllMapPoints();
//取出mvpReferenceMapPoints,也即局部地圖d點
const vector<MapPoint*> &vpRefMPs = mpMap->GetReferenceMapPoints();
```
mpMap->GetAllMapPoints(): 跳到[Map::GetAllMapPoints()](#Map::GetAllMapPoints())
mpMap->GetReferenceMapPoints(): 跳到[Map::GetReferenceMapPoints()](#Map::GetReferenceMapPoints())
2. 繪製不包含局部地圖點地圖點(黑色)
```
//將vpRefMPs從vector容器類型轉化為set容器類型,便於使用set::count快速統計
set<MapPoint*> spRefMPs(vpRefMPs.begin(), vpRefMPs.end());
if(vpMPs.empty())
return;
// for AllMapPoints
//顯示所有的地圖點(不包括局部地圖點),大小為2個像素,黑色
glPointSize(mPointSize);
glBegin(GL_POINTS);
glColor3f(0.0,0.0,0.0);
for(size_t i=0, iend=vpMPs.size(); i<iend;i++)
{
// 不包括ReferenceMapPoints(局部地圖點)
if(vpMPs[i]->isBad() || spRefMPs.count(vpMPs[i]))
continue;
cv::Mat pos = vpMPs[i]->GetWorldPos();
glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
}
glEnd();
```
3. 繪製局部地圖點(紅色)
```
// for ReferenceMapPoints
//顯示局部地圖點,大小為2個像素,紅色
glPointSize(mPointSize);
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
for(set<MapPoint*>::iterator sit=spRefMPs.begin(), send=spRefMPs.end(); sit!=send; sit++)
{
if((*sit)->isBad())
continue;
cv::Mat pos = (*sit)->GetWorldPos();
glVertex3f(pos.at<float>(0),pos.at<float>(1),pos.at<float>(2));
}
glEnd();
```