#include "stdafx.h" #include "VPOperate.h" TUTIL_IMPEXP XPoint Mcs2Lcs(CPoint point) { CRect rect; XPoint pt; acedGetAcadDwgView()->GetClientRect(&rect); pt[X] =double(point.x) / double(rect.Width()); pt[Y] =double(point.y) / double(rect.Height()); pt[Y] = 1 - pt[Y] ; if(pt.x<0.0) pt.x=0.0; if(pt.y<0.0) pt.y=0.0; if(pt.x>1.0) pt.x=1.0; if(pt.y>1.0) pt.y=1.0; return pt; } TUTIL_IMPEXP CPoint Lcs2Mcs(XPoint point, BOOL bVector=FALSE) { CRect rect; CPoint pt; acedGetAcadDwgView()->GetClientRect(&rect); pt.x = AS_INT(point.x*rect.Width()); if(!bVector) { pt.y = rect.bottom - AS_INT(point.y*rect.Height()); } else { pt.y = - AS_INT(point.y*rect.Height()); } return pt; } TUTIL_IMPEXP void ReadVports(DList &vpInfo) //读取视口信息 { int nTileMode; xg_getvar(_T("TILEMODE"), &nTileMode); if(!nTileMode) return; struct resbuf *rb=NULL; TViewportInfo vports; BOOL flag = FALSE; if(acedVports(&rb) !=RTNORM) return; while(rb = rb->rbnext) { if(rb->restype == RTSHORT) { vports.VpID = rb->resval.rint; flag = TRUE; } if(rb->restype == RTPOINT) { if(flag) { vports.ptLeft[X] = rb->resval.rpoint[0]; vports.ptLeft[Y] = rb->resval.rpoint[1]; vports.ptLeft[Z] = 0; flag = FALSE; } else { vports.ptRight[X] = rb->resval.rpoint[0]; vports.ptRight[Y] = rb->resval.rpoint[1]; vports.ptRight[Z] = 0; vpInfo.Append(new TViewportInfo(vports)); } } } if(rb) ads_relrb(rb); } TUTIL_IMPEXP BOOL GetViewportRect(int vpID, CRect &rect) { DList vports; ReadVports(vports); for(int i=0; iVpID==vpID) { CPoint ptLeft=Lcs2Mcs(vp->ptLeft); CPoint ptRight=Lcs2Mcs(vp->ptRight); rect.top = ptRight.y; rect.bottom = ptLeft.y; rect.left = ptLeft.x; rect.right = ptRight.x; return TRUE; } } return FALSE; } //////////////////////////////////////////////////////// // 取得命中目标的矩形 CRect THitViewport::GetRectOnHitPos(int nMethod, CPoint ptOld, CPoint point) const { CRect rect; { XRectAngle box(m_id.ptLeft, m_id.ptRight); CPoint ptTopLeft, ptBottomRight; ptTopLeft=Lcs2Mcs(box.GetUpLeft()); ptBottomRight=Lcs2Mcs(box.GetLowRight()); rect.SetRect(ptTopLeft, ptBottomRight); } if(nMethod==VP_COPY || nMethod==VP_MOVE) {//拷贝或移动 CPoint vtMove=point-ptOld; rect.bottom += vtMove.y; rect.top += vtMove.y; rect.left += vtMove.x; rect.right += vtMove.x; } else { switch(m_nHitPosition) { case 1: if(m_nHitFlag&HV_ONSIDE) { //命中底边 rect.bottom=point.y; } else { // LowLeft rect.bottom=point.y; rect.left=point.x; } break; case 2: if(m_nHitFlag&HV_ONSIDE) {//命中右边 rect.right=point.x; } else { // LowRight rect.bottom=point.y; rect.right=point.x; } break; case 3: if(m_nHitFlag&HV_ONSIDE) { //命中顶边 rect.top = point.y; } else {// UpRight rect.top=point.y; rect.right=point.x; } break; case 4: if(m_nHitFlag&HV_ONSIDE) {//命中左边 rect.left = point.x; } else { //UpLeft rect.top=point.y; rect.left=point.x; } break; } } return rect; } DList TViewportResize::m_lstHitObjects; CPoint TViewportResize::m_ptOld; CPoint TViewportResize::m_ptFirstHit; //第一次点中的点 BOOL TViewportResize::m_bTracking=FALSE; BOOL TViewportResize::m_bApplied=FALSE; //BOOL TViewportResize::m_bApplyExtend=FALSE; int TViewportResize::m_nApplyMethod=0; //拖曳方法 // 根据控制键,确定应用方法 int TViewportResize::GetApplyMethod(int nFlags) { int nMethod=0; if((nFlags&MK_CONTROL) && (nFlags&MK_SHIFT)) {//Shift+Ctrl+左键 nMethod=VP_RESIZE; } else if(nFlags&MK_CONTROL) { //nMethod=VP_COPY; nMethod=VP_RESIZE; } else if(nFlags&MK_SHIFT) { //nMethod=VP_MOVE; nMethod=VP_RESIZE; } else { nMethod=VP_RESIZE_EX; } return nMethod; } ///////////////////////////////////////////////// // 左键按下 BOOL TViewportResize::OnLButtonDown(UINT nFlags, CPoint point) { if(m_bTracking) return FALSE; m_lstHitObjects.Reset(); int nMethod=GetApplyMethod(nFlags); const TCHAR * pszCursor=HitTest(nMethod, point, m_lstHitObjects); if(pszCursor) { // 判断是否存在非延长线命中的视口 BOOL bHitValid=FALSE; for(int n=0; nm_nHitFlag&HV_ONEXTEND)) { bHitValid=TRUE; break; } } if(!bHitValid) return FALSE; m_nApplyMethod=nMethod; ::SetCursor(LoadCursor(NULL, pszCursor)); m_ptFirstHit = m_ptOld=point; CDC *pDC=acedGetAcadDwgView()->GetDC(); ASSERT(pDC); CSize size(1,1); // 绘制矩形拖曳线 for(int i=0; im_nHitFlag&HV_ONEXTEND) continue; } CRect rectNew=pHitObj->GetRectOnHitPos(nMethod, m_ptFirstHit, point); if(rectNew.left>rectNew.right || rectNew.top>rectNew.bottom) continue; pDC->DrawDragRect(rectNew, size, NULL, size); } acedGetAcadDwgView()->ReleaseDC(pDC); StartTracking(); return TRUE; } return FALSE; } //////////////////////////////////////////////////////////// // 左键抬起 BOOL TViewportResize::OnLButtonUp(UINT nFlags, CPoint point) { if(!m_bTracking) //只出来拖曳结束的动作 return FALSE; m_ptOld = point; BOOL bApplyExtend=GetApplyMethod(nFlags);; StopTracking(TRUE, bApplyExtend); return TRUE; } //////////////////////////////////////////////// // 取消拖曳 BOOL TViewportResize::OnEscape() { if(m_bTracking) { StopTracking(FALSE, m_nApplyMethod); } return FALSE; } /////////////////////////////////////////////// // 开始拖曳 void TViewportResize::StartTracking() { acedGetAcadDwgView()->SetCapture(); m_bTracking=TRUE; } // 结束拖曳, 并更加bAccept使得拖曳生效与否 void TViewportResize::StopTracking(BOOL bAccept, int nMethod) { if(m_bTracking) { m_bTracking=FALSE; CDC *pDC=acedGetAcadDwgView()->GetDC(); ASSERT(pDC); CSize size(1,1); // 绘制矩形拖曳线 for(int i=0; im_nHitFlag&HV_ONEXTEND) continue; } CRect rectNew=pHitObj->GetRectOnHitPos(nMethod, m_ptFirstHit, m_ptOld); pDC->DrawDragRect(rectNew, size, NULL, size); } acedGetAcadDwgView()->ReleaseDC(pDC); ::ReleaseCapture(); if(bAccept) { //进行修改 m_bApplied=FALSE; m_nApplyMethod=nMethod; PostCommand(_T("TDragVp\n"), false); } } } BOOL TViewportResize::OnCaptureChanged(CWnd *pWnd) { if (pWnd != acedGetAcadDwgView()) { StopTracking(FALSE, FALSE); // cancel tracking } return FALSE; } //////////////////////////////////////////////////////////// // 鼠标移动: 拖曳或者改变鼠标形状 BOOL TViewportResize::OnMouseMove(UINT nFlags, CPoint point) { int nMethod=GetApplyMethod(nFlags); if(m_bTracking) { if(point!=m_ptOld) { CDC *pDC=acedGetAcadDwgView()->GetDC(); ASSERT(pDC); CSize size(1,1); // 绘制矩形拖曳线 for(int i=0; im_nHitFlag&HV_ONEXTEND) continue; } CRect rectOld=pHitObj->GetRectOnHitPos(nMethod, m_ptFirstHit, m_ptOld); CRect rectNew=pHitObj->GetRectOnHitPos(nMethod, m_ptFirstHit, point); if(rectNew.left>rectNew.right || rectNew.top>rectNew.bottom) continue; pDC->DrawDragRect(rectNew, size, rectOld, size); } m_ptOld=point; acedGetAcadDwgView()->ReleaseDC(pDC); } return TRUE; } else { nMethod=VP_RESIZE; const TCHAR * pCursor=HitTest(nMethod, point, DList()); if(pCursor) { ::SetCursor(LoadCursor(NULL, pCursor)); return TRUE; } } return FALSE; } // 取得命中的目标 // nMethod--应用方法 const TCHAR * TViewportResize::HitTest(int nMethod, CPoint point, DList &lstHitObjects) { const TCHAR *pCursor=NULL; DList ss; ReadVports(ss); CPoint ptDwgView = point; BOOL bHitObj=FALSE; long lCount=ss.Length(); for(long i=0L; im_id = ent; pHitObj->m_nHitPosition = n+1; pHitObj->m_nHitFlag=0; lstHitObjects.Append(pHitObj); bHitCorner=TRUE; const TCHAR *pNewCursor = (n==0 || n==2)? IDC_SIZENESW : IDC_SIZENWSE; if(!pCursor) pCursor=pNewCursor; else if(pNewCursor!=pCursor) pCursor=IDC_SIZEALL; break; } } if(!bHitCorner) {//对边进行命中测试 CPoint ptTopLeft=Lcs2Mcs(box.GetUpLeft()), ptBottomRight=Lcs2Mcs(box.GetLowRight()); CRect rect; rect.SetRect(ptTopLeft, ptBottomRight); Adesk::UInt8 nHitPos=0, nHitFlag=HV_ONSIDE; if(abs(ptDwgView.y-rect.bottom)rect.right) {//延长线命中 if(nMethod==VP_RESIZE_EX) { nHitPos=1; nHitFlag |= HV_ONEXTEND; } } else {//边界线命中 nHitPos=1; } } else if(abs(ptDwgView.x-rect.right)rect.bottom) { if(nMethod==VP_RESIZE_EX) { nHitFlag |= HV_ONEXTEND; nHitPos=2; } } else { nHitPos=2; } } else if(abs(ptDwgView.y-rect.top)rect.right) { if(nMethod==VP_RESIZE_EX) { nHitFlag |= HV_ONEXTEND; nHitPos = 3; } } else { nHitPos=3; } } else if(abs(ptDwgView.x-rect.left)rect.bottom) { if(nMethod==VP_RESIZE_EX) { nHitFlag |= HV_ONEXTEND; nHitPos=4; } } else { nHitPos=4; } } if(nHitPos) { //命中边界 THitViewport *pHitObj = new THitViewport; pHitObj->m_id = ent; pHitObj->m_nHitPosition = nHitPos; pHitObj->m_nHitFlag=nHitFlag; bHitObj=TRUE; if(!pCursor) { pCursor = (nHitPos==1 || nHitPos==3)? IDC_SIZENS : IDC_SIZEWE; } lstHitObjects.Append(pHitObj); } } else { bHitObj=TRUE; } } if(bHitObj) { if(nMethod==VP_COPY || nMethod==VP_MOVE) //拷贝和移动采用四方向的箭头 pCursor=IDC_SIZEALL; } else { pCursor=NULL; } return pCursor; } AcDbObjectId FindVport(const TViewportInfo &vp) { AcDbDatabase *pCurDwg=acdbCurDwg(); AcDbViewportTable *pVPTable=NULL; VERIFY(pCurDwg->getViewportTable(pVPTable, AcDb::kForRead)==Acad::eOk); AcDbViewportTableIterator *pIterator=NULL; VERIFY(pVPTable->newIterator(pIterator)==Acad::eOk); pVPTable->close(); AcDbObjectId idRet; for(pIterator->start(); !pIterator->done(); pIterator->step()) { AcDbViewportTableRecord *pRecord=NULL; Acad::ErrorStatus es=pIterator->getRecord(pRecord, AcDb::kForRead); ASSERT(es==Acad::eOk); const TCHAR *pszName=NULL; VERIFY(pRecord->getName(pszName)==Acad::eOk && pszName); if(_tcsicmp(pszName, _T("__TCHBACK"))==0) { XPoint ptLow=pRecord->lowerLeftCorner(); XPoint ptUp=pRecord->upperRightCorner(); if(vp.ptLeft.Distance2d(ptLow)<1.0E-3 && vp.ptRight.Distance2d(ptUp)<1.0E-3) { idRet=pRecord->objectId(); pRecord->close(); break; } } pRecord->close(); } delete pIterator; return idRet; } Acad::ErrorStatus AddViewport(AcDbViewportTableRecord *pViewport) { AcDbDatabase *pCurDwg=acdbCurDwg(); AcDbViewportTable *pVPTable=NULL; VERIFY(pCurDwg->getViewportTable(pVPTable, AcDb::kForWrite)==Acad::eOk); //VERIFY(pViewport->setName(_T("__TCHBACK"))==Acad::eOk); AcDbObjectId id; Acad::ErrorStatus es=pVPTable->add(id, pViewport); pVPTable->close(); if(es==Acad::eOk) pViewport->close(); return es; } BOOL TViewportResize::ApplyChange() { if(m_bApplied) return FALSE; int nTileMode=0; xg_getvar(_T("TILEMODE"), &nTileMode); if(!nTileMode) return FALSE; CRect rectDwgView; acedGetAcadDwgView()->GetClientRect(rectDwgView); double nXHitSize=double(HTSIZE)/rectDwgView.Width(); double nYHitSize=double(HTSIZE)/rectDwgView.Height(); XPushVar expert(_T("EXPERT"), 4); ads_command(RTSTR, _T("-VPORTS"), RTSTR, _T("S"), RTSTR, _T("__TCHBACK"), RTNONE); BOOL bVpChanged=FALSE; for(int i=0; im_nHitFlag&HV_ONEXTEND) && m_nApplyMethod!=VP_RESIZE_EX) { continue; } TViewportInfo ent=pHitObj->m_id; AcDbObjectId entApply=FindVport(ent); if(!entApply) continue; CRect rect=pHitObj->GetRectOnHitPos(m_nApplyMethod, m_ptFirstHit, m_ptOld); if(rect.left>rect.right || rect.top>rect.bottom) rect.left=rect.right=rect.top=rect.bottom=0; if(abs(rect.left-rectDwgView.left)<=HTSIZE) rect.left=rectDwgView.left; if(abs(rect.right-rectDwgView.right)<=HTSIZE) rect.right=rectDwgView.right; if(abs(rect.top-rectDwgView.top)<=HTSIZE) rect.top=rectDwgView.top; if(abs(rect.bottom-rectDwgView.bottom)<=HTSIZE) rect.bottom=rectDwgView.bottom; if(fabs(ent.ptLeft.x)<=nXHitSize) ent.ptLeft.x=0; if(fabs(ent.ptLeft.y)<=nYHitSize) ent.ptLeft.y=0; if(fabs(ent.ptRight.x-1.0)<=nXHitSize) ent.ptRight.x=1; if(fabs(ent.ptRight.y-1.0)<=nYHitSize) ent.ptRight.y=1; CPoint ptLowLeft(rect.left, rect.bottom), ptUpRight(rect.right, rect.top); XPoint ptLow=Mcs2Lcs(ptLowLeft), ptUp=Mcs2Lcs(ptUpRight); //if(ptLow.x<0.0) ptLow.x=0.0; OPENOBJ_BEGIN(entApply, AcDb::kForWrite, AcDbViewportTableRecord, pViewport); if(pViewport) { //if(m_nApplyMethod==VP_RESIZE || m_nApplyMethod==VP_RESIZE_EX) { //} double xInc=-(ptLow.x-ent.ptLeft.x)+(ptUp.x-ent.ptRight.x); double yInc=-(ptLow.y-ent.ptLeft.y)+(ptUp.y-ent.ptRight.y); // 删除视口 if(rect.Width()<=HTSIZE || rect.Height()<=HTSIZE) { pViewport->erase(); bVpChanged=TRUE; } else if(fabs(xInc)>nXHitSize || fabs(yInc)>nYHitSize) { double xIncRatio=xInc/(ent.ptRight.x-ent.ptLeft.x); double yIncRatio=yInc/(ent.ptRight.y-ent.ptLeft.y); if(ent.ptLeft.x<=nXHitSize && fabs(ptUp.x-ent.ptRight.x)<=nXHitSize && fabs(ptUp.y-ent.ptRight.y)<=nYHitSize && fabs(ptLow.y-ent.ptLeft.y)<=nYHitSize) { //从左边新增一视口 AcDbViewportTableRecord *pCloned=(AcDbViewportTableRecord *)pViewport->clone(); XPoint ptUpRight(ptLow.x, ptUp.y); XPoint ptLowLeft=pCloned->lowerLeftCorner(); ASSERT(ptLowLeft.x>=0.0 && ptLowLeft.y>=0.0 && ptLowLeft.x>=0.0 && ptLowLeft.y>=0.0 && ptLowLeft.xsetUpperRightCorner(ptUpRight); pCloned->setWidth(pViewport->width()*fabs(xIncRatio)); AddViewport(pCloned); } else if(ent.ptLeft.y<=nYHitSize && fabs(ptUp.x-ent.ptRight.x)<=nXHitSize && fabs(ptUp.y-ent.ptRight.y)<=nYHitSize && fabs(ptLow.x-ent.ptLeft.x)<=nXHitSize) { //从底边新增一视口 AcDbViewportTableRecord *pCloned=(AcDbViewportTableRecord *)pViewport->clone(); XPoint ptUpRight(ptUp.x, ptLow.y); XPoint ptLowLeft=pCloned->lowerLeftCorner(); ASSERT(ptLowLeft.xsetUpperRightCorner(ptUpRight); pCloned->setHeight(pViewport->height()*fabs(yIncRatio)); AddViewport(pCloned); bVpChanged=TRUE; } else if(fabs(ent.ptRight.x-1.0)<=nXHitSize && fabs(ptLow.y-ent.ptLeft.y)<=nYHitSize && fabs(ptUp.y-ent.ptRight.y)<=nYHitSize && fabs(ptLow.x-ent.ptLeft.x)<=nXHitSize) { //从右边新增一视口 AcDbViewportTableRecord *pCloned=(AcDbViewportTableRecord *)pViewport->clone(); XPoint ptLowLeft(ptUp.x, ptLow.y); XPoint ptUpRight=pCloned->upperRightCorner(); ASSERT(ptLowLeft.x>=0.0 && ptLowLeft.y>=0.0 && ptLowLeft.xsetLowerLeftCorner(ptLowLeft); pCloned->setWidth(pViewport->width()*fabs(xIncRatio)); AddViewport(pCloned); bVpChanged=TRUE; } else if(fabs(ent.ptRight.y-1.0)<=nYHitSize && fabs(ptUp.x-ent.ptRight.x)<=nXHitSize && fabs(ptLow.y-ent.ptLeft.y)<=nYHitSize && fabs(ptLow.x-ent.ptLeft.x)<=nXHitSize) { //从顶边新增一视口 AcDbViewportTableRecord *pCloned=(AcDbViewportTableRecord *)pViewport->clone(); XPoint ptLowLeft(ptLow.x, ptUp.y); XPoint ptUpRight=pCloned->upperRightCorner(); ASSERT(ptLowLeft.x>=0.0 && ptLowLeft.y>=0.0 && ptLowLeft.xsetLowerLeftCorner(ptLowLeft); pCloned->setHeight(pViewport->height()*fabs(yIncRatio)); AddViewport(pCloned); bVpChanged=TRUE; } ASSERT(ptLow.x>=0.0 && ptLow.y>=0.0 && ptLow.xsetLowerLeftCorner(ptLow); pViewport->setUpperRightCorner(ptUp); pViewport->setWidth(pViewport->width()*(1.0+xIncRatio)); pViewport->setHeight(pViewport->height()*(1.0+yIncRatio)); /* XPoint ptCen=pViewport->centerPoint(); XVector3D vtInc(xInc, yInc); CPoint vtIncNew=Lcs2Mcs(vtInc, TRUE); vtInc.x = vtIncNew.x * pViewport->width()/fabs(Lcs2Mcs(ent.ptRight).x-Lcs2Mcs(ent.ptLeft).x); vtInc.y = vtIncNew.y * pViewport->height()/fabs(Lcs2Mcs(ent.ptRight).y-Lcs2Mcs(ent.ptLeft).y); vtInc.x /= 2.0; vtInc.y /= 2.0; ptCen += vtInc; pViewport->setCenterPoint(ptCen); */ } } OPENOBJ_END(); } ads_command(RTSTR, _T("-VPORTS"), RTSTR, _T("R"), RTSTR, _T("__TCHBACK"), RTNONE); ads_command(RTSTR, _T("-VPORTS"), RTSTR, _T("D"), RTSTR, _T("__TCHBACK"), RTNONE); m_lstHitObjects.Reset(); m_bApplied=TRUE; m_nApplyMethod=0; if(bVpChanged) TDbCamera::ViewportChanged(); return TRUE; }