3

I searched on the web and in this forum but I did not find a solution to my problem. I want to arrange text radially like rays of sunlight, coming out from a center. Something like that: image radial text

The code should be flexible (regarding to amount of lines and their length) and every line should be put on a separate sunbeam.

I created the example above with Inkscape and it was fairly easy to do so. But this would be a pain to do with 30 or more lines of text - and I would need to redo the whole thing whenever I add or remove a line.

Is there a way to automate that with LaTex?

I was fairly fluent in LaTex during my time at the university but did not use it recently... so therefore I don't know all the packages that are around. Maybe there is one which easily can do this ... ?

Further tuning would be to rotate some of the text by 180° (in my example 4th to 6th line) so that the text is not upside down.

Torbjørn T.
  • 206,688

2 Answers2

9

You can rotate lines using Tikz. In the below example I have a command textbeam that rotates the text a certain angle around a coordinate (the sun). That can be used to go through the text strings in a loop and position them around the sun.

For now I have not looked at the direction of the text (upside down problem). And the number of text lines is not automatically counted. But it might be a start.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
%%%%%%%
\newcommand\textbeam[4]{% {pos}{angle}{sep}{text}
  \node[anchor=west,rotate=#2] at ($(#1) + (#2:#3)$) {#4};
}
\newcommand\maketextsunbeams[4]{% {pos}{sep}{num}{text}
  \foreach \x [count=\xind from 0] in {#4}{
    \textbeam{#1}{\xind*360/#3}{#2}{\x}
  }  
}
\begin{document}

\begin{tikzpicture}
  \draw (1,0) circle (5mm);
  \maketextsunbeams{1,0}{7mm}{7}{%
    {First line}, 
    {Second line, maybe longer}, 
    {Third line, can also be long},
    {Fourth line},
    {Fifth line}, 
    {Sixth line}, 
    {Seventh line}}
\end{tikzpicture}
\end{document}

enter image description here

Edit

I updated the \textbeam command so that if the angle is between 90 and 270 degrees it turns it the other way (upside down):

\newcommand\textbeam[4]{% {pos}{angle}{sep}{text}
  \pgfmathparse{int(round(#2))}
  \edef\anglenum{\pgfmathresult}
  \ifnum\anglenum>90
    \ifnum\anglenum<270
      \node[anchor=east,rotate=#2+180] at ($(#1) + (#2:#3)$) {#4};
    \else
      \node[anchor=west,rotate=#2] at ($(#1) + (#2:#3)$) {#4};
    \fi
  \else
     \node[anchor=west,rotate=#2] at ($(#1) + (#2:#3)$) {#4};
  \fi
}

Then the same text-sun becomes

enter image description here

Edit 2

The automatic counting of text strings can be done using a recursive method. This changes also the command \maketextsunbeams so I give the full code.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
%%%%%%%
\newcommand\textbeam[4]{% {pos}{angle}{sep}{text}
  \pgfmathparse{int(round(#2))}
  \edef\anglenum{\pgfmathresult}
  \ifnum\anglenum>90
    \ifnum\anglenum<270
      \node[anchor=east,rotate=#2+180] at ($(#1) + (#2:#3)$) {#4};
    \else
      \node[anchor=west,rotate=#2] at ($(#1) + (#2:#3)$) {#4};
    \fi
  \else
     \node[anchor=west,rotate=#2] at ($(#1) + (#2:#3)$) {#4};
  \fi
}
\newcommand\maketextsunbeams[3]{% {pos}{sep}{text}
  \countargs{#3}
  \foreach \x [count=\xind from 0] in {#3}{
    \textbeam{#1}{\xind*360/\the\numargs}{#2}{\x}
  }  
}
%%%%
\newcount\numargs
\let\stop\empty
\newcommand\countargs[1]{%
  \numargs=0
  \reccountargs#1,\stop
}
\def\reccountargs#1,#2{%
  \advance\numargs 1
  \ifx\stop#2\relax
  \else
    \reccountargs{#2}
  \fi
}
%%%%
\begin{document}

\begin{tikzpicture}
  \draw (1,0) circle (5mm);
  \maketextsunbeams{1,0}{7mm}{%
    {One line}, 
    {A new line},
    {Another line},
    {Yet another line},    
    {A longer line, with a comma}, 
    {More lines},
    {Even more},
    {Next is an epty line}, 
    {}, 
    {More},
    {At last, the last line}}
\end{tikzpicture}
\end{document}

enter image description here

StefanH
  • 13,823
5

A version that automatically does the counting and has a friendlier interface:

\documentclass[border=4]{standalone}
\usepackage{xparse,tikz}

\newcommand\textbeam[3]{%
  \node[anchor=west,rotate=#1] at (#1:#2) {#3};%
}
\NewDocumentCommand{\sunrays}{O{3mm}mm}
 {% optional argument = radius
  % first mandatory = initial angle
  % second mandatory = texts separated by \\
  \begin{tikzpicture}
  \fill (0,0) circle (#1);
  \makesunrays{#1}{#2}{#3}
  \end{tikzpicture}
 }

\ExplSyntaxOn
\NewDocumentCommand{\makesunrays}{mmm}
 {
  \seq_set_split:Nnn \l_atld_sunrays_text_seq { \\ } { #3 }
  \int_set:Nn \l_atld_sunrays_items_int { \seq_count:N \l_atld_sunrays_text_seq }
  \int_step_inline:nnnn { 0 } { 1 } { \l_atld_sunrays_items_int - 1 }
   {
    \textbeam
     { \fp_to_decimal:n { #2 - ##1*360/\l_atld_sunrays_items_int } }
     { #1 }
     { \seq_item:Nn \l_atld_sunrays_text_seq { ##1 + 1 } }
   }
 }
\seq_new:N \l_atld_sunrays_text_seq
\int_new:N \l_atld_sunrays_items_int
\ExplSyntaxOff

\begin{document}

\sunrays{60}{
  First line \\
  Second line, maybe longer \\
  Third line, maybe also long \\
  Fourth line, just text \\
  Fifth line, upside down \\
  Sixth line, I don't know how long
}

\end{document}

All the credit should go to StefanH, from whom I stole the TikZ code.

enter image description here

I used standalone to show the bounding box is correctly computed.

Here's the output of

\sunrays[1cm]{0}{AAA\\BBB\\CCC\\DDD\\EEE\\FFF\\GGG\\HHH\\III}

enter image description here

egreg
  • 1,121,712