Files
ouc_latex_template/试卷/oucexam.sty
T
laoyang 93b03c8a78 试卷字体统一为思源宋体 #20
用户要求:「试卷的字体,需要改一下,全部都用思源宋体就可以了。」

pymupdf 提取两份成品 PDF 定位到四类需要统一的字体:

  试卷题型示例(6 页)            参考答案与评分标准示例(3 页)
  OUCSerif-Regular 203 中文        OUCSerif-Regular 333 中文
  TeXGyreTermes-Regular 133 西文   TeXGyreTermes-Regular 197 西文
  TeXGyreTermes-Bold 85 题号分值   OUCSans-Regular 37 黑体小标题
  OUCSerif-Bold 81 中文加粗         CMR10/CMMI10/CMSY10 49 数学公式
  OUCKai-Regular 25 卷头与成绩表    TeXGyreTermes-Bold 21 数字

一、西文与数字:Termes → 思源宋体(oucexam.sty / ouckey.sty)

先在包里用 \newfontfamily 登记 \OUCLatinSerif / \OUCLatinSerifBold
(四个档位全给,斜体指回 Regular —— 思源宋体没有真斜体),再把
\tnr / \tnrb / \sunfont 都 \let 过去。

⚠️ 只做这一步**不够**,这点踩了一轮:模板里大量文字根本没走 \tnr,
而是走 \setmainfont(默认西文族)——\textbf{learning outcome} 的裸西文、
页脚的页码与总页数、任何 \selectfont 之后的裸 ASCII。
第一轮只 \let 时,PDF 里仍残留 22 个 TeXGyreTermes span:
页脚 6 个页码 + 6 个总页数 + 第 4 页的 A./B./C./D. 与 learning outcome 等。
⇒ 必须连 \setmainfont / \setsansfont 一起指到 OUCSerif。

二、卷头与成绩表题号:霞鹜文楷 → 思源宋体(oucexam.sty)

\kh 与 \scoretable 用 \kaiti。包里 \let\kaiti\songti 一次性收口,
不动 ../fonts.tex 的 \def\kaiti —— 别的模板还要用楷体。

三、答案卷黑体小标题:思源黑体 → 思源宋体(ouckey.sty)

\heiti 共 37 处(卷头大标题与各节小标题)。同样 \let\heiti\songti。

四、数学公式:保持不动

$x$ / $\dfrac{1}{45}\sum f_i x_i$ 等 49 处仍走 Computer Modern。
思源宋体没有 MATH 表(实测只有 GSUB/GPOS),不能作数学字体;
强行塞进正文字体会破坏斜体变量、正体数字、运算符间距。用户已确认。

五、装订线虚线:连字符排字 → 用线画(oucexam.sty)

原卷那 6 段竖虚线是 18bp Times 连字符排出来的。换成思源宋体后连字符
每个宽 0.346 em(Termes 0.333),每串会长 4~7bp,破坏"复刻原卷长度"。
⇒ 改为几何画的短横线段,长度锁死。实测原卷(720dpi 逐笔画测量):
  单个连字符笔画 长 4.40bp、粗 1.10bp、x 中心 51.60bp
  相邻笔画步距 6.00bp
新增 \ouc@dashseg{起点y}{笔画数},六段坐标与笔画数逐段照抄原卷
(含原卷被白底遮断成 13+3 两截的那一段)。
⚠️ \newcommand 必须定义在 \ouc@dobindstrip 外面,否则每次 shipout
重新定义,第二页起报 already defined。
⚠️ y 坐标不能写 \dimexpr#1bp+\i*6bp —— TikZ 坐标解析器不认小数 +
\dimexpr 组合,报 Illegal unit of measure。要先 \pgfmathsetmacro。

六、直引号归入 CJK(ouckey.sty)

