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

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

Следующее изображение иллюстрирует то, что я пытаюсь достичь:

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

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

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

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

Итак, мой друг (math Ph.D. inceptor) проанализировал эту проблему и создал параллельную кривую (третий порядок) кривая Безье является очень сложным и вычислительно дорогостоящим. Для каждой точки параллельной кривой компьютер должен был бы вычислить что-то вроде этого:

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

Возможно, есть способ оптимизировать это выражение, но он все равно будет MUCH MORE вычислительно дорогим, чем стандартная кривая Безье (потому что параллельная кривая представляет собой совершенно другую кривую, чем исходная кривая Безье). Я хочу иметь возможность оживить кривую, поэтому это решение, вероятно, будет слишком дорогостоящим CPU. Это оставляет нам несколько вариантов:

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

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

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

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

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

Дополнительная информация:

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

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

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


Попытка # 1

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

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

4b9b3361

Ответ 1

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

enter image description here

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

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

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

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

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

ИЗМЕНИТЬ 2:

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

enter image description here

Ответ 2

Вы сказали, что хотите создать два объекта Path, которые касаются друг друга, но вы не указали, как создаются пути. Мой ответ предполагает, что у вас есть 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>

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

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

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

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

Ответ 6

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

Update

Попробуйте это (это немного перепроизводство, но это может вам помочь)

<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