Двухцветный объект Path - PullRequest
       34

Двухцветный объект Path

12 голосов
/ 08 апреля 2011

На следующем рисунке показано, чего я пытаюсь достичь:

http://i53.tinypic.com/14ugfpd.png

По сути, я хочу создать два Path объекта, которые "касаются" друг друга (параллельные пути). Это XAML используется для создания этого изображения:

<StackPanel Orientation="Horizontal">
    <StackPanel.LayoutTransform>
        <ScaleTransform CenterX="0" CenterY="0" ScaleX="15" ScaleY="15" />
    </StackPanel.LayoutTransform>

    <Grid Margin="-5,0,0,0">
        <Path Stroke="Blue">
            <Path.Data>
                <PathGeometry>M10,10 C20,10 10,20 20,20</PathGeometry>
            </Path.Data>
        </Path>
        <Path Stroke="Red">
            <Path.Data>
                <PathGeometry>M10,11 C19,10.85 9,20.80 20,21</PathGeometry>
            </Path.Data>
        </Path>
    </Grid>

    <Grid Margin="-5,0,0,0">
        <Path Stroke="Blue">
            <Path.Data>
                <PathGeometry>M10,10 C20,10 10,20 20,20</PathGeometry>
            </Path.Data>
        </Path>
        <Path Stroke="Red">
            <Path.Data>
                <PathGeometry>M10,11 C19,11 9,21 20,21</PathGeometry>
            </Path.Data>
        </Path>
    </Grid>
</StackPanel>

Первая кривая имеет оптимизированные вручную позиции точек, вторая имеет точечные позиции, легко рассчитываемые с учетом толщины хода. Вы можете видеть, что вторая кривая не идеальна, потому что между ними есть пространство. Как я могу создать две идеально «соприкасающиеся» кривые программно, не оптимизируя каждую кривую вручную (что на самом деле невозможно, поскольку кривые генерируются в коде)?

Проще говоря, я генерирую одну кривую (соответственно Path) в коде, и мне нужно, чтобы она имела два цвета. Поэтому я подумал, что создание второй параллели Path поможет, но настройка Geometry второй Path (чтобы сделать ее параллельной) оказалась проблематичной.

Обновление # 1

Параллельные линии и кривые by Charles Petzold может быть одним из способов решения этой проблемы. На самом деле он работает довольно хорошо, но он сглаживает кривых, что создает визуальные артефакты при глубоком увеличении, и, конечно, есть недостаток производительности.

Однако алгоритм не пытается найти кривую Безье, параллельную другой кривой Безье. Вместо этого алгоритм полностью основан на полилиниях: входные данные представляют собой одну или несколько полилиний, а выходные данные состоят из нескольких полилиний для каждой входной полилинии. По этой причине ParallelPath необходимо «сгладить» входную геометрию, что означает преобразование всей геометрии (включая дуги и кривые Безье) в аппроксимацию полилинии.

Обновление № 2

Таким образом, мой друг (математик, доктор философских наук) проанализировал эту проблему, и создание параллельной кривой для (третьего порядка) Кривая Безье очень сложно и вычислительно дорого. Для каждой точки параллельной кривой компьютер должен будет вычислить что-то вроде этого:

(degree 3 polynomial) + (degree 2 polynomial) / sqrt(degree 4 polynomial)

Возможно, есть способ оптимизировать это выражение, но оно все равно будет НАМНОГО БОЛЬШЕ вычислительно дороже, чем стандартная кривая Безье (поскольку параллельная кривая - это совершенно другая кривая, чем исходная кривая Безье). Я хочу иметь возможность анимировать кривую, поэтому это решение, вероятно, будет слишком дорогим для процессора. Это оставляет нам пару вариантов:

  1. Используйте Чарльз Петцольд аппроксимация ломаной линии, которая творит чудеса, но при глубоком увеличении есть визуальные сбои.

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

  3. Может быть, возможно создать что-то вроде двухцветной кисти. Таким образом, мы могли бы использовать только один Path для достижения желаемого результата (как показано на первом изображении). Хотя я нигде не видел, так что это, вероятно, не вариант.

Обновление № 3

Я нашел несколько довольно интересных ссылок:

Подробнее:

  • QPainterПредполагается, что PathStroker из среды Qt использует алгоритм Томаса Ф. Хейна для параллельных кривых
  • Этот Java Stroker также должен быть способен рисовать параллельные кривые

Может быть, окончательное решение? (источник здесь )

