转载: 自定义浏览DWG控件的实现方法, 有时间研究一下

自定义浏览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, 0sizeof (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.01.00.0), 1.01.0); 

}

BOOL fcGsPreviewCtrl::InitInner(AcDbDatabase 
*pDb)
{
if (pDb == NULL)
{
m_pDb 
= new AcDbDatabase(truetrue); 
}
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);
}
}
}

 

posted @ 2010-04-23 18:26  houlinbo  阅读(2351)  评论(0编辑  收藏  举报