转载来源:http://www.cnblogs.com/houlinbo/archive/2010/04/23/1718856.html
自定义浏览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);
}
}
}