Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am designing a poster, which has some geometrical shapes (TikZ paths) surrounded by some text. I would like the text to flow neatly around these shapes. I bet there's some clever TikZ magic that could do this.

EDIT: This is the sort of effect I want, sorry to not be clear:

enter image description here

\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}
share|improve this question
3  
Perhaps you can give us an example with your shapes ? –  Alain Matthes Aug 14 '12 at 4:37
    
Are you familiar with the "Text Decorations" library of TikZ and the "text along path" for instance? –  Dror Aug 14 '12 at 6:09
    
Except for the TikZ-part, is this a duplicate? tex.stackexchange.com/questions/32226/… –  Torbjørn T. Aug 14 '12 at 18:26
    
Thanks for pointing that out. Given that this question is about TikZ, I'd say it's very much not a duplicate. But that shapepar package looks like it might be very useful for producing an answer somehow. –  Jamie Vicary Aug 15 '12 at 7:18
    
I did a similar thing in this answer but no flexibility: tex.stackexchange.com/a/59777/3235 –  percusse Aug 19 '12 at 0:01

2 Answers 2

up vote 59 down vote accepted
+925

Here is my third attempt to use automatically shapepar package with TikZ.

The \shapeparnode macro uses six parameters:

  1. (optional - default: empty) a style for the node (font size, color...)
  2. the horizontal margin (a distance)
  3. the vertical margin (a distance)
  4. the left boundary (a continuous vertical path)
  5. the right boundary (a continuous vertical path)
  6. the text (a single paragraph without \par or empty line)

The \shapeparnodeaccuracy can be locally redefined and gives the accuracy to compute the shape (default: 2 lines per em).

All problems are not resolved, but this method seems promising...

Three examples (the first two uses dotted orange curves to show the boundaries):

enter image description here

The preamble (with the commented code of the \shapeparnode macro):

\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};
}

And the document to build the three examples:

\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}

The last example is from the 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}

enter image description here

share|improve this answer
3  
By further developing it, you could make it into a nifty package! –  Count Zero Aug 25 '12 at 15:01
    
@CountZero A package just for one macro ? –  Paul Gaborit Aug 25 '12 at 15:53
11  
This looks absolutely fantastic. I took a look at the problem a few days ago and gave up in despair. I'm glad I did so now as I don't think I'd've been able to do anything like this. I need to play with this shiny new toy. –  Loop Space Aug 25 '12 at 21:35
2  
I need more sockpuppets to vote this up again. –  Loop Space Aug 26 '12 at 22:32
2  
It is a great piece of work that required not only TeX skills but also thinking carefully about the problem. Having looked at the problem and given up, I can appreciate the thought that went into it. I also think this will be well used and want to encourage you to polish and publish it on CTAN. The original bounty (not from me) was to get attention to this. Now we've seen what can be done, it is worth more. –  Loop Space Aug 26 '12 at 23:18

As suggested by some comments, the only approach I know of offering a certain degree of flexibility is using the shapepar package. I made a stab at it:

\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}

There are three commands, to define three nodes, each of different shape, taking as argument the coordinates where it should be placed and naturally, the text of the paragraph. I used the option text width=0cm to force the node to display random multiline text.

output PDF

share|improve this answer
2  
Using shapepar is a good advice... –  Paul Gaborit Aug 25 '12 at 14:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.