基于dxflib库读取DXF文件并在QT中绘制实体段图元(四)

图元绘制过程中涉及到的计算
箭头绘制以及圆弧角度的获取

在具体绘制时主要使用到QGraphicsItem的子类QGraphicsLineItemQGraphicsEllipseItemQGraphicsPathItemQGraphicsTextItem

涉及到的数学计算主要有OCSWCS坐标的转换,由凸度绘制圆弧的计算。这两点前面已经有文章给出了实现方式。这里我再给出由圆心和圆上一点,得到该点的角度(逆时针方向)

//圆弧的角度获取,此处返回的是圆弧角度值,需要注意在QT中三角函数使用的是弧度值,而在画弧时的角度使用的是角度值,而且一定是逆时针绘制
double GetArcAngle(double cx, double cy, double x, double y) {//cx,cy圆心坐标,x,y圆上任意一点 double r; r = sqrt(pow(x - cx, 2) + pow(y - cy, 2)); double ox, oy; ox = cx + r; oy = cy; double kox, koy;//基准向量k kox = ox - cx; koy = oy - cy; double kx, ky;//要计算的向量 kx = x - cx; ky = y - cy; double pcos, psin;//由向量的点乘和叉乘计算 pcos = (kx * kox + ky * koy) / pow(r, 2); psin = (kox * ky - kx * koy) / pow(r, 2); if (psin >= 0) { if (pcos > 1)//防止浮点数溢出,一定要注意,否则易出现aNa pcos = 1; if (pcos < -1) pcos = -1; return acos(pcos) * 180 / PI; } else { if (pcos > 1) pcos = 1; if (pcos < -1) pcos = -1; return 360 - acos(pcos) * 180 / PI; } }
//双向箭头绘制,用于标注
//对于水平方向和垂直方向的线段可以如下绘制:
void PaintArrow(QPointF & p1, QPointF & p2)//在这两点定义的直线两端画出箭头
{
	double angle = 90 / PI;
	double length = 0.5;
	double temp1 = cos(angle / 180 * PI);
	double temp2 = sin(angle / 180 * PI);

    QPointF max = QPointF(0.0, 0.0);
    QPointF min = QPointF(0.0, 0.0);
    if ( abs(p1.X - p2.X) < 1.0e-6 )//垂直显示
    {
        if (p1.Y > p2.Y)
        {
            max = p1;
            min = p2;
        }
        else
        {
            max = p2;
            min = p1;
        }
        if (max.Y - min.Y < 3)//两者相距太近,箭头在外
        {
            m_dimLineList.push_back(QLineF(max.X, -(max.Y + 2 * length * temp1), min.X, -(min.Y - 2 * length * temp1)));//箭头绘制
            m_dimLineList.push_back(QLineF(max.X, -(max.Y ), max.X - length * temp2, -(max.Y + length * temp1)));
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X + length * temp2, -(max.Y + length * temp1)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X - length * temp2, -(min.Y - length * temp1)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X + length * temp2, -(min.Y - length * temp1)));
        }
        else//箭头在内
        {
            m_dimLineList.push_back(QLineF(max.X, - (max.Y) , min.X, -min.Y ));//箭头绘制
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X - length * temp2, -(max.Y - length * temp1)));
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X + length * temp2, -(max.Y - length * temp1)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X - length * temp2, -(min.Y + length * temp1)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X + length * temp2, -(min.Y + length * temp1)));
        }
    }
    else//水平显示
    {
        if (p1.X > p2.X)
        {
            max = p1;
            min = p2;
        }
        else
        {
            max = p2;
            min = p1;
        }
        if (max.X - min.X < 3)//两者相距太近,箭头在外
        {
            m_dimLineList.push_back(QLineF(max.X + 2 * length * temp1, -(max.Y), min.X - 2 * length * temp1, -(min.Y)));//箭头绘制
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X + length * temp1, -(max.Y + length * temp2)));
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X + length * temp1, -(max.Y - length * temp2)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X - length * temp1, -(min.Y + length * temp2)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X - length * temp1, -(min.Y - length * temp2)));
        }
        else//箭头在内
        {
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), min.X, -min.Y));//箭头绘制
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X - length * temp1, -(max.Y - length * temp2)));
            m_dimLineList.push_back(QLineF(max.X, -(max.Y), max.X - length * temp1, -(max.Y + length * temp2)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X + length * temp1, -(min.Y - length * temp2)));
            m_dimLineList.push_back(QLineF(min.X, -(min.Y), min.X + length * temp1, -(min.Y + length * temp2)));
        }
    }
}

上述箭头绘制只适用于水平和垂直线段,更加通用简单的箭头绘制是适用旋转。

void PaintArrow(QLineF & line)//以该直线起始点为中心分别进行顺逆旋转画出箭头,即在起始点处画箭头
{
    double distance = 3.0;
	double length = 0.5;
	double angle = 90 / PI;
    if (line.length() < distance)//两点间太近,画外箭头
    {
        line.setLength(length * line.length() / line.length());//箭头部分缩短为0.5
        line.setAngle(line.angle() + 180 - angle);
        m_dimLineList.push_back(line);
        line.setAngle(line.angle() - 2 * (180 - angle));//需要先恢复原状再顺时针旋转相同度数
        m_dimLineList.push_back(line);
    }
    else//画内箭头
    {
        line.setLength(length * line.length() / line.length() );//箭头部分缩短
        line.setAngle(line.angle() + angle);
        m_dimLineList.push_back(line);
        line.setAngle(line.angle() - 2 * angle);//需要先恢复原状再顺时针旋转
        m_dimLineList.push_back(line);
    }
}



你可能感兴趣的:(QT)