Полное заполнение пользовательских геометрий - PullRequest
9 голосов
/ 14 декабря 2011

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

У меня есть следующий пример геометрии:

    <Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <PathGeometry
                Figures="M112,296C112,296 136,296 136,320 M112,344C112,344 136,344 136,320 M112,296L112,296 96,296 96,344 112,344"/>
        </Path.Data>
    </Path>

Который дает следующий результат:

Undesired Fill Result

Вот результат, который я хотел бы увидеть:

Desired Fill Result

Есть идеи? Я знаю, что мог бы создать одну дугу, и это разрешило бы этот конкретный случай, но в моем приложении пользователь может нарисовать любой тип геометрии, чтобы результат мог состоять из любого числа «примитивов» (PolyLineSegments, EllipseGeometries, ArcSegments и т. Д.) и в случае, если результирующая геометрия содержит некоторый тип замкнутой области, я бы хотел точно заполнить эту область.

EDIT:

Вот пример того, как выглядит CombinedGeometry, если я обеспечу перекрытие всех трех смежных геометрий и создаю объединенную CombinedGeometry со следующим кодом:

        <Path Grid.Row="2" Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <CombinedGeometry GeometryCombineMode="Union">
                <CombinedGeometry.Geometry1>
                    <CombinedGeometry GeometryCombineMode="Union">
                        <CombinedGeometry.Geometry1>
                            <PathGeometry
                                Figures="M111,293C111,296 136,293 136,325"/>
                        </CombinedGeometry.Geometry1>
                        <CombinedGeometry.Geometry2>
                            <PathGeometry
                                Figures="M111,346C111,344 136,344 136,320"/>
                        </CombinedGeometry.Geometry2>
                    </CombinedGeometry>
                </CombinedGeometry.Geometry1>
                <CombinedGeometry.Geometry2>
                    <PathGeometry
                        Figures="M125,296L115,296 96,296 96,344 120,344"/>
                </CombinedGeometry.Geometry2>
            </CombinedGeometry>
        </Path.Data>
    </Path>

А вот и результат:

Combined Geometry

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

РЕДАКТИРОВАТЬ 2:

Хм, так что я думаю, что я нашел пару возможных решений, ни одно из которых не так просто, как я надеялся. Первым вариантом было бы объединить все геометрии, как описано выше, используя структуру CombineGeometry, затем я вызвал «GetFlattenPathGeometry» для результирующего «CombineGeometry», чтобы получить PathGeometry. Затем я перебираю каждую фигуру в PathGeometry и просто удаляю те, которые являются отверстиями (что, я думаю, вы должны сделать, избавившись от всех фигур, которые полностью содержатся в другой, иначе дыры могут следовать соглашению, что либо по часовой стрелке или против часовой стрелки, не уверен ..), если все пойдет хорошо, вам останется одна полностью заполненная геометрия.

Второй вариант заключается в том, чтобы снова вызвать «GetFlattenPathGeometry» для любого результирующего пути, чтобы получить полигональную аппроксимацию пути на основе вершин (без всех обозначений кривой, дуги, эллипса и т. Д. Нам нужен путь содержит только точки и линии). После этого вы просто объедините все полученные фигуры / сегменты в одну фигуру, чьи сегменты упорядочены по часовой стрелке или против часовой стрелки.

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

РЕДАКТИРОВАТЬ 3:

Вот более сложная геометрия, в которой упорядочение / объединение становится более сложным:

        <Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
        <Path.Data>
            <PathGeometry
            Figures="M104,160C104,160 72,160 72,136
                M104,128C104,128 72,128 72,152
                M152,232L152,232 152,216 120,216 120,160 128,160
                M152,232L152,232 72,232 104,216 104,160 96,160
                M104,128L104,128 168,128
                M128,160L128,160 168,160
                M165,160L168,160 200,128
                M200,160L200,160 200,128
                M200,160L200,160 168,128 152,128"/>
        </Path.Data>
    </Path>

Который производит:

enter image description here

Ответы [ 3 ]

5 голосов
/ 14 декабря 2011

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

Закрытие отверстия становится более сложной проблемой программного обнаружения отверстия и закрытия его соответствующей формы или создания новой комбинированной формы, в которой нет отверстия (возможно, путем обнаружения и отслеживания внешних точек). Мне не известны какие-либо функции в WPF, которые могут помочь вам с этой задачей. Существует класс CombinedGeometry, который может создавать объединение двух перекрывающихся фигур. Фигуры в этом примере не перекрываются.

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

2 голосов
/ 17 декабря 2011

Рассматривайте это как проблему «соединить точки»:)

У вас есть 5 баллов:

  • 96,296 - верхняя левая точка (угол)
  • 112,296- верх - начало кривой Безье
  • 136,320 - крайний правый конец первой кривой Безье, начало второй
  • 112,344 - нижний - конец второй кривой Безье
  • 96,344 -нижняя левая точка (угол)

А теперь мы их соединим.

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
    <Path.Data>
        <PathGeometry Figures="M112,296 C112,296 136,296 136,320 C136,320 136,344 112,344 M112,344 96,344 96,296 112,296"/>
    </Path.Data>
</Path>

Вы также можете использоватьзаполнить свой собственный путь из 1-го поста.По умолчанию FillRule = "EvenOdd", который производит заполнение, как у вас. *

См. Синтаксис разметки пути (http://msdn.microsoft.com/en-us/library/ms752293.aspx) для получения дополнительной информации о мини-языке пути.

  • Изменено на

РЕДАКТИРОВАТЬ 1:

Я немного изменил ваш путь:

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2">
    <Path.Data>
        <PathGeometry Figures="M72,152 C72,152 72,128 104,128 L168,128 200,160 200,128 168,160 120,160 120,216 152,216 152,232 72,232 104,216 104,160 C104,160 72,160 72,136"/>
    </Path.Data>
</Path>

Что даетнас:

Новая фигура

Путь рисования подобен использованию какого-либо инструмента «рисовать фигуру» в программном обеспечении для редактирования векторов, где вам нужно выбрать следующие точки, и когдау вас нет следующего - фигура автоматически закрывается (последняя точка связана с первой, но только с целью заполнения фигуры - мы можем видеть, как это делается, когда мы смотрим на «нос» новой фигуры).В вашем примере у вас есть 9 отдельных фигур (каждая в отдельной строке, где M указывает начало новой фигуры), и все они заполнены указанным выше способом.

Конечно, вы можете использовать GeometryGroup (с FillRule) или CombinedGeometry (с CombinedGeometryMode) для соединения фигур.

1 голос
/ 22 декабря 2011

Я нашел интересную статью о создании фигур с помощью wpf с использованием svg-файла, созданного с помощью графического инструмента, такого как inkscape. Это может дать вам некоторое представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...