Следното изображение илюстрира какво се опитвам да постигна:
По принцип искам да създам два 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
И така, един мой приятел (доктор по математика inceptor) анализира този проблем и създаде успоредна крива на (трети ред) Кривата на Безие е много сложна и изчислително скъпа. За всяка точка от паралелната крива компютърът трябва да изчисли нещо подобно:
(degree 3 polynomial) + (degree 2 polynomial) / sqrt(degree 4 polynomial)
Може би има начин да се оптимизира този израз, но все пак би било МНОГО ПО-скъпо от стандартна крива на Безие (защото паралелната крива е напълно различна крива от оригиналната крива на Безие). Искам да мога да анимирам кривата, така че това решение вероятно би било твърде скъпо за процесора. Това ни оставя няколко опции:
Използвайте приближението на полилинията на Charles Petzold, което върши чудеса, но има визуални проблеми при дълбоко увеличение.
Изведете нашето собствено приближение въз основа на това на Charles Petzond. Използвайте криви на Безие вместо линии (може би дъгите биха били достатъчни). Това би решило проблема с дълбокото увеличение, но вероятно е доста трудно да се кодира (нямам представа как да направя това).
Може би е възможно да се създаде нещо като двуцветна четка. По този начин можем да използваме само едно
Path
, за да постигнем желания резултат (както е показано на първото изображение). Не съм го виждал никъде обаче, така че това вероятно не е опция.
Актуализация #3
Намерих някои доста интересни връзки:
- Как да компенсирам кубична крива на Безие? (Евристичен алгоритъм)
- Очертание на щрих на кубична крива на Безие
- разширяване на пътя на Безие (алгоритъм на Python)
- Офсетни криви на Безие (Имплементация в Java на персонализирани апроксимацията на полилинията на кривата на Безие се различава от тази на Charles Petzold)
- Паралелни криви на Безие (Защо паралелни криви на Безие не са възможни от математиката гледна точка)
- Бързо, прецизно изравняване на кубичен път на Безие и хартия за офсетни криви (Изтегляне на връзка 1, Изтегляне на връзка 2)
Повече информация:
- Предполага се, че QPainterPathStroker от Qt framework използва алгоритъма на Thomas F. Hain за паралелни криви
- Това Java Stroker също се предполага, че може да рисува успоредни криви
Може би окончателното решение? (източник тук)
... Разработих всичко, което знаех за теорията на кривата на Безие, и развих несплесканото компенсиране до нещо, което е правилно, и (чудовище) документирах това на Практика за кривите на Безие
Опит №1
Направете втория път малко по-широк и го плъзнете под първия път, докато използвате Z -Индекс. http://i51.tinypic.com/2r5vwjk.png
Това няма да работи, Geometry
трябва да се трансформира съответно.