... Я разработал все, что я знал о теории кривых Безье, и разработал несмещенное смещение к чему-то правильному, и (монстр) задокументировал это на Учебник для начинающих на кривых Безье


Попытка # 1

Сделайте второй путь немного шире и сдвиньте его под первым путем, используя Z-Index. http://i51.tinypic.com/2r5vwjk.png

Это не сработает, Geometry необходимо соответствующим образом преобразовать.

Ответы [ 6 ]

5 голосов
/ 12 апреля 2011

Вместо того, чтобы использовать одну кривую Безье четвертой степени, почему бы вам просто не использовать сложение двух квадратичных? Вы знакомы с кривой математики Безье? Они предпочитаются в графике , потому что они довольно дешевы в вычислительном отношении. Недавно я создал программу, в которой я анимировал движение клеток (просто для удовольствия):

enter image description here

Программа может легко работать в полноэкранном режиме на HD-мониторе с 100 анимированными и перемещающимися шариками. И все это было GDI +.

Что касается параллельных кривых Безье, то, согласно Википедии, это не может быть сделано: http://en.wikipedia.org/wiki/B%C3%A9zier_curve

Так что вы, вероятно, должны быть довольны эвристическим подходом.

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

Чтобы ваши кривые не были абсолютно случайными, почему бы не создать контур каждой кривой и не заполнить путь? «Нижняя» кривая одного пути будет «верхней» кривой другого.

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

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

enter image description here

3 голосов
/ 10 апреля 2011

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

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

Результат, полученный мной для вашего примера, выглядит следующим образом:

Image showing the joined paths

<StackPanel Orientation="Horizontal">
    <StackPanel.LayoutTransform>
        <ScaleTransform CenterX="0" CenterY="0" ScaleX="15" ScaleY="15" />
    </StackPanel.LayoutTransform>

    <Grid Margin="-5,0,0,0">
        <Path Fill="Blue" Stroke="Transparent">
            <Path.Data>
                <PathGeometry>M10,10 C20,10 10,20 20,20 L20,19 C11,19 21,9 10,9</PathGeometry>
                <!--          |←    original path    →| |←  generated part   →| -->
            </Path.Data>
        </Path>
        <Path Fill="Red" Stroke="Transparent">
            <Path.Data>
                <PathGeometry>M10,10 C20,10 10,20 20,20 L20,21 C9,21 19,11 10,11</PathGeometry>
                <!--          |←    original path    →| |←   generated part   →| -->
            </Path.Data>
        </Path>
    </Grid>
</StackPanel>
1 голос
/ 12 апреля 2011

Рассмотрим немного другой подход к проблеме ...

Предполагая «большое» количество точек на геометрии. Может оказаться целесообразным использовать один из методов интерполяции более высокого качества путем выборки геометрических точек при более низких уровнях масштабирования. При увеличении масштаба вы можете увеличить частоту дискретизации и вместо этого визуализировать только часть кривой; Таким образом, объем вычислений должен оставаться относительно постоянным на всех уровнях масштабирования. Главное, чтобы на экране было постоянное количество пикселей , и вы можете начать выборку, как только точность превысит определенный порог.

0 голосов
/ 13 апреля 2011

Читать это ... Silverlight - Epic Graphical Fail (прямоугольник с двумя треугольниками): (

Обновление

Попробуйте это (это немного излишне, но может помочьВы)

<Grid Margin="-5,0,0,0">
    <Path Stroke="Blue" Data="M10,10 C20,10 10,20 20,20 M20,21 C9,21 19,11 10,11"
            Fill="Blue" Clip="M10,10 C20,10 10,20 20,20 L20,21 C9,21 19,11 10,11"/>
    <Path Stroke="Blue" Data="M10,10 C20,10 10,20 20,20"/>
    <Path Stroke="Red" Data="M10,11 C19,11 9,21 20,21"/>
</Grid>

enter image description here

0 голосов
/ 13 апреля 2011

Допустим, вам нужны две линии шириной 5:

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

Вы бы разбили линию пополам и покрасили половину, проблема в том, что для разделения пополам требуется один пиксель: (*

Но что произойдет, если вы выберете равную ширину, например, 10? Где будет средний пиксель? Может быть, вы сможете что-то использовать ...

0 голосов
/ 08 апреля 2011

Можно ли сделать второй путь (сгенерированный) немного шире и переместить его под (позади) первого пути, используя z-индекс? Таким образом, вы получите беспрепятственное соединение.

...