|
[code]自定义浏览DWG控件的实现方法ARX
总是需要在自定义控件上显示DWG图形,如在一个对话框上动态浏览一个DWG图形,于是写了一个控件,专门用来动态浏览DWG,这个控件从CStatic中派生,运用AcGs类库中的AcGsView,AcGsDevice,AcGsModel来协作显示DWG图形。
从CStatic派生,使用方便,只要在对话框中放一个CStatic,然后把CStatic的对象名换成fcGsPreviewCtrl即可。
fcGsPreviewCtrl.h
/* *******************************************************************
日 期: 2007/10/08
文件 名: fcgspreviewctrl.h
作 者: Racky Ye
单 位:
描 述: 用来预览DWG图形的控件
******************************************************************** */
#ifndef _FC_GS_PREVIEW_CTRL_H__
#define _FC_GS_PREVIEW_CTRL_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include " acgi.h "
#include < math.h >
#include " gs.h "
#include " acgs.h "
#include " acgsmanager.h "
// 用来预览DWG图形的控件
class fcGsPreviewCtrl : public CStatic
{
public :
fcGsPreviewCtrl();
virtual ~ fcGsPreviewCtrl();
public :
// 函数功能:传入dwg文件即可预览
BOOL Init(LPCTSTR szDwgFile);
// 函数功能:传入数据库指针即可预览数据库中的实体
BOOL Init(AcDbDatabase * pDb);
// 缩放到整个图纸可见
void ZoomE();
void Clear();
protected :
void InitGS(HINSTANCE hRes); // 初始化图形系统
BOOL InitInner(AcDbDatabase * pDb); // 内部初始化
bool GetActiveViewPortInfo (ads_real & height, ads_real & width, AcGePoint3d & target,
AcGeVector3d & viewDir, ads_real & viewTwist, bool getViewCenter);
// 获得块中的所有实体
void GetAllEnt( const AcDbObjectId & idBlockRec, AcDbObjectIdArray & IDArray);
// 获得实体的范围
Acad::ErrorStatus GetEntExtents( const AcDbObjectId & idEnt, AcDbExtents & extents);
void GetEntExtents( const AcDbObjectIdArray & aridEnt, AcDbExtents & extents);
void Mid( const AcGePoint3d & pt1, const AcGePoint3d & pt2, AcGePoint3d & ptMid);
protected :
// {{AFX_MSG(fcGsPreviewCtrl)
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg UINT OnNcHitTest(CPoint point);
afx_msg void OnSetFocus(CWnd * pOldWnd);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
// }}AFX_MSG
DECLARE_MESSAGE_MAP()
private :
AcDbExtents m_extents; // 图纸范围
HCURSOR m_hPanCursor; // 移动时的图标
HCURSOR m_hCrossCursor; // 十字图标
HCURSOR m_hOrbitCursor; // 旋转图标
AcGsView * m_pView; // 图形系统中的视图,用来绘制图形的区域
AcGsDevice * m_pDevice; // 图形系统中的设备,
AcGsModel * m_pModel;
bool m_bPanning; // 是否处于移动图形状态
bool m_bOrbiting; // 是否处于旋转图形状态
AcDbDatabase * m_pDb; // 该预览空间绑定的数据库
CPoint m_StartPt; // 移动或旋转时的起点
};
/// //
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(_FC_GS_PREVIEW_CTRL_H__)
CPP文件:
/* *******************************************************************
日 期: 2007/10/08
文件 名: fcgspreviewctrl.cpp
作 者: Racky Ye
单 位:
描 述: 用来预览DWG图形的控件
******************************************************************** */
#include " StdAfx.h "
#include " resource.h "
#include " fcGsPreviewCtrl.h "
#include " dbents.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
fcGsPreviewCtrl::fcGsPreviewCtrl()
{
m_hPanCursor = NULL; // 移动时的图标
m_hCrossCursor = NULL; // 十字图标
m_hOrbitCursor = NULL; // 旋转图标
m_pView = NULL; // 图形系统中的视图,用来绘制图形的区域
m_pDevice = NULL; // 图形系统中的设备,
m_pModel = NULL;
m_bPanning = false ; // 是否处于移动图形状态
m_bOrbiting = false ; // 是否处于旋转图形状态
m_pDb = NULL; // 该预览空间绑定的数据库
}
fcGsPreviewCtrl:: ~ fcGsPreviewCtrl()
{
Clear();
}
BEGIN_MESSAGE_MAP(fcGsPreviewCtrl, CStatic)
// {{AFX_MSG_MAP(fcGsPreviewCtrl)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONDOWN()
ON_WM_MBUTTONDOWN()
ON_WM_MBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_NCHITTEST()
ON_WM_SETFOCUS()
ON_WM_LBUTTONUP()
// }}AFX_MSG_MAP
END_MESSAGE_MAP()
/// //
// fcGsPreviewCtrl message handlers
void fcGsPreviewCtrl::OnPaint()
{
CPaintDC dc( this );
// 刷新图形系统视图
if (m_pView)
{
m_pView -> invalidate();
m_pView -> update();
}
}
void fcGsPreviewCtrl::OnSize(UINT nType, int cx, int cy)
{
CRect rect;
if (m_pDevice)
{
GetClientRect( & rect);
m_pDevice -> onSize(rect.Width(), rect.Height());
}
}
BOOL fcGsPreviewCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
if (m_pView)
{
if (zDelta < 0 )
m_pView -> zoom( 0.5 );
else
m_pView -> zoom( 1.5 );
Invalidate();
}
return TRUE;
}
void fcGsPreviewCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
SetFocus();
// 设置光标样式
m_bOrbiting = true ;
SetCapture();
::SetClassLong(m_hWnd, GCL_HCURSOR, NULL);
::SetCursor(m_hOrbitCursor);
m_StartPt = point;
}
void fcGsPreviewCtrl::OnMButtonDown(UINT nFlags, CPoint point)
{
// 开始移动
m_bPanning = true ;
SetCapture();
::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
::SetCursor(m_hPanCursor);
m_StartPt = point;
}
void fcGsPreviewCtrl::OnMButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
m_bPanning = false ;
::SetClassLong(m_hWnd,GCL_HCURSOR,( long )m_hCrossCursor);
}
// 函数功能:鼠标滚轮放大缩小视图
void fcGsPreviewCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_pView)
{
if (m_bPanning)
{
// 完成从设备坐标系统到世界坐标系统的转换
AcGeVector3d pan_vec( - (point.x - m_StartPt.x),point.y - m_StartPt.y, 0 );
pan_vec.transformBy(m_pView -> viewingMatrix() * m_pView -> worldToDeviceMatrix().inverse());
m_pView -> dolly(pan_vec);
Invalidate();
m_StartPt = point;
}
else if (m_bOrbiting)
{
const double Half_Pi = 1.570796326795 ;
AcGsDCRect view_rect;
m_pView -> getViewport (view_rect);
int nViewportX = (view_rect.m_max.x - view_rect.m_min.x) + 1 ;
int nViewportY = (view_rect.m_max.y - view_rect.m_min.y) + 1 ;
int centerX = int (nViewportX / 2.0f ) + view_rect.m_min.x;
int centerY = int (nViewportY / 2.0f ) + view_rect.m_min.y;
const double radius = min (nViewportX, nViewportY) * 0.4f ;
// 从最后和新的鼠标位置计算出两个矢量
AcGeVector3d last_vector ((m_StartPt.x - centerX) / radius,
- (m_StartPt.y - centerY) / radius,
0.0 );
if (last_vector.lengthSqrd () > 1.0 ) // 超出半径范围
last_vector.normalize ();
else
last_vector.z = sqrt ( 1.0 - last_vector.x * last_vector.x - last_vector.y * last_vector.y);
AcGeVector3d new_vector((point.x - centerX) / radius,
- (point.y - centerY) / radius,
0.0 );
if (new_vector.lengthSqrd () > 1.0 ) // 超出半径范围
new_vector.normalize ();
else
new_vector.z = sqrt ( 1.0 - new_vector.x * new_vector.x - new_vector.y * new_vector.y);
// 确定相机操作的角度
AcGeVector3d rotation_vector (last_vector);
rotation_vector = rotation_vector.crossProduct (new_vector); // rotation_vector = last_vector x new_vector
AcGeVector3d work_vector (rotation_vector);
work_vector.z = 0.0f ; // rotation_vector到xy平面的投影
double roll_angle = atan2 (work_vector.x, work_vector.y); // 假设相机的向上矢量是朝上的
// 计算向上的矢量和工作矢量的夹角
double length = rotation_vector.length ();
double orbit_y_angle = (length != 0.0 ) ? acos (rotation_vector.z / length) + Half_Pi : Half_Pi; // represents inverse cosine of the dot product of the
if (length > 1.0f )
length = 1.0f ;
double rotation_angle = asin (length);
// view操作
m_pView -> roll( roll_angle);
m_pView -> orbit( 0.0f , orbit_y_angle);
m_pView -> orbit( rotation_angle, 0.0f );
m_pView -> orbit( 0.0f , - orbit_y_angle);
m_pView -> roll( - roll_angle);
Invalidate();
m_StartPt = point;
}
else
{
::SetClassLong(m_hWnd,GCL_HCURSOR,( long )m_hCrossCursor);
SetFocus();
}
}
}
UINT fcGsPreviewCtrl::OnNcHitTest(CPoint point)
{
return HTCLIENT;
}
void fcGsPreviewCtrl::OnSetFocus(CWnd * pOldWnd)
{
::SetClassLong(m_hWnd, GCL_HCURSOR, ( long )m_hCrossCursor);
}
void fcGsPreviewCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bOrbiting = false ;
::SetClassLong(m_hWnd,GCL_HCURSOR,( long )m_hCrossCursor);
ReleaseCapture();
}
void fcGsPreviewCtrl::Clear()
{
AcGsManager * pGsManager = acgsGetGsManager();
RXASSERT(pGsManager);
if (m_pView)
{
m_pView -> eraseAll();
if (m_pDevice)
{
bool b = m_pDevice -> erase(m_pView);
RXASSERT(b);
}
AcGsClassFactory * pFactory = pGsManager -> getGSClassFactory();
RXASSERT(pFactory);
pFactory -> deleteView(m_pView);
m_pView = NULL;
}
if (m_pModel)
{
pGsManager -> destroyAutoCADModel(m_pModel);
m_pModel = NULL;
}
if (m_pDevice)
{
pGsManager -> destroyAutoCADDevice(m_pDevice);
m_pDevice = NULL;
}
if (m_pDb)
{
delete m_pDb;
m_pDb = NULL;
}
}
// 函数功能:传入dwg文件即可预览
BOOL fcGsPreviewCtrl::Init(LPCTSTR szDwgFile)
{
Clear();
m_pDb = new AcDbDatabase( false , true );
Acad::ErrorStatus es = m_pDb -> readDwgFile(szDwgFile);
if (es != Acad::eOk)
{
delete m_pDb;
m_pDb = NULL;
}
return InitInner(m_pDb);
}
// 函数功能:传入数据库指针即可预览数据库中的实体
BOOL fcGsPreviewCtrl::Init(AcDbDatabase * pDb)
{
Clear();
return InitInner(pDb);
}
// 函数功能:获得当前视口的信息。
// 输出参数:height 视口高度,width 视口宽度,target 视口中心点,viewDir 视口的观察向量,twist 扭曲的视口
bool fcGsPreviewCtrl::GetActiveViewPortInfo (ads_real & height, ads_real & width,
AcGePoint3d & target, AcGeVector3d & viewDir,
ads_real & viewTwist, bool getViewCenter)
{
AcDbDatabase * pDb = acdbHostApplicationServices() -> workingDatabase();
if (pDb == NULL)
return false ;
AcDbViewportTable * pVTable = NULL;
Acad::ErrorStatus es = pDb -> getViewportTable (pVTable, AcDb::kForRead);
if (es == Acad::eOk)
{
AcDbViewportTableRecord * pViewPortRec = NULL;
es = pVTable -> getAt ( " *Active " , pViewPortRec, AcDb::kForRead);
if (es == Acad::eOk)
{
height = pViewPortRec -> height ();
width = pViewPortRec -> width ();
if (getViewCenter == true )
{
struct resbuf rb;
memset ( & rb, 0 , sizeof ( struct resbuf));
acedGetVar ( " VIEWCTR " , & rb);
target = AcGePoint3d (rb.resval.rpoint[X], rb.resval.rpoint[Y], rb.resval.rpoint[Z]);
}
else
{
target = pViewPortRec -> target ();
}
viewDir = pViewPortRec -> viewDirection ();
viewTwist = pViewPortRec -> viewTwist ();
}
pVTable -> close ();
pViewPortRec -> close();
}
return ( true );
}
// 函数功能:初始化图形系统
void fcGsPreviewCtrl::InitGS(HINSTANCE hRes)
{
// 加载光标
if (m_hPanCursor == NULL)
m_hPanCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_PAN));
if (m_hCrossCursor == NULL)
m_hCrossCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_CROSS));
if (m_hOrbitCursor == NULL)
m_hOrbitCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_ORBIT));
::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
// 初始化视图
// 获得图形系统管理器
AcGsManager * pGsManager = acgsGetGsManager();
RXASSERT(pGsManager);
// 获得图形系统类工厂
AcGsClassFactory * pFactory = pGsManager -> getGSClassFactory();
RXASSERT(pFactory);
// 创建图形系统设备
m_pDevice = pGsManager -> createAutoCADDevice(m_hWnd);
RXASSERT(m_pDevice);
CRect rect;
GetClientRect( & rect);
m_pDevice -> onSize(rect.Width(), rect.Height());
// 创建图形系统视图
m_pView = pFactory -> createView();
RXASSERT(m_pView);
m_pModel = pGsManager -> createAutoCADModel();
RXASSERT(m_pModel);
m_pDevice -> add(m_pView);
double height = 0.0 , width = 0.0 , viewTwist = 0.0 ;
AcGePoint3d ptTargetView;
AcGeVector3d vecViewDir;
GetActiveViewPortInfo (height, width, ptTargetView, vecViewDir, viewTwist, true );
m_pView -> setView(ptTargetView + vecViewDir, ptTargetView,
AcGeVector3d( 0.0 , 1.0 , 0.0 ), 1.0 , 1.0 );
}
BOOL fcGsPreviewCtrl::InitInner(AcDbDatabase * pDb)
{
if (pDb == NULL)
{
m_pDb = new AcDbDatabase( true , true );
}
else
{
m_pDb = pDb;
}
if (m_pDb == NULL)
return FALSE;
Acad::ErrorStatus es = Acad::eOk;
AcDbBlockTableRecord * pRec = NULL;
AcDbBlockTable * pTab = NULL;
if ((es = m_pDb -> getBlockTable(pTab, AcDb::kForRead)) != Acad::eOk)
return FALSE;
if ((es = pTab -> getAt(ACDB_MODEL_SPACE,pRec,AcDb::kForRead)) != Acad::eOk)
{
pTab -> close();
return FALSE;
}
pTab -> close();
AcDbObjectId idRec = pRec -> id();
AcDbObjectIdArray aridEnt;
GetAllEnt(idRec, aridEnt);
GetEntExtents(aridEnt, m_extents);
InitGS(_hdllInstance);
m_pView -> add(pRec, m_pModel);
pRec -> close();
ZoomE();
return TRUE;
}
// 缩放到整个图纸可见
void fcGsPreviewCtrl::ZoomE()
{
AcGePoint3d ptTargetView;
Mid(m_extents.maxPoint(), m_extents.minPoint(), ptTargetView);
double dLenght = m_extents.maxPoint().x - m_extents.minPoint().x;
double dWidth = m_extents.maxPoint().y - m_extents.minPoint().y;
m_pView -> setView(ptTargetView + AcGeVector3d::kZAxis,ptTargetView,AcGeVector3d::kYAxis,dLenght * 1.05 ,dWidth * 1.05 );
OnPaint();
}
void fcGsPreviewCtrl::Mid( const AcGePoint3d & pt1, const AcGePoint3d & pt2, AcGePoint3d & ptMid)
{
ptMid.x = 0.5 * (pt1.x + pt2.x);
ptMid.y = 0.5 * (pt1.y + pt2.y);
ptMid.z = 0.5 * (pt1.z + pt2.z);
}
// 函数功能:获得块中的所有实体
void fcGsPreviewCtrl::GetAllEnt( const AcDbObjectId & idBlockRec, AcDbObjectIdArray & IDArray)
{
IDArray.setPhysicalLength( 0 );
Acad::ErrorStatus es;
AcDbBlockTableRecord * pBlkRec = NULL;
if (Acad::eOk != (es = acdbOpenObject(pBlkRec,idBlockRec,AcDb::kForRead)))
{
return ;
}
AcDbBlockTableRecordIterator * pIt = NULL;
pBlkRec -> newIterator(pIt);
pBlkRec -> close();
for (pIt -> start(); ! pIt -> done(); pIt -> step())
{
AcDbObjectId idEnt;
if (Acad::eOk == pIt -> getEntityId(idEnt))
{
IDArray.append(idEnt);
}
}
delete pIt;
pIt = NULL;
}
// 函数功能:获得实体的范围
Acad::ErrorStatus fcGsPreviewCtrl::GetEntExtents( const AcDbObjectId & idEnt, AcDbExtents & extents)
{
Acad::ErrorStatus es;
AcDbEntity * pEnt = NULL;
if (Acad::eOk == acdbOpenObject(pEnt, idEnt, AcDb::kForRead))
{
AcDbBlockReference * pBlkRef = AcDbBlockReference::cast(pEnt);
if (pBlkRef)
{
es = pBlkRef -> geomExtentsBestFit(extents);
}
else
{
es = pEnt -> getGeomExtents(extents);
}
pEnt -> close();
}
return (es);
}
void fcGsPreviewCtrl::GetEntExtents( const AcDbObjectIdArray & aridEnt, AcDbExtents & extents)
{
for ( int i = 0 ; i < aridEnt.length();i ++ )
{
AcDbExtents tem;
if (GetEntExtents(aridEnt[i], tem) == Acad::eOk)
{
extents.addExt(tem);
}
}
}[/code] |
|