已知圆弧、扇形的中心点ptCT、起始点ptDrawStart、终点ptDrawEnd、选择框的LT/RB点、起始角度StartAngle、圆弧或扇形对应的角度SweepAngle、半径Radius等
一、点选
在while循环中,根据SweepAngle角度的自增或自减,然后来根据中心点、偏移角度、起点算得偏移后的pt点,然后拿pt点与传进来的点ptReserve(如果对线被旋转缩放过,会进代码中的反旋转缩放回来)点计算距离。如果两点距离小于等于线宽,则判定是在圆弧或扇形上的弧线点。
扇形还需通过点是否在两边直线上,可以判定点是否在两点线段上来判定是否在两边直线上。
如果扇形是填充的,点在扇形里面怎么判断呢?也可以通过上面的while(SweepAngle)循环中判断该点是否在中心点与弧线上点的两点线段直线上。
1 //点旋转 2 //CPoint ptReserve; 3 //ReservePoint(pt, ptReserve); 4 CPoint ptReserve = pt; 5 if (m_dbAngle != 0 || m_dbXZoomScale != 1 || m_dbYZoomScale != 1) 6 {//根据旋转缩放后的点求旋转缩放前的点,如果没有旋转缩放不会进 7 double y = (m_xform.eDy - pt.y + pt.x* m_xform.eM12/m_xform.eM11 - m_xform.eDx*m_xform.eM12/m_xform.eM11)/(m_xform.eM21*m_xform.eM12/m_xform.eM11-m_xform.eM22); 8 double x = (pt.x - y*m_xform.eM21 - m_xform.eDx)/m_xform.eM11; 9 ptReserve = CPoint((int) x, (int) y); 10 } 11 12 if (m_bSelectFrameIsShow) 13 { 14 if (m_pWBImageButton != NULL) 15 { 16 if (m_pWBImageButton->IsInButtonArea(pt)) //判断点是否在选择框的按钮上 17 { 18 return WB_PS_SELECTBUTTON; 19 } 20 } 21 22 if (m_pRectSelect != NULL && m_pRectSelect->PointIn(pt)) //判断点是否在选择框内 23 { 24 return WB_PS_SELECTFRAME; 25 } 26 27 return WB_PS_NONE; 28 } 29 XAutoLock lock(m_csSectorItemLock); 30 if (m_pWBSectorItem->bIsFillSolid || !m_bHaveFillRgn) //如果是填充的,或者没有填充区域 31 { 32 if (PointIn(ptReserve)) 33 { 34 return WB_PS_OBJ; 35 } 36 return WB_PS_NONE; 37 } 38 else 39 { 40 41 int nWidth = m_pWBSectorItem->nWidth/2; 42 double dbZoomScale = GetXZoomScale() > GetYZoomScale() ? GetXZoomScale() : GetYZoomScale(); 43 nWidth = (int)((nWidth * dbZoomScale) > WB_OBJECT_SELECT_SEGMENT ? (nWidth * dbZoomScale) : WB_OBJECT_SELECT_SEGMENT); 44 45 double dSweepAngle = m_pWBSectorItem->dSectorSweepAngle; 46 CPoint ptTemp; 47 CPoint ptDrawStart = m_pWBSectorItem->ptDrawStart; 48 double dDistan = 0; 49 //根据选择角度的自增、自减,通过起点旋转得到旋转角度后的点,判断这些点到中心点的距离是否为半径大小 50 if (dSweepAngle > 0) 51 { 52 while(dSweepAngle > 0) 53 { 54 PointRotationPoint(m_pWBSectorItem->ptSectorCT,dSweepAngle, ptDrawStart, ptTemp); 55 if (CalDistancePointToPoint(ptTemp, ptReserve) < nWidth) 56 { 57 return WB_PS_OBJ; 58 } 59 dSweepAngle -= 1; 60 } 61 } 62 else 63 { 64 while(dSweepAngle < 0) 65 { 66 PointRotationPoint(m_pWBSectorItem->ptSectorCT, dSweepAngle, ptDrawStart, ptTemp); 67 if (CalDistancePointToPoint(ptTemp, ptReserve) < nWidth) 68 { 69 return WB_PS_OBJ; 70 } 71 dSweepAngle += 1; 72 } 73 } 74 //判断是否在边线上 75 if (CWBObject::PointInLine(ptReserve, m_pWBSectorItem->ptDrawStart, m_pWBSectorItem->ptSectorCT, m_pWBSectorItem->nWidth) 76 || CWBObject::PointInLine(ptReserve, m_pWBSectorItem->ptDrawEnd, m_pWBSectorItem->ptSectorCT, m_pWBSectorItem->nWidth)) 77 { 78 return WB_PS_OBJ; 79 } 80 else 81 { 82 return WB_PS_NONE; 83 } 84 85 }
二、框选
对象创建的时候会跟着创建虚线框(矩形选择框),框选的判断是如果该对象的虚线框的四条边的中点都在框选的区域内,那么该对象就会被认为是被选中的。
1 //判断对象选择框的四条边的中点是否都在框选的区域内 2 if (pRgn == NULL) 3 { 4 return FALSE; 5 } 6 if (m_pWBSectorItem == NULL) 7 { 8 return FALSE; 9 } 10 11 CPoint pPoint; 12 CPoint ptReserve; //转换后的点坐标 13 14 CPoint ptLeftTop = m_pRectSelect->GetLeftTop(); 15 CPoint ptRightTop = m_pRectSelect->GetRightTop(); 16 CPoint ptRightBottom = m_pRectSelect->GetRightBottom(); 17 CPoint ptLeftBottom = m_pRectSelect->GetLeftBottom(); 18 19 pPoint.x = (int)((ptLeftTop.x + ptRightTop.x) / 2); 20 pPoint.y = ptLeftTop.y; 21 ReserveObjPoint(pPoint, ptReserve); 22 if (!pRgn->PtInRegion(ptReserve)) 23 { 24 return FALSE; 25 } 26 27 pPoint.x = ptRightTop.x; 28 pPoint.y = (int)((ptRightTop.y + ptRightBottom.y) / 2); 29 ReserveObjPoint(pPoint, ptReserve); 30 if (!pRgn->PtInRegion(ptReserve)) 31 { 32 return FALSE; 33 } 34 35 pPoint.x = (int)((ptRightBottom.x + ptLeftBottom.x) / 2); 36 pPoint.y = ptRightBottom.y; 37 ReserveObjPoint(pPoint, ptReserve); 38 if (!pRgn->PtInRegion(ptReserve)) 39 { 40 return FALSE; 41 } 42 43 pPoint.x = ptLeftBottom.x; 44 pPoint.y = (int)((ptLeftBottom.y + ptLeftTop.y) / 2); 45 ReserveObjPoint(pPoint, ptReserve); 46 if (!pRgn->PtInRegion(ptReserve)) 47 { 48 return FALSE; 49 }
根据中心点、偏移角度、起点得到旋转角度后的点坐标
1 void PointRotationPoint( 2 const CPoint& ptCenter, 3 double dbAngle, 4 const CPoint& ptSrc, 5 CPoint& ptDes) 6 /*计算点绕中心点旋转后的坐标 7 参数: 8 ptCenter:输入,中心点坐标 9 dbAngle:输入,旋转角度,顺时针为正 10 ptSrc:输入,点旋转前的坐标 11 ptDes:输出:点旋转后的坐标 12 返回值:成功返回TRUE,否则返回FALSE 13 */ 14 { 15 //角度转弧度 16 double dbRadian = dbAngle * PI / 180; 17 18 ptDes.x = (LONG)((ptSrc.x - ptCenter.x) * cos(dbRadian) + (ptSrc.y - ptCenter.y) * sin(dbRadian) + ptCenter.x + 0.5); 19 ptDes.y = (LONG)(-(ptSrc.x - ptCenter.x) * sin(dbRadian) + (ptSrc.y - ptCenter.y) * cos(dbRadian) + ptCenter.y + 0.5); 20 }
1 /************************************************************************* 2 ***** 计算点到直线的距离 ***** 3 *************************************************************************/ 4 double CalDistancePointToLine(const CPoint pt, const CPoint ptA, const CPoint ptB) 5 { 6 7 //计算点pt到线段(A,B)的距离 8 double length; /* 直线长度 */ 9 double a = ptB.y-ptA.y; 10 double b = ptA.x-ptB.x; 11 double c = ptB.x * ptA.y - ptA.x * ptB.y; 12 return length = abs(a * pt.x + b *pt.y + c)/sqrt(a * a + b * b); 13 /* length = CalDistancePointToPoint(ptA,ptB); 14 if(length == 0.0) 15 return( CalDistancePointToPoint(ptA,pt)); 16 r = ((ptA.y - pt.x )*(ptA.y - ptB.y) - (ptA.x - pt.x )*(ptB.x - ptA.x))/(length*length); 17 if(r > 1) /* perpendicular projection of P is on the forward extention of AB */ 18 /* return(min(CalDistancePointToPoint(pt, ptB),CalDistancePointToPoint(pt, ptA))); 19 if(r < 0) /* perpendicular projection of P is on the backward extention of AB */ 20 /* return(min(CalDistancePointToPoint(pt, ptB),CalDistancePointToPoint(pt, ptA))); 21 s = ((ptA.y - pt.y)*(ptB.x - ptA.x) - (ptA.x - pt.x )*(ptB.y - ptA.y))/(length*length); 22 23 return(fabs(s*length));*/ 24 }
上面是计算点到直线的距离
下面是两点间距离
1 /************************************************************************* 2 ***** 计算直线的长度 ***** 3 *************************************************************************/ 4 double CalDistancePointToPoint(const CPoint ptA, const CPoint ptB) 5 { 6 //计算两点间的距离 7 double dx = ptA.x - ptB.x; 8 double dy = ptA.y - ptB.y; 9 return sqrt(dx*dx + dy*dy); 10 } 11 12 /*
实时计算MouseMove过程中偏移的小角度(大角度没有用,会出现问题)
1 double PointRotationPoint(const CPoint& ptCenter, const CPoint& ptBegin, const CPoint& ptEnd) 2 /*计算点绕中心点旋转后的角度 3 参数: 4 ptCenter:输入,旋转中心点坐标 5 ptBegin:输入,旋转开始点 6 ptEnd:输入,旋转结束点 7 返回值:旋转角度 8 */ 9 { 10 double dbAngle = 0; 11 double dbRadian = 0; //弧度 12 int y; //用于判断终点在起点与中心点所成直线的上下 13 //计算结束点到基线的距离 14 double dbDistance = CalDistancePointToLine(ptEnd, ptCenter, ptBegin); 15 16 //计算中心点与结束点直线的距离 17 double dbLine = CalDistancePointToPoint(ptCenter, ptEnd); 18 19 if (dbLine == 0) 20 { 21 return 0; 22 } 23 24 if (ptBegin.x == ptCenter.x) 25 { 26 return 0; 27 } 28 29 dbRadian = asin(dbDistance / dbLine); 30 31 dbAngle = dbRadian * 180 / PI; //偏移角度 32 if(ptBegin.x == ptCenter.x && ptEnd.y < ptCenter.y) //当起点与中心点组成的直线垂直,且终点在中心点之上时 33 { 34 if (ptEnd.x < ptBegin.x) //终点与起点位置比较 35 { 36 return dbAngle; 37 } 38 else 39 { 40 return 0 - dbAngle; 41 } 42 } 43 if(ptBegin.x == ptCenter.x && ptEnd.y > ptCenter.y) //当起点与中心点组成的直线垂直,且终点在中心点之下时 44 { 45 if (ptEnd.x > ptBegin.x) 46 { 47 return dbAngle; 48 } 49 else 50 { 51 return 0 - dbAngle; 52 } 53 } 54 55 y = (ptEnd.x - ptCenter.x) * (ptBegin.y - ptCenter.y) / (ptBegin.x - ptCenter.x) + ptCenter.y; 56 //鼠标位于以中心点为原点的第一象限 57 if(ptEnd.x >= ptCenter.x && ptEnd.y < ptCenter.y) 58 { 59 if (ptBegin.x < ptCenter.x && ptBegin.y < ptCenter.y) //如果是从第二象限移动至第一象限 60 { 61 return 0 - dbAngle; 62 } 63 if (ptEnd.x == ptCenter.x && ptBegin.x > ptCenter.x && ptBegin.y < ptCenter.y) 64 { 65 return dbAngle; 66 } 67 if(ptEnd.y < y) 68 { 69 return dbAngle; 70 } 71 else 72 { 73 dbAngle = 0 - dbAngle;//偏移角度 74 return dbAngle; 75 } 76 } 77 //鼠标位于以中心点为原点的第二象限 78 if(ptEnd.x < ptCenter.x && ptEnd.y <= ptCenter.y) 79 { 80 if (ptBegin.x > ptCenter.x && ptBegin.y < ptCenter.y) //如果是从第一象限移动至第二象限 81 { 82 return dbAngle; 83 } 84 if(ptEnd.y > y) 85 { 86 return dbAngle; 87 } 88 else 89 { 90 dbAngle = 0 - dbAngle;//偏移角度 91 return dbAngle; 92 } 93 } 94 //鼠标位于以中心点为原点的第三象限 95 if(ptEnd.x <= ptCenter.x && ptEnd.y > ptCenter.y) 96 { 97 if (ptBegin.x > ptCenter.x && ptBegin.y > ptCenter.y) //如果是从第四象限移动至第三象限 98 { 99 return 0 - dbAngle; 100 } 101 if (ptEnd.x == ptCenter.x && ptBegin.x < ptCenter.x && ptBegin.y > ptCenter.y) 102 { 103 return dbAngle; 104 } 105 if(ptEnd.y > y) 106 { 107 return dbAngle; 108 } 109 else 110 { 111 dbAngle = 0 - dbAngle;//偏移角度 112 return dbAngle; 113 } 114 } 115 //鼠标位于以中心点为原点的第四象限 116 if(ptEnd.x > ptCenter.x && ptEnd.y >= ptCenter.y) 117 { 118 if (ptBegin.x < ptCenter.x && ptBegin.y > ptCenter.y) //如果是从第三象限移动至第四象限 119 { 120 return dbAngle; 121 } 122 if(ptEnd.y < y) 123 { 124 return dbAngle; 125 } 126 else 127 { 128 dbAngle = 0 - dbAngle;//偏移角度 129 return dbAngle; 130 } 131 } 132 return dbAngle; 133 }
根据原点计算旋转缩放后得到的点坐标函数
1 void CWBObject::ReserveObjPoint(const CPoint& ptOriginal, CPoint& ptReserve) const 2 { 3 ptReserve = ptOriginal; 4 5 if (m_dbAngle == 0 && m_dbXZoomScale == 1 && m_dbYZoomScale == 1) 6 { 7 return; 8 } 9 10 //添加缩放比例 11 CPoint ptScale = ptOriginal; 12 13 if (m_nType == WB_OBJ_ARC||m_nType == WB_OBJ_SECTOR||m_nType == WB_OBJ_CURVE || m_nType == WB_OBJ_POLYGON || m_nType == WB_OBJ_TEXT||m_nType == WB_OBJ_ARBITRARYTRIANGLE || m_nType == WB_OBJ_ICOCURVE /* add by jiangchao 4月12日*/)//如果对象是曲线、多边形、文本 14 { 15 //根据坐标系的变化算出映射到窗口坐标系的点 16 ptReserve.x = (LONG)(ptScale.x * m_xform.eM11 + ptScale.y * m_xform.eM21 + m_xform.eDx); 17 ptReserve.y = (LONG)(ptScale.x * m_xform.eM12 + ptScale.y * m_xform.eM22 + m_xform.eDy); 18 return; 19 } 20 21 PointRotationPoint(m_ptRotationCenter, m_dbAngle, ptScale, ptReserve); 22 23 return; 24 }
旋转世界坐标系
1 int CWBObject::RotateXForm(double dbAngle) 2 { 3 4 if (m_pDC == NULL || 5 (dbAngle == 0 && m_dbXZoomScale == 1 && m_dbYZoomScale == 1)) 6 { 7 return -1; 8 } 9 10 HDC hDC = m_pDC->GetSafeHdc(); 11 Graphics graphic(hDC); 12 int a = m_ptRotationCenter.x; 13 int b = m_ptRotationCenter.y; 14 //取对象旋转中心点 15 CPoint ptCenter = m_ptRotationCenter; 16 //GetCenterPoint(ptCenter); 17 18 //计算缩放后的中心点 19 CPoint ptZoomOffset = CPoint(0, 0); 20 if (m_dbXZoomScale != 1 || m_dbYZoomScale != 1 ) 21 { 22 if (m_pRectSelect != NULL) 23 { 24 CPoint ptLeftTop; 25 CPoint ptZoomLeftTop; 26 27 ptLeftTop = m_pRectSelect->GetLeftTop(); 28 ptZoomLeftTop.x = (LONG)(ptLeftTop.x * m_dbXZoomScale + 0.5); 29 ptZoomLeftTop.y = (LONG)(ptLeftTop.y * m_dbYZoomScale + 0.5); 30 31 //旋转后算偏移量 32 CPoint ptRotationLeftTop, ptRotationZoomLeftTop; 33 PointRotationPoint(ptCenter, m_dbAngle, ptLeftTop, ptRotationLeftTop); 34 PointRotationPoint(ptCenter, m_dbAngle, ptZoomLeftTop, ptRotationZoomLeftTop); 35 36 ptZoomOffset = ptRotationZoomLeftTop - ptRotationLeftTop; 37 //ptZoomOffset = ptZoomLeftTop - ptLeftTop; 38 } 39 } 40 41 //旋转 42 int nGraphicsMode = SetGraphicsMode(hDC, GM_ADVANCED); 43 44 XFORM xform; 45 double fangle = -dbAngle / 180. * PI; 46 /* xform.eM11 = (float)cos(fangle); 47 xform.eM12 = (float)sin(fangle); 48 xform.eM21 = (float)-sin(fangle); 49 xform.eM22 = (float)cos(fangle); 50 xform.eDx = (float)(ptCenter.x - cos(fangle)*ptCenter.x + sin(fangle)*ptCenter.y); 51 xform.eDy = (float)(ptCenter.y - cos(fangle)*ptCenter.y - sin(fangle)*ptCenter.x);*/ 52 53 //加缩放因子 54 xform.eM11 = (float)cos(fangle)*(float)m_dbXZoomScale; 55 xform.eM12 = (float)sin(fangle)*(float)m_dbXZoomScale; 56 xform.eM21 = (float)-sin(fangle)*(float)m_dbYZoomScale; 57 xform.eM22 = (float)cos(fangle)*(float)m_dbYZoomScale; 58 xform.eDx = (float)(ptCenter.x - cos(fangle)*ptCenter.x + sin(fangle)*ptCenter.y) - ptZoomOffset.x; 59 xform.eDy = (float)(ptCenter.y - cos(fangle)*ptCenter.y - sin(fangle)*ptCenter.x) - ptZoomOffset.y; 60 61 m_xform = xform; //保存坐标系的变化 62 63 //计算对象中心点映射到窗口坐标系中的坐标 64 GetCenterPoint(ptCenter); 65 m_ptMapCenter.x = (LONG)(ptCenter.x * xform.eM11 + ptCenter.y * xform.eM21 + xform.eDx + 0.5); 66 m_ptMapCenter.y = (LONG)(ptCenter.x * xform.eM12 + ptCenter.y * xform.eM22 + xform.eDy + 0.5); 67 68 SetWorldTransform(hDC, &xform); 69 70 return nGraphicsMode; 71 }
恢复世界坐标系
1 void CWBObject::ResumeXForm(int nGraphicsMode) 2 { 3 if (m_pDC == NULL) 4 { 5 return; 6 } 7 8 HDC hDC = m_pDC->GetSafeHdc(); 9 10 // 恢复DC 11 XFORM xform; 12 13 xform.eM11 = (float)1.0; 14 xform.eM12 = (float)0; 15 xform.eM21 = (float)0; 16 xform.eM22 = (float)1.0; 17 xform.eDx = (float)0; 18 xform.eDy = (float)0; 19 SetWorldTransform(hDC, &xform); 20 21 SetGraphicsMode(hDC, nGraphicsMode); 22 }