Tikz 将段落分成几行并将它们放在不同的位置

Tikz 将段落分成几行并将它们放在不同的位置

我对一个可以让我的生活变得轻松很多的功能有疑问。是否可以取一个段落,让 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。这样就可以从页面上的任意位置绘制箭头到任何线开头的基线。

A

手动模式

b

自动模式:线的起点遵循二次曲线。

C

\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}

d

答案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

相关内容