
Estoy intentando dibujar texto en formas (usando escala y ruta). Quiero que el texto se muestre así:
He probado muchos métodos diferentes, pero tengo problemas para hacerlo. Puedo acercarme a él usando algo como esto:
\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}
Lo que resulta en :
Quiero que la parte superior del texto se curve hacia arriba como en el ejemplo que se muestra.
Respuesta1
Simplemente incorporé la \outline
macro (requiere pdflatex) por diversión.
El \outline
material está en el preámbulo, mientras que el código de cuello está en el documento principal. Originalmente robé el código que compone \outline
de Malipivo enTikZ: ¿halo alrededor del texto?
Lo que hago es crear un cuadro ( \mytext
) con el texto (rellenado un poco para que ninguno se recorte posteriormente) y luego aplico sucesivamente un \clipbox
cuadro que corta verticalmente el cuadro de texto \cuts
. En cada corte, aplico a \scalebox
para reducir el texto en función del número de corte y \dip
, que representa la fracción máxima de estrechamiento. La función que elijo aquí es parabólica, aunque también se pueden desarrollar otras.
\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}
Sin el \outline
código, el código es más manejable. (EDITADO) Aquí lo convierto en una macro \parabtext[<mode>]{<lift>}{<neck>}{<cuts>}{<content>}
con varias adiciones desde arriba:
<mode>
es 0 para el medio estrecho y 1 para los extremos estrechos;
<lift>
es la elevación máxima fraccionaria de la línea base durante la transformación
<neck>
es la reducción fraccionaria de la altura total en el cuello;
<cuts>
son el número de cortes verticales que se aplicarán a la caja (si son demasiado pequeños, se verá escalonado)
<content>
es lo que hay que poner en una caja y transformar.
\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}
La opción EDITADA más reciente <mode>
, cambia la función de forma de la transformación. En ambos modos, se evalúa una función.
\FPeval{\myprod}{\NA*\NB*4/\cuts/\cuts}%
Esa es una parábola que tiene un valor de 1 en ambos extremos de la caja y un valor de 0 en el medio de la caja. Entonces, si la moda es 0, la transformación es
\FPeval{\myprod}{1 - \neck*(\myprod)}%
mientras que, si no es cero, la transformación es
\FPeval{\myprod}{1 - \neck*(1-\myprod)}%
Esta simple diferencia producirá las versiones con cuello y con cañón, respectivamente.
METODOLOGÍA PROPUESTA
El método es algo costoso desde el punto de vista computacional, pero está pensado para usarse con moderación en el programa Wow! efecto.
Primero, mostraré un código ligeramente modificado que lo lleva, en efecto, de una diferencia directa a una diferencia central, aunque puede costar un poco más en cálculo.
Pero lo que creo que funciona mejor es establecer el número de sectores en una variable definida por el usuario en un número bajo, por ejemplo, \def\slices{5}
y desarrollar su documento sobre esa base. En la compilación final, cuando todo esté configurado en el diseño final, vuelva \def\slices
al número deseado, por ejemplo {200}
, y vuelva a compilar por última vez.
\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}
Aquí está, por ejemplo, el resultado \slices
configurado en 5
para la compilación de baja resolución:
NOTA PARA LOS USUARIOS DE XeLaTeX
El OP señaló que este enfoque no funcionó en XeLaTeX. Después de estudiar un poco, reduje el problema a un error en el trimclip
paquete (\clipbox de un \scalebox no funciona correctamente en xelatex). Joseph Wright tuvo la amabilidad de diagnosticar el problema y proporcionar un parche para el trimclip
código cuando se ejecuta en 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
Respuesta2
Actualizar
Usando una malla triangular, podemos aproximar cualquier transformación continua.
\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}
Antigua respuesta
Simplemente copio la idea de @Steven B. Segletes, solo que la grilla es 2D y está hecha en PGF/Ti.kZ.
% !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}
Algunas matemáticas
En mi código una transformación está definida por
(x,y) |--> ( fxx(x)+fyx(y) , fxy(x)+fyy(y) )
donde fxx, fyx, fxy, fyy sonbienfunciones. Tal transformación convertirá un cuadrado en un paralelogramo. Casualmente, PDF admite la transformación afín, que también envía un cuadrado a un paralelogramo. Por lo tanto, puedo utilizar una transformación afín por partes para aproximarme a la transformación original. El resultado es que cualquier curva permaneceráconectado, aunque no diferenciable.