在具体绘制时主要使用到QGraphicsItem的子类QGraphicsLineItem、QGraphicsEllipseItem、QGraphicsPathItem、QGraphicsTextItem。
涉及到的数学计算主要有OCS到WCS坐标的转换,由凸度绘制圆弧的计算。这两点前面已经有文章给出了实现方式。这里我再给出由圆心和圆上一点,得到该点的角度(逆时针方向)
//圆弧的角度获取,此处返回的是圆弧角度值,需要注意在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);
}
}