Обновлять

Обновлять

Я пытаюсь нарисовать текст в фигурах (используя масштабирование и контур). Я хочу, чтобы текст отображался так:

Текст Долины

Я перепробовал много разных методов, но у меня возникли проблемы. Я могу приблизиться к этому, используя что-то вроде этого:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations.text}

\begin{document}
\pagenumbering{gobble}

\begin{tikzpicture}
\node (One) at (-15,0) {.}; 
\node (Two) at (15,0) {.};
\draw [decorate,decoration={text effects along path, 
                    text={TTTTTTTTTTTTTTTT},
                    text align=center,
                    text effects/.cd,
                    path from text,
                    character count=\i, character total=\n, 
                    characters= {text along path, scale=(2 + abs(\i - (\n / 2) - 0.5) * 1 )}}] (One) to (Two);

\end{tikzpicture}

\end{document}

Что приводит к:

Результат

Я хочу, чтобы верхняя часть текста была изогнута вверх, как показано на примере.

решение1

\outlineЯ просто ради интереса добавил макрос (требуется pdflatex).

Материал \outlineнаходится в преамбуле, тогда как код сужения находится в основном документе. Я изначально украл код, который составляет \outlineиз Malipivo вTikZ: ореол вокруг текста?

Я создаю поле ( \mytext) с текстом (немного отступающим, чтобы ничего впоследствии не обрезалось), а затем последовательно применяю , \clipboxкоторое вертикально разрезает текстовое поле \cutsраз. На каждом разрезе я применяю , \scaleboxчтобы сжать текст как функцию от номера разреза и \dip, что представляет собой максимальную долю сужения. Функция, которую я здесь выбираю, является параболической, хотя можно разработать и другие.

