Почему QPainter :: drawPoint рисует горизонтальный отрезок? - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь нарисовать 3-пиксельную большую точку с QPainter. Но следующий код вместо этого рисует горизонтальную линию шириной 3 пикселя.

#include <QPainter>
#include <QImage>

int main()
{
    const int w=1000, h=1000;
    QImage img(w, h, QImage::Format_RGBX8888);
    {
        QPainter p(&img);
        p.fillRect(0,0,w,h,Qt::black);
        p.scale(w,h);
        p.setPen(QPen(Qt::red, 3./w, Qt::SolidLine, Qt::RoundCap));
        p.drawPoint(QPointF(0.1,0.1));
    }
    img.save("test.png");
}

Вот верхний левый угол получившегося изображения:

line instead of a point

Я ожидаю получить точку, которая является красным кругом или хотя бы квадратом - но вместо этого я получаю этот отрезок. Если я закомментирую p.scale(w,h) и нарисую точку с шириной 3 (вместо 3./w) в позиции (100,100), то получу небольшой в основном симметричный 3-пиксельный по высоте и ширине пункт.

Что происходит? Почему я получаю отрезок, а не точку, как ожидалось? И как это исправить, не прибегая к рисованию эллипса или избегая QPainter::scale?

Я использую Qt 5.10.0 на Linux x86 с g ++ 5.5.0. То же самое происходит в Qt 5.5.1.

Ответы [ 2 ]

0 голосов
/ 06 сентября 2018

Похоже, что QPaintEngineEx::drawPoints отображает точки в виде отрезков длиной 1/63.. Смотрите следующий код из qtbase / src / gui / painting / qpaintengineex.cpp в источниках Qt:

void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount)
{
    QPen pen = state()->pen;
    if (pen.capStyle() == Qt::FlatCap)
        pen.setCapStyle(Qt::SquareCap);

    if (pen.brush().isOpaque()) {
        while (pointCount > 0) {
            int count = qMin(pointCount, 16);
            qreal pts[64];
            int oset = -1;
            for (int i=0; i<count; ++i) {
                pts[++oset] = points[i].x();
                pts[++oset] = points[i].y();
                pts[++oset] = points[i].x() + 1/63.;
                pts[++oset] = points[i].y();
            }
            QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::LinesHint);
            stroke(path, pen);
            pointCount -= 16;
            points += 16;
        }
    } else {
        for (int i=0; i<pointCount; ++i) {
            qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + qreal(1/63.), points[i].y() };
            QVectorPath path(pts, 2, 0);
            stroke(path, pen);
        }
    }
}

Обратите внимание на линию pts[++oset] = points[i].x() + 1/63.; в непрозрачной ветви кисти. Это вторая вершина пути - смещенная относительно нужного положения точки.

Это объясняет, почему линия проходит справа от запрошенной позиции и почему она зависит от масштаба. Таким образом, кажется, что код в OP не является неправильным для идеальной реализации QPainter, а только что столкнулся с ошибкой Qt (будь то в реализации метода или в его документации).

Итак, вывод: у одного есть , чтобы обойти эту проблему, используя другой масштаб, или рисуя эллипсы, или рисуя отрезки линий гораздо меньшей длины, чем то, что делает QPainter::drawPoints.

Я сообщил об этом как QTBUG-70409 .

0 голосов
/ 06 сентября 2018

Хотя мне не удалось точно определить, почему именно возникает проблема, я достаточно близко подошел к решению. Проблема заключается в масштабировании. Я сделал много проб и ошибок с разным масштабированием и шириной точки с помощью приведенного ниже кода.

const int w=500, h=500;
const int scale = 100;
float xPos = 250;
float yPos = 250;
float widthF = 5;
QImage img(w, h, QImage::Format_RGBX8888);
{
    QPainter p(&img);
    p.setRenderHints(QPainter::Antialiasing);
    p.fillRect(0,0,w,h,Qt::black);
    p.scale(scale, scale);
    p.setPen(QPen(Qt::red, widthF/(scale), Qt::SolidLine, Qt::RoundCap));
    p.drawPoint(QPointF(xPos/scale, yPos/scale));
}
img.save("test.png");

Приведенный выше код создает изображение
enter image description here

Мои наблюдения
1) Из-за высокого масштабирования точка (ширина которой составляет всего 3 пикселя) не может пропорционально масштабироваться при более низкой ширине (ширине точки), если вы установите ширину, равную примерно 30, круглая форма видна.
2) Если вы хотите, чтобы ширина точки была низкой, то вам нужно уменьшить масштаб.
К сожалению, я не могу объяснить, почему при высоком масштабировании оно не расширяется пропорционально.

...