雾月
雾月
这家伙很懒,什么也没写!

注册于 5年前

回答
265
文章
2
关注者
26

  1. 计算宽度要用 interrupt 环境,直接在绘图环境里是不行的。
  2. blur shadow 里创建了新的绘图环境,盲猜是因为这个把原本的 bottom 图层清空了,解决办法同 1,把标题样式放到单独的绘图环境,先让它画完这部分,就不会被后面影响了。
  3. 分别在 extra unbroken/first/middle/last 里使用 /tcb/interior code 重写 interior,让 first 末尾的颜色等于 middle 开始的颜色,依此类推,但 middle 部分最好不使用渐变,因为 tcb 好像没有直接判断是否是 unbroken 还是 first-middle-last 还是 first-last,需要 hack。

我实现了 1,2。对于 3,middle 不使用渐变的情况下应该不难。

\documentclass[12pt]{ctexbook}
\usepackage{lipsum}
\usepackage[margin=2cm]{geometry}
\RequirePackage{cncolours,newtx}
\RequirePackage{etoolbox} % 判断函数
\RequirePackage{tikz,calc} %%页面样式设计核心包 %提供\pgfonlayer命令
\usetikzlibrary{cd,calc,shadows,shadows.blur,hobby,intersections, decorations.markings, decorations.pathreplacing,spy,arrows,shapes,fadings,trees,mindmap,patterns,shapes.arrows,shapes.symbols,tikzmark,shapes.geometric,graphs, quotes, angles,decorations.pathmorphing,through,shadings,backgrounds,positioning,fit,arrows.meta,shapes.misc,decorations.shapes}
\pgfdeclarelayer{background} %背景%底层
\pgfdeclarelayer{foreground} %上层
\pgfdeclarelayer{top} %顶部
\pgfdeclarelayer{bottom} %底部
\pgfsetlayers{bottom,background,main,foreground,top}
\RequirePackage[most]{tcolorbox}
\tcbuselibrary{breakable, skins,theorems,minted}

