zoukankan      html  css  js  c++  java
  • 关于圆弧、扇形对象的点选和框选

    已知圆弧、扇形的中心点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     }
    View Code

    二、框选

    对象创建的时候会跟着创建虚线框(矩形选择框),框选的判断是如果该对象的虚线框的四条边的中点都在框选的区域内,那么该对象就会被认为是被选中的。

     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     }
    View Code

    根据中心点、偏移角度、起点得到旋转角度后的点坐标

     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 }
    View Code
     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 }
    View Code

    上面是计算点到直线的距离

    下面是两点间距离

     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 /*
    View Code

    实时计算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 }
    View Code

    根据原点计算旋转缩放后得到的点坐标函数

     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 }
    View Code

    旋转世界坐标系

     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 }
    View Code

    恢复世界坐标系

     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 }
    View Code
  • 相关阅读:
    免费的视频、音频转文本
    Errors are values
    Codebase Refactoring (with help from Go)
    Golang中的坑二
    Cleaner, more elegant, and wrong(msdn blog)
    Cleaner, more elegant, and wrong(翻译)
    Cleaner, more elegant, and harder to recognize(翻译)
    vue控制父子组件渲染顺序
    computed 和 watch 组合使用,监听数据全局数据状态
    webstorm破解方法
  • 原文地址:https://www.cnblogs.com/lisuyun/p/3491413.html
Copyright © 2011-2022 走看看