源:D:\Yongquan\code\sre =《软件需求工程导论》完整教材
(13 章 + 5 附录,78 万字节,265 页 PDF,elegantbook 文档类)
## 新增文件
教材/ouctextbook.sty 版式配置
教材/elegantbook.cls 本地化过的文档类(改过字体)
教材/教材.tex 示例正文(1 章 + 附录 + 参考文献)
教材/reference.bib 参考文献库(虚构条目)
教材/README.md 用法 + 踩坑记录
## 核心约束:字体的共用性
用户明确要求「注意字体的共用性」。原教材用 elegantbook 的
chinesefont=founder 档,加载方正四大字体:
FZShuSong-Z01 / FZHei-B01 / FZKai-Z03 / FZFangSong-Z02
这些是**商业字体,不能随仓库分发**(#17 定下的规矩)。
### elegantbook 三档字体全都不通用
| 选项 | 实际字体 | 问题 |
|---|---|---|
| founder(默认) | 方正四大字体 | 商业字体,换机器就废 |
| ctexfont | 系统字体(Win=SimSun,macOS=PingFang) | 三平台三种样子 |
| nofont | 不设 | 不配置就报错 |
### 只写 nofont 还不够 —— cls 自身还硬编码字体
elegantbook.cls 第 176/184 行:
\setmainfont{TeXGyreTermesX}[...]
\setsansfont{texgyreheros}[...]
这两款在精简 TeX Live 上都没有,报 9 个错误连发:
! Package fontspec Error: The font "texgyreheros-regular" cannot be found
**实测:在 \documentclass 之后用 \setsansfont 覆盖无效** ——
类加载时字体族已注册失败,后面重新指定救不回来。
⇒ 所以本模板必须带一份**本地化的 cls**,改三处(都留了"本地化"注释):
| 位置 | 改动 |
|---|---|
| ~176 行 | TeXGyreTermesX → texgyretermes + Path=../fonts/tex-gyre-termes/ |
| ~184 行 | texgyreheros → OUCSans + Path=../fonts/ouc-sans/ |
| \maketitle | example-image → \ouc@coverblank |
这是本模板与仓库其他模板的**唯一结构性差异**:别的模板只要
\input{../fonts.tex},本模板还要那份改过字体的 cls。
## 踩到的三个坑
### 1. 封面不写 \cover{} 会插一张 "Image" 占位图
cls 第 1288~1300 行:
\ifcsname @cover\endcsname ... \else
\includegraphics[width=\linewidth]{example-image} ← mwe 的灰底占位图
首页顶着 "Image" 两个大字。已把 else 分支换成空盒子。
### 2. 占位盒宽度不能是 0(这个坑耗了最久)
第一版 \rule{0pt}{0pt}(0 宽),立刻冒出:
Overfull \hbox (5.00002pt too wide) in paragraph at lines 44--44
试过全部无效,溢出量死钉在 5.00002pt 不动:
改 \hspace{2em} / \hspace{2.5em} 无效
改 minipage 的 0.67/0.27\linewidth 无效
改 tabular 列间距 @{}l@{} 无效
改 \colorbox 的 \makebox[\hsize] 无效
根因:0 宽空盒让 \linewidth 在 titlepage 里与 \textwidth 差 5pt,
后续并排的 \parbox{0.8\textwidth} + 两个 minipage 整体超宽。
✅ 正解:给占位盒满宽
\newcommand{\ouc@coverblank}{%
\rule{0pt}{0pt}\hspace{\linewidth}\rule{0pt}{0pt}}
实测 0 Overfull。
### 3. 封面色带改不动(一行 \colorlet 的位置问题)
cls 第 345 行 `\colorlet{coverlinecolor}{second}` 在**类加载末尾**执行,
把 coverlinecolor 绑到 second 色(black 模式下就是黑)。
⇒ 导言区写 \colorlet 会被覆盖,实测色带仍是纯黑。
必须用 \AtBeginDocument 排到它后面。
## build.sh 补了 bibtex 支持
原来只跑两遍 xelatex,教材的参考文献出不来。
新增:目录下有 .bib(排除 *-blx.bib 这种中间产物)就插一次 bibtex,
再补一遍 xelatex,最后跑统计那一遍。
## 验证
8 页 error 0 Overfull 0 Underfull 0
封面色带 RGB(32,178,170) 青绿,实测 fill=(0.125,0.698,0.667)
封面无 example-image 占位
字体(PDF 内嵌实测,全部来自仓库):
OUCSerif-Regular / -Bold 中文正文
OUCKai-Regular 中文斜体(楷体代)
TeXGyreTermes-Regular/-Bold/-Italic 西文
LMMono10-Regular \texttt 等宽(TeX Live 自带)
→ **无方正、无 SimSun/SimHei、无 Times New Roman**
全库 16/16 通过(新增第 16 项,已加入 verify_all.sh)。
⚠️ Windows 端本机未能编译:TeX Live 写字体缓存
(C:\texlive\2022\texmf-var)被安全策略拦截,属环境限制非模板问题。
模板只依赖 TeX Live 标准宏包与发行版自带字体;原教材本身就是在
Windows + TeX Live 2022 上编出来的。
## .gitignore 补充
新增 *-blx.bib、*.run.xml(biblatex 中间产物)、*/.preview/(预览图)。
## 与原教材的差异
| 项 | 原教材 | 本模板 | 原因 |
|---|---|---|---|
| 封面图 | cover.jpg | 无(纯色带) | 模板不附图片 |
| 字体 | 方正四大字体 | 仓库开源字体 | 商业字体不能分发 |
| 西文无衬线 | texgyreheros | OUC Sans | 仓库没有 Hero |
| 正文 | 13 章 265 页 | 1 章示例 | 只抽骨架 |
225 lines
10 KiB
TeX
225 lines
10 KiB
TeX
%======================================================================
|
||
% ouctextbook.sty —— 中国海洋大学 教材 版式包
|
||
%
|
||
% 从《软件需求工程导论》(sre 仓库) 的版式抽取而来,
|
||
% 底层是 elegantbook 文档类,保留其全部排版特性。
|
||
%
|
||
% 编译: xelatex 教材.tex (单次即可;有参考文献时 xelatex→bibtex→xelatex×2)
|
||
%
|
||
% ------------------------------------------------------------------
|
||
% ⚠️⚠️ 本模板与其他模板最大的不同:它是**文档类**不是宏包
|
||
%
|
||
% elegantbook 是 \documentclass 级别的类,不能 \usepackage。
|
||
% 所以本文件只提供**配置命令**,正文首行必须自己写
|
||
% \documentclass[...]{elegantbook},再 \usepackage{ouctextbook}。
|
||
%
|
||
% 顺序不能反:\documentclass 必须第一行。
|
||
% ------------------------------------------------------------------
|
||
%======================================================================
|
||
\NeedsTeXFormat{LaTeX2e}
|
||
\ProvidesPackage{ouctextbook}[2026/11/01 v1.0 OUC textbook style]
|
||
|
||
%======================================================================
|
||
% 一、公共字体(本模板的核心约束)
|
||
%
|
||
% ⚠️⚠️ 为什么必须在 \documentclass 里写 chinesefont=nofont
|
||
%
|
||
% elegantbook 的 chinesefont 只有三档,全都不通用:
|
||
%
|
||
% founder(默认) 方正四大字体 FZShuSong-Z01 / FZHei-B01 /
|
||
% FZKai-Z03 / FZFangSong-Z02
|
||
% ⇒ **商业字体,不能随仓库分发**,换机器就废
|
||
% ctexfont ctex 按**系统**字体配(Windows=SimSun/SimHei,
|
||
% macOS=PingFang,Linux 视装了什么而定)
|
||
% ⇒ 同一份源码在三个平台排出三种样子
|
||
% nofont 不设字体,完全交给用户
|
||
% ⇒ 不额外配置就直接报错
|
||
%
|
||
% ⇒ 本模板用 nofont,然后在正文 \input{../fonts.tex} 接入仓库字体。
|
||
%
|
||
% ⚠️⚠️ 但只写 nofont 还不够 —— elegantbook.cls 自身还硬编码了两处字体:
|
||
%
|
||
% \setmainfont{TeXGyreTermesX}[...] % 西文衬线
|
||
% \setsansfont{texgyreheros}[...] % 西文无衬线
|
||
%
|
||
% 这两款在精简版 TeX Live 和很多机器上**都没有**,会直接报
|
||
% ! Package fontspec Error: The font "texgyreheros-regular"
|
||
% cannot be found
|
||
% 而且是 9 个错误连发,因为在类的每个字体档位上都会失败。
|
||
%
|
||
% 实测:在 \documentclass 之后用 \setsansfont 覆盖**无效** ——
|
||
% 类加载时该字体族已经注册失败,后面的重新指定救不回来。
|
||
%
|
||
% ⇒ 唯一可靠的做法是**本地化 cls 本身**:模板目录里带一份
|
||
% elegantbook.cls 副本,把那两处改成仓库字体:
|
||
% \setmainfont{texgyretermes}[Path=../fonts/tex-gyre-termes/]
|
||
% \setsansfont{OUCSans}[Path=../fonts/ouc-sans/]
|
||
% 改动处有 "本地化" 注释,便于将来对比上游版本。
|
||
%
|
||
% ⇒ 这也是本模板与仓库其他模板的**唯一结构性差异**:
|
||
% 别的模板只需要 \input{../fonts.tex},
|
||
% 本模板还需要那份改过字体的 cls 副本。
|
||
%
|
||
% ⚠️ fonts.tex 已用 \def 定义 \songti / \heiti / \kaiti / \fangsong,
|
||
% elegantbook 内部依赖 \heiti(用于 \cbfseries、章节标题),
|
||
% 所以这层依赖是通的。若哪天 fonts.tex 改了这几个命令的名字,
|
||
% 本模板的章节标题会立刻失去中文字体。
|
||
%======================================================================
|
||
\RequirePackage{etoolbox}
|
||
|
||
% 检查是否已加载 elegantbook 且用了 nofont。
|
||
% 若用户忘了写 nofont,给出明确提示而不是让方正字体报一堆乱码错误。
|
||
\AtBeginDocument{%
|
||
\ifcsname ELEGANT@chinesefont\endcsname
|
||
\ifdefstring{\ELEGANT@chinesefont}{nofont}{}{%
|
||
\PackageWarning{ouctextbook}{%
|
||
检测到 chinesefont 不是 nofont。请把文档类选项改为
|
||
\string\documentclass[lang=cn,newtx,10pt,black,chinesefont=nofont]{elegantbook}%
|
||
\MessageBreak
|
||
否则会加载方正商业字体或系统字体,失去跨平台一致性}%
|
||
}%
|
||
\fi
|
||
}
|
||
|
||
%======================================================================
|
||
% 二、标题编号层级
|
||
%
|
||
% 原教材主文件里的自定义,很有用,保留:
|
||
% 编号最多到第 4 级 章(1) → 节(1.1) → 小节(1.1.1) → 小小节(1.1.1.1)
|
||
% 第 5 级(\paragraph)不再进编号体系,改用「(1)(2)(3)」形式,
|
||
% 避免出现 3.1.1.1.1 这种过长编号。
|
||
%
|
||
% ⚠️ 这段必须在 \begin{document} 之前执行,用 \AtBeginDocument 会太晚
|
||
% (编号层级在导言区就被读取)。
|
||
%======================================================================
|
||
\setcounter{secnumdepth}{3}
|
||
\setcounter{tocdepth}{3}
|
||
|
||
\makeatletter
|
||
\newcounter{paranum}[subsubsection] % 随小小节自动重置
|
||
\renewcommand\paragraph[1]{%
|
||
\par\addvspace{0.9ex}%
|
||
\stepcounter{paranum}%
|
||
\noindent{\bfseries (\arabic{paranum})\,#1}%
|
||
\par\nobreak\addvspace{0.1ex}%
|
||
\@afterindentfalse\@afterheading}
|
||
\makeatother
|
||
|
||
%======================================================================
|
||
% 三、封面色带
|
||
%
|
||
% 原教材用青绿色 RGB(32,178,170),比 elegantbook 默认的蓝色沉稳,
|
||
% 与清华社的封面观感接近。保留。
|
||
%
|
||
% ⚠️⚠️ 必须在 \begin{document} 之后才能改 coverlinecolor
|
||
%
|
||
% elegantbook.cls 第 345 行有
|
||
% \colorlet{coverlinecolor}{second}
|
||
% 这行在**类加载末尾**执行,把 coverlinecolor 绑到 "second" 色上
|
||
% (color=black 选项下 second 就是黑色)。
|
||
%
|
||
% ⇒ 在导言区写 \colorlet{coverlinecolor}{...} 会被它覆盖,
|
||
% 实测封面色带仍是纯黑,改了半天没反应。
|
||
% 必须用 \AtBeginDocument 排到它后面。
|
||
%======================================================================
|
||
\definecolor{ouccoverlinecolor}{RGB}{32,178,170}
|
||
|
||
\AtBeginDocument{%
|
||
\colorlet{coverlinecolor}{ouccoverlinecolor}%
|
||
}
|
||
|
||
% 需要临时换别的色时,在正文里调这个(不调则用上面的青绿)
|
||
\newcommand{\oucSetCoverColor}[1]{%
|
||
\colorlet{coverlinecolor}{#1}%
|
||
}
|
||
|
||
%======================================================================
|
||
% 四、图形与表格
|
||
%
|
||
% 原教材用到的宏包,逐个说明为什么需要:
|
||
% array \makecell(表格内换行)
|
||
% cprotect \verb 等脆弱命令进表格/标题
|
||
% graphicx 插图
|
||
% float [H] 强制定位(教材排版要求图跟文字,不能漂走)
|
||
% longtable 跨页表格
|
||
%======================================================================
|
||
\RequirePackage{array}
|
||
\RequirePackage{cprotect}
|
||
\RequirePackage{graphicx}
|
||
\RequirePackage{float}
|
||
\RequirePackage{longtable}
|
||
|
||
% TikZ 绘图库(原教材的流程图/关系图用这些)
|
||
\RequirePackage{tikz}
|
||
\usetikzlibrary{
|
||
shapes.geometric, shapes.misc,
|
||
arrows.meta, arrows,
|
||
decorations.pathreplacing, decorations.markings,
|
||
positioning, calc, fit, backgrounds
|
||
}
|
||
|
||
%======================================================================
|
||
% 五、断行宽容度
|
||
%
|
||
% ⚠️ 教材正文长、中文多、行内夹英文术语和公式,默认 \tolerance
|
||
% 会产生大量 Overfull(原教材明确加过这一条)。
|
||
% 2em 是原教材实测的值,既消掉大部分告警,又不会排出稀疏的行。
|
||
%======================================================================
|
||
\setlength{\emergencystretch}{2em}
|
||
|
||
%======================================================================
|
||
% 六、常用排版命令
|
||
%======================================================================
|
||
% 表格里的色块占位(原教材 \ccr 的用途:图例色块)
|
||
\newcommand{\ouccolorcell}[1]{%
|
||
\makecell{{\color{#1}\rule{1cm}{1cm}}}}
|
||
|
||
%======================================================================
|
||
% 七、章节末的标准小节
|
||
%
|
||
% 原教材每章固定以「本章小结」+「习题」收尾。
|
||
% 做成命令,避免各章写法不一致。
|
||
%======================================================================
|
||
\newcommand{\oucsummary}{\section{本章小结}}
|
||
\newcommand{\oucexercises}{\section{习题}}
|
||
|
||
%======================================================================
|
||
% 八、封面:无封面图时不插 example-image
|
||
%
|
||
% ⚠️⚠️ elegantbook 在没写 \cover{} 时会插入 mwe 宏包的 example-image,
|
||
% 也就是**一张印着 "Image" 字样的灰底占位图**,铺满首页。
|
||
% 源码(cls 第 1288~1300 行):
|
||
% \ifcsname @cover\endcsname
|
||
% \includegraphics[width=\linewidth]{\@cover}
|
||
% \else
|
||
% \includegraphics[width=\linewidth]{example-image} ← 就是这个
|
||
% \fi
|
||
% 交付给别人的模板首页顶着 "Image" 两个大字,不合适。
|
||
%
|
||
% ⇒ 解法在 cls 里,不在本文件:本地化版本的 elegantbook.cls 已把
|
||
% 那两处 example-image 换成了 \ouc@coverblank(一个占位盒子)。
|
||
% 这样不写 \cover{} 时封面只有色带和文字,没有占位图。
|
||
%
|
||
% ⚠️⚠️ 占位盒的宽度**不能是 0**。
|
||
%
|
||
% 第一版写成 \rule{0pt}{0pt}(0 宽),立刻冒出
|
||
% Overfull \hbox (5.00002pt too wide) in paragraph at lines 44--44
|
||
% 而且它只出现在 \maketitle 那一行,改 \hspace{2em}、\hspace{2.5em}、
|
||
% minipage 的 0.67/0.27\linewidth、tabular 的列间距,**全部无效**,
|
||
% 溢出量死钉在 5.00002pt 不动。
|
||
%
|
||
% 根因:0 宽空盒让 \linewidth 在 titlepage 里的计算与 \textwidth
|
||
% 差了 5pt,后续并排的 \parbox{0.8\textwidth} + 两个 minipage
|
||
% 就整体超宽。
|
||
%
|
||
% ✅ 正解:给占位盒一个满宽
|
||
% \newcommand{\ouc@coverblank}{%
|
||
% \rule{0pt}{0pt}\hspace{\linewidth}\rule{0pt}{0pt}}
|
||
% 实测 0 Overfull。
|
||
%
|
||
% ⚠️ 不要试图在本文件里用 \ifcsname 覆盖 \@cover 来绕开 —— 实测
|
||
% \@cover 即使定义成空串也会走 \includegraphics{} 分支报错。
|
||
% 改 cls 是唯一干净的办法。
|
||
%======================================================================
|
||
|
||
\endinput |