我正在写一份关于人类历史上重要数学家和物理学家生活的文档(以 plainTeX 编写)。
现在我有一个问题想解决。我需要能够可视化它们的寿命(这样读者就能知道谁是谁的同时代人/同代人)。不幸的是,我不太擅长制作 TeX 的宏。有人能给我一点提示吗?
具体来说,我想象它会这样工作:
\person{name}{surname}{year_of_birth}{year_of_death}
\person{name}{surname}{year_of_birth}{year_of_death}
...
\renderpeople
会产生(例如,巴赫和莫扎特的实例)
Bach J.S. |----------------|
Mozart A. |-----------------|
...
|----------|-----------|----------|-----------|---------|
1750 1800 1850 1900 1950 2000
主要是,如何实现线条的重新缩放,以使它们能够适应?
答案1
使用 vanilla TeX 快速破解纯 TeX。首先收集个人资料并计算一些值(最小年份、最大年份、姓名宽度),然后设置收集的个人资料,最后打印整个时间线。
\newdimen\NameWidth
\NameWidth=0pt
\newcount\MinYear
\MinYear=100000
\newcount\MaxYear
\MaxYear=-100000
\newtoks\PersonData
\PersonData={}
\newdimen\ScaleWidth
\newdimen\ScaleUnit
\newcount\TempCount
\newdimen\TickMarkWidth
\TickMarkWidth=.4pt
\newdimen\TickMarkHeight
\TickMarkHeight=8pt
\newdimen\LineWidth
\LineWidth=.4pt
\newdimen\LastYearCorr
\def\person#1#2#3#4{%
\setbox0=\hbox{\makeperson{#1}{#2}\personsep}%
\ifdim\wd0>\NameWidth
\NameWidth=\wd0 %
\fi
\ifnum#3<\MinYear
\MinYear=#3\relax
\fi
\ifnum#4>\MaxYear
\MaxYear=#4\relax
\fi
\ifnum#3>#4\relax
\errmessage{#2 #1 has negative live span, born in #3 and died in #4}%
\fi
\PersonData=\expandafter{\the\PersonData
\DoPerson{#1}{#2}{#3}{#4}%
}%
}
\def\makeperson#1#2{#1, #2}%
\def\personsep{ }
\def\renderpeople{%
\par
\divide\MinYear by 50\relax
\multiply\MinYear by 50\relax
\advance\MaxYear by 49\relax
\divide\MaxYear by 50\relax
\multiply\MaxYear by 50\relax
\ScaleWidth=\hsize
\advance\ScaleWidth by -\NameWidth
\setbox0=\hbox{$\textstyle\the\MaxYear$}%
\LastYearCorr=.5\wd0 %
\advance\ScaleWidth by -\LastYearCorr
\ScaleUnit=\ScaleWidth
\TempCount=\MaxYear
\advance\TempCount by -\MinYear
\divide\ScaleUnit by \TempCount
\ScaleWidth=\ScaleUnit
\multiply\ScaleWidth by \TempCount
\noindent
\the\PersonData
\ScaleLine
\par
}
\def\DoPerson#1#2#3#4{%
\hbox to \hsize{%
\hbox to \NameWidth{%
\makeperson{#1}{#2}%
\hfill
\personsep
}%
\hfill
\hbox to \ScaleWidth{%
\kern#3\ScaleUnit
\kern-\MinYear\ScaleUnit
\SetTickMark
\TempCount=#4\relax
\advance\TempCount by -#3\relax
\SetLine\TempCount
\SetTickMark
\hfill
}%
\kern\LastYearCorr
}%
\hskip0pt\relax
}
\def\ScaleLine{%
\hbox to \hsize{%
\hbox to \NameWidth{\hfill}%
\hfill
\hbox to \ScaleWidth{%
\TempCount=\MinYear
\SetTickYearMark
\loop
\ifnum\TempCount<\MaxYear
\SetLine{50}%
\advance\TempCount by 50 %
\SetTickYearMark
\repeat
}%
\kern\LastYearCorr
}%
\hskip0pt\relax
}
\def\SetTickYearMark{%
\hbox to 0pt{%
\hss
$\mathsurround=0pt\relax
\mathop{\vcenter{%
\hrule width \TickMarkWidth
height .5\TickMarkHeight
depth .5\TickMarkHeight
}}\limits_{\textstyle\the\TempCount}%
$%
\hss
}%
}
\def\SetTickMark{%
\hbox to 0pt{%
\hss
$\mathsurround=0pt\vcenter{%
\hrule width \TickMarkWidth
height .5\TickMarkHeight
depth .5\TickMarkHeight
}$%
\hss
}%
}
\def\SetLine#1{%
$\mathsurround=0pt\vcenter{%
\hrule width#1\ScaleUnit
height.5\LineWidth
depth.5\LineWidth
}$%
}
\person{Pachelbel}{J.}{1653}{1706}
\person{Bach}{J. S.}{1685}{1750}
\person{Mozart}{W. A.}{1756}{1791}
\person{Euler}{L.}{1707}{1783}
\renderpeople
\bye
评论:
我更喜欢 e-TeX
\dimexpr
,\numexpr
如果有的话;它们更舒服。但是除法不同,因为它们\...expr
对结果进行了四舍五入。强大的功能
pgf/TikZ
也可以在纯 TeX 中使用。
答案2
这是一个类似的 TeX 解决方案:
\input pst-grad
\input pstricks-add
\newbox\TBox
\psset{gradbegin=white,gradend=lightgray}
\catcode`\@11\relax
\def\BoxText{\@ifnextchar[\BoxText@i{\BoxText@i[3cm]}}
\def\BoxText@i[#1]#2#3#4{%
\emergencystretch=3em
\setbox\TBox\vbox{\hsize #1 #4\par}
\rput[t](#2){\psframebox[fillstyle=gradient]{\leavevmode\copy\TBox\relax}}%
\pnode(#2|0,0){A}\pnode(#2){B}
\ncline{->}{A}{B}%
\uput*{0.5cm}[-90](A){#3}%
}
\catcode`\@12\relax
\pspicture(0,0.25)(2.5,-10)
\psset{xunit=5}
\psaxes[yAxis=false,Ox=1518]{|->}(0,0)(2.5,-10)%
\BoxText[4cm]{1.1123,-5.5}{10.2.}{%
Hier muss jetzt irgendetwas hinkommen, was, weiss ich auch nicht genau}
\BoxText{.767,-2}{15.10.}{%
Hier muss jetzt irgendetwas hinkommen, was, weiss ich auch nicht genau}
\endpspicture
\pspicture(0,0.25)(2.5,-10)
\psset{xunit=5cm}
\psaxes[yAxis=false,Ox=1518]{|->}(0,0)(2.5,-10)%
\BoxText{.787,-5}{17.10.}{%
Hier muss jetzt irgendetwas hinkommen, was, weiss ich auch nicht genau}
\pnode(A){A0}
\BoxText{.767,-2}{15.10.}{%
Hier muss jetzt irgendetwas hinkommen, was, weiss ich auch nicht genau}
\uput*{1.2cm}[-90](A0){17.10.}%
\endpspicture
\bye