📄 imagemap.cpp
字号:
// ImageMap.cpp: implementation of the CImageMap class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ImageTest.h"
#include "ImageMap.h"
#include "dib.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CImageMap::CImageMap()
{
m_dZoomAmount = 1.5;
m_dZoomFactor = 1.0;
m_dZoomOrigin = 1.0;
m_dScale = 1.0;
m_dScaleAll = 1.0;
m_dScaleOrigin= 1.0;
m_nShiftSize = 50;
m_dOffsetX = 0.0;
m_dOffsetY = 0.0;
m_x1 = m_y1 = m_x2 = m_y2 = 0;
m_cx = m_cy = 0;
m_bSetMBRC = FALSE;
m_bIsLoadMap = FALSE;
m_hWnd = NULL;
m_pOldBitmap = NULL;
m_pDib = NULL;
m_lImageWidth = 0; //图像宽度
m_lImageHeight = 0; //图像高度
memset(&m_rcRect, 0, sizeof(m_rcRect));
}
CImageMap::~CImageMap()
{
UnloadMap();
}
//加载地图数据
int CImageMap::LoadMapFile(LPCTSTR filename)
{
if(m_bIsLoadMap)//如果已加载地图
{
if(m_strMapFile == filename)//如果已加载该地图
return 1;
UnloadMap();//卸载先前地图
}
CString szExt = filename;
int id = szExt.ReverseFind(_T('.'));
if(id == -1)
{
MessageBox(NULL, _T("文件无效!"), NULL, MB_OK);
return 0;
}
CString left = szExt.Left(id);
szExt = szExt.Right(szExt.GetLength() - id - 1);
szExt.MakeUpper();
if(szExt == _T("BMP")) //bmp type
{
m_pDib = new CDib;
if(!m_pDib->ReadDIBFile(filename))
{
MessageBox(NULL, _T("加载地图错误!"), NULL, MB_OK);
delete m_pDib;
m_pDib = NULL;
return 0;
}
m_lImageWidth = m_pDib->GetWidth(); //图像宽度
m_lImageHeight = m_pDib->GetHeight(); //图像高度
}
else
{
CString output = _T("不支持") + szExt;
output += _T("类型!");
MessageBox(NULL, output, _T("错误"), MB_OK);
return 0;
}
id = left.ReverseFind(_T('\\'));
m_strMapName = left.Right(left.GetLength() - id - 1);
m_strMapFile = filename;
if(m_pDib->m_bIsImageMap)//如果地图文件中有地图范围
{
m_rcRect.x1 = m_pDib->m_x1;
m_rcRect.x2 = m_pDib->m_x2;
m_rcRect.y1 = -m_pDib->m_y1;
m_rcRect.y2 = -m_pDib->m_y2;
//调整包围矩形,使左上角顶点坐标最小
if(m_rcRect.y1 > m_rcRect.y2)
{
float tempy = m_rcRect.y1;
m_rcRect.y1 = m_rcRect.y2;
m_rcRect.y2 = tempy;
}
if(m_rcRect.x1 > m_rcRect.x2)
{
float tempx = m_rcRect.x1;
m_rcRect.x1 = m_rcRect.x2;
m_rcRect.x2 = tempx;
}
InitialParam(m_rcRect); //初始化参数
m_dScaleOrigin = m_pDib->m_dScale;
m_dScale = m_dScaleOrigin;
double x1 = 0, y1 = 0;
double x2 = m_cx, y2 = m_cy;
m_dZoomFactor = m_dZoomOrigin * m_dScale/m_dScaleAll;
ScreenToMap(&x1, &y1);
ScreenToMap(&x2, &y2);
double x = (m_rcRect.x1 + m_rcRect.x2)/2;
double y = (m_rcRect.y1 + m_rcRect.y2)/2;
m_dOffsetX = x - fabs(x2 - x1);
m_dOffsetY = y - fabs(y2 - y1);
m_bSetMBRC = TRUE;
}
m_bIsLoadMap = TRUE;
return 1;
}
/* 设置地图的边界和比例尺,在DrawMap之前调用 */
void CImageMap::SetMapMBRC(double left, double top, double right, double bottom, double dScale)
{
m_rcRect.x1 = (float)left;
m_rcRect.x2 = (float)right;
m_rcRect.y1 = -(float)top;
m_rcRect.y2 = -(float)bottom;
//调整包围矩形,使左上角顶点坐标最小
if(m_rcRect.y1 > m_rcRect.y2)
{
float tempy = m_rcRect.y1;
m_rcRect.y1 = m_rcRect.y2;
m_rcRect.y2 = tempy;
}
if(m_rcRect.x1 > m_rcRect.x2)
{
float tempx = m_rcRect.x1;
m_rcRect.x1 = m_rcRect.x2;
m_rcRect.x2 = tempx;
}
InitialParam(m_rcRect); //初始化参数
m_dScaleOrigin = dScale;
m_dScale = m_dScaleOrigin;
double x1 = 0, y1 = 0;
double x2 = m_cx, y2 = m_cy;
m_dZoomFactor = m_dZoomOrigin * m_dScale/m_dScaleAll;
ScreenToMap(&x1, &y1);
ScreenToMap(&x2, &y2);
double x = (m_rcRect.x1 + m_rcRect.x2)/2;
double y = (m_rcRect.y1 + m_rcRect.y2)/2;
m_dOffsetX = x - fabs(x2 - x1);
m_dOffsetY = y - fabs(y2 - y1);
m_bSetMBRC = TRUE;
if(!m_strMapFile.IsEmpty() &&m_pDib)
{
CFile cf;
if(cf.Open(m_strMapFile, CFile::modeReadWrite))
{
m_pDib->m_x1 = (float)fabs(left);
m_pDib->m_y1 = (float)fabs(top);
m_pDib->m_x2 = (float)fabs(right);
m_pDib->m_y2 = (float)fabs(bottom);
m_pDib->m_dScale = (float)fabs(dScale);
if(m_pDib->m_bIsImageMap)
cf.Seek(-long(sizeof(float)*5), CFile::end);
else
cf.SeekToEnd();
cf.Write(&m_pDib->m_x1, sizeof(float));
cf.Write(&m_pDib->m_y1, sizeof(float));
cf.Write(&m_pDib->m_x2, sizeof(float));
cf.Write(&m_pDib->m_y2, sizeof(float));
cf.Write(&m_pDib->m_dScale, sizeof(float));
cf.Close();
m_pDib->m_bIsImageMap = TRUE;
}
else
{
MessageBox(NULL, _T("写文件错误,请检查文件是否是只读类型!"), _T("错误"), MB_OK);
}
}
}
BOOL CImageMap::IsSetMapMBRC(void)
{
if(m_pDib && m_pDib->m_bIsImageMap)
return TRUE;
return FALSE;
}
void CImageMap::UnloadMap()//卸载地图
{
m_bIsLoadMap = FALSE;
m_strMapFile.Empty();
m_strMapName.Empty();
m_bSetMBRC = FALSE;
if(m_pDib)
delete m_pDib;
m_pDib = NULL;
if(m_hWnd)
{
HDC dc = GetDC(m_hWnd);
CRect rc;
GetClientRect(m_hWnd, &rc);
PatBlt(dc, rc.left, rc.top, rc.right, rc.bottom, WHITENESS);
ReleaseDC(m_hWnd, dc);
}
}
void CImageMap::SetMapHwnd(HWND hWnd)
{
m_hWnd = hWnd;
}
void CImageMap::SetClientRect(long x1, long y1, long x2, long y2)
{
m_x1 = x1;
m_y1 = y1;
m_x2 = x2;
m_y2 = y2;
//计算屏幕中心点坐标
m_cx = (m_x1 + m_x2)/2;
m_cy = (m_y1 + m_y2)/2;
/* 如果内存DC已经存在,则重新创建新的*/
if(m_memDC.GetSafeHdc() != NULL)
{
m_memDC.SelectObject(m_pOldBitmap);
m_memDC.DeleteDC();
CDC *pdc = NULL;
HDC hdc = NULL;
if(m_hWnd)
{
//获取窗口显示DC
hdc = GetDC(m_hWnd);
pdc = CDC::FromHandle(hdc);
}
m_memDC.CreateCompatibleDC(pdc);//如果pdc=NULL,则创建和屏幕DC兼容的DC
if(m_Bitmap.GetSafeHandle())
{
m_Bitmap.DeleteObject();
m_Bitmap.CreateCompatibleBitmap(pdc, m_x2 - m_x1, m_y2 - m_y1);//创建空白内存位图
}
m_pOldBitmap = m_memDC.SelectObject(&m_Bitmap);
ReleaseDC(m_hWnd, hdc);
DrawMap();
}
}
void CImageMap::SetClientRect(LPRECT rc)
{
if(rc == NULL) return;
SetClientRect(rc->left, rc->top, rc->right, rc->bottom);
}
void CImageMap::InitialParam(MBRECT mbrc)
{
if(mbrc.x2 == mbrc.x1 || mbrc.y2 == mbrc.y1) return;
double blcx = (m_x2 - m_x1)/(mbrc.x2 - mbrc.x1);
double blcy = (m_y2 - m_y1)/(mbrc.y2 - mbrc.y1);
HDC hdc = GetDC(m_hWnd);
//厘米/像素,每英寸=2.54厘米
double cmp = 2.54/GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(m_hWnd, hdc);
if(blcx > blcy) //取较小的一个作为比例基数
{
m_dZoomOrigin = blcy;
double cm = (m_y2 - m_y1) * cmp;
m_dScaleAll = Distance(mbrc.x1, mbrc.y1, mbrc.x2, mbrc.y2)/cm;
}
else
{
m_dZoomOrigin = blcx;
double cm = (m_x2 - m_x1) * cmp;
m_dScaleAll = Distance(mbrc.x1, mbrc.y1, mbrc.x2, mbrc.y2)/cm;
}
m_dOffsetX = mbrc.x1;
m_dOffsetY = mbrc.y1;
m_dZoomFactor = m_dZoomOrigin;
m_dScale = m_dScaleAll;
double x1 = m_x1;
double y1 = m_y1;
double x2 = m_x2;
double y2 = m_y2;
ScreenToMap(&x1, &y1);
ScreenToMap(&x2, &y2);
m_dOffsetX = mbrc.x1 + (mbrc.x2 - mbrc.x1)/2 - (x2 - x1)/2;
m_dOffsetY = mbrc.y1 + (mbrc.y2 - mbrc.y1)/2 - (y2 - y1)/2;
}
void CImageMap::ScreenToMap(double *x, double *y)
{
*x = m_dOffsetX + *x / m_dZoomFactor;
*y = m_dOffsetY + *y / m_dZoomFactor;
}
void CImageMap::MapToScreen(double *x, double *y)
{
*x = (*x - m_dOffsetX) * m_dZoomFactor;
*y = (*y - m_dOffsetY) * m_dZoomFactor;
}
//地图坐标转换为图像坐标
void CImageMap::MapToImage(double *x, double *y)
{
*x = (*x - m_rcRect.x1) * m_lImageWidth/(m_rcRect.x2 - m_rcRect.x1);
*y = (*y - m_rcRect.y1) * m_lImageHeight/(m_rcRect.y2 - m_rcRect.y1);
}
//图像坐标转换为地图坐标
void CImageMap::ImageToMap(double *x, double *y)
{
*x = *x * (m_rcRect.x2 - m_rcRect.x1)/m_lImageWidth + m_rcRect.x1;
*y = *y * (m_rcRect.y2 - m_rcRect.y1)/m_lImageHeight + m_rcRect.y1;
}
//屏幕坐标转换为图像坐标
void CImageMap::ScreenToImage(long *x, long *y)
{
double tx = *x;
double ty = *y;
ScreenToMap(&tx, &ty);
MapToImage(&tx, &ty);
*x = (long)tx;
*y = (long)ty;
}
//图像坐标转换为屏幕坐标
void CImageMap::ImageToScreen(long *x, long *y)
{
double tx = *x;
double ty = *y;
ImageToMap(&tx, &ty);
MapToScreen(&tx, &ty);
*x = (long)tx;
*y = (long)ty;
}
void CImageMap::Draw(CDC *pdc, CRect& rcInvalid) //刷新地图
{
if(m_memDC.m_hDC && pdc && m_bIsLoadMap)
{
pdc->BitBlt(rcInvalid.left, rcInvalid.top, rcInvalid.Width(), rcInvalid.Height(),
&m_memDC, rcInvalid.left, rcInvalid.top, SRCCOPY);
}
else if(pdc) //未加载地图时用白色填充
pdc->PatBlt(m_x1, m_y1, m_x2 - m_x1, m_y2 - m_y1, WHITENESS);
}
void CImageMap::DrawMap(CDC *pdc)
{
//绘制地图........
if(m_pDib && pdc && m_bSetMBRC)
{
long x1 = m_x1, y1 = m_y1;
long x2 = m_x2, y2 = m_y2;
ScreenToImage(&x1, &y1);
ScreenToImage(&x2, &y2);
if(x1 < 0) x1 = 0;
if(y1 < 0) y1 = 0;
if(x2 >= m_lImageWidth)
x2 = m_lImageWidth - 1;
if(y2 >= m_lImageHeight)
y2 = m_lImageHeight - 1;
CRect rcDc(x1, y1, x2, y2);
ImageToScreen(&rcDc.left, &rcDc.top);
ImageToScreen(&rcDc.right, &rcDc.bottom);
rcDc.NormalizeRect();
//如果图像是倒序存储
if(m_lImageHeight > 0)
{
y1 = m_lImageHeight - y1 - 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -