tikz-花括号实现

tikz-花括号实现

我想了解有关 tikz 花括号实现的详细信息,然后希望获得 d3.js 的 svg 等效版本。

例如

\documentclass{article}
\usepackage{tikz, pgfplots}
\begin{document}
\begin{tikzpicture}[
>=stealth,]
\draw [decorate,decoration={brace,amplitude=4pt,aspect=0.67}]
(0,2)--(0,0) node[pos=0.67, right, font=\footnotesize, xshift=2pt] {Compromise loss};
\end{tikzpicture}
\end{document}

在此处输入图片描述

如果有任何这样的代码片段(svg 或 d3.js)或文档可用!那就太好了!

使用 pdf2svg 工具,我可以将 pdf 转换为 svg,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="4.384pt" height="57.091pt" viewBox="0 0 4.384 57.091" version="1.1">
<defs>
<clipPath id="clip1">
  <path d="M 0 0 L 4.382812 0 L 4.382812 57.089844 L 0 57.089844 Z M 0 0 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0.00021875 56.692781 C 1.195531 56.095125 1.992406 54.700594 1.992406 52.708406 L 1.992406 22.692781 C 1.992406 20.700594 2.789281 19.306063 3.984594 18.708406 C 2.789281 18.11075 1.992406 16.716219 1.992406 14.724031 L 1.992406 3.98575 C 1.992406 1.993563 1.195531 0.599031 0.00021875 0.001375 " transform="matrix(1,0,0,-1,0.199,56.892)"/>
</g>
</g>
</svg>

该路径如下所示:

M 0.00021875 56.692781 
C 1.195531 56.095125 1.992406 54.700594 1.992406 52.708406 
L 1.992406 22.692781 
C 1.992406 20.700594 2.789281 19.306063 3.984594 18.708406 
C 2.789281 18.11075 1.992406 16.716219 1.992406 14.724031 
L 1.992406 3.98575 
C 1.992406 1.993563 1.195531 0.599031 0.00021875 0.001375

它使用 4 条三次贝塞尔曲线来绘制花括号。我仍然不知道如何计算每条三次贝塞尔曲线的控制点!

答案1

