// GsPreviewCtrl.cpp : implementation file // #include "stdafx.h" #include "resource.h" #include "GsPreviewCtrl.h" #include "acgsmanager.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern TARCH_IMPEXP double g_nWalkDistStep, g_nWalkAngleStep; #define RXASSERT ASSERT double GetLatitude(XPoint ptCam, XPoint ptTar) //-PI/2 ~ PI/2 { double nDist=ptTar.Distance(ptCam); if(nDist<_DIST_SNAP) return 0.0; if(ptTar.Distance2d(ptCam)<_DIST_SNAP) { return ((ptTar.z > ptCam.z)? PI/2 : -PI/2); } return asin((ptTar.z-ptCam.z)/nDist); } double GetLongitude(XPoint ptCam, XPoint ptTar) // 0 ~ 2*PI { if(ptTar.Distance2d(ptCam)<_DIST_SNAP) return 0.0; return ads_angle(ptCam, ptTar); } ///////////////////////////////////////////////////////////////////////////// // CGsPreviewCtrl IMPLEMENT_DYNAMIC(CGsPreviewCtrl, CStatic) CGsPreviewCtrl::CGsPreviewCtrl(int nOrbitFlag) : CStatic(), mOrbitFlag(nOrbitFlag), mpManager(NULL), mpFactory(NULL), mpDevice(NULL), mpView(NULL), mpModel(NULL),mbModelCreated(false),mbPanning(false),mbOrbiting(false), mDistStep(g_nWalkDistStep), mAngStep(g_nWalkAngleStep) { } BOOL CGsPreviewCtrl::DestroyWindow() { clearAll(); return CStatic::DestroyWindow(); } BEGIN_MESSAGE_MAP(CGsPreviewCtrl, CStatic) //{{AFX_MSG_MAP(CGsPreviewCtrl) 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() ON_WM_KEYDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CGsPreviewCtrl message handlers void CGsPreviewCtrl::OnPaint() { CPaintDC dc(this); //update the gs view if(mpView) { mpView->invalidate(); mpView->update(); } } // Erase view and delete model void CGsPreviewCtrl::erasePreview() { if (mpView) mpView->eraseAll(); if (mpManager && mpModel) { mpManager->destroyAutoCADModel (mpModel); mpModel = NULL; } } void CGsPreviewCtrl::setModel(AcGsModel* pModel) { erasePreview(); mpModel = pModel; mbModelCreated =false; } void CGsPreviewCtrl::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 CGsPreviewCtrl::init(bool bCreateModel) { //Load our special cursors { CTemporaryResourceOverride vTemp; CWinApp *pApp=AfxGetApp(); mhPanCursor=pApp->LoadCursor(IDI_PAN); mhCrossCursor=pApp->LoadCursor(IDI_CROSS); mhOrbitCursor=pApp->LoadCursor(IDI_ORBIT); } //Instantiate view, a device and a model object CRect rect; if (!mpManager) { mpManager = acgsGetGsManager(); RXASSERT(mpManager); #if (ADS >= 20) AcGsKernelDescriptor desc; desc.addRequirement(AcGsKernelDescriptor::k3DDrawing); mpFactory = AcGsManager::acquireGraphicsKernel(desc); if (!mpFactory) return; #else mpFactory = mpManager->getGSClassFactory(); #endif RXASSERT(mpFactory); //a device with standard autocad color palette #if (ADS >= 20) //mpDevice = mpFactory->createOffScreenDevice(); mpDevice = mpManager->createAutoCADDevice(*mpFactory, m_hWnd); #else mpDevice = mpManager->createAutoCADDevice(m_hWnd); #endif RXASSERT(mpDevice); GetClientRect( &rect); mpDevice->onSize(rect.Width(), rect.Height()); //a simple view mpView = mpFactory->createView(); RXASSERT(mpView); if (bCreateModel) { RXASSERT(mpModel==NULL); //a model with open/close protocol #if (ADS >= 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); if(mOrbitFlag) { /* mpView->add(&mOrbitGadget,mpGhostModel); mOrbitGadget.setGsView(mpView); */ } mpDevice->add(mpView); mpView->setView(AcGePoint3d(0.0, 0.0, 1.0), AcGePoint3d(0.0, 0.0, 0.0), AcGeVector3d(0.0, 1.0, 0.0), 1.0, 1.0); } } void CGsPreviewCtrl::OnSize(UINT nType, int cx, int cy) { CRect rect; if (mpDevice) { GetClientRect( &rect); mpDevice->onSize(rect.Width(), rect.Height()); } } BOOL CGsPreviewCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { if(!(mOrbitFlag&OBF_ZOOM)) return CStatic::OnMouseWheel(nFlags, zDelta, pt); if (mpView) { if(mpView->isPerspective()) { AcGePoint3d ptTar=mpView->target(); AcGePoint3d ptCam=mpView->position(); AcGeVector3d vtView=ptTar-ptCam; vtView.normalize(); double nScale=mDistStep; if(zDelta<0) nScale=-nScale; vtView *= nScale; ptCam += vtView; ptTar += vtView; mpView->setView(ptCam, ptTar, AcGeVector3d(0,0,1), mpView->fieldWidth(), mpView->fieldHeight(), AcGsView::kPerspective); //mpView->setTarget(ptTar); //mpView->setCamera(ptCam); } else { if (zDelta<0) mpView->zoom(0.9); else mpView->zoom(1.1); } Invalidate(); } return TRUE; } void CGsPreviewCtrl::OnLButtonDown(UINT nFlags, CPoint point) { SetFocus(); if(!(mOrbitFlag&OBF_ORBIT)) { CStatic::OnLButtonDown(nFlags, point); return; } //start orbit mbOrbiting = true; SetCapture(); //set up the proper cursor //::SetClassLong(m_hWnd,GCL_HCURSOR,NULL); ::SetCursor(mhOrbitCursor); //store the start point mStartPt = point; } void CGsPreviewCtrl::OnLButtonUp(UINT nFlags, CPoint point) { if(!(mOrbitFlag&OBF_ORBIT)) { CStatic::OnLButtonUp(nFlags, point); return; } //end orbit mbOrbiting = false; //::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor); ::SetCursor(mhCrossCursor); ReleaseCapture(); } void CGsPreviewCtrl::OnMButtonDown(UINT nFlags, CPoint point) { if(!(mOrbitFlag&OBF_PAN)) { CStatic::OnMButtonDown(nFlags, point); return; } //start pan mbPanning = true; SetCapture(); //set up the proper cursor //::SetClassLong(m_hWnd,GCL_HCURSOR,NULL); ::SetCursor(mhPanCursor); //store the start point mStartPt = point; } void CGsPreviewCtrl::OnMButtonUp(UINT nFlags, CPoint point) { if(!(mOrbitFlag&OBF_PAN)) { CStatic::OnMButtonUp(nFlags, point); return; } //end pan ReleaseCapture(); mbPanning = false; //::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor); ::SetCursor(mhCrossCursor); } void CGsPreviewCtrl::Invalidate(BOOL bErase) { if(g_nAcadVer<17.05)//2008以下 CStatic::Invalidate(bErase); else { CWnd*pParent=GetParent(); if(pParent!=NULL)//2008+vista发现刷新问题,暂用此方法解决 { CRect rect; GetWindowRect(rect); pParent->ScreenToClient(rect); pParent->InvalidateRect(rect,bErase); } else CStatic::Invalidate(bErase); } } void CGsPreviewCtrl::OnMouseMove(UINT nFlags, CPoint point) { if (mpView && mbPanning && (mOrbitFlag&OBF_PAN) ) { //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; } else if (mpView && mbOrbiting && (mOrbitFlag&OBF_ORBIT)) { AcGeVector3d vtMov(mStartPt.x-point.x, point.y-mStartPt.y, 0.0); //AcGeVector3d vtOff(point.x-m_ptLast.x, point.y-m_ptLast.y, 0.0); //if(max(fabs(vtOff[0]), fabs(vtOff[1]))<10) // return; AcGePoint3d ptCam=mpView->position(); AcGePoint3d ptTar=mpView->target(); AcGeVector3d vtUp=mpView->upVector(); vtUp=AcGeVector3d(0,0,1); CRect rect; GetClientRect(rect); //Modify bu xlc on 111222 Y向反向,解决预览图里拖动方向与实际方向相反的问题 //double nRotX = -vtMov.y/rect.Height()*PI/2; //double nRotY = -vtMov.x/rect.Width()*PI/2; double nRotX = vtMov.y/rect.Height()*PI/2; double nRotY = vtMov.x/rect.Width()*PI/2; AcGeVector3d vtZ=ptCam-ptTar; AcGePlane plan(ptCam, vtZ); AcGePoint3d ptUp=ptCam + vtUp*10000.0; AcGePoint3d ptUp1=ptUp.orthoProject(plan); if(ptCam.distanceTo(ptUp1)<0.1) return; AcGeVector3d vtY=ptUp1-ptCam; //Modify bu xlc on 111222 Y向反向,解决预览图里拖动方向与实际方向相反的问题 vtY.negate(); AcGeVector3d vtX=vtY.crossProduct(vtZ); vtX.normalize(); vtY.normalize(); vtZ.normalize(); AcGeVector3d vtView=ptTar-ptCam; //if(fabs(vtMov.y)>fabs(vtMov.x)) { //m_vtUp.rotateBy(nRotX, vtX); vtView.rotateBy(nRotX, vtX); //} else { vtY.rotateBy(nRotX, vtX); //m_vtUp.rotateBy(nRotY, vtY); vtView.rotateBy(nRotY, vtY); //} ptTar = ptCam + vtView; mpView->setView(ptCam, ptTar, vtUp, mpView->fieldWidth(), mpView->fieldHeight(), mpView->isPerspective()? AcGsView::kPerspective : AcGsView::kParallel); Invalidate(); //m_ptLast = point; mStartPt=point; /* 原来的代码 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 = AS_INT(nViewportX / 2.0f + view_rect.m_min.x); int centerY = AS_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; */ } else { CStatic::OnMouseMove(nFlags, point); } } #if ADS<17 UINT CGsPreviewCtrl::OnNcHitTest(CPoint point) #else LRESULT CGsPreviewCtrl::OnNcHitTest(CPoint point) #endif { return HTCLIENT; } void CGsPreviewCtrl::OnSetFocus(CWnd* pOldWnd) { if(mOrbitFlag && mhCrossCursor) { //::SetClassLong(m_hWnd,GCL_HCURSOR,(long)mhCrossCursor); ::SetCursor(mhCrossCursor); } } void CGsPreviewCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { BOOL bShift = IsKeyPressed(VK_SHIFT); BOOL bCtrl = IsKeyPressed(VK_CONTROL); XPoint ptCam=mpView->position(); XPoint ptTar=mpView->target(); XVector3D vtView=ptTar-ptCam; vtView.Normalize(); XVector3D vtUp(0,0,1); if(nChar==VK_LEFT || nChar==VK_RIGHT) { double nFactor=1.0; if(nChar==VK_RIGHT) nFactor=-1.0; if(!bShift && !bCtrl){ //左右移 double nStepLen=mDistStep*nRepCnt; double longitude=GetLongitude(ptCam, ptTar); ads_matrix mat; XPoint().GetMoveMatrix(XPoint(nStepLen*cos(longitude + PI/2.0*nFactor), nStepLen*sin(longitude + PI/2.0*nFactor)), mat); ptCam.TransformBy(mat); ptTar.TransformBy(mat); } else if(bCtrl){ //左右转 PI/2 double val=GetLongitude(ptCam, ptTar) + PI / 2.0 * nFactor; double nElev=ptTar.z; ads_polar(ptCam, val, ptCam.Distance2d(ptTar), ptTar); ptTar.z=nElev; } else if(bShift) { //左右转 double val = GetLongitude(ptCam, ptTar) + mAngStep*nRepCnt*nFactor; double nElev=ptTar.z; ads_polar(ptCam, val, ptCam.Distance2d(ptTar), ptTar); ptTar.z=nElev; } } else if(nChar==VK_UP || nChar==VK_DOWN) { double nFactor=1.0; if(nChar==VK_DOWN) nFactor=-1.0; if(!bShift && !bCtrl){ //前进或后退 ads_matrix mat; double nStepLen=mDistStep*nRepCnt*nFactor; double longitude = GetLongitude(ptCam, ptTar); XPoint().GetMoveMatrix(XPoint(nStepLen*cos(longitude), nStepLen*sin(longitude)), mat); ptCam.TransformBy(mat); ptTar.TransformBy(mat); } else if(bCtrl){ //上下移动 ptCam.z += mDistStep*nRepCnt*nFactor; ptTar.z += mDistStep*nRepCnt*nFactor; } else if(bShift) { //上下转动 double val = GetLatitude(ptCam, ptTar) + mAngStep*nRepCnt*nFactor; double nElevDiff=ptCam.Distance2d(ptTar)*tan(val); ptTar.z = ptCam.z + nElevDiff; } } else { CStatic::OnKeyDown(nChar, nRepCnt, nFlags); return; } mpView->setView(ptCam, ptTar, vtUp, mpView->fieldWidth(), mpView->fieldHeight(), mpView->isPerspective()? AcGsView::kPerspective : AcGsView::kParallel); Invalidate(); } BOOL CGsPreviewCtrl::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if(pMsg->message==WM_KEYDOWN) { int vk=pMsg->wParam; if(vk==VK_LEFT || vk==VK_RIGHT || vk==VK_DOWN || vk==VK_UP) { int nRepCnt=LOWORD(pMsg->lParam); OnKeyDown(vk, nRepCnt, 0); return TRUE; } } return CStatic::PreTranslateMessage(pMsg); }