Подтвердить что ты не робот

Как визуализировать толстые 2D-линии как полигоны?

У меня есть путь, составленный из списка двумерных точек. Я хочу превратить их в полосу треугольников, чтобы сделать текстурированную линию с определенной толщиной (и другими такими вещами). Таким образом, по существу, список 2D-точек должен стать списком вершин, определяющих контур многоугольника, который, если рендеринг будет отображать линию. Проблема заключается в обработке угловых соединений, миттеров, колпачков и т.д. Полученный многоугольник должен быть "идеальным" в смысле отсутствия переутомления, чистых соединений и т.д., Чтобы его можно было экструдировать или иным образом использовать.

Существуют ли какие-либо простые ресурсы, которые могут обеспечить проницательность, код или любую дополнительную информацию об этом эффективно?

Я абсолютно НЕ хочу полноценную библиотеку 2D-векторов (cairo, antigrain, OpenVG и т.д.) с кривыми, дугами, тире и всеми колокольчиками. Я копал в нескольких источниках деревьев для реализации OpenVG и других вещей, чтобы найти некоторое представление, но все это ужасно запутано.

Я определенно готов сам его закодировать, но есть много дегенеративных случаев (небольшие сегменты + толстые ширины + острые углы), которые создают всевозможные проблемы с объединением. Даже небольшая помощь спасет меня от попыток разобраться с ними.

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

http://www.freeimagehosting.net/uploads/52dc639727.png

4b9b3361

Ответ 1

Хорошо, я сам пытался решить эту проблему. Я потратил два месяца на решение, которое попыталось решить проблему с избыточным избытком. Как вы уже выяснили, вы не можете справиться со всеми вырожденными случаями и одновременно иметь нулевое овердрауз.

Однако вы можете использовать гибридный подход:

Напишите себе процедуру, которая проверяет, могут ли объединения быть построены из простой геометрии без проблем. Для этого вам необходимо проверить угол соединения, ширину линии и длину соединенных сегментов линии (сегменты линии, которые короче их ширины, являются PITA). С некоторыми эвристиками вы сможете разобраться во всех тривиальных случаях.

Я не знаю, как выглядят ваши средние данные линии, но в моем случае более 90% широких линий не имели вырожденных случаев.

Для всех остальных строк:

Вы, скорее всего, уже выяснили, что если вы переносите overdraw, генерировать геометрию намного проще. Сделайте так, и пусть алгоритм CSG многоугольника и алгоритм тесселяции выполняют тяжелую работу.

Я оценил большинство доступных пакетов тесселяции, и я закончил с тестером GLU. Он был быстрым, надежным, никогда не разбивался (в отличие от большинства других алгоритмов). Это было бесплатно, и лицензия позволила мне включить его в коммерческую программу. Качество и скорость тесселяции в порядке. Вы не получите качество триангуляции delaunay, но поскольку вам просто нужны треугольники для рендеринга, это не проблема.

Так как я не любил API-интерфейс tesselator, я снял код тесселяции из бесплатной ссылочной реализации SGI OpenGL, переписал весь внешний интерфейс и добавил пулы памяти, чтобы уменьшить количество распределений. Это заняло два дня, но это стоило того (как улучшение производительности пятого уровня). Решение оказалось в коммерческой реализации OpenVG: -)

Если вы выполняете рендеринг с OpenGL на ПК, вам может потребоваться переместить tesselation/CSG-задание из CPU на графический процессор и использовать трюки шаблона-буфера или z-буфера для удаления переустановки. Это намного проще и может быть даже быстрее, чем тесселяция процессора.

Ответ 2

Простейший метод с головы.

Разделите угол каждой вершины 2d, это создаст хорошую линию митра. Затем двигайтесь вдоль этой линии, как внутри, так и снаружи, количество вашей "толщины" (или толщина делится на два?), Теперь у вас есть свои внутренние и внешние точки полигона. Перейдите к следующей точке, повторите тот же процесс, создав новые точки полигона по пути. Затем примените треугольник, чтобы получить свои готовые вершины.

Ответ 3

Я только что нашел эту удивительную работу:

http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation

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

Ответ 4

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

Для меня проблема заключалась в том, что мне нужны жирные строки в OpenGL, у которых не было таких артефактов, которые я видел с OpenGL на iPhone. Рассмотрев различные решения; кривые безье и т.п. - я решил, что было бы проще всего просто сделать свой собственный. Существует несколько различных подходов.

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

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

Я работал над проблемой острого угла с двумя подходами. Алгоритм пересечения линии Поля Бурка (который я использовал неоптимизированным образом) предложил определить, было ли пересечение внутри сегментов. Поскольку оба сегмента идентичны, мне нужно было только проверить один из сегментов для пересечения. Тогда я мог бы решить, как это решить; либо путем сгибания наилучшей точки между двумя концами, либо путем установки торцевой крышки - оба подхода выглядят хорошо - подход с концевой крышкой может отбросить ортогональный фронт/обратную сторону для opengl.

См. http://paulbourke.net/geometry/lineline2d/

Смотрите мой исходный код здесь: https://gist.github.com/1474156

Ответ 5

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

В Интернете есть множество алгоритмов тесселяции и кода - я несколько раз закрыл C-образную библиотеку в DLL для использования с ландшафтным рендером Delphi, и они не являются необычным предметом для передовых графических руководств по кодированию и.

Ответ 6

Мне это тоже интересно, так как я хочу совершенствовать приложение для сопоставления (Kosmos) рисование дорог. Один из способов, который я использовал, состоит в том, чтобы нарисовать полилинию дважды, один раз с более толстой линией и один раз с тоньше, с другим цветом. Но это не очень многоугольник, это просто быстрый способ имитации. Смотрите здесь несколько примеров: http://wiki.openstreetmap.org/wiki/Kosmos_Rendering_Help#Rendering_Options

Я не уверен, что это то, что вам нужно.

Ответ 8

В моем случае я мог позволить себе перехитрить. Я просто дроу кругов с радиусом = ширина /2 с центром по каждой из вершин полилинии.

Артефакты маскируются таким образом, и их очень легко реализовать, если вы можете жить с "закругленными" углами и некоторым перерасходом.

Ответ 9

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

Почему вы не можете использовать примитив GL_LINES для выполнения своих действий? Вы можете указать ширину, фильтрацию, гладкость, текстуру. Вы можете отображать все вершины с помощью glDrawArrays(). Я знаю, что это не то, что вы имеете в виду, но поскольку вы фокусируетесь на 2D-чертеже, это может быть проще. (поиск текстурных линий и т.д.)