笔记: 显然我误解了这个问题......看起来,答案与问题相关,就像问题与 LaTeX 相关一样 :-(

对于这种情况,在tikz库中decorations定义了选项aspect

\documentclass[border=3.14159]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\begin{document}
\begin{tikzpicture}[
B/.style= {decorate,
    decoration={brace, amplitude=5pt,
    raise=2pt,
    aspect=#1},     % <---
    thick},
                    ]
\draw[B=0.6]  (0,4)--  node[pos=0.6, right=7pt] {Compromise loss} (0,0);
\end{tikzpicture}
\end{document}

在此处输入图片描述

或者使用库来增加一些趣味calligraphy

\documentclass[border=3.14159]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing,%
                calligraphy,% had to be after decorations.pathreplacing
                }

\begin{document}
BC/.style = {decorate,
    decoration={calligraphic brace, amplitude=5pt,
    raise=2pt,
    aspect=#1},
    very thick,
    pen colour={red}},
                    ]
\draw[BC=0.6]   
    (4,4) --  node[pos=0.6, right=7pt] {Compromise loss} (4,0);
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案2

在我的计算机上,可以在这里找到实现:

/usr/local/texlive/2021/texmf-dist/tex/generic/pgf/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex

完整的实现如下brace

% brace decorations
%
% Parameters: \pgfdecorationsegmentamplitude

\pgfdeclaredecoration{brace}{brace}
{%
  \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
  {
    \pgf@yc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance
    \ifdim2\pgfdecorationsegmentamplitude>\pgf@yc
      \pgf@yc=0.5\pgf@yc
    \else
      \pgf@yc=\pgfdecorationsegmentamplitude
    \fi
    \pgf@xc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance
    \advance\pgf@xc-\pgfdecoratedremainingdistance
    \ifdim-2\pgfdecorationsegmentamplitude<\pgf@xc
      \pgf@xc=-0.5\pgf@xc
    \else
      \pgf@xc=\pgfdecorationsegmentamplitude
    \fi
    \pgfpathmoveto{\pgfpointorigin}
    \pgfpathcurveto
    {\pgfqpoint{.15\pgf@yc}{.3\pgfdecorationsegmentamplitude}}
    {\pgfqpoint{.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
    {\pgfqpoint{\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
    {
      \pgftransformxshift{+\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance}
      \pgfpathlineto{\pgfqpoint{-\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
      \pgfpathcurveto
      {\pgfqpoint{-.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{-.15\pgf@yc}{.7\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{0\pgf@yc}{1\pgfdecorationsegmentamplitude}}
      \pgfpathcurveto
      {\pgfqpoint{.15\pgf@xc}{.7\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
    }
    {
      \pgftransformxshift{+\pgfdecoratedremainingdistance}
      \pgfpathlineto{\pgfqpoint{-\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
      \pgfpathcurveto
      {\pgfqpoint{-.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{-.15\pgf@xc}{.3\pgfdecorationsegmentamplitude}}
      {\pgfqpoint{0pt}{0pt}}
    }
  }%
  \state{final}
  {}%
}%

例如,所有命令\pgfdecorationsegmentamplitude都再次由 PGF 代码实现,然后再次实现/解释为某个东西,最后才变成坐标。这似乎是制作 SVG 括号的完全错误的方向。

答案3

从 pdf2svg 输出的 svg 点中,我们可以用 tikz 绘制图形(上部用于演示目的),如下所示:

\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc,intersections}

\usepackage{tikz,fp}
\makeatletter
\def\calcLength(#1,#2)#3{%
    \pgfpointdiff{\pgfpointanchor{#1}{center}}%
    {\pgfpointanchor{#2}{center}}%
    \pgf@xa=\pgf@x%
    \pgf@ya=\pgf@y%
    \FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
    \FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
    \FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
    \FProot{\FPMathLen}{\@temp@sum}{2}%
    \FPround\FPMathLen\FPMathLen5\relax
    \global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother

\tikzset{
    ctrlpoint/.style={%
        draw=gray,
        circle,
        inner sep=0,
        minimum width=1ex,
    }
}
\newcommand{\Bezier}[5][]{% \bezier (lowercase 'b') was already defined elsewhere
    \node (p1) [ctrlpoint] at (#2) {};
    \node (p2) [ctrlpoint] at (#3) {};
    \node (p3) [ctrlpoint] at (#4) {};
    \node (p4) [ctrlpoint] at (#5) {};
    \draw [gray] (p1) -- (p2) -- (p3) -- (p4);
    \draw [blue,#1] (#2) .. controls (#3) and (#4) .. (#5);
}
\begin{document}
    \begin{tikzpicture}[x=1pt,y=1pt,scale=5]    
    \coordinate (A) at (28.347812,28.347969); 
    \coordinate (C1) at (27.289219,31.515938); 
    \coordinate (C2) at (28.347812,35.390938); 
    \coordinate (P2) at (31.867344,38.914375); 
    \coordinate (P3) at (46.070469,53.113594); 
    \coordinate (C3) at (49.59,56.637031); 
    \coordinate (C4) at (50.648594,60.512031); 
    \coordinate (P8) at (49.59,63.68); 
    \coordinate (C5) at (52.761875,62.625313); 
    \coordinate (C6) at (56.636875,63.68); 
    \coordinate (P5) at (60.156406,67.203438); 
    \coordinate (P6) at (74.359531,81.402656); 
    \coordinate (C7) at (77.879063,84.926094); 
    \coordinate (C8) at (81.754063,85.980781); 
    \coordinate (B) at (84.925938,84.926094);
    
    \draw[line width=1] (A) .. controls (C1) and (C2) .. (P2) -- (P3) .. controls (C3) and (C4) .. (P8) .. controls (C5) and (C6) .. (P5) -- (P6) .. controls (C7) and (C8) .. (B);
        
%\Bezier[line width=1]{A}{C1}{C2}{P2};
%\Bezier[line width=1]{P3}{C3}{C4}{P8};
%\Bezier[line width=1]{P8}{C5}{C6}{P5};
%\Bezier[line width=1]{P6}{C7}{C8}{B};
    
\def\w{10}  
\draw [red,line width=1]
let 
\p{A}=(A),
\p{B}=(B),
\n{len}={veclen(\x{B}-\x{A},\y{B}-\y{A})},
\n{dx}={(\x{B}-\x{A})/\n{len}},
\n{dy}={(\y{B}-\y{A})/\n{len}},
\p{P2}=({\x{A}+\n{dx}*\w-\n{dy}*\w/2},{\y{A}+\n{dy}*\w+\n{dx}*\w/2}),
\p{P6}=({\x{B}-\n{dx}*\w-\n{dy}*\w/2},{\y{B}-\n{dy}*\w+\n{dx}*\w/2}),
\p{C1}=({\x{A}+\n{dx}*\w*.15-\n{dy}*\w*.3},{\y{A}+\n{dy}*\w*.15+\n{dx}*\w*.3}),
\p{C2}=({\x{P2}-\n{dx}*\w/2},{\y{P2}-\n{dy}*\w/2}),
\p{P4}=({\x{A}+\n{dx}*\n{len}/2-\n{dy}*\w/2},{\y{A}+\n{dy}*\n{len}/2+\n{dx}*\w/2}),
\p{P8}=({\x{P4}-\n{dy}*\w/2},{\y{P4}+\n{dx}*\w/2}), \p{P3}=({\x{P4}-\n{dx}*\w},{\y{P4}-\n{dy}*\w}), 
\p{P5}=({\x{P4}+\n{dx}*\w},{\y{P4}+\n{dy}*\w}),     \p{C3}=({\x{P3}+\n{dx}*\w/2},{\y{P3}+\n{dy}*\w/2}),
\p{C4}=({\x{P8}-\n{dx}*\w*.15 + \n{dy}*\w*.3},{\y{P8}-\n{dy}*\w*.15-\n{dx}*\w*.3}), 
\p{C5}=({\x{P8}+\n{dx}*\w*.15 + \n{dy}*\w*.3},{\y{P8}+\n{dy}*\w*.15-\n{dx}*\w*.3}), 
\p{C6}=({\x{P5}-\n{dx}*\w/2},{\y{P5}-\n{dy}*\w/2}),
\p{C7}=({\x{P6}+\n{dx}*\w/2},{\y{P6}+\n{dy}*\w/2}),
\p{C8}=({\x{B}-\n{dx}*\w*.15-\n{dy}*\w*.3},{\y{B}-\n{dy}*\w*.15+\n{dx}*\w*.3}),
in
%(A) -- (\p{C1}) -- (\p{C2}) -- (\p{P2}) -- (\p{P3}) -- (\p{C3}) -- (\p{C4}) -- (\p{P8}) -- (\p{C5}) -- (\p{C6}) -- (\p{P5}) -- (\p{P6}) -- (\p{C7}) -- (\p{C8}) -- (B)
(A) .. controls (\p{C1}) and  (\p{C2}) .. (P2) -- (P3) .. controls (\p{C3}) and (\p{C4}) .. (\p{P8}) .. controls (\p{C5}) and (\p{C6}) .. (\p{P5}) -- (\p{P6}) .. controls (\p{C7}) and (\p{C8}) .. (B);
        
%\draw[gray] (A) -- (B); 

\coordinate (P2P) at ($(A)!(P2)!(B)$);
\coordinate (C1P) at ($(A)!(C1)!(B)$);
\coordinate (C2P) at ($(A)!(C2)!(B)$);

%\calcLength(A,C1P){mylenc};
%\calcLength(A,C2P){mylend};
%\calcLength(A,P2P){mylenp};
\end{tikzpicture}
% \mylenc , \mylend , \mylenp
\end{document}

输出:

在此处输入图片描述

从该图中我们可以看到:

  1. C1 位置在 y 轴偏移 1/8 单位,x 轴偏移 1/2 单位。
  2. C2 位置在 y 轴偏移 1/2 个单位处,在 x 轴偏移 1 个单位处。

x 单位是 P2 到 P2P 的距离。y 单位是 A 到 P2P 的距离。

这同样适用于其他曲线。

使用 tikz 命令模拟花括号的完整 tikz 代码:

\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc,intersections}
\tikzset{
    ctrlpoint/.style={%
        draw=gray,
        circle,
        inner sep=0,
        minimum width=1ex,
    }
}
\newcommand{\Bezier}[5][]{% \bezier (lowercase 'b') was already defined elsewhere
    \node (p1) [ctrlpoint,label=90:$#2$] at (#2) {};
    \node (p2) [ctrlpoint,label=90:$#3$] at (#3) {};
    \node (p3) [ctrlpoint,label=90:$#4$] at (#4) {};
    \node (p4) [ctrlpoint,label=90:$#5$] at (#5) {};
    \draw [gray] (p1) -- (p2) -- (p3) -- (p4);
    \draw [blue,#1] (#2) .. controls (#3) and (#4) .. (#5);
}
\begin{document}
    \begin{tikzpicture}[x=1pt,y=1pt,scale=10]
    \coordinate (A) at (28.347812,28.347969); 
    \coordinate (C1) at (27.289219,31.515938); \coordinate (C2) at (28.347812,35.390938); \coordinate (P2) at (31.867344,38.914375); 
    \coordinate (P3) at (46.070469,53.113594); 
    \coordinate (C3) at (49.59,56.637031); \coordinate (C4) at (50.648594,60.512031); \coordinate (P8) at (49.59,63.68); 
    \coordinate (C5) at (52.761875,62.625313); \coordinate (C6) at (56.636875,63.68); \coordinate (P5) at (60.156406,67.203438); 
    \coordinate (P6) at (74.359531,81.402656); 
    \coordinate (C7) at (77.879063,84.926094); \coordinate (C8) at (81.754063,85.980781); \coordinate (B) at (84.925938,84.926094);
    
    \draw[line width=1] (A) .. controls (C1) and (C2) .. (P2) -- (P3) .. controls (C3) and (C4) .. (P8) .. controls (C5) and (C6) .. (P5) -- (P6) .. controls (C7) and (C8) .. (B);
    
\Bezier[line width=1]{A}{C1}{C2}{P2};
\Bezier[line width=1]{P3}{C3}{C4}{P8};
\Bezier[line width=1]{P8}{C5}{C6}{P5};
\Bezier[line width=1]{P6}{C7}{C8}{B};
    
\def\w{10}  
\draw [red,line width=.5]
let 
\p{A}=(A),
\p{B}=(B),
\n{len}={veclen(\x{B}-\x{A},\y{B}-\y{A})},
\n{dx}={(\x{B}-\x{A})/\n{len}},
\n{dy}={(\y{B}-\y{A})/\n{len}},
\p{P2}=({\x{A}+\n{dx}*\w-\n{dy}*\w/2},{\y{A}+\n{dy}*\w+\n{dx}*\w/2}),
\p{P6}=({\x{B}-\n{dx}*\w-\n{dy}*\w/2},{\y{B}-\n{dy}*\w+\n{dx}*\w/2}),
\p{C1}=({\x{A}+\n{dx}*\w/8-\n{dy}*\w/4},{\y{A}+\n{dy}*\w/8+\n{dx}*\w/4}),
\p{C2}=({\x{P2}-\n{dx}*\w/2},{\y{P2}-\n{dy}*\w/2}),
\p{P4}=({\x{A}+\n{dx}*\n{len}/2-\n{dy}*\w/2},{\y{A}+\n{dy}*\n{len}/2+\n{dx}*\w/2}),
\p{P8}=({\x{P4}-\n{dy}*\w/2},{\y{P4}+\n{dx}*\w/2}), \p{P3}=({\x{P4}-\n{dx}*\w},{\y{P4}-\n{dy}*\w}), 
\p{P5}=({\x{P4}+\n{dx}*\w},{\y{P4}+\n{dy}*\w}),     \p{C3}=({\x{P3}+\n{dx}*\w/2},{\y{P3}+\n{dy}*\w/2}),
\p{C4}=({\x{P8}-\n{dx}*\w/8 + \n{dy}*\w/4},{\y{P8}-\n{dy}*\w/8-\n{dx}*\w/4}), 
\p{C5}=({\x{P8}+\n{dx}*\w/8 + \n{dy}*\w/4},{\y{P8}+\n{dy}*\w/8-\n{dx}*\w/4}), 
\p{C6}=({\x{P5}-\n{dx}*\w/2},{\y{P5}-\n{dy}*\w/2}),
\p{C7}=({\x{P6}+\n{dx}*\w/2},{\y{P6}+\n{dy}*\w/2}),
\p{C8}=({\x{B}-\n{dx}*\w/8-\n{dy}*\w/4},{\y{B}-\n{dy}*\w/8+\n{dx}*\w/4}),
in
%(A) -- (\p{C1}) -- (\p{C2}) -- (\p{P2}) -- (\p{P3}) -- (\p{C3}) -- (\p{C4}) -- (\p{P8}) -- (\p{C5}) -- (\p{C6}) -- (\p{P5}) -- (\p{P6}) -- (\p{C7}) -- (\p{C8}) -- (B)

(A) .. controls (\p{C1}) and  (\p{C2}) .. (P2) -- (P3) .. controls (\p{C3}) and (\p{C4}) .. (\p{P8}) .. controls (\p{C5}) and (\p{C6}) .. (\p{P5}) -- (\p{P6}) .. controls (\p{C7}) and (\p{C8}) .. (B);
        
\draw[gray] (A) -- (B); 
\end{tikzpicture}
\end{document}

所有计算均在 let 命令中完成! 在此处输入图片描述

相关内容