在 TikZ 中将文本调整到形状

在 TikZ 中将文本调整到形状

我正在设计一张海报,上面有一些几何形状(TikZ 路径),周围有一些文字。我希望文字能整齐地围绕这些形状。我敢打赌,一定有一些巧妙的 TikZ 魔法可以做到这一点。

编辑:这是我想要的效果,抱歉没有说清楚:

在此处输入图片描述

\documentclass[a4paper]{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0,0) to (2,-2) to (2,-4) to (4,-4) to [out=up, in=down] (6.5,0);
\node [text width=6cm, anchor=north west] at (0,0) {
\hspace{5pt}  This is the sort of effect I want to \\
\hspace{23pt} achieve, with text automatically \\
\hspace{36pt} constrained by some \\
\hspace{46pt} geometrical form. Here \\
\hspace{55pt} it's just a curve, \\
\hspace{57pt} but this could \\
\hspace{57pt} also be the \\
\hspace{57pt} text label \\
\hspace{57pt} of a node.};
\end{tikzpicture}
\end{document}

答案1

这是我第三次尝试使用自动地 shapepar采用 Ti 封装Z。

\shapeparnode宏使用六个参数:

  1. (可选 - 默认值:空)节点样式(字体大小、颜色……)
  2. 水平边距(距离)
  3. 垂直边距(距离)
  4. 左边界(连续的垂直路径)
  5. 右边界(连续的垂直路径)
  6. 文本(无行\par或空行的单个段落)

\shapeparnodeaccuracy局部重新定义并给出计算形状的精度(默认值:2每 em 行数)。

所有问题都没有得到解决,但是这种方法看起来很有希望......

三个例子(前两个使用虚线橙色曲线显示边界):

在此处输入图片描述

序言(带有宏的注释代码\shapeparnode):

\documentclass{standalone}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\usepackage{shapepar}
\usepackage{microtype}
\usepackage{lipsum}
\usepackage{tikz}
\usetikzlibrary{calc,fit,intersections}

