pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.1k stars 105 forks source link

Add 3d support for decorations.text #898

Closed ZhiyuanLck closed 3 years ago

ZhiyuanLck commented 4 years ago

Brief outline of the proposed feature I have attemped to add 3d support to text along text, it seems to work well, but I don't know if the patch will break something else.

See place text on curved surface

I also paste my code below.

main.tex

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{3d, decorations,decorations.text}
\usepackage{etoolbox}
\usepackage{xpatch}
\makeatletter
\newif\ifpgfdecorateabs
\newif\ifpgfdecoratetransformcs

% settings
\pgfqkeys{/pgf/decoration}{
  yvec/.code={
    \pgfqkeys{/pgf/decoration/yvec}{%
      transform cs,
      #1
    }%
  },
  yvec/.cd,
  absolute/.is if=pgfdecorateabs,
  absolute,
  transform cs/.is if=pgfdecoratetransformcs,
  transform cs=false,
  raise/.store in=\pgftransformraise,
  raise=0pt,
  angle/.code={
    \def\pgf@decorate@absolute@angle{#1}
    \pgfkeysalso{absolute}
  },
  point/.code={
    \def\pgf@decorate@rel@point{\tikz@scan@one@point\pgfutil@firstofone#1}
    \pgfkeysalso{absolute=false}
  }
}
\xpretocmd{\pgf@decorate@do@code}{%
  \ifpgfdecorateabs
  \else
    \pgfmathanglebetweenpoints%
    {\pgfpointlineatdistance{\pgfdecoratedinputsegmentcompleteddistance}{\pgf@decorate@inputsegment@first}{\pgf@decorate@inputsegment@last}}%
    {\pgf@decorate@rel@point}
    \xdef\pgf@decorate@yvec@angle{\pgfmathresult}
  \fi
}{}{}
\input{text.tex}
\makeatother

\tikzset{
  mytext/.style={
    postaction=decorate,
    decoration={
      text along path,
      yvec/raise=.8ex,
      text align={align=center},#1
    }
  }
}

\begin{document}
\begin{tikzpicture}
\draw [mytext={text={Do you know $x + y = z$? You don't know, what a pity!}}] (0, 0) arc (90:90+360:4cm and 1cm);
\draw [yshift=2.5cm, mytext={text={Do you know $x + y = z$? You don't know, what a pity!}, yvec={point={(0, 8)}}}] (0, 0) arc (90:90+360:4cm and 1cm);
\draw [yshift=5cm, mytext={text={Do you know $x + y = z$? You don't know, what a pity!}, yvec={angle=90}}] (0, 0) arc (90:90+360:4cm and 1cm);
\draw [yshift=6cm, mytext={text={Do you know $x + y = z$? You don't know, what a pity!}, yvec={angle=90}}] (0, 0) to[relative, out=80, in=-80, distance=7cm] (0, 4);
\node at (0, -1) {ellipse plane};
\node at (0, 1.5) {point to curve plane};
\node at (0, 4) {shifted curve plane};
\end{tikzpicture}
\end{document}

text.tex, add some code in state typeset

\pgfdeclaredecoration{text along path}{initial}{%
    \state{initial}[
        width=+0pt, next state=left indent,
        persistent precomputation={%
            \edef\pgf@lib@dec@text@indent@left{\pgfkeysvalueof{/pgf/decoration/text align/left indent}}%
            \edef\pgf@lib@dec@text@indent@right{\pgfkeysvalueof{/pgf/decoration/text align/right indent}}%
            \edef\pgf@lib@dec@text@align{\pgfkeysvalueof{/pgf/decoration/text align/align}}%
            \pgfdecoratedremainingdistance=\pgfdecoratedpathlength%
        \advance\pgfdecoratedremainingdistance by-\pgf@lib@dec@text@indent@right\relax%
        \edef\pgfdecoratedpathlength{\the\pgfdecoratedremainingdistance}%
        \pgf@lib@dec@text@getwidth%
        \pgf@x=\pgf@lib@dec@text@width\relax%
        \pgf@y=\pgfdecoratedremainingdistance%
        \ifpgf@lib@dec@text@fit%
            \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax%
            \advance\pgf@y by-\pgf@x%
            \ifpgf@lib@dec@text@stretch@spaces%
                \def\pgf@lib@dec@text@character@shift{0pt}%
                \divide\pgf@y by\pgf@lib@dec@space@count\relax%
                \edef\pgf@lib@dec@text@space@shift{\the\pgf@y}%
            \else%
                \c@pgf@counta=\pgf@lib@dec@character@count\relax%
                \advance\c@pgf@counta by-1\relax%
                \divide\pgf@y by\c@pgf@counta\relax%
                \edef\pgf@lib@dec@text@character@shift{\the\pgf@y}%
                \def\pgf@lib@dec@text@space@shift{0pt}%
            \fi%
            \ifdim\pgf@y<0pt\relax%
                \pgf@lib@dec@text@fitfalse%
                \pgf@lib@dec@text@stretch@spacesfalse%
                \def\pgf@lib@dec@text@character@shift{0pt}%
                \def\pgf@lib@dec@text@space@shift{0pt}%
            \fi%
        \else%
            \def\pgf@lib@dec@text@character@shift{0pt}%
            \def\pgf@lib@dec@text@space@shift{0pt}%
                \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@left@text%
                \else%
                    \ifx\pgf@lib@dec@text@align\pgf@lib@dec@text@right@text%
                        \advance\pgf@y by-\pgf@x%
                        \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}%
                    \else%
                        \advance\pgf@y by-\pgf@x%
                        \advance\pgf@y by-\pgf@lib@dec@text@indent@left\relax%
                        \pgf@y=0.5\pgf@y%
                        \advance\pgf@y by\pgf@lib@dec@text@indent@left\relax%
                        \edef\pgf@lib@dec@text@indent@left{\the\pgf@y}%
                    \fi%
                \fi%
        \fi%
        \let\pgfdecorationrestoftext=\pgfdecorationtext%
    }]{}%
\state{left indent}[width=+\pgf@lib@dec@text@indent@left, next state=scan]{}%
%
\state{scan}[
    width=+0pt,
    next state=before typeset,
    persistent precomputation={
        \pgf@lib@dec@text@scanchar%
        \ifvoid\pgf@lib@dec@text@box%
            \setbox\pgf@lib@dec@text@box\hbox{}%
            \wd\pgf@lib@dec@text@box16383pt\relax%
        \fi%
}]{}%
%
\state{before typeset}[width=+.5\wd\pgf@lib@dec@text@box, next state=typeset]{}%
%
\state{typeset}[width=+0pt, next state=after typeset]
{%
  \pgftransformxshift{+-.5\wd\pgf@lib@dec@text@box}%
  \setbox\pgf@hbox\hbox{\copy\pgf@lib@dec@text@box}%
  \ifpgfdecoratetransformcs
    \let\pgf@decorate@correct@angle\pgfdecoratedangle%
    \typeout{tf cs}
    \ifpgfdecorateabs%
      \let\pgf@decorate@planey@angle\pgf@decorate@absolute@angle%
    \else%
      \let\pgf@decorate@planey@angle\pgf@decorate@yvec@angle%
    \fi%
  \else%
    \def\pgf@decorate@correct@angle{0}%
    \def\pgf@decorate@planey@angle{90}%
  \fi%
  \pgftransformtriangle%
  {\pgfpointxy{0}{0}}%
  {\pgfpointxy{1}{0}}%
  {\pgfpointpolar{\pgf@decorate@planey@angle-\pgf@decorate@correct@angle}{1cm}}%
  \pgftransformscale{0.035146}%
  \pgfsetxvec{\pgfpointxy{1}{0}}%
  \pgfsetyvec{\pgfpointxy{0}{1}}%
  \pgfsetzvec{\pgfpointxy{0}{0}}%
  \pgftransformshift{\pgfpoint{0pt}{\pgftransformraise}}
  \pgfqboxsynced\pgf@hbox%
}%
\state{after typeset}[width=+.5\wd\pgf@lib@dec@text@box, next state=shift,
    persistent precomputation={%
    \ifpgf@lib@dec@text@fit%
        \ifpgf@lib@dec@text@stretch@spaces%
            \ifpgf@lib@dec@text@scan@space%
                \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@space@shift%
            \else%
                \def\pgf@lib@dec@text@shift{0pt}%
            \fi%
        \else%
            \let\pgf@lib@dec@text@shift=\pgf@lib@dec@text@character@shift%
          \fi%
        \else%
            \def\pgf@lib@dec@text@shift{0pt}%
      \fi%
  }]{}%
\state{shift}[width=+\pgf@lib@dec@text@shift, next state=scan]{}%
\state{final}{}%
}%
hmenke commented 4 years ago

it seems to work well, but I don't know if the patch will break something else

Where is the patch?

ZhiyuanLck commented 4 years ago

I patch \pgf@decorate@do@code to calculate the angle from segment to some point.

muzimuzhi commented 4 years ago

I think @hmenke means a git patch file generated by git diff --cached and ready for being applied (doc of git apply) to the code base, since the issue title seems like a title of "I want to contribute ...".

ZhiyuanLck commented 4 years ago

Well, I'll try, but I want to know how to debug with local repo.

ZhiyuanLck commented 4 years ago

I have submit a pull request #899