Проверка попадания точки в GraphicsPath

117
16 июня 2019, 11:30

Был создан полигон, состоящий из трёх точек и одна независимая точка:

GraphicsPath gps = new GraphicsPath(); gps.AddPolygon(new PointF[] {new PointF(0, 6), new PointF(0, 13), new PointF(1.66667, 13)});
PointF p0 = new PointF(0, 3);

Требуется проверить, есть ли точка в данном пути. Как делаю:

if (gps.IsOutlineVisible(p0, new Pen(new SolidBrush(Color.Black), 1)) || gps.IsVisible(p0))
{
    // etc
}

Однако, проверка выполняется! Почему это происходит, ведь 0;3 явно вне полигона. Спасибо.

Answer 1

Такое возможно, если используется MiterLimit по умолчанию 10 (судя по созданию пера по месту использования- это так), что приводит к длинному хвосту (Cap) на месте сочленения двух сторон под очень острым углом.

Однако, если перо центрировано на линии, то до точки 3 хвост не достанет (точка D у меня чуть ближе, чем нужно, чтобы обеспечить расстояние 0.5 между параллельными прямыми), только до 4, а вот если оно снаружи, то и до 2 дотянется (прямая через точку E). Я не исключаю, что перо с шириной 1 рисуется снаружи базовой линии, хотя в описании Alignment этого явно не сказано, но вот в простом GDI есть тонкости с положением перьев c чётной, нечётной и единичной шириной. Вполне вероятно также, что "под капотом" выполняется Widen полигона с шириной пера.

Собственно говоря, надо посмотреть, как оно рисуется. На таком мелком ничего не увидишь, а вот всё в 10 раз больше и сдвинуто на 100 вправо:

  GraphicsPath gps = new GraphicsPath();
 gps.AddPolygon(new PointF[] { new PointF(100, 60), 
                               new PointF(100, 130), 
                               new PointF(116.6667f, 130) });
    Pen pe = new Pen(new SolidBrush(Color.Black), 10);
    e.Graphics.DrawPath(pe, gps);
    Pen blackPen = new Pen(Color.Black, 1);
    e.Graphics.DrawLine(blackPen, 0, 30, 200, 30);
    e.Graphics.DrawLine(blackPen, 100, 0, 100, 300);

Как видим, треугольник пересекает линию y=30, но точку (100, 30) не задевает (и IsOutlineVisible не срабатывает) - но как оно будет для единичной ширины - MS его знает. Видимо, даже единичный пиксел перекрывает ту точку.

Что делать в данном случае? Использовать point in polygon алгоритм

READ ALSO
Почему иногда не удается найти html-узел (HTMLAgilityPack)?

Почему иногда не удается найти html-узел (HTMLAgilityPack)?

Этот код выполняется в нескольких потоках и обычно все нормальноНо иногда SelectSingleNode возвращает null

135
Как заблокировать только горизонтальную автопрокрутку?

Как заблокировать только горизонтальную автопрокрутку?

Как заблокировать только горизонтальную автопрокрутку и оставить автопрокрутку вертикальную?

126
LINQ to SQL использование списка как фильтр

LINQ to SQL использование списка как фильтр

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

115
Ошибка при проверке файла Hunspell

Ошибка при проверке файла Hunspell

Как можно поднять на ubuntu 1604 сервере hunspell php После дебага ругается на отсутствия файлов

148