如何使用.slib文件中的圆弧坐标在Qt中正确绘制圆弧
.slib门电路符号绘制:圆弧参数解析与Qt实现方案
问题背景
开发需求为读取.slib格式文件,生成AND、NOT、XNOR、MUX等标准门电路符号。解析图元时,line(直线)类型参数逻辑清晰可直接使用,但arc(圆弧)类型的参数定义无明确说明,无法正确映射到绘制接口,导致图形渲染出错。
现有文件格式样例
直线(line)格式
直线参数共4个,依次为起点X坐标、起点Y坐标、终点X坐标、终点Y坐标,所有参数值乘以文件头定义的全局缩放系数SCALE即为实际坐标:
line (66 * SCALE, 80 * SCALE, 0 * SCALE, 80 * SCALE); line (94 * SCALE, 70 * SCALE, 62 * SCALE, 70 * SCALE); ...
圆弧(arc)格式
圆弧参数共6个,现有样例如下:
arc (145 * SCALE, 100 * SCALE, 94 * SCALE, 70 * SCALE,94.9268 * SCALE,126.774 * SCALE); arc (94 * SCALE, 130 * SCALE, 145 * SCALE, 100 * SCALE,94.9268 * SCALE, 73.2256 * SCALE); arc (61 * SCALE, 130 * SCALE, 61 * SCALE, 70 * SCALE,8.75 * SCALE, 100 * SCALE);
根据文件标注的点位对应关系:
- 第一行arc:从点O(145,100)绘制到点F(94,70)
- 第二行arc:从点L(94,130)绘制到点O(145,100)
- 第三行arc:从点K(62,30)绘制到点E(62,70)
已尝试方案与问题
初期仅使用每行arc的前4个参数(即起点、终点坐标),手动估算圆弧外接矩形和角度参数编写Qt绘制代码:
QPainterPath path; // arc from L ---> F path.moveTo(94,70); QRect bound1 (44,70,102,60); path.arcTo(bound1,90,-180); QPainterPath path1; // arc from K ---> E path1.moveTo(62,70); QRect bound2 (42,70,40,60); path1.arcTo(bound2,90,-180);
渲染结果存在明显偏差:或门输入导线与相邻圆弧无法正确衔接。核心问题是未明确arc最后2个参数的含义,无法生成精确的圆弧路径。
圆弧参数定义与正确绘制方法
参数含义确认
.slib中arc的6个参数按顺序定义为:arc (起点X, 起点Y, 终点X, 终点Y, 圆弧圆心X, 圆弧圆心Y)
可通过距离公式校验:所有样例中,最后两个参数对应的点到起点、终点的距离完全相等,符合圆弧圆心的几何定义。
Qt端绘制步骤
Qt的QPainterPath::arcTo接口需要三个核心参数:圆弧外接矩形、起始角度、扫描角度,所有参数均可通过slib给出的6个值精确计算,无需手动估算:
- 坐标缩放:将读取到的6个原始值统一乘以
SCALE,得到实际绘制坐标:起点(x1,y1)、终点(x2,y2)、圆心(cx,cy) - 半径计算:圆心到起点的直线距离即为圆弧半径
r = sqrt(pow(x1 - cx, 2) + pow(y1 - cy, 2)),可用圆心到终点的距离做校验,二者误差应在浮点精度范围内 - 外接矩形计算:圆弧为外接矩形的内切圆的一部分,矩形左上角坐标为
(cx - r, cy - r),宽、高均为2*r - 角度计算:Qt角度规则为0度指向X轴正方向(3点钟方向),逆时针为角度正方向。起始角度为圆心到起点连线与0度方向的夹角,可通过
qRadiansToDegrees(atan2(y1 - cy, x1 - cx))计算;终点角度为圆心到终点连线的夹角,二者差值即为扫描角度,负值代表顺时针旋转绘制。
通用绘制代码
#include <QPainterPath> #include <QtMath> // 传入slib读取的6个未缩放圆弧参数、全局缩放系数,将圆弧路径追加到指定QPainterPath void addSlibArcToPath(QPainterPath* path, qreal rawX1, qreal rawY1, qreal rawX2, qreal rawY2, qreal rawCx, qreal rawCy, qreal scale) { // 坐标缩放 qreal x1 = rawX1 * scale; qreal y1 = rawY1 * scale; qreal x2 = rawX2 * scale; qreal y2 = rawY2 * scale; qreal cx = rawCx * scale; qreal cy = rawCy * scale; // 计算半径 qreal radius = qSqrt(qPow(x1 - cx, 2) + qPow(y1 - cy, 2)); // 生成外接矩形 QRectF arcBounds(cx - radius, cy - radius, 2 * radius, 2 * radius); // 计算起始、扫描角度 qreal startAngle = qRadiansToDegrees(qAtan2(y1 - cy, x1 - cx)); qreal endAngle = qRadiansToDegrees(qAtan2(y2 - cy, x2 - cx)); qreal spanAngle = endAngle - startAngle; // 绘制圆弧 path->moveTo(x1, y1); path->arcTo(arcBounds, startAngle, spanAngle); }
使用该方法绘制时,圆弧会精确经过给定的起点、终点,弧度完全匹配文件定义,可与相邻直线、圆弧无缝衔接,不会出现导线错位的问题。
内容的提问来源于stack exchange,提问作者tushar
相关产品推荐
相关产品推荐

