Files
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

506 lines
13 KiB
C++

//
// (C) Copyright 2002-2006 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
#include "StdAfx.h"
#if defined(_DEBUG) && !defined(AC_FULL_DEBUG)
//#error _DEBUG should not be defined except in internal Adesk debug builds
#endif
#include "resource.h"
#include "GsPreviewCtrlEx.h"
#include "acgs.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifdef _DEBUG
#define RXASSERT(f) assert(f)
#else
#define RXASSERT(f) ((void)0)
#endif
#define WM_VIEWDBLCLKSEL (WM_USER + 0x1200)
BEGIN_MESSAGE_MAP(CGsPreviewCtrlEx, CStatic)
//{{AFX_MSG_MAP(CGsPreviewCtrlEx)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONDOWN()
ON_WM_MBUTTONDOWN()
ON_WM_MBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDBLCLK()
ON_WM_NCHITTEST()
ON_WM_SETFOCUS()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CGsPreviewCtrlEx::OnPaint()
{
CPaintDC dc(this);
//update the gs view
if (mpView != NULL)
{
mpView->invalidate();
mpView->update();
}
}
// Erase view and delete model
void CGsPreviewCtrlEx::erasePreview()
{
if (mpView)
mpView->eraseAll();
if (mpManager && mpModel) {
mpManager->destroyAutoCADModel (mpModel);
mpModel = NULL;
}
}
void CGsPreviewCtrlEx::setModel(AcGsModel* pModel)
{
erasePreview();
mpModel = pModel;
mbModelCreated =false;
}
void CGsPreviewCtrlEx::clearAll()
{
if (mpView)
{
mpView->eraseAll();
}
if (mpDevice)
{
bool b = mpDevice->erase(mpView);
RXASSERT(b);
}
if (mpFactory)
{
if (mpView)
{
mpFactory->deleteView(mpView);
mpView = NULL;
}
if (mpGhostModel)
{
mpFactory->deleteModel(mpGhostModel);
mpGhostModel = NULL;
}
mpFactory = NULL;
}
if (mpManager)
{
if (mpModel)
{
if (mbModelCreated)
mpManager->destroyAutoCADModel(mpModel);
mpModel = NULL;
}
if (mpDevice)
{
mpManager->destroyAutoCADDevice(mpDevice);
mpDevice = NULL;
}
mpManager = NULL;
}
}
void CGsPreviewCtrlEx::init(HMODULE hRes, bool bCreateModel)
{
//Load our special cursors
mhPanCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_PAN));
mhCrossCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_CROSS));
mhOrbitCursor = LoadCursor(hRes,MAKEINTRESOURCE(IDI_ORBIT));
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,NULL);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
#endif
//Instantiate view, a device and a model object
CRect rect;
if (!mpManager)
{
// get the AcGsManager object for a specified AutoCAD MDI Client CView
mpManager = acgsGetGsManager();
RXASSERT(mpManager);
// get the GS class factory
#if (ARX >= 20)
AcGsKernelDescriptor desc;
desc.addRequirement(AcGsKernelDescriptor::k3DDrawing);
mpFactory = AcGsManager::acquireGraphicsKernel(desc);
if (!mpFactory) return;
#else
mpFactory = mpManager->getGSClassFactory();
#endif
RXASSERT(mpFactory);
// create an AcGsDevice object. The window handle passed in to this
// function is the display surface onto which the graphics system draws
//a device with standard autocad color palette
#if (ARX >= 20)
//mpDevice = mpFactory->createOffScreenDevice();
mpDevice = mpManager->createAutoCADDevice(*mpFactory, m_hWnd);
#else
mpDevice = mpManager->createAutoCADDevice(m_hWnd);
#endif
RXASSERT(mpDevice);
// get the size of the window that we are going to draw in
GetClientRect( &rect);
// make sure the gs device knows how big the window is
mpDevice->onSize(rect.Width(), rect.Height());
// construct a simple view
mpView = mpFactory->createView();
RXASSERT(mpView);
if (bCreateModel)
{
RXASSERT(mpModel==NULL);
// create an AcGsModel object with the AcGsModel::kMain RenderType
// (which is a hint to the graphics system that the geometry in this
// model should be rasterized into its main frame buffer). This
// AcGsModel is created with get and release functions that will open and close AcDb objects.
#if (ARX >= 20)
mpModel = mpManager->createAutoCADModel(*mpFactory);
#else
mpModel = mpManager->createAutoCADModel();
#endif
RXASSERT(mpModel);
mbModelCreated = true;
}
//another model without open/close for the orbit gadget
mpGhostModel = mpFactory->createModel(AcGsModel::kDirect,0,0,0);
//mpView->add(&mOrbitGadget,mpGhostModel);
//mOrbitGadget.setGsView(mpView);
mpDevice->add(mpView);
}
}
void CGsPreviewCtrlEx::OnSize(UINT nType, int cx, int cy)
{
CRect rect;
if (mpDevice) {
GetClientRect( &rect);
mpDevice->onSize(rect.Width(), rect.Height());
}
}
BOOL CGsPreviewCtrlEx::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
if (mpView)
{
if (zDelta<0)
mpView->zoom(0.5);
else
mpView->zoom(1.5);
Invalidate();
}
return TRUE;
}
void CGsPreviewCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
// if zooming
if (mZooming)
{
mMouseDown = true;
mMouseMoving = false;
}
else
{
SetFocus();
//start orbit
mbOrbiting = true;
SetCapture();
//set up the proper cursor
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,NULL);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
#endif
::SetCursor(mhOrbitCursor);
}
//store the start point
mStartPt = point;
ClientToScreen(&point);
GetParent()->ScreenToClient(&point);
GetParent()->SendMessage(WM_LBUTTONDOWN,nFlags,MAKELPARAM(point.x,point.y));
}
void CGsPreviewCtrlEx::OnLButtonDblClk(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
GetParent()->ScreenToClient(&point);
GetParent()->SendMessage(WM_LBUTTONDBLCLK,nFlags,MAKELPARAM(point.x,point.y));
GetParent()->SendMessage(WM_VIEWDBLCLKSEL,0,0);
}
void CGsPreviewCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
if (mZooming && mMouseDown)
{
// end zoom
mZooming = false;
mMouseDown = false;
mMouseMoving = false;
// AcGsView Y coordinates origin is at the screen bottom
RECT rect;
GetClientRect(&rect);
//mpView->zoomWindow(AcGePoint2d(mStartPt.x,rect.bottom - mStartPt.y),AcGePoint2d(mEndPt.x,rect.bottom - mEndPt.y));
mpView->invalidate();
mpView->update();
}
else
{
//end orbit
mbOrbiting = false;
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,(LONG_PTR)mhCrossCursor);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
#endif
ReleaseCapture();
}
ClientToScreen(&point);
GetParent()->ScreenToClient(&point);
GetParent()->SendMessage(WM_LBUTTONUP,nFlags,MAKELPARAM(point.x,point.y));
}
void CGsPreviewCtrlEx::OnMButtonDown(UINT nFlags, CPoint point)
{
//start pan
mbPanning = true;
SetCapture();
//set up the proper cursor
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,NULL);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,NULL);
#endif
::SetCursor(mhPanCursor);
//store the start point
mStartPt = point;
}
void CGsPreviewCtrlEx::OnMButtonUp(UINT nFlags, CPoint point)
{
//end pan
ReleaseCapture();
mbPanning = false;
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,(LONG_PTR)mhCrossCursor);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
#endif
}
void CGsPreviewCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
// is the GsView valid
if (mpView)
{
if (mZooming)
{
// if left button is down
if (mMouseDown)
{
if (mMouseMoving)
{
// erase the old rectangle
RubberRectangle(mStartPt, mEndPt);
}
// draw the new rectangle
RubberRectangle(mStartPt, point);
mMouseMoving = true;
// save the new point for next time
mEndPt = point;
}
}
else
{
if (mbPanning)
{
//transform the point from device coordinates to
//world coordinates
AcGeVector3d pan_vec(-(point.x-mStartPt.x),point.y-mStartPt.y,0);
pan_vec.transformBy(mpView->viewingMatrix() * mpView->worldToDeviceMatrix().inverse());
mpView->dolly(pan_vec);
Invalidate();
mStartPt = point;
}
if (mbOrbiting)
{
const double Half_Pi = 1.570796326795;
AcGsDCRect view_rect;
mpView->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;
// compute two vectors from last and new cursor positions:
AcGeVector3d last_vector ((mStartPt.x - centerX) / radius,
-(mStartPt.y - centerY) / radius,
0.0);
if (last_vector.lengthSqrd () > 1.0) // outside the radius
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) // outside the radius
new_vector.normalize ();
else
new_vector.z = sqrt (1.0 - new_vector.x * new_vector.x - new_vector.y * new_vector.y);
// determine angles for proper sequence of camera manipulations:
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; // projection of rotation_vector onto xy plane
double roll_angle = atan2 (work_vector.x,
work_vector.y); // assuming that the camera's up vector is "up",
// this computes the angle between the up vector
// and the work vector, which is the roll required
// to make the up vector coincident with the rotation_vector
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) // rotation_vector and the up_vector divided by the
length = 1.0f; // magnitude of both vectors. We add pi/2 because we
// are making the up-vector parallel to the the rotation
double rotation_angle = asin (length); // vector ... up-vector is perpin. to the eye-vector.
// perform view manipulations
mpView->roll( roll_angle); // 1: roll camera to make up vector coincident with rotation vector
mpView->orbit( 0.0f, orbit_y_angle); // 2: orbit along y to make up vector parallel with rotation vector
mpView->orbit( rotation_angle, 0.0f); // 3: orbit along x by rotation angle
mpView->orbit( 0.0f, -orbit_y_angle); // 4: orbit along y by the negation of 2
mpView->roll(-roll_angle); // 5: roll camera by the negation of 1
Invalidate();
mStartPt = point;
}
}
}
}
#if _MSC_VER < 1400
UINT
#else
LRESULT
#endif
CGsPreviewCtrlEx::OnNcHitTest(CPoint point)
{
return HTCLIENT;
}
void CGsPreviewCtrlEx::OnSetFocus(CWnd* pOldWnd)
{
#ifdef _WIN64
::SetClassLongPtr(m_hWnd,GCLP_HCURSOR,(LONG_PTR)mhCrossCursor);
#else
::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor);
#endif
}
void CGsPreviewCtrlEx::RubberRectangle(CPoint startPt, CPoint endPt)
{
// get the device context for the client area
CDC *cdc = this->GetDC();
// if ok
if (cdc != NULL)
{
HDC hdc = cdc->GetSafeHdc();
// Create a black pen with a dotted style to draw the border of the rectangle.
HPEN gdiPen = CreatePen(PS_DOT, 1, RGB(0,0,0));
// Set the ROP cdrawint mode to XOR.
SetROP2(hdc, R2_XORPEN);
// Select the pen into the device context.
HGDIOBJ oldPen = SelectObject(hdc, gdiPen);
// Create a stock NULL_BRUSH brush and select it into the device
// context so that the rectangle isn't filled.
HGDIOBJ oldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH) );
// Now XOR the hollow rectangle on the Graphics object with
// a dotted outline.
Rectangle(hdc, startPt.x, startPt.y, endPt.x, endPt.y);
// Put the old stuff back where it was.
SelectObject(hdc, oldBrush); // no need to delete a stock object
SelectObject(hdc, oldPen);
DeleteObject(gdiPen); // but we do need to delete the pen
// Return the device context to Windows.
this->ReleaseDC(cdc);
}
}
void CGsPreviewCtrlEx::OnZoomExtents(AcDbDatabase* pDb)
{
AcDbExtents viewExtents(pDb->extmin(), pDb->extmax());
AcGeMatrix3d viewMatrix;
viewExtents.transformBy (viewMatrix);
mpView->zoomExtents(viewExtents.minPoint(),viewExtents.maxPoint());
RefreshView();
}
void CGsPreviewCtrlEx::RefreshView()
{
if (mpView != NULL)
{
mpView->invalidate();
mpView->update();
}
}