Tikzcd Hattında Tek Dalga

Jan 10 2021

Tikzcd'deki oklar için etkili bir şekilde uzatılmış tilde olan bir format oluşturmaya çalışıyorum:

Bu cevapta Seçenek 1'i kullanarak bu örneği çizdim , ancak yılan için doğru segment uzunluğunu manuel olarak hesaplamak zorunda kaldım.

Bunu otomatik olarak hesaplamanın bir yolu var mı? Örneğin şunları söyleyin:

arrows={decorate, decoration={snake, segment length=DISTANCE/2, amplitude=0.5mm}}

Değilse, alternatif bir yaklaşım var mı?

Herhangi bir yardım çok takdir edilecektir.

Yanıtlar

2 Dave Jan 11 2021 at 04:03

Bu cevaba dayalı kısmi bir çözümüm var .

Stil tanımlarının ilk yarısının çoğuyla birlikte yardımcı makrosunu bir bütün olarak kopyaladım. Sorumlu olduğum tek kod, "Dalgayı çizin" yorumunun altındaki kod:

\makeatletter

% This helper macro finds the start and endpoints of a line between the source and target nodes and stores them in \sourcecoordinate and \targetcoordinate.
% #1 -- source node
% #2 -- target node
\def\findedgesourcetarget#1#2{
\let\sourcecoordinate\pgfutil@empty
\ifx\tikzcd@startanchor\pgfutil@empty % Check that the source doesn't have a specified anchor
    \def\tempa{\pgfpointanchor{#1}{center}}% if so, start by taking the center of that coordinate
\else
    \edef\tempa{\noexpand\pgfpointanchor{#1}{\expandafter\@gobble\tikzcd@startanchor}} % If it has an anchor, use that
    \let\sourcecoordinate\tempa
\fi
\ifx\tikzcd@endanchor\pgfutil@empty % check that the target doesn't have a specified anchor
    \def\tempb{\pgfpointshapeborder{#2}{\tempa}}% if so, our end point is the point on the boundary of node b that is in the direction of our initial start coordinate
\else
    \edef\tempb{\noexpand\pgfpointanchor{#2}{\expandafter\@gobble\tikzcd@endanchor}}% If it has a specified anchor, use that
\fi
\let\targetcoordinate\tempb
\ifx\sourcecoordinate\pgfutil@empty%
    \def\sourcecoordinate{\pgfpointshapeborder{#1}{\tempb}}%
\fi
}

\tikzset{wave/.style = {
-,
to path={\pgfextra{
        \findedgesourcetarget{\tikzcd@ar@start}{\tikzcd@ar@target} % find endpoints
    % Rotate coordinate system so that line goes in x direction
    \ifx\tikzcd@startanchor\pgfutil@empty
        \def\tikzcd@startanchor{.center}
    \fi
    \ifx\tikzcd@endanchor\pgfutil@empty
        \def\tikzcd@endanchor{.center}
    \fi
    \pgfmathanglebetweenpoints{\pgfpointanchor{\tikzcd@ar@start}{\expandafter\@gobble\tikzcd@startanchor}}{\pgfpointanchor{\tikzcd@ar@target}{\expandafter\@gobble\tikzcd@endanchor}}
    \pgftransformrotate{\pgfmathresult}
    % Draw the wave
    \newdimen\xdiff
    \pgfextractx{\xdiff}{\pgfpointdiff{\sourcecoordinate}{\targetcoordinate}}
    \newdimen\ydiff
    \pgfextracty{\ydiff}{\pgfpointdiff{\sourcecoordinate}{\targetcoordinate}}
    \newdimen\finalDist
    \pgfmathparse{abs(veclen(\xdiff,\ydiff))*0.85}
    \pgfmathsetlength\finalDist{\pgfmathresult pt}

    \pgfmathsetlength\pgfdecorationsegmentlength{\finalDist}

    \pgfmathparse{0.038*\finalDist+0.6}
    \pgfmathsetlength\pgfdecorationsegmentamplitude{\pgfmathresult pt}

    \pgfsetarrows{->}

    \pgfpathmoveto{\sourcecoordinate}
    \pgfpathsnaketo{snake}{\targetcoordinate}

    \pgfusepath{stroke}
}}}}

\makeatother

Yardımcı makroyu kullanarak, birleştirilecek noktaları alıp aralarındaki mesafeyi hesaplıyorum. Sonra bunu yılanın genliğini ve segment uzunluğunu tanımlamak için kullanıyorum.

Bu tanımlarda kullandığım sabitler keyfi görünüyor, onları deneme ve geliştirme yoluyla buldum, ancak daha titiz bir yaklaşım üzerinde çalışacağım.


Sonra

\begin{center}
    Original method:
    \begin{tikzcd}[arrows={decorate, decoration={snake,segment length=7.3mm, amplitude=0.5mm}}]
        A \arrow[r,"",decorate=true] & B
    \end{tikzcd}
\end{center}
\hspace{2cm}
\begin{center}
    Custom style
    \begin{tikzcd}
        A \arrow[r, wave] & B & & \\
        A \arrow[rr, wave] & & B & \\
        A \arrow[rrr, wave] & & & B
    \end{tikzcd}
\end{center}

verir


Şu anda ana sorunum, okların üzerindeki etiketlerin artık çalışmamasıdır. Bunu düzeltmeye çalışacağım ve yapabilirsem bu yanıtı güncelleyeceğim.

Herhangi birinin bu tür sorunları önleyen daha basit bir yaklaşımı varsa, lütfen bana bildirin!