答案卷正文用 ASCII 直引号 "" 表示中文引号(32 处)。U+0022 在
Basic Latin,xeCJK 判为西文 ⇒ 引号走 \setmainfont,与两侧汉字不同字体,
并挤压出 Overfull(第 88 行 +8.07pt)。
\xeCJKDeclareCharClass{CJK}{"0022} 归位后解决。
⚠️ 不在 fonts.tex 里改:那里全库共用,会让正文真正的英文引号(代码
   片段 "hello world")也变全角。

七、Overfull 的修法:改源码断行,不调参数(ouckey.sty 留有完整记录)

换字体后 \keyitem{3}{4} 那段 Overfull 2.61pt,实际压出版心
(最右 527.01bp,版心止于 524.41)。试过并确认**全部无效**的五种:
  · \emergencystretch 1.5em —— 本行没有弹性胶可拉,无从施展
  · \tolerance 3000 —— 不是不满意断点,是没有更早的合法断点
  · PunctStyle=kaiming —— 能消 Overfull,但标点悬挂探出版心 6.5bp
  · PunctStyle=quanjiao —— 同样探出 8bp
    (xeCJK 这几个 PunctStyle 做的是"标点悬挂"不是"标点压缩",
      指望它消 Overfull 必翻车)
  · \rightskip 0pt plus 6bp(含 \AtBeginDocument 版)—— 6bp 远小于
    需要的 150bp,TeX 仍选"撑破"这个解
正解:第 124 行句号「。」后加 \\。分项给分的答案本来就该一句一行,
读者靠句号扫分点 —— 既解决排版,又让内容结构更清楚。

验证(两套环境各跑,逐项同数)

  WSL / TeX Live 2025    试卷 rc=0 err=0 over=0 6页
                         答案卷 rc=0 err=0 over=0 3页
  Windows / TeX Live 2022 试卷 rc=0 err=0 over=0 6页
                         答案卷 rc=0 err=0 over=0 3页

pymupdf 提取字体分布:

  试卷题型示例      OUCSerif-Regular 291 + OUCSerif-Bold 70
                    → 非宋体文字字体:无
  参考答案示例      OUCSerif-Regular 235 + OUCSerif-Bold 53
                    + CMR10/CMMI10/CMSY10/CMMI7/CMEX10(数学,保留)
                    → 非宋体文字字体:无

几何核对(逐 span 比对,均与基线一致或更优):
  · 成绩表 17 栏逐字符坐标与基线**完全相同**(硬编码坐标,不受字体影响)
  · 装订线 96 笔全部绘出:x 49.40~53.60(宽 4.40bp)、步距 6.00bp,
    六段位置与原卷实测一致
  · 三页最右墨迹均为 524.41bp,与版心严丝合缝,无越界
  · 试卷 6 页最右最大 523.33bp(第 4 页 \mtpair 的 44% 栏宽设计,
    基线同位置同样数值,非本次引入)

涉及文件:
  试卷/oucexam.sty                 默认族、西文字族、\kaiti、装订线虚线
  试卷/ouckey.sty                  默认族、西文字族、\heiti、直引号、踩坑记录
  试卷/参考答案与评分标准示例.tex  第 124 行句号后加断行
2026-10-29 21:29:15 +08:00

854 lines
44 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
%======================================================================
% oucexam.sty — 中国海洋大学 期末考试试卷 版式包
% 依据:数字逻辑 2025 秋 B 卷(195mm × 270mm 专用试卷纸)
% 所有尺寸单位 bp(PDF 点,1bp = 1/72in),与原卷 PDF 逐项对齐
%
% 用法见同目录 example-数字逻辑B卷.tex
%======================================================================
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{oucexam}[2026/10/21 v1.0 OUC exam paper layout]
\RequirePackage{geometry}
\RequirePackage{fontspec}
\RequirePackage{xeCJK}
\RequirePackage{tikz}
\RequirePackage{graphicx}
\RequirePackage{eso-pic}
\RequirePackage{lastpage}
\RequirePackage{keyval}
\RequirePackage{ragged2e} % \justifying:原卷第3页设计题是两端对齐
\usetikzlibrary{calc}
%======================================================================
% 1. 页面版心
% 195mm × 270mm;左边距 29mm(装订侧),版心宽 154mm
% 版心上边界 34.13bp;首行基线落在 46.13bp
%======================================================================
\geometry{
paperwidth = 195mm,
paperheight = 270mm,
left = 82.2bp,
textwidth = 436.55bp,
top = 34.13bp,
textheight = 665.87bp,
headheight = 0pt,
headsep = 0pt,
footskip = 0pt,
}
\setlength{\parindent}{0pt}
\setlength{\parskip}{0pt}
\setlength{\topskip}{12bp} % 首行基线 = 34.13 + 12 = 46.13bp
\pagestyle{empty}
\raggedright % 左对齐,右端不拉伸(与原卷一致)
% 注意:ctexart 会在 \begin{document} 时把 \linespread 设为 1.3,
% 必须用同一钩子(后注册者后执行)压回 1,否则基线网格全乱。
\AtBeginDocument{\linespread{1}\Fivhao\selectfont}
%======================================================================
% 2. 字体(#20:全部统一为思源宋体)
% 全部取自仓库公共字体包 ../fonts.tex(字体文件在 ../fonts/ 下)。
%
% ★ 本版把试卷的所有文字统一为**思源宋体(OUC Serif)**,中西文同一字族:
% 中文正文 / 标题 OUC Serif(真粗体,不再 AutoFakeBold)
% 西文 / 阿拉伯数字 OUC Serif ✅ 与中文同族(本版改动)
% 卷头三行填空 OUC Serif ✅ 原为霞鹜文楷
% 成绩表"题号/得分/一~八/总分" OUC Serif ✅ 原为霞鹜文楷
%
% ⚠️ 为什么西文也能用思源宋体
% 已实测 OUCSerif-Regular.otf / -Bold.otf:13714 字形、cmap 7555 条,
% ASCII 字母数字与常用标点 35/35 全部命中。它不是纯中文字体,
% 西文字形是配套设计的,与汉字同灰度 —— 这正是要的效果。
%
% ⚠️⚠️ 与 Termes 的度量差异(换字体必然推动版面,别当回归)
% 旧版西文用 TeX Gyre Termes(Times 度量)。原卷 SimSun 的西文是
% 全 ASCII 0.500 em 等宽,Termes 的数字也是 0.500 em,所以选它能让
% 数字零漂移。思源宋体的西文**不是等宽**,比 Termes 宽:
% 数字 0-9 0.549~0.562 em (+0.049~+0.062)
% 小写 m 0.974 vs 0.778 (+0.196,最明显)
% 小写 b 0.638 vs 0.500 (+0.138)
% 句点 . 0.327 vs 0.250 (+0.077)
% 连字符 - 0.346 vs 0.333 (+0.013)
% 影响:题号、分值、页码右移约 6%,题干里的英文单词变长。
% 这是用户明确要求"全部用思源宋体"的必然代价,已确认接受。
%
% ⚠️ 装订线的 4 组连字符虚线已改为**用线画**(见第 6 节),
% 不再受字体宽度影响。旧版是靠 18bp 连字符排出来的,
% 换字体后每串会长 4~7bp,故锁定为几何坐标。
%
% ⚠️ 数学公式**不在统一范围内**(答案卷的 $x$、$\dfrac{}{}$ 等仍走
% Computer Modern)。理由:思源宋体没有 MATH 表(实测只有
% GSUB/GPOS),不能作数学字体;强行塞进正文字体会破坏斜体变量、
% 正体数字、运算符间距这些数学排版规则。用户已确认保持不动。
%======================================================================
\input{../fonts.tex}
%----------------------------------------------------------------------
% 西文字族:把思源宋体登记成一个**独立字族** \OUCLatinSerif
%
% 为什么不直接把 \tnr 改成 \setmainfont 指过去:
% ① ../fonts.tex 是**全库共用**的,改它的 \tnr 会连带改掉科技报告和
% 简历 —— 那两个模板有自己的西文设定(Cochineal / Termes),不该外溢。
% ② 试卷需要的是"西文也用宋体",这在排版上是**回到中文字体的西文字形**,
% 本质是让西文跟 CJK 主字体一致,而不是"换一套西文字体"。
% 所以在试卷包内单独登记一族,只改本包的命令指向。
%
% ⚠️ 用 \newfontfamily 而不是 \setCJKfamilyfont:这里要的是西文字族,
% 走 fontspec 的 Latin 通道;中文由 \setCJKmainfont 那边管,互不干扰。
% ⚠️ 四个档位必须全给。少给会在 \bfseries 里静默回落到默认字体,
% 表现为"加粗失效"而不是报错(试卷的 \TNRB / \qnum / 大题标题都会踩到)。
% ⚠️ 斜体档:思源宋体没有真正的意大利斜体(只有 Regular / Bold 两档)。
% 这里让 Italic 指回 Regular、BoldItalic 指回 Bold —— 即"中文式斜体"
% (不倾斜)。本模板正文没有 \textit / \emph 用法,此设定只是防止将来
% 有人用了就报 Font shape undefined。真要斜体请用 \kaiti 代斜的惯例。
%----------------------------------------------------------------------
\newfontfamily\OUCLatinSerif{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
% 粗体专职档:与 \tnrb 的语义一致("取粗体那一字形当常规用")。
% \TNRB{} 用它,保证括号、分值数字是真的粗,而不是靠 AutoFakeBold 描边。
\newfontfamily\OUCLatinSerifBold{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Bold,
BoldFont = *-Bold,
ItalicFont = *-Bold,
BoldItalicFont = *-Bold,
]
%----------------------------------------------------------------------
% 把**默认西文字体**也换成思源宋体(这是关键一步)
%
% ⚠️⚠️ 只重定向 \tnr / \tnrb 是**不够**的,这一点踩过:
% 模板里有大量文字**根本没走 \tnr**,而是走 \setmainfont(默认西文族):
% · \textbf{learning outcome} —— 裸加粗,西文走 \setmainfont
% · 页脚的页码 / 总页数 —— \node{...\thepage} 裸排
% · 任何 \fontsize..\selectfont 之后的裸 ASCII
% 第一轮只做了 \let\tnr\OUCLatinSerif,结果 PDF 里仍残留 22 个
% TeXGyreTermes span:页脚 6 个页码 + 6 个总页数 + 第 4 页的
% A./B./C./D. 与 learning outcome 等。
% ⇒ 必须连 \setmainfont 一起改,才算"全部用思源宋体"。
%
% ⚠️ 为什么可以安全地在这里 \setmainfont:
% 本包由试卷/答案卷各自的 .tex \usepackage 载入,\setmainfont 只影响
% 当前文档。其他模板(科技报告/简历/幻灯片)各自 \input ../fonts.tex
% 并各自设主字体,互不干扰。
%
% ⚠️ 四个档位必须全给。缺斜体档时 \textit 会报
% Font shape `TU/OUCSerif(0)/m/it' undefined 并静默回落。
% 思源宋体没有真斜体,这里让 it 指回 Regular(中文式斜体,不倾斜)。
%----------------------------------------------------------------------
\setmainfont{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
% sans 位也指到思源宋体:本试卷没有真正的 sans 用法,但 \textsf 之类的
% 兜底也应该是宋体,不能漏回 Termes。sans 位不加粗体档,用 Regular 顶上。
\setsansfont{OUCSerif}[
Extension = .otf,
Path = ../fonts/ouc-serif/,
UprightFont = *-Regular,
BoldFont = *-Bold,
ItalicFont = *-Regular,
BoldItalicFont = *-Bold,
]
%----------------------------------------------------------------------
% 把本包内的字体命令全部重定向到思源宋体
%
% ⚠️ \let 是一次性绑定:绑完再改 \tnr 的定义,\tnr 仍指旧目标。
% 这里 \let 到 \OUCLatinSerif 是**有意为之** —— 让 \tnr / \tnrb 与
% \setmainfont 走同一族,但保持两个独立命令名,因为 \tnrb 是
% "取粗体当常规用"(\TNRB 需要),与 \bfseries 语义不同。
%----------------------------------------------------------------------
\let\tnr\OUCLatinSerif
\let\tnrb\OUCLatinSerifBold
% \sunfont 原指 SimSun("宋体西文"占位),现一并指思源宋体。
% 保留命令名是为了不动 \qnum / \logicexpr / \sumsig 等所有调用点。
\let\sunfont\OUCLatinSerif
% \kaiti 在试卷里只用于卷头填空与成绩表题号(见 \kh / \scoretable)。
% #20 要求统一为思源宋体,故整个包内把 \kaiti 也指到思源宋体。
% ⚠️ 用 \let 而不是改 \def\kaiti —— 后者会破坏 ../fonts.tex 的定义,
% 而 \kaiti 在别的模板里还要用楷体。
% ⚠️ 若将来要恢复楷体卷头,把下面这行注释掉即可,其余代码不用动。
\let\kaiti\songti
%----------------------------------------------------------------------
% ⚠️ xeCJK 陷阱:字体切换命令若紧邻 \par(或位于段落末尾),
% 该段结束时的字体状态会"溢出"到后续段落,导致后面的 ASCII
% 字符全部被排成 Times(实测:\tnr{ABC}\par 会让下一段的 "3" 变 Times)。
% 故所有局部字体切换一律走下面两个包装:内部显式 \normalfont 收尾。
% ⇒ 正文中请用 \TNR{...} / \TNRB{...} / \SUN{...},不要裸用 \tnr。
%----------------------------------------------------------------------
\newcommand{\TNR}[1]{{\tnr #1\normalfont}}
\newcommand{\TNRB}[1]{{\tnrb #1\normalfont}}
\newcommand{\SUN}[1]{{\sunfont #1\normalfont}}
% Word「字符间距展开」模拟:逐字之间插入固定胶
% \spreadtext{0.30}{文字} —— 0.30bp 即 10.50→10.80bp 的步距
% 实现:先输出首字,再对余下每个字"先插空隙、后出字"(首字前不插,否则整体右移)
\newcommand{\spreadtext}[2]{%
\begingroup\spread@amt=#1bp\relax
\expandafter\@spreadtext#2\@nil\endgroup}
\newdimen\spread@amt
\def\@spreadtext#1#2\@nil{#1\@spreadeach#2\@nil}
\def\@spreadeach#1{%
\ifx#1\@nil\else\hspace*{\spread@amt}#1\expandafter\@spreadeach\fi}
% 中文与西文间自动间距:原卷实测固定 2.70bp(不随字号缩放,
% 故用绝对 bp 而非 em;原卷 10.5bp 与 12bp 处均为 2.7bp)
\xeCJKsetup{CJKecglue={\hskip 2.70bp\relax},PunctStyle=plain}
%======================================================================
% 3. 字号(bp,直接对应原卷)
%======================================================================
\newcommand{\Fivhao}{\fontsize{10.5bp}{15.6bp}\selectfont} % 五号 正文(原卷 10.5bp)
\newcommand{\Sihao}{\fontsize{12bp}{15bp}\selectfont} % 小四 大题
\newcommand{\DaSihao}{\fontsize{14.05bp}{16bp}\selectfont} % 四号 卷头
\newcommand{\Xiaowu}{\fontsize{9bp}{11bp}\selectfont} % 小五 图题
\AtBeginDocument{\Fivhao}
%======================================================================
% 4. 卷头参数
%======================================================================
\def\ouc@year{}\def\ouc@term{}\def\ouc@course{}\def\ouc@college{}
\def\ouc@type{}\def\ouc@proposer{}\def\ouc@reviewer{}
\def\ouc@mode{}\def\ouc@allowed{}
\define@key{ouc}{year}{\def\ouc@year{#1}}
\define@key{ouc}{term}{\def\ouc@term{#1}}
\define@key{ouc}{course}{\def\ouc@course{#1}}
\define@key{ouc}{college}{\def\ouc@college{#1}}
\define@key{ouc}{type}{\def\ouc@type{#1}}
\define@key{ouc}{proposer}{\def\ouc@proposer{#1}}
\define@key{ouc}{reviewer}{\def\ouc@reviewer{#1}}
\define@key{ouc}{mode}{\def\ouc@mode{#1}}
\define@key{ouc}{allowed}{\def\ouc@allowed{#1}}
\newcommand{\examsetup}[1]{\setkeys{ouc}{#1}}
%----------------------------------------------------------------------
% 页脚是否印"试卷类型字母"(课程名之后那个 A / B)
%
% ★ 原卷实测:A 卷页脚【没有】字母(数字逻辑 + 一串短横线),
% B 卷页脚【有】B(392.48 处)。
% 即:这是出卷人手工敲的,不是规则。故默认不印,需要时显式打开:
% \examsetup{foottype = {B}} → 页脚印 B
% \examsetup{foottype = {}} → 页脚不印(默认)
%----------------------------------------------------------------------
\def\ouc@foottype{}
\define@key{ouc}{foottype}{\def\ouc@foottype{#1}}
%======================================================================
% 5. 页脚:+…………………………课程名称 X……… 第 N 页 共 M 页 + 基线 713.33bp
%
% 本地实测(原卷字符级):
% 82.20 '+' | 91.20~343.20 连续 29 个 '…'(每个步距 9.00)
% 352.20 起课程名(长度不定)| 类型字母在 390.48
% 396.48 起 3 个 '…' | 432.48 '第' | 443.64 页码 | 448.20 '页'
% 461.64 '共' | 472.92 总页 | 477.48 '页' | 499.92 '+'
%
% ★ 课程名长度可变,前面那串圆点必须"自动伸缩":
% · 课程名 ≤ 36bp(4 个汉字)→ 左锚保持 352.20,点区 29 个点(与原卷一致)
% · 课程名更长 → 左锚左移,点区自动缩短(这就是用户要的"按名称长度缩减")
% 点区终点固定在左锚前 3bp,绝不与课程名重叠。
%======================================================================
\newbox\ouc@dotbox
\newdimen\ouc@cnw
\newdimen\ouc@cstart
\newdimen\ouc@fw
\newdimen\ouc@tstart
\newdimen\ouc@tfw
% 测课程名宽度 -> 定左锚 -> 定点区宽度(shipout 时执行,读的是 \ouc@course)
\newcommand{\ouc@prepfooter}{%
\setbox\ouc@dotbox\hbox{\fontsize{9bp}{9bp}\selectfont\ouc@course}%
\ouc@cnw=\wd\ouc@dotbox
\ifdim\ouc@cnw>36bp
% 偏长:右端钉在 388.20,向左生长(点区自动变短)
\ouc@cstart=\dimexpr 388.20bp-\ouc@cnw\relax
\else
% 不长:用原卷锚点(此时点区正好 29 个点)
\ouc@cstart=352.20bp
\fi
% 点区宽度 = 左锚 - 起点 91.20
% ★ 不减空隙:\leaders 按整步距铺,最后一点的右缘正好落在左锚上
% (原卷正是这样:点占 91.20~352.20,课程名紧接 352.20 起)
\ouc@fw=\dimexpr\ouc@cstart-91.20bp\relax
\ifdim\ouc@fw<9bp \ouc@fw=9bp \fi
% ---- 无字母模式:三点从课程名右缘 +4bp 起,铺到"第"(432.48) 之前 ----
\ifx\ouc@foottype\@empty
\ouc@tstart=\dimexpr\ouc@cstart+\ouc@cnw+4bp\relax
\ouc@tfw=\dimexpr 432.48bp-\ouc@tstart\relax
\ifdim\ouc@tfw<9bp \ouc@tfw=9bp \fi
\fi}
% 点区:\leaders 按 9bp 步距自动铺满(个数自动取整)
\newcommand{\ouc@dotsfill}{%
\hbox to \ouc@fw{\leaders\hbox{\makebox[9bp][c]{…}}\hfill}}
% 无字母模式下课程名之后的点区(步距 9bp,铺到"第"之前)
\newcommand{\ouc@taildots}{%
\hbox to \ouc@tfw{\leaders\hbox{\makebox[9bp][c]{…}}\hfill}}
\newcommand{\ouc@makefooter}{%
\ouc@prepfooter
\begin{tikzpicture}[remember picture,overlay]
\coordinate (F) at ([yshift=-713.33bp]current page.north west);
% 左端 +
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=82.20bp]F) {+};
% 伸缩圆点区(\leaders 自动铺满,步距 9bp)
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=91.20bp]F) {\ouc@dotsfill};
% 课程名(左锚随长度自动左移)
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=\ouc@cstart]F) {\ouc@course};
% 类型字母(可选)+ 后随 3 点
% ★ 原卷 A 卷无字母、B 卷有 B,属手工差异 ⇒ 由 foottype 开关控制,
% 默认空(不印)。印字母时字母在 390.48、三点从 396.48 起;
% 不印时三点紧接课程名右侧 4bp 处(与原卷 A 卷一致)。
\ifx\ouc@foottype\@empty
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=\ouc@tstart]F) {\ouc@taildots};
\else
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=390.48bp]F) {\ouc@foottype};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=396.48bp]F) {\makebox[27bp][l]{………}};
\fi
% 逐段定位,避开 xeCJK 在中西文之间自动加的间距
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=432.48bp]F) {第};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=443.64bp]F) {\thepage};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=448.20bp]F) {页};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=461.64bp]F) {共};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=472.92bp]F) {\pageref{LastPage}};
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=477.48bp]F) {页};
% 右端 +
\node[anchor=base west,inner sep=0pt,font=\fontsize{9bp}{9bp}\selectfont]
at ([xshift=499.92bp]F) {+};
\end{tikzpicture}%
}
% ★ 挂到 shipout 钩子:每页自动出页脚,\ouc@prepfooter 在 shipout 时机测宽度
\AddToShipoutPictureFG{\ouc@makefooter}
%======================================================================
% 6. 装订线(左侧竖栏)
%
% ★ 印张规则:试卷用大纸双面印刷,偶数页拼在奇数页背面(同一张纸)。
% "装订线 + 学号/姓名/…" 只印在**奇数页**(右页,即正面);
% 偶数页是它的背面,不能再印一遍,否则折进去看不见、还浪费。
% ⇒ 默认自动判断:本页是奇数页才画(用 \ifodd\value{page})。
%
% 用法:
% \bindstrip → 自动(奇数页画、偶数页不画)★推荐
% \bindstrip[on] → 强制画(比如检查偶数页效果)
% \bindstrip[off] → 强制不画
% \bindstrip[1.3] → 自动 + 纵向整体下移 1.3bp(复刻原卷该页瑕疵)
% \bindstrip[1.3,on] → 强制画 + 下移
% 局部覆盖单页:\ouc@bindforce 置 1/0
%
% 本地实测(原卷 p1,x 坐标全部 bp):
% 竖虚线 x=33.8,5 段:101.1~148.5 / 222.4~290.8 / 359.4~427.9
% 489.3~557.8 / 600.0~668.6
% 18bp Times 连字符串 x=55.69("装/订/线"三字压在上面,白底遮断)
% 栏目名 x=32.65(竖排,自下而上);冒号单列在 x=32.89
% ★ 竖线每段 = 对应栏目的"填写区"(冒号之后向上延伸),共 6 段。
% 第 6 段 37.6~69.4 是"座号"的填写区——原 B 卷 PDF 里漏画了这一段,
% 看起来就是"座号后面没横线",学生无处可填。此处按 A 卷补齐。
% 另有一圈细边框(x=17.4 / 60.2 两条竖线 + 上下横封)。
%======================================================================
\newdimen\ouc@bindshift
%--------------------------------------------------------------------
% 开关:\bindstriptrue / \bindstripfalse(全局是否启用装订线)
% \bindstripoddfalse(默认 false = 只在奇数页画)
% \bindstripoffset{1.3bp}(整体纵向偏移,复刻原卷瑕疵)
%--------------------------------------------------------------------
\newif\ifouc@bindon \ouc@bindontrue
\newif\ifouc@bindodd \ouc@bindoddfalse % false: 只画奇数页
\newcommand{\ouc@bindshiftdimen}{0bp}
\newcommand{\bindstripoffset}[1]{\setlength{\ouc@bindshift}{#1}}
\setlength{\ouc@bindshift}{0pt}
% \bindstrip:保留兼容。现在只在需要"本页强制"时才用它;
% 正常情况装订线由 shipout 钩子自动画(见文件末尾),无需逐页调用。
\newcommand{\bindstrip}[1][]{%
\ifx\relax#1\relax\else
\ifx\@empty#1\@empty\else \setlength{\ouc@bindshift}{#1bp}\fi
\fi}
%----------------------------------------------------------------------
% 装订线虚线段:一个连字符笔画 = 一条 4.40bp 长、1.10bp 粗的横线
%
% 参数:#1 = 这一串最上一笔的 y 坐标(bp,从页面顶端往下量)
% #2 = 笔画个数
% 相邻笔画间隔 6.00bp,与原卷 18bp 连字符的步距一致。
%
% ⚠️ 必须定义在 \ouc@dobindstrip **外面**。放进去的话每次 shipout 都会
% 重新 \newcommand 一次,第二页起报 "command already defined"。
% ⚠️ x 坐标:笔画左端 49.40bp、右端 53.80bp(宽 4.40bp),
% 中心 51.60bp —— 这是原卷实测值,不是从 \tnr 连字符推的,
% 所以换任何字体都不会动。
% ⚠️ y 坐标**不能**写成 \dimexpr#1bp+\i*6bp:TikZ 的坐标解析器不认
% 带小数点的小数 + \dimexpr 组合,会报
% Illegal unit of measure (pt inserted)
% Package PGF Math Error: Unknown operator `.' or `.0'
% 必须先 \pgfmathsetmacro 算成纯数字,再拼 "bp"。
%----------------------------------------------------------------------
\newcommand{\ouc@dashseg}[2]{%
\foreach \i in {0,...,\the\numexpr#2-1\relax}{%
\pgfmathsetmacro{\ouc@dyy}{#1+\i*6.00}%
\draw[line width=1.10bp,line cap=butt]
([xshift=49.40bp,yshift=-\ouc@dyy bp]B) --
([xshift=53.80bp,yshift=-\ouc@dyy bp]B);}}
\newcommand{\ouc@dobindstrip}{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (B) at ([yshift=-\ouc@bindshift]current page.north west);
% ---- ★ 原卷此处【没有】外框 ----
% 曾误把 PDF 里 x=17.4/18.12/60.15/60.87 那组线当成黑色外框,
% 实测它们是 fill=(1,1,1) 的**白色遮挡块**(Word 里盖住页眉页脚
% 的底色块),可见黑线只有 x=33.80 那 6 段竖虚线。
% 故此处不画任何竖线/封口线。
% ---- 竖虚线:每段 = 对应栏目的"填写区"(紧接栏目名冒号之后,向上延伸)----
% 原卷 6 段,逐段对应:
% 600.05~668.60 ← 学号(冒号止于 668.6)
% 489.30~557.80 ← 姓名(止于 557.8)
% 359.35~427.85 ← 专业年级(止于 427.8)
% 222.40~290.80 ← 授课教师
% 101.10~148.50 ← 考场教室号(止于 148.5)
% 37.60~ 69.40 ← 座号(冒号止于 69.6)★ 原 B 卷 PDF 漏画,此处补上
% —— 这就是"座号后面那条线",缺了学生没法填座号。
\foreach \a/\b in {37.60/69.40, 101.10/148.50, 222.40/290.80,
359.35/427.85, 489.30/557.80, 600.05/668.60}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=33.8bp,yshift=-\a bp]B) -- ([xshift=33.8bp,yshift=-\b bp]B);}
% ---- 虚线段(#20:由「18bp 连字符排成」改为「用线画」)----
% 原卷这四段确实是 18bp Times 连字符排出来的,但 #20 把试卷字体
% 统一到思源宋体之后,连字符每个宽 0.346 em(Termes 是 0.333),
% 18bp 下每串会长出 4~7bp,正好破坏"复刻原卷长度"这个前提。
% ⇒ 改为几何画的短横线段,长度锁死在 \ouc@dashseg 的坐标里,
% 不受任何字体宽度影响。
% 实测原卷(720dpi 渲染后逐笔画测量):
% 单个连字符笔画 长 4.40bp、粗 1.10bp、x 中心 51.60bp
% → 左 49.40bp、右 53.80bp
% 相邻笔画步距 6.00bp(= 18bp × 0.333 em)
% 六段坐标与笔画数取自原卷逐笔画实测,见下方调用处。
\ouc@dashseg{62.20}{24}% 最下一串(座号区)
\ouc@dashseg{216.50}{24}% 考场教室号区
\ouc@dashseg{364.80}{3}% 截断的短线(原卷被白底遮断,照抄)
\ouc@dashseg{393.40}{13}% 授课教师区(上半截)
\ouc@dashseg{475.80}{16}% 专业年级区
\ouc@dashseg{582.10}{16}% 学号 + 姓名区(最上一串)
% ---- 竖排栏目名(自下而上读)----
% 原卷只有"姓名:""授课教师:"把冒号连排,其余冒号单独一行
\foreach \lab/\pos in {学号/694.06, 姓名:/585.10, 专业年级/474.46,
授课教师:/349.78, 考场教室号/207.46, 座号/96.70}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=0.7bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=32.65bp,yshift=-\pos bp]B) {\lab};}
% ---- 单独的冒号行:学号 / 专业年级 / 考场教室号 / 座号 ----
\foreach \pos in {672.94, 432.22, 154.66, 75.70}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=0.7bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=32.89bp,yshift=-\pos bp]B) {:};}
% ---- 装 / 订 / 线 ----
\foreach \lab/\pos in {装/581.44, 订/392.68, 线/215.80}{%
\node[anchor=base west,rotate=90,inner sep=0pt,fill=white,inner xsep=1.2bp,
font=\fontsize{10.45bp}{12bp}\selectfont]
at ([xshift=52.69bp,yshift=-\pos bp]B) {\lab};}
\end{tikzpicture}%
}
%======================================================================
% 7. 成绩表(题号 / 得分)
% 默认 8 个题号 + 总分共 9 栏,与原卷逐项对齐(栏宽 44.05bp)。
% 大题数不是 8 时,用 \examsetup{nsec = 11} 指定,自动按等宽重算。
%======================================================================
\def\ouc@nsec{8}
\define@key{ouc}{nsec}{\def\ouc@nsec{#1}}
% 题号汉字(支持到十六)
\newcommand{\ouc@cnnum}[1]{%
\ifcase\numexpr#1\relax\or 一\or 二\or 三\or 四\or 五\or 六%
\or 七\or 八\or 九\or 十\or 十一\or 十二%
\or 十三\or 十四\or 十五\or 十六\fi}
\newcommand{\scoretable}{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (S) at (current page.north west);
\ifnum\ouc@nsec=8
% ---- 原卷版:坐标逐项硬对齐 ----
\foreach \y in {159.04,181.99,212.44}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=122.81bp,yshift=-\y bp]S) -- ([xshift=478.24bp,yshift=-\y bp]S);}
\foreach \x in {123.05,167.10,201.10,235.10,269.10,303.10,337.10,
371.10,405.10,439.10,478.00}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=\x bp,yshift=-158.80bp]S) -- ([xshift=\x bp,yshift=-212.20bp]S);}
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=145.075bp,yshift=-174.89bp]S) {题号};
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=145.075bp,yshift=-201.53bp]S) {得分};
\foreach \name/\cx in {一/184.10, 二/218.10, 三/252.10, 四/286.10,
五/320.10, 六/354.10, 七/388.10, 八/422.10,
总分/458.55}{%
\node[anchor=base,inner sep=0pt,font=\fontsize{12bp}{12bp}\selectfont\kaiti]
at ([xshift=\cx bp,yshift=-174.89bp]S) {\name};}
\else
% ---- 自适应版:标签栏 + nsec 格 + 总分格 ----
% 横向:标签栏 123.05~163.05(宽 40),其后 nsec+1 格等分到 478.00
% 12 个大题时每格 (478-163.05)/13 = 24.2bp,正好容得下"十一"(12bp×2=24)
\pgfmathsetmacro{\ouc@cwl}{163.05}
\pgfmathsetmacro{\ouc@cw}{(478.00-\ouc@cwl)/(\ouc@nsec+1)}
% 题号字号自适应:两字题号(如“十一”)需 2×字号 ≤ 格宽 - 2bp 余量
% 12 题 → 格宽 24.2bp → 字号 11.1bp(仍按 12bp 上限,视觉不变)
% 16 题 → 格宽 18.5bp → 字号 8.3bp(自动缩小,不溢出)
\pgfmathsetlengthmacro{\ouc@fs}{min(12,(\ouc@cw-2)/2)*1bp}
% 三条横线(原卷 159.04 / 181.99 / 212.44)
\foreach \y in {159.04,181.99,212.44}{%
\draw[line width=0.48bp,line cap=butt]
([xshift=123.05bp,yshift=-\y bp]S) -- ([xshift=478.00bp,yshift=-\y bp]S);}
% 内容区竖线(标签栏右界即第一格左界,一并画上)
\foreach \i in {0,...,\the\numexpr\ouc@nsec+1\relax}{%
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+\i*\ouc@cw}%
\draw[line width=0.48bp,line cap=butt]
([xshift=\ouc@xx bp,yshift=-158.80bp]S) --
([xshift=\ouc@xx bp,yshift=-212.20bp]S);}
% 标签栏左侧那条竖线(原卷 123.05)
\draw[line width=0.48bp,line cap=butt]
([xshift=123.05bp,yshift=-158.80bp]S) --
([xshift=123.05bp,yshift=-212.20bp]S);
% 标签栏文字
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=143.05bp,yshift=-174.89bp]S) {题号};
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=143.05bp,yshift=-201.53bp]S) {得分};
% 题号 一…十二(居中于各自格子)
\foreach \i in {0,...,\the\numexpr\ouc@nsec-1\relax}{%
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+(\i+0.5)*\ouc@cw}%
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=\ouc@xx bp,yshift=-174.89bp]S)
{\ouc@cnnum{\numexpr\i+1\relax}};}
% 总分
\pgfmathsetmacro{\ouc@xx}{\ouc@cwl+(\ouc@nsec+0.5)*\ouc@cw}%
\node[anchor=base,inner sep=0pt,font=\fontsize{\ouc@fs}{\ouc@fs}\selectfont\kaiti]
at ([xshift=\ouc@xx bp,yshift=-174.89bp]S) {总分};
\fi
\end{tikzpicture}%
}
%======================================================================
% 8. 卷头
% 标题 + 三行填空 + 成绩表;随后补足垂直空白,
% 使正文首行基线正好落在 240.41bp
%======================================================================
\newcommand{\kh}[1]{\node[anchor=base west,inner sep=0pt,
font=\fontsize{10.45bp}{12bp}\selectfont\kaiti] at ([xshift=#1]H)}
\newcommand{\examhead}[1][184.39bp]{%
\begin{tikzpicture}[remember picture,overlay]
\coordinate (H) at (current page.north west);
% ---- 标题 ----
\node[anchor=base west,inner sep=0pt,
font=\fontsize{14.05bp}{16bp}\selectfont\bfseries]
at ([xshift=151.92bp,yshift=-54.65bp]H) {中国海洋大学全日制本科课程期末考试试卷};
% ---- 第 1 行 ----
\kh{113.52bp,yshift=-96.29bp} {\ouc@year};
\kh{139.80bp,yshift=-96.29bp} {年};
\kh{160.80bp,yshift=-96.29bp} {\ouc@term};
\kh{181.80bp,yshift=-96.29bp} {季学期};
\kh{224.04bp,yshift=-96.29bp} {考试科目:};
\kh{287.16bp,yshift=-96.29bp} {\ouc@course};
\kh{360.84bp,yshift=-96.29bp} {学院:};
\kh{402.96bp,yshift=-96.29bp} {\ouc@college};
\draw[line width=0.96bp,line cap=butt]
([xshift=113.50bp,yshift=-97.80bp]H) -- ([xshift=139.80bp,yshift=-97.80bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=150.20bp,yshift=-97.80bp]H) -- ([xshift=181.80bp,yshift=-97.80bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=276.70bp,yshift=-97.80bp]H) -- ([xshift=360.80bp,yshift=-97.80bp]H);
\draw[line width=0.48bp,line cap=butt]
([xshift=402.95bp,yshift=-97.40bp]H) -- ([xshift=508.40bp,yshift=-97.40bp]H);
% ---- 第 2 行 ----
\kh{116.40bp,yshift=-119.69bp} {试卷类型:};
\kh{184.92bp,yshift=-119.69bp} {\ouc@type};
\kh{207.60bp,yshift=-119.69bp} {卷};
\kh{228.60bp,yshift=-119.69bp} {命题人:};
\kh{276.00bp,yshift=-119.69bp} {\ouc@proposer};
\kh{363.60bp,yshift=-119.69bp} {审核人:};
\kh{410.00bp,yshift=-119.69bp} {\ouc@reviewer};
\draw[line width=0.96bp,line cap=butt]
([xshift=169.20bp,yshift=-121.20bp]H) -- ([xshift=207.60bp,yshift=-121.20bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=269.00bp,yshift=-121.20bp]H) -- ([xshift=358.30bp,yshift=-121.20bp]H);
\draw[line width=0.96bp,line cap=butt]
([xshift=405.70bp,yshift=-121.20bp]H) -- ([xshift=495.00bp,yshift=-121.20bp]H);
% ---- 第 3 行:考试说明 ----
\kh{108.48bp,yshift=-154.73bp} {考试说明:本课程为\ouc@mode 考试,共};
\kh{264.84bp,yshift=-154.73bp} {\pageref{LastPage}};
\kh{275.40bp,yshift=-154.73bp} {页,除考场规定的必需用品外还可携带的文具有};
\kh{497.90bp,yshift=-154.73bp} {\ouc@allowed。};
\draw[line width=0.48bp,line cap=butt]
([xshift=259.55bp,yshift=-156.10bp]H) -- ([xshift=275.40bp,yshift=-156.10bp]H);
\draw[line width=0.48bp,line cap=butt]
([xshift=492.60bp,yshift=-156.10bp]H) -- ([xshift=513.60bp,yshift=-156.10bp]H);
\end{tikzpicture}%
\scoretable
\par\vspace*{#1}\nointerlineskip
}
%======================================================================
% 9. 正文构件
%======================================================================
% 大题标题:宋体小四伪粗;与下一行基线距 15.0bp(正文 15.6bp)
% 标题内数字/括号用 Times Bold,中文与它们之间是固定 bp 空隙(原卷如此),
% 故局部关掉 xeCJK 自动间距,空隙一律显式给:\oucsp{6}
\newcommand{\oucsp}[1]{\hspace*{#1bp}}
\newcommand{\examheading}[2][0bp]{%
\par\ifdim#1>0bp\vspace*{#1}\fi
\noindent{\xeCJKsetup{CJKecglue={}}\fontsize{12bp}{15bp}\selectfont\bfseries #2}\par
\vspace*{\ouc@headgap}}
% 小题:\qi[题号栏宽]{题号}{题干}
% 原卷第 1 页题号用宋体半角("1." 占 10.44bp)+ 5.28bp 空隙 = 栏宽 15.72bp
% 第 2/3 页题号用 Times("1." 占 8.16bp)+ 空格,栏宽 13.08bp
% 少数题(如 3. 6.)题号后不留空,栏宽 10.44bp
\newcommand{\qnum}[1]{\makebox[15.72bp][l]{\sunfont #1.}}
\newcommand{\qi}[3][15.72bp]{\par\noindent\makebox[#1][l]{\sunfont #2.}#3\par}
% 注意:\tnr 只包住题号本身,必须用 {\tnr #2.} 关掉,否则 Times 泄到正文
% ★ 题干内部换行一律用 \\*(禁止分页),不要用裸 \\:
% 裸 \\ 是"允许在此断页",题干会被切到上下两页,学生看到半句话。
\newcommand{\qiT}[3][13.08bp]{\par\noindent\makebox[#1][l]{{\tnr #2.}}\ignorespaces#3\par}
% 宋体题号版(第 3 页设计题:原卷 "1." 是 SimSun 10.45,且题号后无空格)
\newcommand{\qiS}[3][15.72bp]{\par\noindent\makebox[#1][l]{{\sunfont #2.}}\ignorespaces#3\par}
% 选项:每栏 84bp,标签栏 15.72bp(与原卷逐字对齐)
\newcommand{\opt}[2]{\makebox[84bp][l]{\qnum{#1}#2}}
\newcommand{\choices}[4]{%
\par\noindent\opt{A}{#1}\opt{B}{#2}\opt{C}{#3}\opt{D}{#4}\par}
\newcommand{\optone}[2]{\par\noindent\opt{#1}{#2}\par}
% 图题:小五,居中于版心
\newcommand{\examfigcaption}[1]{%
\par\nointerlineskip\centerline{\Xiaowu #1}\par\nointerlineskip}
% 图题(五号):原卷第 3 页 "图3" 实测 10.45bp
\newcommand{\examfigcaptioniii}[1]{%
\par\nointerlineskip\centerline{\Fivhao #1}\par\nointerlineskip\vspace*{5.40bp}}
% 插图:\examfig[水平偏移]{宽度}{文件}
% 用 \vspace* 精确控制与上一基线的距离,偏移以版心左边界为基准
\newcommand{\examfig}[3][0bp]{%
\par\nointerlineskip\vspace*{\ouc@figskip}%
\noindent\hspace*{#1}\includegraphics[width=#2]{#3}%
\par\nointerlineskip\vspace*{\ouc@figtail}}
\def\ouc@headgap{-0.6bp}
\def\ouc@figskip{0bp}
\def\ouc@figtail{0bp}
\newcommand{\figskip}[1]{\def\ouc@figskip{#1}}
\newcommand{\figtail}[1]{\def\ouc@figtail{#1}}
% 逻辑表达式:按原卷用宋体直排文本,不用数学模式(字距才对得上)
\newcommand{\logicexpr}[1]{{\sunfont #1}}
% 求和符号 Σ / 带 Φ 的 Σ,跟正文同高(原卷是混排文本,不是数学符号)
\newcommand{\sumsig}{\hbox{\sunfont ∑}}
\newcommand{\sumphisig}{\hbox{\sunfont ∑Φ}}
% 下标(原卷 M_L / M_S)
% 实测:L/S 字号 5.30bp(SimSun),基线相对正文下移 1.56bp;
% M(210.00) → L(215.16) 步距 5.16bp(M 的半角宽),
% L → 和 3.96bp,故 M 起点到"和"共 9.12bp。
% 用宽度 3.87bp 的盒接管下标宽度,使 5.25 + 3.87 = 9.12 对齐原卷。
\newcommand{\ssub}[1]{%
\raisebox{-1.56bp}{\makebox[3.87bp][l]{\fontsize{5.30bp}{5.30bp}\selectfont #1}}}
%======================================================================
% 10. 题型构件(通用)
% 设计原则:不依赖任何具体课程,只提供"骨架",
% 题目内容由正文填写。所有题型都沿用本卷实测的版面参数:
% · 正文 10.5bp / 行距 15.6bp
% · 中英之间 2.70bp(ecglue)
% · 题号栏 15.72bp(宋体题号,题号后空 5.28bp)
%======================================================================
%----------------------------------------------------------------------
% 10.1 分值标注(题号右侧、行尾右对齐)
% \qscore{5} → 在当前位置右对齐显示 "(5分)"
% 单独成行右对齐:\scorerow{5}
%----------------------------------------------------------------------
\newcommand{\qscore}[1]{{\Fivhao\hfill(#1分)}}
\newcommand{\scorerow}[1]{\par\noindent\hfill{\Fivhao(#1分)}\par}
%----------------------------------------------------------------------
% 10.2 填空横线
% \blank → 5 个下划线的短空(约 3 个汉字宽)
% \blank[8] → 指定字宽的横线(8 个字宽)
% \lblank → 通栏长横线(整行)
% 用 \rule 画,落在基线下方,与 Word 的下划线观感一致
%----------------------------------------------------------------------
\newlength\ouc@blw
\newcommand{\blank}[1][5]{%
\settowidth{\ouc@blw}{\Fivhao 国}%
\setlength{\ouc@blw}{\dimexpr\ouc@blw*#1\relax}%
\hspace*{0.6bp}\rule[0.35bp]{\ouc@blw}{0.5bp}\hspace*{0.6bp}}
\newcommand{\lblank}{\par\noindent\rule[0.35bp]{\linewidth}{0.5bp}\par}
%----------------------------------------------------------------------
% 10.3 括号填空(\tk 在括号内留出可写空间)
% \tk → 3 个字宽的括号空:\tk 写成 (\hspace.. )
%----------------------------------------------------------------------
\newcommand{\tk}{\makebox[2.4em]{\dotfill}}
%----------------------------------------------------------------------
% 10.4 选项:两种版式
% \choices{...}{...}{...}{...} 一行四栏(3 个汉字以内的短选项)
% \choicesII{...}{...}{...}{...} 两行两栏(长选项,每栏半行宽)
% \optgrid{...}{...} 任意栏数,自动按半行宽排
%----------------------------------------------------------------------
% 长选项:每栏半行宽(含标签栏)
\newlength\ouc@halfw
\newcommand{\optII}[2]{%
\setlength{\ouc@halfw}{\dimexpr\linewidth/2\relax}%
\makebox[\ouc@halfw][l]{\qnum{#1}#2}}
\newcommand{\choicesII}[4]{%
\par\noindent\optII{A}{#1}\optII{B}{#2}\par
\noindent\optII{C}{#3}\optII{D}{#4}\par}
% 任意栏数(每行 #1 栏)
% \optgrid{3}{甲,乙,丙,丁} → 每行 3 栏,逗号分隔
% ⚠️ 两个坑:
% (1) 不能用 LaTeX2e 的 \@for 遍历:它对每个元素做 \edef 展开,
% 中文(xeCJK 活动字符)会被提前展开,选项内容直接丢失。
% (2) expl3 里 @ 不是字母,控制序列名不能再含 @(\ouc@foo 会被读成
% \ouc + "@foo"),故 expl3 侧一律用 \__ouc_ 前缀。
\ExplSyntaxOn
\seq_new:N \l__ouc_opt_seq
\int_new:N \l__ouc_opt_i
\cs_new_protected:Npn \__ouc_optgrid:nn #1#2
{
\seq_set_split:Nnn \l__ouc_opt_seq {,} {#2}
\int_zero:N \l__ouc_opt_i
\seq_map_inline:Nn \l__ouc_opt_seq
{
\makebox[\dim_eval:n {\linewidth/#1}][l]{##1}
\int_incr:N \l__ouc_opt_i
\int_compare:nT { \l__ouc_opt_i = #1 }
{ \par \noindent \int_zero:N \l__ouc_opt_i }
}
\par
}
\NewDocumentCommand \optgrid { m m } { \par \noindent \__ouc_optgrid:nn {#1} {#2} }
\ExplSyntaxOff
%----------------------------------------------------------------------
% 10.5 判断题:括号在题首(原卷常见写法)
% \judge{序号}{题干} → "( )1. 题干",括号默认 3 字宽
% \judge[5]{序号}{题干} → 括号 5 字宽(长答案用)
% 括号用 \makebox + \hfill 撑开,"("居左、")"居右,中间留答题位。
% 括号在行尾的写法直接用 \qi{1}{题干(\hspace{1.67em})} 即可。
%----------------------------------------------------------------------
\newlength\ouc@jdw
\newlength\ouc@juw
\newcommand{\judge}[3][3]{%
\par\noindent
\settowidth{\ouc@juw}{\Fivhao 国}%
\setlength{\ouc@jdw}{\dimexpr\ouc@juw*#1\relax}%
\makebox[\ouc@jdw][l]{(\hfill )}%
\hspace*{2bp}\SUN{#2.}\hspace*{5.28bp}#3\par}
%----------------------------------------------------------------------
% 10.6 答题横线
% \answerlines[行数] → 在当前位置下方排 n 条等距横线(每条占 1 行距 15.6bp)
% 注意:不能用 \vbox 整体打包 —— 那样它会成为一个不可分割的原子块,
% 页面剩余空间不够时整块被推到下一页,页脚会留出大片空白。
% 改为逐条 "\par\nointerlineskip\vspace*{..}\hrule" 输出,允许跨页断开。
%----------------------------------------------------------------------
\newcommand{\answerlines}[1][3]{%
\par
\@tempcnta=0
\loop\ifnum\@tempcnta<#1
\nointerlineskip\vspace*{15.0bp}%
\noindent\hrule height 0.4bp width \linewidth
\par
\advance\@tempcnta by 1
\repeat
\nointerlineskip\vspace*{3bp}}
%----------------------------------------------------------------------
% 10.7 大题标题的"带分值"简写
% \bigsection{一}{填空题}{3 小题,每题 4 分,共 12 分}
% 中间的"共"字由宏自己补,第三个参数不要再写"共"
%----------------------------------------------------------------------
\newcommand{\bigsection}[3]{%
\examheading{#1、#2\TNRB{(}共\oucsp{6}#3\TNRB{)}}}
%----------------------------------------------------------------------
% 10.8 答题方框
% \answerbox{高度bp} → 通栏、指定高度的矩形框(作图 / 计算作答用)
%----------------------------------------------------------------------
\newcommand{\answerbox}[1]{%
\par\nointerlineskip\vspace*{4bp}\noindent
\framebox[\linewidth]{\rule{0pt}{#1}}%
\par\nointerlineskip\vspace*{6bp}}
%----------------------------------------------------------------------
% 10.10 配伍题(连线匹配)
% \mtpair{左侧内容}{右侧内容} → 左 44% | 中 12% 空白(供连线)| 右 44%
% 逐行写即可,行列自动对齐:
% \mtpair{\qnum{1} 甲}{A. 子}
% \mtpair{\qnum{2} 乙}{B. 丑}
% 中间空白留给学生画连线,不需要画虚线。
%----------------------------------------------------------------------
\newcommand{\mtpair}[2]{%
\par\noindent
\makebox[0.44\linewidth][l]{#1}%
\makebox[0.12\linewidth][c]{}%
\makebox[0.44\linewidth][l]{#2}\par}
% 配伍题整体上下留白
\newcommand{\matchinggap}{\par\vspace*{3bp}}
%----------------------------------------------------------------------
% 10.11 表格(成绩表 / 数据表):等宽 tabular,自动加横线
% \datatable{列格式}{表体}
% 表内数字请用 \TNR{},不要用 $...$(数学模式基线偏低,会与中文错行)
%----------------------------------------------------------------------
\newcommand{\datatable}[2]{%
\par\vspace*{5bp}%
\centerline{\begin{tabular}{@{}#1@{}}#2\end{tabular}}%
\par\vspace*{5bp}}
%======================================================================
% 11. 自动装订线钩子
% ★ 印张规则:试卷用大纸双面印,偶数页拼在奇数页背面(同一张纸)。
% "装订线 + 学号/姓名/专业年级/授课教师/考场教室号/座号"只印正面,
% 即**只画奇数页**;偶数页是背面,再画一遍折进去也看不见。
% ⇒ 钩到这里,按 \value{page} 自动判断,.tex 里不必逐页调用。
% ⚠️ 必须放在最后:\ouc@dobindstrip 依赖前面定义的 \ouc@bindshift 等。
%======================================================================
\AddToShipoutPictureFG{%
\ifouc@bindon
\ifouc@bindodd
\ouc@dobindstrip % 每页都画(nup 拼版等特殊需要)
\else
\ifodd\value{page}\ouc@dobindstrip\fi % 默认:只画奇数页
\fi
\fi}
\endinput