我对一个可以让我的生活变得轻松很多的功能有疑问。是否可以取一个段落,让 TeX 将其分成几行,然后让 tikz 访问各个行并将它们放在页面上的不同位置?例如,我有一个 10 行的段落(但我不一定事先知道会有 9 行、10 行或 11 行),我希望 tikz 取各个行并将它们放在不同的位置,例如使它们的原点是圆的点。
(我猜这会使用\unvbox
一个对我来说仍然很神秘的命令,以及某种循环来访问 vbox 中包含的各个 hbox,这是一个 TeX 循环还是 tikz 循环?)
根据 user202729 的要求给出一个明确的例子,我们如下:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit, positioning}
\usepackage{lipsum}
\begin{document}
\begin{tikzpicture}[remember picture,overlay,shift=(current page.south west)]
\node[align=left,text width=4cm] at (1in,1in) {some text spanning three lines with very nice automatic line breaks};
\end{tikzpicture}
\end{document}
使用此代码我得到
文本框的中心位于坐标 (1in,1in)(页面左下角为 (0,0))。
第一个(次要)问题:我怎样才能引用这里的观点:
这是第一行文本基线的左边界吗?(我称之为起源的线)
第二个(主要)问题:我怎样才能将这段文本分成几行,并让 tikz 将这些行放在不同的位置?例如,我希望第一行(原点)位于坐标 (2in,2in),第二行(原点)位于坐标 (3.5in,0.75in),第三行(原点)位于其他给定位置?
确实有一个回答对于“我如何为文本的每一行添加框架”这个问题,这确实是朝着正确方向迈出的一步,但我如何才能\lastbox
与 tikz 进行交互呢?
理想情况下,我需要的是能够告诉 tikz“取出此段落并将其各行放置在位置 (2in,2in)、(3in,50pt)、(11bp,22345sp)… 等等”。
答案1
这个原型回答了主要问题和次要问题。它将逐行捕获段落的每一行,并将它们加载到tikz
节点中。
捕获使用
沃纳的命令它使用\lastbox
。
该命令\TypesetLines{<text>}
将使用 x 和 y 偏移以及可选旋转显示线条,使用由生成的命令
\RotateAndGo[<optional rotation angle>]{<consecutive number id>}{<x offset from corner>}{<y offset from corner>}
有两种操作模式:
(1)在手动模式下,您可以选择每条线的旋转和位置\RotateAndGo
。所需的数量\RotateAndGo
至少与线数相等。
(2)在自动模式下,所需的参数\RotateAndGo
是通过在命令中包含其执行来根据number id
(或其他变量)动态生成的\makenodes
。
tikz
每条线都与一个与线tikzmark
相同的一起添加到节点number id
。这样就可以从页面上的任意位置绘制箭头到任何线开头的基线。
手动模式
自动模式:线的起点遵循二次曲线。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark} % needed <<<<<<<<<<
\usepackage[showframe]{geometry}
\newsavebox{\singleline}
\newcounter{xcount}\setcounter{xcount}{0}
\newcounter{xlinecount}
% From https://tex.stackexchange.com/a/57140/161015
\newcommand{\getlines}{% capture all lines of a paragraph and puts them in their place
\setbox\singleline\lastbox%
\ifvoid\singleline%
\noindent\ignorespaces%
\else
\unskip\unpenalty%
\begingroup\getlines\endgroup
\stepcounter{xcount}\setcounter{xlinecount}{\value{xcount}}\par
\makenodes
\fi}
\newcommand{\makenodes}{}
\newcommand{\TypesetLines}[1]{\parindent0pt\vbox{#1\par\getlines}} % load the paragraph and display the lines
%\RotateAndGo[<optional rotation angle>]{<number ID >}{<x shift from corner>}{<y shift from corner>}
\newcommand{\RotateAndGo}[4][0]{% save rotation and shifts
\expandafter\expandafter\expandafter\newcommand \csname R#2\endcsname{#1}%
\expandafter\expandafter\expandafter\newcommand \csname Cx#2\endcsname{#3}%
\expandafter\expandafter\expandafter\newcommand \csname Cy#2\endcsname{#4}%
}
\begin{document}
\pagestyle{empty}
% First example ********************************************
\newgeometry{textwidth=4.0cm}
\renewcommand{\makenodes}{%put the lines in their place, automatic mode
\RotateAndGo{\thexcount}{1cm}{-0.5in*\thexcount} % only y-shift
\tikz\node[inner sep=0pt,rotate=\expandafter\csname R\thexcount\endcsname, remember picture, overlay, anchor= west ,draw]
at ([xshift=\expandafter\csname Cx\thexcount\endcsname, yshift=\expandafter\csname Cy\thexcount\endcsname] current page.south west)
{\tikzmark{\thexcount}\usebox{\singleline}}; % typeset
}
\noindent Some text spanning three lines with very nice automatic line breaks \bigskip
From \tikzmarknode{here}~HERE to the first line baseline
\TypesetLines{Some text spanning three lines with very nice automatic line breaks}
\tikz[remember picture,overlay] \draw[->,red, very thick] (here) -- (pic cs:1); % the arrow to the baseline of the first line (# 1)
\newpage
% Second example ********************************************
\newgeometry{textwidth=4in}
\renewcommand{\makenodes}{%put the lines in their place, manual mode <<<<<<<<<<<<<<<<<<<<
\tikz\node[inner sep=0pt,rotate=\expandafter\csname R\thexcount\endcsname, remember picture, overlay, anchor= west ,draw]
at ([xshift=\expandafter\csname Cx\thexcount\endcsname, yshift=\expandafter\csname Cy\thexcount\endcsname] current page.south west)
{\tikzmark{\thexcount}\usebox{\singleline}}; % typeset
}
\noindent As any dedicated reader can clearly see, the Ideal of
practical reason is a representation of, as far as I know, the things
in themselves; as I have shown elsewhere, the phenomena should only be
used as a canon for our understanding.The paralogisms of practical
reason are what first give rise to the architectonic of practical
reason.
\bigskip
Arrow to the \tikzmarknode{last}~LAST line (\# \verb|\thexlinecount|)
Last used line= \thexlinecount
\newcounter{ctrx}\setcounter{ctrx}{\value{xlinecount}}
\addtocounter{ctrx}{1}
\RotateAndGo[0]{\thectrx}{0in}{-1in} % first line here is # 4
\addtocounter{ctrx}{1}
\RotateAndGo[-90]{\thectrx}{0in}{-1in}
\addtocounter{ctrx}{1}
\RotateAndGo[-90]{\thectrx}{2in}{-1in+\baselineskip}
\addtocounter{ctrx}{1}
\RotateAndGo[-90]{\thectrx}{4in}{-1in+2\baselineskip}
\addtocounter{ctrx}{1}
\RotateAndGo{\thectrx}{0.in}{-4.7in}
\TypesetLines{As any dedicated reader can clearly see, the Ideal of
practical reason is a representation of, as far as I know, the things
in themselves; as I have shown elsewhere, the phenomena should only be
used as a canon for our understanding.The paralogisms of practical
reason are what first give rise to the architectonic of practical
reason.}
\tikz[remember picture,overlay] \draw[->,red, very thick] (last) -- (pic cs:\thexlinecount); % the arrow to the baseline of the last line
\newpage
% Third example********************************************
\newgeometry{textwidth=3in,showframe=false}
\renewcommand{\makenodes}{%put the lines in their place
\RotateAndGo{\thexcount}{-10pt*(\thexcount-9)*(\thexcount-9)+4in}{-1ex*\thexcount-1in} %changed <<<<<
\tikz\node[blue, inner sep=0pt,rotate=\expandafter\csname R\thexcount\endcsname, remember picture, overlay] %changed <<<<<
at ([xshift=\expandafter\csname Cx\thexcount\endcsname, yshift=\expandafter\csname Cy\thexcount\endcsname] current page.south west)
{\tikzmark{\thexcount}\usebox{\singleline}}; % typeset
}
\TypesetLines{\raggedright As any dedicated reader can clearly see, the Ideal of
practical reason is a representation of, as far as I know, the things
in themselves; as I have shown elsewhere, the phenomena should only be
used as a canon for our understanding.The paralogisms of practical
reason are what first give rise to the architectonic of practical
reason.}
\end{document}
这是一个“精简”版本,只能在自动模式下使用(即无需事先对每条线路进行单独分配)。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{tikzmark} % needed <<<<<<<<<<
\usepackage{calc}% needed <<<<<<<<<<
\usepackage[showframe]{geometry}
\newsavebox{\singleline}
\newcounter{xcount}\setcounter{xcount}{0}
\newcounter{xlinecount}
% From https://tex.stackexchange.com/a/57140/161015
\newcommand{\getlines}{% capture all lines of a paragraph and puts them in their place
\setbox\singleline\lastbox%
\ifvoid\singleline%
\noindent\ignorespaces%
\else
\unskip\unpenalty%
\begingroup\getlines\endgroup
\stepcounter{xcount}\setcounter{xlinecount}{\value{xcount}}\par
\makenodes
\fi}
\newcommand{\makenodes}{}
\newcommand{\TypesetLines}[1]{\parindent0pt\vbox{#1\par\getlines}} % load the paragraph and display the lines
\newcounter{anglex} \newlength{\Cx}\newlength{\Cy}
\newcommand{\RotateAndGo}[3][0]{% save rotation and shifts changed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
\setcounter{anglex}{#1}\setlength{\Cx}{#2}\setlength{\Cy}{#3}
}
\begin{document}
\pagestyle{empty}
% First example ********************************************
\newgeometry{textwidth=4.0cm}
\renewcommand{\makenodes}{%put the lines in their place, automatic mode
\RotateAndGo{1cm}{-0.5in*\thexcount} % only y-shift
\tikz\node[inner sep=0pt,rotate=\theanglex, remember picture, overlay, anchor= west ,draw]
at ([xshift=\the\Cx, yshift=\the\Cy] current page.south west)
{\tikzmark{\thexcount}\usebox{\singleline}}; % typeset
}
\noindent Some text spanning three lines with very nice automatic line breaks \bigskip
From \tikzmarknode{here}~HERE to the first line baseline
\TypesetLines{Some text spanning three lines with very nice automatic line breaks}
\tikz[remember picture,overlay] \draw[->,red, very thick] (here) -- (pic cs:1); % the arrow to the baseline of the first line (# 1)
\newpage
% Fourth example ********************************************
\newgeometry{textwidth=2in,showframe=false}
\renewcommand{\makenodes}{%put the lines in their place
\RotateAndGo{-10pt*(\thexcount-9)*(\thexcount-9)+3in}{-1ex*\thexcount-1in} %changed <<<<<
\tikz\node[blue, inner sep=0pt,rotate=\theanglex, remember picture, overlay] %changed <<<<<
at ([xshift=\the\Cx, yshift=\the\Cy] current page.south west)
{\tikzmark{\thexcount}\usebox{\singleline}}; % typeset
}
\TypesetLines{\raggedright As any dedicated reader can clearly see, the Ideal of
practical reason is a representation of, as far as I know, the things
in themselves; as I have shown elsewhere, the phenomena should only be
used as a canon for our understanding.The paralogisms of practical
reason are what first give rise to the architectonic of practical
reason.}
\end{document}
答案2
在 OpTeX 中,我们不需要 TikZ,因为\puttext
宏会将文本放到指定位置。段落分成单独的行的方式与此处的另一个答案类似。行被保存到框等中,\count14+1
因为\count14+2
是\count14
的最大分配数\newbox
。
\newcount\numlines
\def\putlines#1{\setbox0=\vbox{\noindent#1\par \numlines=0 \getlines}%
\putlinesA
}
\def\getlines{%
\setbox1=\lastbox
\unless \ifvoid1 \unskip\unpenalty {\getlines}
\incr\numlines
\global\setbox\numexpr\numlines+\count14=\box1
\fi
}
\def\putlinesA#1{\tmpnum=0
\ifx^#1^\else
\foreach#1,\do(##1,##2),{\incr\tmpnum\puttext##1##2{\putline\tmpnum}}
\fi
}
\def\putline{\box\numexpr\count14+}
\vglue10cm
\putlines{\hsize=10cm \lorem[1]}{(2in,2in),(3in,50pt),(11bp,22345sp)}
\bigskip\hrule\bigskip
or:
\putlines{\hsize=10cm \lorem[1]}{} % boxes are saved only
\tmpdim=0pt % all boxes are printed:
\fornum 1..\numlines \do {\hbox{\kern\tmpdim #1: \putline#1}\advance\tmpdim by5pt }
\bye