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


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


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

c++ - 使用Qt绘制像素完美的圆-LMLPHP

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

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

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

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

最佳答案

我偶然发现了一个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,但是从正方形渲染了一个不对称的圆。对于位置和大小的某些组合,即使大小为正方形,也会呈现不规则的不对称圆形。

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

c++ - 使用Qt绘制像素完美的圆-LMLPHP

使用以下代码生成它:

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的圆,所以现在我只允许我的应用程序中不使用粗圆。如果无法完美渲染,则完全不会渲染。我并未将此答案标记为已接受,尽管我仍希望此方法有效。

关于c++ - 使用Qt绘制像素完美的圆,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54776781/

10-11 22:28
查看更多