使用Qt

时间:2019-02-20 00:00:53

标签: c++ qt geometry qt5 qpainter

我正在尝试使用QPainter::drawEllipse画圆。我希望能够:

  • 设置圆的笔触宽度(QPen::width
  • 选择位于圆心(1x11x22x12x2)上的像素的形状
  • 可以选择填充圆圈而不是描边
  • 确保圆具有正确的半径(即使笔划宽度大于1时)

这些目标令人惊讶地难以实现。这是我要渲染(手工绘制)的示例:

Example

图片为32x32(放大至512x512)。红色中心点位于(15,15)。中心是1x2,因此中心像素下方有一个额外的红色像素。笔划的宽度为2像素。如果将笔划变宽,则像素将添加到圆的内部。无论笔划宽度如何,圆的边界框都是相同的。半径为8像素。每条蓝线长8像素。 请注意,红色和蓝色像素仅用于描述圆圈。它们不是我想要的输出的一部分。

我的问题的实质归结为渲染一个完全适合矩形的椭圆。我可以使用中心点,半径和中心形状来计算矩形。这部分很容易。仅使用此矩形调用drawEllipse无效。我认为我必须在调用drawEllipse之前以某种方式调整此矩形,但是我不太确定如何调整它。我尝试摆弄它,但发现了一些适用于某些笔宽而不适用于其他笔宽的解决方案。

笔帽重要吗?我一直在使用RoundCap。我应该使用其他上限吗?

我快要考虑自己进行像素处理了。我正在渲染到QImage并使用Source复合操作,因此我的代码可能比drawEllipse快一点。 memsetQImage::fill快10倍,因此编写更快的代码可能不会太难!我宁可不必这样做。

2 个答案:

答案 0 :(得分:0)

我偶然发现了section in the docs,它讨论了QRect的呈现方式。它描述了渲染像素与逻辑矩形之间的关系。渲染的矩形大于逻辑矩形。我要做的就是使逻辑矩形变小以进行补偿。

QRect adjustStrokedRect(const QRect rect, const int thickness) {
  return QRect{
    rect.left() + thickness / 2,
    rect.top() + thickness / 2,
    rect.width() - thickness,
    rect.height() - thickness
  };
}

好,现在我可以将笔触的矩形渲染到正确的位置。椭圆由QRect来描述,那么如果我仅将变换应用于该矩形怎么办?

不。

如果厚度为1, 2, 4, 6而不是3, 5, 7,这是可行的。当厚度为3, 5, 7时,圆圈太小一个像素。因此,我尝试将1添加到矩形大小中,如果thickness % 2 == 1 && thickness != 1,则从正方形渲染不对称圆。对于位置和大小的某些组合,即使大小为正方形,也会呈现出不规则的不对称圆形。

这是您可以轻松复制的怪异图像:

Example

使用以下代码进行生产:

QImage image{32, 32, QImage::Format_ARGB32_Premultiplied};
QPainter painter{&image};
QPen pen{Qt::NoBrush, 3.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin};
pen.setColor(QColor{0, 255, 0, 255});
painter.setPen(pen);
painter.drawEllipse(8, 8, 17, 17);
image.save("weird.png");

我什至不知道怎么可能。在我看来,drawEllipse似乎正在绘制一个大致适合矩形的椭圆。我无法在文档中的任何地方找到矩形和椭圆之间的关系。也许是因为这是一种非常松散的关系。

我可以毫不费力地让QPainter::drawEllipse绘制笔划宽度为1的圆,所以现在我只允许我的应用程序中不使用粗圆。如果无法完美渲染,则完全不会渲染。尽管我仍希望此方法有效,但我并未将此答案标记为可接受。

答案 1 :(得分:0)

我可能为时已晚,但仍供将来参考:

不幸的是,Qt 使用贝塞尔曲线绘制椭圆(截至目前,可能很快就会改变),这是椭圆的一个很好的近似值,但并不完美。绘制像素完美的椭圆需要在像素级别手动实现。