\def\shapeparnodeaccuracy{2}
\newcommand\shapeparnode[6][]{
  % 6 parameters:
  % style for node (default:empty),
  % h margin, v margin, left path, right path, text (just one paragraph!)

  % name left and right paths and compute there bounding boxes
  \begin{scope}[local bounding box=leftbb]
    \path[name path global=left,xshift=#2] #4;
  \end{scope}
  \node[inner ysep=-#3,inner xsep=0pt,fit=(leftbb)](leftbb){};
  \begin{scope}[local bounding box=rightbb]
    \path[name path global=right,xshift=-#2] #5;
  \end{scope}
  \node[inner ysep=-#3,inner xsep=0pt,fit=(rightbb)](rightbb){};

  % global bounding box
  \path let
  \p1=(leftbb.north west), \p2=(leftbb.south west),
  \p3=(rightbb.north east), \p4=(rightbb.south east)
  in
  \pgfextra{
    \pgfmathsetmacro{\ymin}{(\y1 < \y3) ? \y1 : \y3}
    \pgfmathsetmacro{\ymax}{(\y2 > \y4) ? \y2 : \y4}
    \typeout{ymin \ymin}
    \typeout{ymax \ymax}
  } node[inner sep=0,fit={(\x1,\ymin pt)(\x3,\ymax pt)}](mybb){};

  % compute nb steps
  \path let \p1=(mybb.north), \p2=(mybb.south) in
  \pgfextra{
    \pgfmathsetmacro{\fnthght}{1em/\shapeparnodeaccuracy}
    \pgfmathtruncatemacro{\nbsteps}{(\y1-\y2)/\fnthght}
    \xdef\nbsteps{\nbsteps}
    \typeout{nb steps \nbsteps}
  };

  % horizontal references
  \path (mybb.north) -- (mybb.south)
  \foreach \cnt in {0,1,...,\nbsteps}{
    \pgfextra{\pgfmathsetmacro{\pos}{\cnt/\nbsteps}}
    coordinate[pos=\pos] (ref \cnt)
  };

  % left and right boundaries coordinates
  \foreach \cnt in {0,1,...,\nbsteps}{
    % an horizontal line from left to right
    \path[name path=ltor]
    (mybb.west |- ref \cnt) --  (mybb.east |- ref \cnt);
    % same line from right to left
    \path[name path=rtol]
    (mybb.east |- ref \cnt) -- (mybb.west |- ref \cnt);
    % left boundary
    \path[name intersections={of=rtol and left,by={l \cnt},sort by=rtol}];
    % right boundary
    \path[name intersections={of=ltor and right,by={r \cnt},sort by=ltor}];
  }
  % start point (and initial value of boundshape)
  \path let \p1=(l 0) in 
  \pgfextra{
    \pgfmathsetmacro{\xstart}{\x1}
    \xdef\boundshape{{0}{0}b{\xstart}}
    \xdef\xmin{\xstart}
    \xdef\xmax{\xstart}
  };

  % top and bottom
  \path let \p1=(l 0), \p2=(l \nbsteps) in
  \pgfextra{
    \pgfmathsetmacro{\ystart}{\y1}\xdef\ystart{\ystart}
    \pgfmathsetmacro{\yending}{\y2}\xdef\yending{\yending}
  };
  % incremental definition of boundshape
  \foreach \cnt in {0,1,...,\nbsteps}{
    \path let \p1=(l \cnt), \p2=(r \cnt) in
    \pgfextra{
      \pgfmathsetmacro{\start}{\x1}
      \pgfmathsetmacro{\len}{\x2-\x1}
      \pgfmathsetmacro{\ypos}{\cnt/\nbsteps*(\ystart - \yending)}
      {\let\\=\relax \xdef\boundshape{\boundshape\\{\ypos}t{\start}{\len}}}
      \pgfmathsetmacro{\xmin}{(\xmin < \start) ? \xmin : \start}
      \xdef\xmin{\xmin}
      \pgfmathsetmacro{\xmax}{(\xmax > \start + \len) ? \xmax : \start + \len}
      \xdef\xmax{\xmax}
    };
  }
  % draw the node with text in a shapepar
  \pgfmathsetmacro{\ymax}{\ystart - \yending}
  {\let\\=\relax \xdef\boundshape{\boundshape\\{\ymax}e{0}}}
  \node[#1,text width=\xmax pt - \xmin pt,align=flush left,
  anchor=north west,inner sep=0]
  at (mybb.north west -| \xmin pt,0)
  {\Shapepar[1pt]{\boundshape}#6\par};
}

以及构建三个示例的文档:

\def\mytext{Lorem ipsum dolor sit amet, consectetur adipiscing
  elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue
  ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis
  dolor. Praesent et diam eget libero egestas mattis sit amet vitae
  augue. Nam tincidunt congue enim, ut porta lorem lacinia
  consectetur. $x = y + z$ arcu vehicula ultricies a non tortor. Lorem
  ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida
  lorem. \textbf{Ut turpis felis}, pulvinar a semper sed, adipiscing id
  dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur
  dapibus enim sit amet elit pharetra tincidunt feugiat nisl
  imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed
  odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu
  rhoncus. \emph{\large Cum sociis natoque} penatibus et magnis dis
  parturient montes, nascetur ridiculus mus. In rutrum accumsan
  ultricies. Mauris vitae nisi at sem facilisis semper ac in
  est. Vivamus fermentum semper porta. Nunc diam velit, adipiscing ut
  tristique vitae, sagittis vel odio. Maecenas convallis ullamcorper
  ultricies.}

\begin{document}%
  \begin{tikzpicture}
    \begin{scope} % first example
      \def\pathone{(0,0) to[out=270,in=90] (2,-3) to[out=270,in=90] (-1,-7) to[out=270,in=90] (1,-10)}%
      \def\pathtwo{[xshift=8.2cm]\pathone}%
      \shapeparnode{1em}{.5em}{\pathone}{\pathtwo}{\mytext}%
      \draw[dotted,orange] \pathone;
      \draw[dotted,orange] \pathtwo;
    \end{scope}
    \begin{scope}[yshift=-11cm] % second example
      \small
      \def\pathone{(0,0) -- (-.5,-7) -- (2,-5.2) to[bend right] (3,-10)}%
      \def\pathtwo{(10,0) --  (7,-5)  to[bend right] (10,-10)}%
      \shapeparnode[text=blue,font=\small\itshape]
      {1em}{.5em}{\pathone}{\pathtwo}{\mytext}%
      \draw[dotted,orange] \pathone;
      \draw[dotted,orange] \pathtwo;
    \end{scope}
    \begin{scope}[yshift=-22cm] % third example
      \footnotesize
      \def\radius{3.1}
      \def\pathone{(3,0)
        arc(90:225:\radius)
        arc (45:-45:\radius/2.415)
        arc(135:270:\radius)}
      \def\pathtwo{(3,-4*\radius)
        arc(-90:0:\radius)
        arc(180:90:\radius)
        arc(270:180:\radius)
        arc(0:90:\radius)}
      \fill[top color=lime,bottom color=orange,middle color=yellow,draw=white]
      \pathone -- \pathtwo -- cycle;
      \shapeparnode[text=black,font=\footnotesize\scshape]
      {2em}{1em}{\pathone}{\pathtwo}{\mytext}%
      %\draw[orange] \pathone;
      %\draw[orange] \pathtwo;
    \end{scope}
\end{tikzpicture}
\end{document}

最后一个例子来自MWE:

\begin{tikzpicture}  
  \def\pathone{(0,0) to (2,-2) to (2,-4)}
  \def\pathtwo{(4,-4) to [out=up, in=down] (6.5,0)}
  \shapeparnode{1em}{.2em}{\pathone}{\pathtwo}{%
    This is the sort of effect I want to achieve, with text
    automatically constrained by some geometrical form. Here it's just a
    curve, but this could also be the text label of a node.}
  \draw \pathone -- \pathtwo -- cycle;
\end{tikzpicture}

在此处输入图片描述

答案2

正如一些评论所建议的那样,我所知道的唯一提供一定程度灵活性的方法是使用该shapepar包。我尝试了一下:

\documentclass{standalone}

\usepackage{shapepar}
\usepackage{tikz}

\usetikzlibrary{shapes.geometric}

\newcommand\circlenodetext[3]{\node [draw, shape=circle, text width=0cm, inner sep=5mm] at (#1,#2) {\shapepar{\circleshape} #3\par};}
\newcommand\squarenodetext[3]{\node [draw, regular polygon, regular polygon sides=4, text width=0cm, inner sep=0mm] at (#1,#2) {\shapepar{\squareshape} #3\par};}
\newcommand\diamondnodetext[3]{\node [draw, shape=diamond, text width=0cm, inner sep=5mm] at (#1,#2) {\shapepar{\diamondshape} #3\par};}

\begin{document}
    \begin{tikzpicture}
        \circlenodetext{0}{0}{\texttt{lipsum} causes an arithmetic overflow error, so this is what I fill this space with instead}
        \squarenodetext{0}{5}{\texttt{lipsum} causes an arithmetic overflow error, so this is what I fill this space with instead}
        \diamondnodetext{0}{11}{an arith\-metic overflow error, so this is what I fill this space with instead -- so lean back and enjoy it!}
    \end{tikzpicture}
\end{document}

有三个命令,用于定义三个节点,每个节点具有不同的形状,以应放置的坐标作为参数,当然还有段落的文本。我使用该选项text width=0cm强制节点显示随机多行文本。

输出 PDF

答案3

对于规则形状,可以使用 ConTeXt MKIV 中的 MetaFun 相当好地实现这一点。详细信息可参见MetaFun 手册参见 »10.6 库« 一节。任意形状都是可能的,但构造起来比较困难。

\useMPlibrary[txt]

\startuseMPgraphic{parshape}
  path p; p := fullcircle scaled 8cm;

  build_parshape(p,5pt,5pt,0,
    \baselinedistance,\strutheight,\strutdepth,\strutheight);

  draw p withpen pencircle scaled 1pt;
\stopuseMPgraphic

\defineoverlay
  [parshape]
  [\useMPgraphic{parshape}]

\starttext

\startshapetext[parshape]
  \input knuth
\stopshapetext

\startframed
  [
    frame=off,
    offset=overlay,
    background=parshape,
  ]
  \getshapetext
\stopframed

\stoptext

在此处输入图片描述

相关内容