\makeatletter
\tcbset{my@basic@tcbthm/.style={detach title,}}
\newcommand{\@my@newtcbtheorem@n}[1]{\ERROR}
\newcommand{\@my@newtcbtheorem@nn}[2]{%
  \@ifundefined{#1}{\@my@newtcbtheorem{#1}{#2}}{\@my@renewtcbtheorem{#1}{#2}}}
\newcommand{\@my@newtcbtheorem}[2]{%
  \edef\my@curr@thmenvname{#1}% 它保存当前定理环境的名称
  \mytcbtheoremset{#2}%
  \NewTColorBox{#1}{ O{} O{} o }
  {my@basic@tcbthm, my@#1@tcbthmstyle, title={##2}, IfNoValueF={##3}{label={##3}}, ##1}}
\newcommand{\@my@renewtcbtheorem}[2]{\edef\my@curr@thmenvname{#1}\mytcbtheoremset{#2}}

% 键值设置
\pgfkeys{/mytcbtheorem/.is family}
\newcommand{\mytcbtheoremset}{\pgfqkeys{/mytcbtheorem}}
\mytcbtheoremset{
  name/.code=\@namedef{\my@curr@thmenvname @name}{#1}, %无效
  counter/.code=\@namedef{my@\my@curr@thmenvname @counter}{#1}\newcounter{#1}[chapter],
  % 计数器遇到subsection就会自动归零 % https://zhuanlan.zhihu.com/p/57454848#circle=on
  the counter/.code=\@namedef{the\@nameuse{my@\my@curr@thmenvname @counter}}{#1},
  autoref name/.code=\@namedef{\@nameuse{my@\my@curr@thmenvname @counter}autorefname}{#1},
  style/.code=\tcbset{my@\my@curr@thmenvname @tcbthmstyle/.style={#1}},
  thmcolor/.code=\@namedef{\my@curr@thmenvname @thmcolor}{#1}, %无效
  lemcolor/.code=\@namedef{\my@curr@thmenvname @lemcolor}{#1}, %无效
}
% 存储键值 (LaTeX3)
\ExplSyntaxOn
\cs_new_protected:Npn \mynewtheorem
   { \keyval_parse:NNn \@my@newtheorem@n \@my@newtheorem@nn }
\cs_new_protected:Npn \mynewtcbtheorem
{ \keyval_parse:NNn \@my@newtcbtheorem@n \@my@newtcbtheorem@nn }
\ExplSyntaxOff

% /* ------------------ Second theorem style overlay settings ----------------- */
%%定义标题文字长度%%
\newlength{\thmtcbtextlen}
%%设置临界长度%%
\newlength{\thmcriticstarlen}
\setlength{\thmcriticstarlen}{.6\linewidth}
%
\def\my@thm@a#1#2{%
  \begin{scope}
    \path[
      fill=#2,
      drop shadow={shadow blur steps=10,shadow xshift=-1pt, shadow yshift=-1pt,shadow blur radius=1.5pt,shadow opacity=35}
    ]
    node
    [
      append after command={
        ([xshift=-1.5*\rad]thmname.north west) to[out=0,in=180,looseness=1] ([xshift=2.5*\rad]thmname.south west) --([xshift=-\rad]thmname.south east) to[out=0,in=180,looseness=1] ([xshift=3*\rad]thmname.north east) --cycle},
      text=white,font=\bfseries,align=center,inner ysep=1.5mm,minimum height=0.6cm,right
    ]
    (thmname) at
    ([xshift=\rad,yshift=-.7*\rad]frame.north west)
    {\hspace*{10pt}#1.\ \ifdefvoid{\tcbtitletext}{}{(\itshape\tcbtitletext)}};

    %%============== 两边的阴影/折叠部分 ==============%%
    \my@thm@a@layer{#1}{#2}
  \end{scope}%
}
\def\my@thm@a@layer#1#2{%
  \begin{pgfonlayer}{bottom}
      % 左侧翅膀样式一
      % \shade[left color=#2!20, right color=#2!80!black]
      % ([xshift=-1.5*\rad]thmname.north west)
      % to[out=180, in=0] ++(-2*\rad, -\rad)
      % -| +(5*\rad,\rad)
      % -- cycle;
      % /* -------------------------------------------------------------------------- */
      % 左侧翅膀样式二:镜像翻转为向上折叠效果
      \shade[left color=#2!20, right color=#2!80!black]
      ([shift={(-.5*\rad,-\rad)}]thmname.north west)
      to[out=180, in=0] ++(-2*\rad, \rad) % 将 -\rad 改为 \rad,使其向上延伸
      -| +(5*\rad, -\rad)                 % 将 \rad 改为 -\rad,使其向下回到主体水平线
      -- cycle;
      % 右侧翅膀:完全镜像处理
      % \shade[right color=#2!20, left color=#2!80!black]
      % ([xshift=3*\rad]thmname.north east) % 注意这里起点需对应你核心代码中的 3*\rad
      % to[out=0, in=180] ++(2*\rad, -\rad) % 镜像:out 180->0, in 0->180, x -2->2
      % -| +(-5*\rad,\rad)                % 镜像:x 5->-5
      % -- cycle;
      % ===== 右翅膀按条件切换 =====
      %判断标题文字长度与临界长度的关系
      \ifdim\thmtcbtextlen>\thmcriticstarlen
        %-------- 右侧小翅膀:上下翻转版本 --------
        \shade[right color=#2!20, left color=#2!80!black]
            ([xshift=2*\rad,yshift=-1*\rad]thmname.north east)
            to[out=0, in=180] ++(2*\rad, \rad)
            -| +(-5*\rad,-\rad)
            -- cycle;
      \else
        % -------- 右侧小翅膀:原版本 --------
        \shade[right color=#2!20, left color=#2!80!black]
            ([xshift=3*\rad]thmname.north east)
            to[out=0, in=180] ++(2*\rad, -\rad)
            -| +(-5*\rad,\rad)
            -- cycle;
      \fi
  \end{pgfonlayer}
}
\def\my@thm@b#1#2{%
  \begin{scope} % <--- 添加 scope 隔离环境
    \path[fill=#2,
    % drop shadow={opacity=0.3,shadow xshift=.3pt}
    blur shadow={shadow blur steps=10,shadow xshift=-1pt, shadow yshift=-1pt,shadow blur radius=1.5pt,shadow opacity=35}
    ]
    ([xshift=-2*\rad,yshift=-5pt]frame.south east) coordinate (SE)  to[out=0,in=180] +(4*\rad,5pt+\theight) --([shift={(-\tlen+4*\rad,5pt+\theight)}]SE) to[out=180,in=0] +(-4*\rad,-5pt-\theight) --cycle;
    \begin{pgfonlayer}{bottom}
        % 左侧翅膀:镜像翻转为向上折叠效果
        \shade[left color=#2!20, right color=#2!80!black]
        ([shift={(-1.35*\tlen+\Rad,-5pt)}]frame.south east)
        to[out=180, in=0] ++(-2*\rad, \rad) % 将 -\rad 改为 \rad,使其向上延伸
        -| +(5*\rad, -\rad)                 % 将 \rad 改为 -\rad,使其向下回到主体水平线
        -- cycle;
    \end{pgfonlayer}
  \end{scope}%
}
\newcommand{\my@lemma@overlay@unbroken}[2]{
   %%============== First ==============%%
  \def\rad{7pt}%
  %%% 注意这里!
  \begin{pgfinterruptpicture}
    \settowidth{\thmtcbtextlen}{\hspace*{10pt}#1.\ \ifdefvoid{\tcbtitletext}{}{(\itshape\tcbtitletext)}}
    % \global\thmtcbtextlen\thmtcbtextlen % \my@thm@a放到interrupt环境外面就需要global
    \begin{tikzpicture}
      % 这里可能需要调整细节!
      \path[use as bounding box]([xshift=\rad]frame.north west) rectangle (frame.south east);
      \my@thm@a{#1}{#2}%
    \end{tikzpicture}
  \end{pgfinterruptpicture}
  % \my@thm@a{#1}{#2}% 把它放到单独的tikz环境里,如上
   %
   %%============== End ==============%%
   \def\tlen{1.5cm}
   \def\Rad{3.5pt}
   \def\theight{0.5cm}
  \my@thm@b{#1}{#2}
}

%% first 和 last 没在 MWE 里!
\newcommand\my@lemma@overlay@first[2]{
  \def\rad{7pt}%
  \begin{pgfinterruptpicture}
    \settowidth{\thmtcbtextlen}{\hspace*{10pt}#1.\ \ifdefvoid{\tcbtitletext}{}{(\itshape\tcbtitletext)}}
    % \global\thmtcbtextlen\thmtcbtextlen % \my@thm@a放到interrupt环境外面就需要global
    \begin{tikzpicture}
      \path[use as bounding box]([xshift=\rad]frame.north west) rectangle (frame.south east);
      \my@thm@a{#1}{#2}%
    \end{tikzpicture}
  \end{pgfinterruptpicture}
}
\newcommand\my@lemma@overlay@last[1]{
  \def\rad{7pt}%
  \def\tlen{1.5cm}
  \def\Rad{3.5pt}
  \def\theight{0.5cm}
  \my@thm@b{}{#1}
}

\mynewtcbtheorem{
  theorem={
    counter=tcbthm,
    the counter=\thesection.\arabic{tcbthm},
    autoref name=\bfseries Theorem,
    style={
      arc=0mm,breakable,enhanced,
                % 针对跨页片段的特殊处理
      extras first={
            bottom=3mm, % 第一段的底部不需要留白
        },
      extras middle={
            top=3mm,    % 中间段的顶部不需要留白
            bottom=0mm, % 中间段的底部不需要留白
        },
      extras last={
            top=0mm,    % 最后一段的顶部不需要留白
        },
      % 建议同时加入以下设置以确保彻底消除干扰
      pad at break=2mm,
      bottomsep at break=0mm,
      topsep at break=2mm,
      interior style={top color=黛绿!9 ,middle color=黛绿!6, bottom color=黛绿!3},arc=3pt,boxrule=0pt,top=6mm,bottom=5mm,
      fuzzy shadow={-0.6mm}{0.6mm}{0mm}{0.3mm}{white!50!gray},% 上
      fuzzy shadow={0.6mm}{-0.6mm}{0mm}{0.3mm}{fill=white!40!gray},%下
      opacityframe=0, opacityback=0.98,
      fontupper=\itshape,step={tcbthm},
      before pre=\smallskip, after app=\smallskip,
      overlay unbroken=\my@lemma@overlay@unbroken{Theorem\ \thetcbthm}{黛绿},
      overlay first=\my@lemma@overlay@first{Theorem\ \thetcbthm}{黛绿},
      overlay last=\my@lemma@overlay@last{黛绿},
    }
  },
}
\makeatother
\begin{document}
\chapter{Test}
\begin{theorem}[][Semidefinite vanishing theorem for vector bundle of rank $k$ (General Case)][thm:Semidefinite vanishing theorem for vector bundle of rank $k$ (General Case)]
   Let $M$ be a compact complex manifold, and assume that there exists a hermitian metric on $E$, whose curvature tensor $\Theta$ satisfies the following condition at each point of $M$.
        
   For any $\zeta\in C^r-0$, the quadratic form in $\eta,\Theta(\zeta,\eta)$, has at least $n-k_1$ positive eigenvalues and at least $k_2$ negative eigenvalues. Then 
    \[H^q(M,\Omega(S^\mu E\otimes D))=0\]
    for any $q\not\in (k_1,\ldots,k_2)$ if $\mu\geq 0$.
\end{theorem}

\begin{theorem}[][lorem lipsum]
  \lipsum[1-10]
\end{theorem}
\end{document}

\listoffigures
\goodbreak\thepage

\thepage 这行一般不能包含 typesetting material,否则它可能不会和 \listoffigures 保持在同一页。

\listoffigures
\mbox{}
\thepage

有空格是因为 \mbox{} 离开水平模式,并且有了一个空盒子,导致它后面的空格不会被忽略,从而 \thepage 前面多了个空格。加上注释符就没有空格了。当然这可能会出现不想要的空行。

xeCJKfntef 基于 ulem 实现,ulem 限制很多,不能随便加组,\zhlipsum 就有:

\NewDocumentCommand \zhlipsum { s o +o }
  {
    \group_begin:
      \IfBooleanF {#1}
        ...
  }

保存在宏里的文字一般也无法换行,见 ulem.pdf 第 5 页。
image.png

不是已经实现了吗,没懂哪里有问题,除了 label 单独一行外,也没懂一二种列表有什么区别。

enumitem 的实现,需要用 verb 的地方,在合适的地方用 \scantokens 重新扫描一下就行了(\sitem 的实现方式):

\NewDocumentCommand\sitem{+v}{\item[\scantokens{#1}]}
\newlist{mydesc}{description}{2}
\setlist[mydesc,1]{}
\setlist[mydesc,2]{style=nextline}

\begin{mydesc}
\sitem{\Verb|something|} 劳仑
\sitem{\mintinline{asy}|Rotate(pair z)|} 普桑
  \begin{mydesc}
    \sitem{wa hh} 劳仑\\ 衣
    % \item[wa hh] 也可以用
    \sitem=\Verb|\{}|= 普桑
  \end{mydesc}
\end{mydesc}

label 宽度可以自己改改。
image.png

\documentclass[fontset=fandol]{ctexart}
\ctexset{section/format+={\raggedright}}
\parindent=0pt
\begin{document}

\begingroup\ctexset{section/format+=\centering}
\tableofcontents
\endgroup

\section{aaaa}

\section{bbbb}

\section{cccc}

\section*{ddd}

\end{document}

一般情况下 \section 等命令不建议放在组中(因为它们可能为了实现某些效果会重定义 \par),但只在目录里这么做还是问题不大的,目录条目一般都会使用自定义的格式,而不像普通段落那样。

listing 环境就是一个浮动体,tcolorbox 自己就有对应的功能,没必要再套一个浮动环境,tcolorbox 也不能用 beforeafter 随便套一个环境。\label 也有对应的选项。

如果只要给代码添加目录,无需使用浮动体。要改目录条目的样式只要重定义 \l@tcolorbox 即可(\renewcommand\l@tcolorbox[2]{\@dottedtocline{1}{1.5em}{2.3em}{#1}{#2}}),见 tcolorbox 文档 5.2 节 /tcb/new/list type 选项的说明。

\documentclass[UTF8]{ctexbook}
%代码排版
\usepackage{tcolorbox}
\tcbuselibrary{minted,breakable,hooks}
\newtcblisting[auto counter,list inside=abMATLABlist]{abMATLAB}[3][]{%
    coltitle=black,
    colbacktitle=white,
    colupper=black,
    colback=white,
    boxrule=0pt,
    toprule=0.08em,
    titlerule=0.05em,
    bottomrule=0.08em,
    fonttitle=\bfseries,
    title={\heiti 代码列表 \thetcbcounter: #2},
    listing only,
    sharp corners=all,
    minted language=matlab,
    label={#3}, % \label    %% <--
    float=htbp!, % 浮动环境  %% <--,如果代码不要浮动,删掉这行
    #1,
}

\begin{document}
\tableofcontents
\tcblistof[\chapter*]{abMATLABlist}{MATLAB 代码}
%\tcblistof[\section*]{abMATLABlist}{MATLAB 代码}
%\begin{abMATLAB}{拉普拉斯展开计算行列式}{abMATLABlist:DetLaplace}

%\end{abMATLAB}
\chapter{AAA}

\begin{abMATLAB}{拉普拉斯展开计算行列式}{abMATLABlist:DetLaplace}
function d=DetLaplace(A)
% DETLAPLACE 使用 Lapace 展开计算行列式
% d = DetLaplace(A); 计算矩阵 A 的行列式 (determinant)
% 对第一行 (row) 使用 Laplace 展开 (expansion)
n = length(A);
if n==1
    d=A(1,1);
else
    d=0; v=1;
    for j=1:n
        M1j = [A(2:n,1:j-1) A(2:n,j+1:n)];
        d = d + v*A(1,j)*DetLaplace(M1j);
        v = -v;
    end
end
\end{abMATLAB}
\end{document}

至于 \chapter 前面那个例子可以编译,可能是某个奇怪的 bug,不去管就行了。

\documentclass{article}
\usepackage{ctex,lipsum}
\usepackage[most]{tcolorbox}
\usepackage{geometry}
\geometry{a4paper,left=2.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm}

\makeatletter
\ExplSyntaxOn
\cs_new_protected:Npn \@Line@check@last
  {
    \int_case:nnTF { \tex_lastnodetype:D }
      {
        { 11 } { \tl_put_left:Ne \@Line@save { \vskip\the\lastskip\relax } \unskip }
        { 12 } { \tl_put_left:Ne \@Line@save { \kern\the\lastkern\relax } \unkern }
        { 13 } { \tl_put_left:Ne \@Line@save { \penalty\the\lastpenalty\relax } \unpenalty }
      }
      { \@Line@check@last }
      { \tl_set:Ne \@Line@last@type { \int_value:w \tex_lastnodetype:D } }
  }
\cs_new:Npn \@Line@is@print@number
  {
    \int_case:nnTF { \@Line@last@type }
      {
        { -1 } {}
        { 0 } {}
        { 1 } {}
        { 9 } {}
      }
      { 1~ } { 0~ }
  }
\ExplSyntaxOff

\newsavebox\linebox
\newcommand{\@Line@Number}{%
    \def\@line@no{0}
    \def\@Line@save{\nointerlineskip}%
    \def\@Line@last@type{-1}%
    \setbox\linebox\lastbox%
    \ifvoid\linebox%如果行文字盒子为空则什么都不执行
      \relax%
    \else%
      \@Line@check@last
      {\@Line@Number}%
      \@Line@save
      \ifcase\@Line@is@print@number\else
        \xdef\@line@no{\number\numexpr\@line@no+1\relax}%
        \ifnum\numexpr(\@line@no/5)*5=\@line@no\relax%判断行号能否被5整除
          \noindent\llap{\mbox{\@line@no\hskip7.5mm\relax}}%
        \else%
          \ifnum\@line@no=1%判断行号是否等于1
            \noindent\llap{\mbox{\@line@no\hskip7.5mm\relax}}%
      \fi\fi\fi
      \box\linebox\par
    \fi}
\makeatother

\begin{document}

    \makeatletter
    \noindent 不含行间公式
    \begin{tcolorbox}[breakable]
        \lipsum
        \par\@Line@Number
    \end{tcolorbox}
    
    \clearpage
    \noindent 含行间公式
    \begin{tcolorbox}[breakable]    
    \lipsum[1]
    \begin{align}% 不能用 equation 和 $$
    \int_\Omega x^2{\rm d}V=\frac{1}{5}
    \end{align}
    \lipsum[2-8]
    \par\@Line@Number
    \end{tcolorbox}
    \makeatother

\end{document}

默认就是不打印显式空格,不过某些字体下,LaTeX 会把字符码为 32,类别码为 12 的字符显示为非空白。

新版本里,我修改了实现,可以更新一下(只需更新 texhigh.sty 这个文件)。但是这个问题始终是和字体有关的。

提到的 texhigh 已经设置 \THSetCharReplacement{\ }{\textvisiablespace} 就是字面意思,这是设置字符要被替换为哪些代码,它只设置而不启用,要靠 char-replacements 键来启用。

texhigh 还额外设置了 \raggedright,所以一般是靠左而不是默认分散的,可以设置 font=\ttfamily 移除这个,也可使用 ragged2e 宏包的 \justifyingfont+=\justifying
image.png

其它问题可以参考 Sagittarius Rover 的回答。

@u70550 说的很对,仓库里有中文文档

texhigh 是高亮 TeX 代码的宏包,也可以用来输出颜文字等(实验性质的)。

需要首先安装 texhigh 命令行工具到指定位置:
执行 kpsewhich --var-value SELFAUTOLOC,得到一个路径,然后在 https://github.com/Sophanatprime/texhigh-rs/releases 下载以 texhigh-x86... 开头的对应操作系统的压缩文件(比如 Windows 是 texhigh-x86_64-pc-windows-msvc.zip),将其解压缩后复制到刚才得到的路径中(比如把 texhigh.exe 复制到 D:/texlive/2025/bin/windows)。然后执行 texhigh -V 可以得到版本信息(比如 texhigh 0.4.0),否则就是安装出错了。

然后执行 kpsewhich --var-value TEXMFLOCAL 得到一个路径,再将 https://github.com/Sophanatprime/texhigh 仓库里的 texhigh.stytexhigh.prelude.ths 复制到这个路径中:$TEXMFLOCAL/tex/latex/texhigh$TEXMFLOCAL 就是刚才执行 kpsewhich --var-value TEXMFLOCAL 得到的路径,如何没有对应的路径可以直接创建,比如创建 D:/texlive/texmf-local/tex/latex/texhigh,把这两个文件复制到这个路径即可)。然后再执行 texhash 刷新缓存即可。

总之,安装就是复制文件到指定的路径中,比较简单,不过需要确保命令行工具的版本和宏包版本一致,一般情况下,只要仓库不是刚刚更新,同一时间下载到的版本都是一致的。

然后就和使用其它宏包,比如 minted 是一样的了。

\documentclass{article}
\usepackage[tikz]{texhigh}

\begin{document}

\texhighverb|\hello, \LaTeX|.

\texhighverb[use-ctab=latex3]|\latex_hello:|.

\texhighverb[style=tikz.gradient]|\relax|.

\end{document}

执行 xelatex --shell-escape main.tex(其它引擎也可以,--shell-escape 是必要的)。
image.png

更详细的用法可以参考文档例子以及我写的一个显示TikZ图形和代码的例子

\documentclass{article}
\usepackage{showframe}
\newenvironment{abc}{\par}{\par}
\newcommand\NoindentNextPara{\AddToHookNext{para/begin}{\OmitIndent}}
\begin{document}
text1\par
text2\NoindentNextPara
\begin{abc}
abc
\end{abc}
text4\par
text5
\end{document}

image.png

https://bithesis.bitnp.net/faq/biber-perl-cache.html

image.png

LaTeX Workshop 可以设置环境变量。修改用户设置,biber 命令的环境变量改为:

"latex-workshop.latex.tools": [
        {
            "name": "biber",
            "command": "biber",
            "env": {
                "TEMP": "%WORKSPACE_FOLDER%",
            },
            "args": [
                "%DOCFILE%"
            ]
        },
        ....
]

最简单的办法是加上这行

\pgfkeys{...
  /mycmd/.search also={/tikz}, % <- 自动找 /tikz/...
}
\documentclass{article}
\usepackage{tikz}

\pgfkeys{%
  /mycmd/.is family,
  /mycmd/.cd,
  /mycmd/.search also={/tikz},
  default/.style={color=black},
  color/.store in = \mycmdcolor,
}

\pgfkeys{%
  /tikz/mycmd/.code args={#1}{%
    \pgfkeys{/mycmd, default, #1}
    \pgfkeysalso{color=\mycmdcolor,}
  }
}

\newcommand{\mydraw}[1][]{%
\draw[mycmd={#1}] (0,0) -- (4,0); }

\begin{document}
\begin{tikzpicture}
  \mydraw[color=blue, line width=1mm]
\end{tikzpicture}
\end{document}

\documentclass[tikz,border=5pt]{standalone}
\usepackage{tkz-euclide}

\ExplSyntaxOn\makeatletter
\pgfmathdeclarefunction{pointveclen}{3}{
  \begingroup
  \tikz@scan@one@point\pgfutil@firstofone(#1)\relax
    \pgf@xx\pgf@x \pgf@xy\pgf@y
  \tikz@scan@one@point\pgfutil@firstofone(#2)\relax
    \pgf@yx\pgf@x \pgf@yy\pgf@y
  \pgfmathparse{veclen(\the\pgf@xx+#3\the\pgf@yx,\the\pgf@xy+#3\the\pgf@yy)}
  \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\NewDocumentCommand\tkzAutoLabelPolygons{O{} r()} {
  \group_begin:
  \seq_gclear:N \g_tmpa_seq
  \foreach \x in {#2} { \seq_gput_right:Ne \g_tmpa_seq { \x } }
  \seq_get_left:NN \g_tmpa_seq \l_tmpa_tl
  \seq_get_right:NN \g_tmpa_seq \l_tmpb_tl
  \seq_gput_left:NV \g_tmpa_seq \l_tmpb_tl
  \seq_gput_right:NV \g_tmpa_seq \l_tmpa_tl
  \int_step_inline:nnn { 2 } { \seq_count:N \g_tmpa_seq - 1 }
    {
      \seq_gpop_left:NN \g_tmpa_seq \l_tmpa_tl
      \tl_set:Ne \l_tmpb_tl { \seq_item:Nn \g_tmpa_seq { 1 } }
      \tl_set:Ne \l_tmpc_tl { \seq_item:Nn \g_tmpa_seq { 2 } }
      \pgfinterruptboundingbox
      \coordinate (tempa) at ($1cm/pointveclen("\l_tmpa_tl","\l_tmpb_tl","-")
        *($(\l_tmpa_tl)-(\l_tmpb_tl)$)$);
      \coordinate (tempb) at ($1cm/pointveclen("\l_tmpc_tl","\l_tmpb_tl","-")
        *($(\l_tmpc_tl)-(\l_tmpb_tl)$)$);
      \coordinate (tempc) at ($0.3*1cm/pointveclen("tempa","tempb","+")
        *($(tempa)+(tempb)$)$);
      \endpgfinterruptboundingbox
      \path (\l_tmpb_tl) -- ($(\l_tmpb_tl)-(tempc)$)
        node[label~style,anchor=center,#1] {$\l_tmpb_tl$};
    }
  \group_end:
}
\ExplSyntaxOff\makeatother

\begin{document}

\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 3/0/C, 2/4/D, 0/5/E,-3/2/F}  
  \tkzDrawPolygons[thick](A,...,F)
  \tkzAutoLabelPolygons(A,...,F)
\end{tikzpicture}

\begin{tikzpicture}
  \tkzDefPoints{-1/-1/A, 1/-2/B, 0.5/0/C, 2/4/D, 0/5/E,-3/2/F}
  \tkzDrawPolygons[thick](A,...,F)
  \tkzAutoLabelPolygons(A,...,F)
\end{tikzpicture}

\end{document}

image.png

见 The TeXBook 第 258 页(2021 年版),The LaTeX Companion 第三版 5.3.4、5.3.5 节。

TeX 遇到某些内容和输出这些内容所在的页码并不一定相同,比如,TeX 在准备第 5 页所需的内容时遇到太多文字,直到第 5 页输出完成后才能知道哪些文字是多余的,然而它们是在第 5 页中发现的,却并不是在第 5 页输出的,这就存在某些问题,比如假如这些多出来的文字中获取了 page 计数器的值,由于它在第 5 页中执行,得到的结果是 5,而不是 6。TeX 为了解决这个问题提供了几个方案,一个是把要获取的这些值延迟到页面输出完成之后再获取,另一个就是 mark 机制。

firstmark 就是输出的那一页最开始遇到的 mark,botmark 就是最后遇到的 mark,topmark 就是上一页的 botmark。最开始的 TeX 只有一个 mark 类,e-TeX 扩展为了 32767 个。

如果你用 LaTeX 2022-06-01 及之后的版本,那么 LaTeX 提供了 \FirstMark \LastMark \TopMark,并且不但能获得当前页的,还能获得上一页、当前栏、上一栏的。建议使用这些命令。如果用的是 2025-06-01 的版本,还能获得 multicols 每一栏的 marks。

不过,如果 marks 出现在其它盒子中,那么 TeX 无法正确更新,可以用我写的 updatemarks 宏包。

发布
问题