Как избежать ломаных пунктирных линий в GDI+?

На этих снимках экрана, взятых из моего приложения MFC, показаны строки 2, которые должны быть параллельны. 2 пунктирные параллельные линии2 параллельные линии, одна сплошная, другая пунктирная

Линии рисуются с использованием Gdiplus::Graphics::Drawline().

Незначительная проблема заключается в том, что пунктирные линии не прямые, а ломаные. Вы замечаете это, но это не имеет большого значения...

Настоящая проблема в том, что это непоследовательно, и линии, нарисованные с помощью Gdiplus::DashStyleSolid, действительно прямые.

Это ошибка в GDI+? Есть ли обходной путь?

Обновление 1

Я попытался сделать минимальный пример, но я изо всех сил пытаюсь его воспроизвести... Это может иметь какое-то отношение к очень большим значениям координат и небольшой разнице между их координатами. Вот некоторые примерные координаты линии:

Line 1: PointF(2.21866e+006, 1.40198e+006), PointF(2.21732e+006, 1.40111e+006)
Line 2: PointF(2.21866e+006, 1.40198e+006), PointF(2.21732e+006, 1.40112e+006)

Я заметил, что начальные точки идентичны, но это может быть вызвано округлением в выводе отладки...

Обновление 2

Я мог воспроизвести это сейчас: пример приложения был сгенерирован как проект SDI, а класс представления наследует CScrollView (код и снимок экрана ниже). Эффект ломаной линии также связан с толщиной пера. Линия проходит немного по-разному с разной толщиной, но я не нашел значения, которое все время приводит к параллельным линиям.

Винсент Порвик предполагает в комментарии, что это может быть результатом ошибок округления, поскольку Gdiplus::REAL определяется как float. Я тоже считаю, что это так...

Есть ли у меня какие-либо другие варианты, кроме как использовать здесь меньшие значения координат?

Код и скриншот

Эти функции были добавлены/изменены (в дополнение к коду инициализации GDI+):

void CgdiplusLinesView::OnDraw(CDC* pDC)
{
    CgdiplusLinesDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    pDC->SetBkMode(TRANSPARENT);

    using namespace Gdiplus;
    Graphics g(pDC->m_hDC);
    g.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);

    Pen solidPen(Color(0,0,0), 2.f);
    Pen dashedPen(Color(0,0,0), 2.f);
    dashedPen.SetDashStyle(DashStyleDash);

    g.DrawLine(&dashedPen, PointF(4438749.500000, 2805806.500000), PointF(4434280.500000, 2802106.500000));
    g.DrawLine(&solidPen,  PointF(4438746.500000, 2805809.500000), PointF(4434277.500000, 2802109.500000));
}

void CgdiplusLinesView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
    pDC->SetMapMode(MM_ISOTROPIC);

    const int mapSizePixels = 8388608;
    pDC->SetWindowExt(mapSizePixels, mapSizePixels);
    pDC->SetViewportExt(mapSizePixels, mapSizePixels);
    pDC->SetWindowOrg(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));

    //__super::OnPrepareDC(pDC, pInfo);
}

void CgdiplusLinesView::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();

    SetScrollSizes(MM_TEXT, CSize(8388608, 8388608), CSize(1361, 1054));
    SetScrollPos(SB_HORZ, 4434897.5);
    SetScrollPos(SB_VERT, 2802645.);
}

пересечение линий


person foraidt    schedule 26.10.2012    source источник
comment
GDI+ работает с 32-битными числами с плавающей запятой, а точность 32-битного числа с плавающей запятой при такой величине составляет около 0,05. Вы можете увидеть результат ошибок округления, которые не будут проблемой при меньших значениях.   -  person Esme Povirk    schedule 27.10.2012
comment
То же самое происходит, когда вы отключаете сглаживание? Я уверен, что виновата величина значений с плавающей запятой; к сожалению, я сомневаюсь, что есть простой выход, кроме как самостоятельно обрабатывать отображение координат области просмотра.   -  person adzm    schedule 17.11.2012
comment
@adzm Да, он тоже ломается без сглаживания.   -  person foraidt    schedule 19.11.2012


Ответы (1)


Я не думаю, что это связано с пунктиром и сплошным шрифтом, но с точностью с плавающей запятой. Ваши координаты кажутся географическими координатами. Обычная хорошая практика заключалась в том, чтобы хранить все координаты как двойники, а когда вам нужно работать с библиотекой с более низкой точностью, смещайте все координаты самостоятельно, прежде чем передавать их графическим функциям.

Правильный способ сделать это — выбрать опорную точку, которая близка к точкам в вашем наборе данных (первая найденная вами координата в порядке), а затем вычесть ее координаты из всех других точек. Это удерживает числовые значения около 0,0, где поплавки имеют более высокую плотность разрешения.

person tato    schedule 25.01.2013