\documentclass{article}
\usepackage{ifthen,trimclip,calc,fp,graphicx,xcolor}
%%%%% FOR TEXT OUTLINING
\input pdf-trans
\newbox\qbox
\def\usecolor#1{\csname\string\color@#1\endcsname\space}
\newcommand\bordercolor[1]{\colsplit{1}{#1}}
\newcommand\fillcolor[1]{\colsplit{0}{#1}}
\newcommand\outline[1]{\leavevmode%
  \def\maltext{#1}%
  \setbox\qbox=\hbox{\maltext}%
  \boxgs{Q q 2 Tr \thickness\space w \fillcol\space \bordercol\space}{}%
  \copy\qbox%
}
\newcommand\colsplit[2]{\colorlet{tmpcolor}{#2}\edef\tmp{\usecolor{tmpcolor}}%
  \def\tmpB{}\expandafter\colsplithelp\tmp\relax%
  \ifnum0=#1\relax\edef\fillcol{\tmpB}\else\edef\bordercol{\tmpC}\fi}
\def\colsplithelp#1#2 #3\relax{%
  \edef\tmpB{\tmpB#1#2 }%
  \ifnum `#1>`9\relax\def\tmpC{#3}\else\colsplithelp#3\relax\fi
}
\bordercolor{blue}
\fillcolor{yellow}
\def\thickness{.5}
%%%%%
\begin{document}
\Huge
\edef\dip{.5}% percent to depress the amplitude
\def\cuts{200}% Number of cuts
\newsavebox\mytext
\savebox{\mytext}{\kern.3pt\textbf{\textsf{\outline{Valley Text}}}\kern.3pt}% TEXT
\newlength\clipsize
\FPeval{\myprod}{1/cuts}
\clipsize=\myprod\wd\mytext\relax
\newcounter{mycount}
\whiledo{\value{mycount}<\cuts}{%
  \stepcounter{mycount}%
  \edef\NA{\themycount}%
  \edef\NB{\the\numexpr\cuts-\themycount\relax}%
  \FPeval{\myprod}{1 - \dip*\NA*\NB*4/\cuts/\cuts}%
  \clipbox{%
    \value{mycount}\clipsize\relax{} %
    -1pt %
    \wd\mytext-\value{mycount}\clipsize-\clipsize\relax{} %
    -1pt%
  }{\scalebox{1}[\myprod]{\usebox{\mytext}}}%
}
\end{document}

введите описание изображения здесь

Без \outlineкода код более управляем. (ОТРЕДАКТИРОВАНО) Здесь я преобразую его в макрос \parabtext[<mode>]{<lift>}{<neck>}{<cuts>}{<content>}с несколькими дополнениями из вышеприведенного:

<mode>0 — для узкой середины и 1 — для узких концов;

<lift>это дробный максимальный подъем базовой линии во время трансформации

<neck>дробное уменьшение общей высоты шеи;

<cuts>количество вертикальных срезов, которые нужно применить к коробке (если слишком мало, она будет выглядеть ступенчатой)

<content>это то, что можно положить в коробку и трансформировать.

\documentclass{article}
\usepackage{ifthen,trimclip,calc,fp,graphicx,xcolor}
\newsavebox\mytext
\newcounter{mycount}
\newlength\clipsize
\newcommand\parabtext[5][0]{%
  \edef\neck{#3}% percent to depress the amplitude
  \def\cuts{#4}% Number of cuts
  \savebox{\mytext}{\kern.2pt#5\kern.2pt}% TEXT
  \FPeval{\myprod}{1/cuts}%
  \clipsize=\myprod\wd\mytext\relax%
  \setcounter{mycount}{0}%
  \whiledo{\value{mycount}<\cuts}{%
    \stepcounter{mycount}%
    \edef\NA{\themycount}%
    \edef\NB{\the\numexpr\cuts-\themycount\relax}%
    \FPeval{\myprod}{\NA*\NB*4/\cuts/\cuts}%
    \ifnum0#1=0\relax%
      \FPeval{\myprod}{1 - \neck*(\myprod)}%
    \else%
      \FPeval{\myprod}{1 - \neck*(1-\myprod)}%
    \fi%
    \clipbox{%
      \value{mycount}\clipsize\relax{} %
      -1pt %
      \wd\mytext-\value{mycount}\clipsize-\clipsize\relax{} %
      -1pt%
    }{\raisebox{#2\dimexpr\ht\mytext-\myprod\ht\mytext}{%
        \scalebox{1}[\myprod]{\usebox{\mytext}}}}%
  }%
}
\begin{document}
\Huge\centering\def\X{\textbf{XXX}}%
\parabtext{0}{.7}{200}{\textbf{\textcolor{brown}{Valley Text}}}\par
\X\parabtext{0}{.7}{200}{\X}\parabtext[1]{0}{.7}{200}{\X}\X\par
\X\parabtext{1}{.7}{200}{\X}\parabtext[1]{1}{.7}{200}{\X}\X\par
\X\parabtext{.425}{.7}{200}{\X}\parabtext[1]{.425}{.7}{200}{\X}\X
\end{document}

введите описание изображения здесь

Последняя опция EDITED, <mode>, изменяет функцию формы преобразования. В обоих режимах функция оценивается

\FPeval{\myprod}{\NA*\NB*4/\cuts/\cuts}%

Это парабола, которая имеет значение 1 на обоих концах ящика и значение 0 в середине ящика. Тогда, если мода равна 0, преобразование будет

\FPeval{\myprod}{1 - \neck*(\myprod)}%

тогда как, если не ноль, преобразование равно

\FPeval{\myprod}{1 - \neck*(1-\myprod)}%

Это простое различие позволит получить версии с шейкой и бочкой соответственно.


ПРЕДЛАГАЕМАЯ МЕТОДОЛОГИЯ

Этот метод требует довольно больших вычислительных затрат, но его следует использовать экономно для достижения эффекта «Вау!».

Сначала я покажу слегка измененный код, который, по сути, преобразует прямую разность в центральную разность, хотя это может потребовать немного больше вычислений.

Но я думаю, что лучше всего работает установка количества срезов в пользовательской переменной на низкое число, скажем, \def\slices{5}и разработка вашего документа на этой основе. На финальной компиляции, когда все установлено в окончательном макете, затем установите \def\slicesжелаемое число, скажем {200}, и перекомпилируйте в последний раз.

\documentclass{article}
\usepackage{ifthen,trimclip,calc,fp,graphicx,xcolor}
\newsavebox\mytext
\newcounter{mycount}
\newlength\clipsize
\newcommand\parabtext[5][0]{%
  \edef\neck{#3}% percent to depress the amplitude
  \def\cuts{#4}% Number of cuts
  \savebox{\mytext}{\kern.2pt#5\kern.2pt}% TEXT
  \FPeval{\myprod}{1/cuts}%
  \clipsize=\myprod\wd\mytext\relax%
  \setcounter{mycount}{0}%
  \whiledo{\value{mycount}<\cuts}{%
    \stepcounter{mycount}%
    \edef\NA{\themycount}%
    \edef\NB{\the\numexpr\cuts-\themycount\relax}%
    \FPeval{\myprod}{(\NA-.5)*(\NB+.5)*4/\cuts/\cuts}%
    \ifnum0#1=0\relax%
      \FPeval{\myprod}{1 - \neck*(\myprod)}%
    \else%
      \FPeval{\myprod}{1 - \neck*(1-\myprod)}%
    \fi%
    \clipbox{%
      \value{mycount}\clipsize-\clipsize\relax{} %
      -1pt %
      \wd\mytext-\value{mycount}\clipsize\relax{} %
      -1pt%
    }{\raisebox{#2\dimexpr\ht\mytext-\myprod\ht\mytext}{%
        \scalebox{1}[\myprod]{\usebox{\mytext}}}}%
  }%
}
\begin{document}
\def\slices{200}
\Huge\centering\def\X{\textbf{XXX}}%
\parabtext{0}{.7}{\slices}{\textbf{\textcolor{brown}{Valley Text}}}\par
\X\parabtext{0}{.7}{\slices}{\X}\parabtext[1]{0}{.7}{\slices}{\X}\X\par
\X\parabtext{1}{.7}{\slices}{\X}\parabtext[1]{1}{.7}{\slices}{\X}\X\par
\X\parabtext{.425}{.7}{\slices}{\X}\parabtext[1]{.425}{.7}{\slices}{\X}\X
\end{document}

Вот, например, вывод с \slicesустановкой 5для компиляции в низком разрешении:

введите описание изображения здесь

ПРИМЕЧАНИЕ ДЛЯ ПОЛЬЗОВАТЕЛЕЙ XeLaTeX

OP отметил, что этот подход не сработал в XeLaTeX. После некоторого изучения я свел проблему к ошибке в пакете trimclip(\clipbox из \scalebox не работает должным образом в xelatex). Джозеф Райт был настолько любезен, что диагностировал проблему и предоставил исправление для trimclipкода при запуске в XeLaTeX.

\makeatletter
\ifdefined\XeTeXversion
  \def\@cliptoboxdim#1{%
    \setbox #1=\hbox{%
      \Gin@defaultbp\WIDTH{\wd #1}%
      \Gin@defaultbp \DEPTH {\dp #1}%
      \@tempdima \ht #1%
      \advance\@tempdima\dp#1%
      \Gin@defaultbp \TOTALHEIGHT {\@tempdima }%
      \special{pdf:literal q}% 
      \special{pdf:literal 0 -\DEPTH \space \WIDTH \space \TOTALHEIGHT \space re W n }%
      \rlap{\copy #1}%
      \special {pdf:literal Q}%
      \hskip\wd#1%
    }%
  }
\fi
\makeatother

решение2

Обновлять

Используя треугольную сетку, мы можем аппроксимировать любое непрерывное преобразование.

\documentclass[border=9,tikz]{standalone}
\begin{document}

\pgfmathdeclarefunction{fx}{2}{\pgfmathparse{#1*(3+cos(#2*20))/3}}
\pgfmathdeclarefunction{fy}{2}{\pgfmathparse{#2*(3-cos(#1*20))/3}}
\pgfmathdeclarefunction{fxx}{2}{\pgfmathparse{fx(#1+1,#2)-fx(#1,#2)}}
\pgfmathdeclarefunction{fxy}{2}{\pgfmathparse{fy(#1+1,#2)-fy(#1,#2)}}
\pgfmathdeclarefunction{fyx}{2}{\pgfmathparse{fx(#1,#2+1)-fx(#1,#2)}}
\pgfmathdeclarefunction{fyy}{2}{\pgfmathparse{fy(#1,#2+1)-fy(#1,#2)}}

\tikz{
    \path(-15,-15)(15,15);
    \foreach\i in{-10,...,9}{
        \foreach\j in{-10,...,9}{
            \pgfmathsetmacro\aa{fxx(\i,\j)}
            \pgfmathsetmacro\ab{fxy(\i,\j)}
            \pgfmathsetmacro\ba{fyx(\i,\j)}
            \pgfmathsetmacro\bb{fyy(\i,\j)}
            \pgfmathsetmacro\xx{fx (\i,\j)}
            \pgfmathsetmacro\yy{fy (\i,\j)}
            \pgflowlevelobj{
                \pgfsettransformentries{\aa}{\ab}{\ba}{\bb}{\xx cm}{\yy cm}
            }{
                \fill[black!10](1,0)--(0,0)--(0,1);
                \clip(1,0)--(0,0)--(0,1)--cycle;
                \tikzset{shift={(-\i,-\j)}}
                \path(0,0)node{\includegraphics[width=20cm]{lena.png}};
            }
            \pgfmathsetmacro\aa{fxx(\i  ,\j+1)}
            \pgfmathsetmacro\ab{fxy(\i  ,\j+1)}
            \pgfmathsetmacro\ba{fyx(\i+1,\j  )}
            \pgfmathsetmacro\bb{fyy(\i+1,\j  )}
            \pgfmathsetmacro\xx{fx (\i+1,\j+1)}
            \pgfmathsetmacro\yy{fy (\i+1,\j+1)}
            \pgflowlevelobj{
                \pgfsettransformentries{\aa}{\ab}{\ba}{\bb}{\xx cm}{\yy cm}
            }{
                \clip(0,0)--(-1,0)--(0,-1)--cycle;
                \tikzset{shift={(-\i-1,-\j-1)}}
                \path(0,0)node{\includegraphics[width=20cm]{lena.png}};
            }
        }
    }
}

\end{document}

Старый ответ

Просто копирую идею @Steven B. Segletes, только сетка двухмерная и сделана в PGF/TiкЗ.

% !TEX program = XeLaTeX
% !TEX encoding = UTF-8 Unicode

\documentclass[border=9,tikz]{standalone}
\usepackage{fontspec}\setmainfont{Arial Unicode MS}

\begin{document}

\pgfmathdeclarefunction{fxx}{1}{\pgfmathparse{#1}}
\pgfmathdeclarefunction{fxy}{1}{\pgfmathparse{sin(222+30*#1)}}
\pgfmathdeclarefunction{fyx}{1}{\pgfmathparse{sin(20*#1)}}
\pgfmathdeclarefunction{fyy}{1}{\pgfmathparse{#1}}
\pgfmathdeclarefunction{gxx}{1}{\pgfmathparse{fxx(#1+1)-fxx(#1)}}
\pgfmathdeclarefunction{gxy}{1}{\pgfmathparse{fxy(#1+1)-fxy(#1)}}
\pgfmathdeclarefunction{gyx}{1}{\pgfmathparse{fyx(#1+1)-fyx(#1)}}
\pgfmathdeclarefunction{gyy}{1}{\pgfmathparse{fyy(#1+1)-fyy(#1)}}

\tikz{
    \path(-2,-2)(103,23);
    \foreach\i in{0,...,100}{
        \foreach\j in{0,...,20}{
            {
                \pgfmathsetmacro\aa{gxx(\i)}
                \pgfmathsetmacro\ab{gxy(\i)}
                \pgfmathsetmacro\ba{gyx(\j)}
                \pgfmathsetmacro\bb{gyy(\j)}
                \pgfmathsetmacro\xx{fxx(\i)+fyx(\j)}
                \pgfmathsetmacro\yy{fxy(\i)+fyy(\j)}
                \pgflowlevelobj{
                    \pgfsettransformentries{\aa}{\ab}{\ba}{\bb}{\xx cm}{\yy cm}
                }{
                    \clip(0,0)--(1,0)--(1,1)--(0,1)--cycle;
                    \draw[gray](1,0)--(0,0)--(0,1);
                    \path(-\i,-\j)+(50,10)node{\fontsize{500pt}{0}\selectfont Valley Text};
                }
            }
        }
    }
}

\end{document}

Немного математики

В моем коде преобразование определяется как

(x,y) |--> ( fxx(x)+fyx(y) , fxy(x)+fyy(y) )

где fxx, fyx, fxy, fyy — этохорошийфункции. Такое преобразование преобразует квадрат в параллелограмм. По совпадению, PDF поддерживает аффинное преобразование, которое также преобразует квадрат в параллелограмм. Таким образом, я могу использовать кусочно-аффинное преобразование для аппроксимации исходного преобразования. Результатом является то, что любая кривая останетсясвязанный, хотя и не дифференцируемы.

Связанный контент