列车数据

小技巧

关于列车数据的技术实现,可以参见专栏文章:https://zhuanlan.zhihu.com/p/401090271

列车数据通常是本系统中最重要、最复杂、体量最大的一类数据。一个运行图文件包含一组列车数据,每趟列车包含车次名、时刻表以及一些显示设定等数据。本文档(及软件)中,在不致产生歧义的情况下,列车车次两个名词常常通用。

列车与运行线

一趟列车有一套时刻表(timetable),依次给出列车在各个车站的到达、出发时刻。在本系统的具体实现中,时刻表不要求是完整的,也不要求是连续的,也即时刻表不必涵盖始发站到终到站的每一个站,具有其中一段、或一部分非连续的车站数据也可以绘制运行图,但在具体问题处理上可能有一些更严格的限制。

重要

强调时刻表顺序的重要性。由于时刻具有(24小时的)周期性,本软件会认为时刻表从前到后的时间是严格单调不减的,如果出现后一站时刻比前一站时刻“早”的情况,会将后一站时刻判定为第二天的时刻。因此时刻表顺序错误通常会造成非预期的结果。

运行线是运行图上一段表示列车的线条(包括可能具有的开始和结束标签)。在本系统中,运行线仅描述一趟列车在同一条线路上的一段单向、连续的运行情况。一趟列车可以具有多段不同方向、属于不同线路的运行线。

重要

以上表述是本系统列车运行线逻辑的核心概括,是理解运行线及相关算法的关键,特别是涉及列车分段、折返运行时。

鉴于以上表述在概念上的重要性,这里进一步做些解读。(1) 运行线仅是同一线路上的,不在同一条线路上的区段一定不属于同一运行线;(2) 运行线必然是单向(指在线路中的上行或者下行)的,如果列车运行发生折返,则折返前后必分属两段运行线;(3) 运行线是连续的,如果列车在两站之间经由其他线路而非本线运行,则前后应当为两条运行线;(4) 列车在某线路上的运行里程就是其在该线路上每一条运行线对应里程之和,而不是列车在该线路上第一站和最后一站之间的距离。这对于正确处理分段和折返运行的情况,是关键的。

下图给出了运行线分段的例子。40001在成都-成都西和红牌楼-石羊线路所分为两段运行线;而40103/4次在成都-红牌楼区间下行运行,在红牌楼-成都西区间折返为上行运行,故也是两段运行线。

运行线分段

与pyETRC不一样的是,qETRC目前仅支持自动运行线管理,而不支持手动配置运行线信息。工具栏上下文页面 列车审阅 | 运行线一览 功能可以查看当前所选列车的所有运行线信息,如下图所示。其中,左侧表格列出了属于当前列车的所有运行线的基本信息;右侧表格则是当前(在左侧表格中)所选运行线的详细铺画信息。

运行线一览

左侧表格清晰示出了各段运行线的起点、终点、所属线路及其行别。起止标签两列指出该运行线是否带有起点和终点标签(由系统判定,用户不能自行修改)。起止标签的判定规则是:对于在同站发生折返而造成的运行线分段点(例如前面例图中的40103/4在红牌楼站的运行线分段),前段运行线不带终点标签,后段运行线不带起点标签;其他情况都带有标签。

右侧表格反映了列车数据与线路数据之间的匹配关系,有时也称为绑定(binding)关系。其中,左侧几列(蓝色或灰色字体)是列车时刻表中的数据,右侧几列(红色或灰色字体)是线路站表数据。对于每一行,如果左侧字体为蓝色、右侧字体为红色,则表示列车数据与线路数据匹配成功,称为一个成功铺画的站;如果只有一侧有内容且字体为灰色,另一侧为空白,则表示此站无法匹配,例如图中是列车时刻表中的重庆北11#岔在线路上没有对应的站,无法匹配。两个铺画成功的站之间,匹配不成功的行数至多为 最大跨越站数 所示的数据;如果超过这个数据,将被截断为两条运行线。这也是不完整时刻表铺画运行线时,需要将 最大跨越站数 设置得充分大的原因。

备注

从上面的论述可以看到,行别是列车运行线的属性,不是列车的属性。我们只能说,某次列车在某线路的某个区间为下行/上行,而(原则上)不能说某列车为下行列车/上行列车。

另外,我们已经提过,本系统中线路的上下行方向是由线路中站表的排列从前到后为下行的规则严格定义的,而(原则上)与实际情况的上下行无关。

警告

qETRC虽然支持(原则上)任意多段的运行线,(原则上)支持列车任意折返,但程序设计和优化时通常只是将折返视为特殊情况的。因此不建议维护包含大量折返的数据,特别是不建议把同一线路上反复折返的一组车底维护成单一车次(此种情况应每段运行维护成独立车次,然后使用交路功能互相联系)。

列车反复折返在本系统设计中属于极端情况,可能触发不正常/不正确的行为,如果确实打算这样维护数据,请及时做好数据保存。如果遇到相关问题也可以反馈,但作者不保证总是对极端情况作出合适的处置。

站名匹配规则

按:我比较纠结,这一部分应当放到哪一篇文档里面。从逻辑上讲,既然上面已经提到了列车与线路的车站铺画问题,就应该提一下站名匹配规则,才比较完整;但站名匹配规则似乎与一些微调功能的关系更大(pyETRC文档就是把这部分和微调功能的文档放在一起的)。我暂时决定还是在这里说明。为防止本文档的“前摇”过长,还是给个省流版的表述,如果读者需要用到详细的匹配逻辑,可阅读下面的具体内容。

小技巧

省流版:对于绝大多数的情况,站名匹配规则就是简单的严格字符串匹配除非站名中含有域解析符:: (双半角冒号,即C++语言的域解析符),才适用更复杂的规则。

在不存在域解析符 :: (双半角冒号)的情况下,站名匹配就是按照严格的字符串匹配进行的。列车时刻表的站名与线路站表的站名匹配,以及列车始发终到站(设置项)与其时刻表中首末站匹配,都是当且仅当站名完全相同。

域解析符的引入,使得车站的匹配可以一定程度上放宽。含域解析符站名的格式是: 站名::场名 ,例如 成都东::达成场 。在一些特定的情况下,站名相同而场名不完全相同的站可以认为是匹配的。在具体的场景下,匹配的细节规则可能有所不同。

列车时刻表中站名与线路站表的匹配采用的实现代码为: 线路站名.equalOrContains(列车站名) ,即线路的站名与列车站名完全相同,或者线路站名只有站名(没有场名)、列车站名是 站名::场名 格式的情况。举例来说,列车站名 成都东::达成场 可以匹配到线路站名 成都东 ,但不能匹配到线路站名 成都东::城际场

列车始发终到站的匹配规则与上面的规则类似,但匹配的双方取对等关系。具体的表述为:列车时刻表中车站与始发终到站(设置的字段)匹配,当且仅当两者完全一样,或者两边的站名部分完全一样而其中一方只有站名没有场名。举例来说, 成都东::达成场成都东 可以匹配(无论何者是时刻表中首站)。

备注

注意在没有域解析符的情况下是严格匹配的,即 成都东达成场 无论如何不能匹配到 成都东 。但这种类型的情况用于始发终到站匹配时,可以用 自动始发终到站匹配 功能转换。

域解析符的非严格匹配主要用于线路上一个站存在多个场的情况。举例来说,若 贵阳北::渝贵贵广场贵阳北::沪昆场 存在于同一运行图文件时,若将线路上的站名直接设为 贵阳北 ,则上述两个站名皆可铺画,且不会丢失具体的场名信息。

列车始发终到站与时刻表站名的匹配决定了运行线标签(如果有)的性质。qETRC参照国铁的运行线标签规则(但并不完全照搬,主要是允许运行线结束标签带上车次),制定了一系列标签样式,如下图所示。若运行线开始端点同时是始发站,则使用始发站的标签;若运行线开始的端点不是始发站,则使用“从邻线驶来”的标签。结束标签类似处理。

运行线标签

关于站名匹配规则的更多应用,以及相关的调整功能,请参见 修订与微调

列车增删与管理

由于运行图文件中可包含大量列车数据,为了方便管理,我们在运行图资源管理器之外提供了(pyETRC风格的) 列车管理 停靠面板。通过工具栏 开始(1) 或者 列车(3) 页的 列车管理 按钮可以打开或关闭,其界面如下图所示。

列车管理

每行为一趟列车的基本信息,勾选或取消勾选 显示 列可以立即显示或隐藏该列车的所有运行线。点击 添加 可以添加空白车次;选中车次后点击 编辑 或者双击单元格,可以编辑列车的详细信息(参见 列车信息编辑 );表格支持多选,多选后点击 删除 可以批量删除;点击 批量 菜单下的选项可以执行对应的批量操作(参见 修订与微调 )。

在顶部输入框输入车次名的一部分,然后点击 筛选 ,则在表格中仅列出包含对应关键字的列车;再点击 清空筛选 则重新显示所有车次。注意此过程只是显示的变化,不会造成列车的增删、排序、变动等。点击表头可以按对应字段排序。

备注

与pyETRC不同,对表格排序会立即改变运行图文件中的列车排列顺序,并在保存文件之后,保存到(物理的)文件中。此操作可以撤销。

表中的 铺画里程 是指列车(在本运行图文件中所有线路上的)所有运行线里程之和,单位为千米(km); 铺画旅速 是指铺画里程与对应运行线的总运行时间之比(包含停站时间),单位为千米每小时(km/h)。

以下方式可以新建空白列车:

运行图资源管理器

列车 | 右键菜单 | 新建空白车次

列车管理

添加

运行图窗口

右键菜单 | 新建车次

工具栏

列车(3) | 新建车次

快捷键

Ctrl + Shift + C

以下方式可以删除已有的列车:

运行图资源管理器

列车 具体项目 | 右键菜单 | 删除列车

列车管理

删除

工具栏

列车编辑(7) | 删除

被删除的列车如果属于某个交路,则该交路中的对应项目被设置为虚拟车次(参见 交路数据 )。除此之外,还可以通过工具栏 列车(3) | 批量操作 菜单下的 删除所有车次 或者 删除所有车次和交路 功能清空列车。

警告

请注意上述两个清空功能是不可撤销的,请谨慎执行。

列车数据的导入

除了在本系统中从头创建、编辑列车数据,通常也可以采用从外部导入列车数据的方法快速构建运行图。从外部导入通常能获得更大的自由度,且数据可能有更好的复用性。目前qETRC主要支持的是从车次数据库文件( *.pyetdb )或者其他的运行图文件(无损地)导入车次信息;以及辅助性的从CSV或者ETRC的 *.trf 格式导入列车数据。

从车次数据库导入

备注

qETRC中的车次数据库文件通常以 *.pyetdb 后缀名标记。但车次数据库文件实质上就是一个运行图文件;此功能实际上也可以选择任意一个 *.pyetgr 格式的运行图文件导入。以下统一称为车次数据库。

从以下方式可以打开导入车次的对话框:

工具栏

列车(3) | 导入车次

快捷键

Ctrl + D

导入车次

在右上角选择数据库文件,左侧表格将显示要导入的车次。

备注

默认情况下, 仅与本运行图有重叠的车次 选项是勾选的。此时被导入的文件中,只有与本运行图当前线路存在至少一个车站交集的列车会被引入到左边的表格中。如果需要无条件导入所有车次,需先取消这个勾选,再选择文件。

左侧表格列出了将要导入的车次基本信息。这个表格实质上与 列车增删与管理 中所述的列车管理列表是相同的。可以在导入前对列车做一些编辑,删除不需要导入的车次。

右侧的选项指出了对重复车次名和重复交路的处理方式。 导入车次的同时可以对所有要导入的车次名附加前缀或者后缀,以与既有的车次形成区分。

点击 OK 完成导入操作,并立即重新铺画运行图。

警告

由于导入车次过程涉及了新旧车次的替代、重组以及交路中数据的替换等,使得操作较为复杂,此操作不支持撤销。注意不支持撤销的操作将同时导致此前的所有操作都不可撤销。请谨慎执行。

从CSV导入时刻表

qETRC支持从一种特定格式的CSV(逗号分隔值,comma splitted value)文件中导入车次时刻表。此功能位于工具栏 列车(3) | 导入车次 | 导入时刻表 (CSV) 。所给文件应当具有下列格式,且采用 UTF-8 编码:

车次

站名

到达时刻

出发时刻

股道(可选)

备注(可选)

K4113

成都

13:00:00

13:00:00

2

K4113

成都西

13:20

13:25

1

K4145

双流

14:53

14:53

K4145

公兴

15:02

15:02

1

8805

红牌楼

22:00

22:05

实际给出的文件中不需要表头。其中 车次 列应当输入全车次,到达、出发时刻可以带秒数也可以不带,股道、备注两列皆可不填。

程序在导入csv文件时,从前到后逐行依次、无条件地导入数据。每一行中,如果所给车次已经存在于运行图中,则将该行的站附加到已有车次的时刻表最后;如果不存在,则以该车次新建车次。因此所给的csv文件中可以包含多个车次,车次之间车站的顺序可以交叉,但同一车次内的车站顺序必须是正确的。

导入trf车次

trf是ETRC支持的车次描述文件,它是一种文本文件,可以由ETRC软件导出或者导入。trf文件的内容实质上就是trc运行图文件中描述列车的部分,但每个trf文件只能包含一个车次。qETRC提供对批量导入trf文件的支持,功能位于工具栏 列车(3) | 导入车次 | 批量导入车次(trf) 。可以一次性选择多个trf文件,每个文件作为一个车次,导入到当前运行图文件中。以下是trf文件的一个示例。

trf2,G8592,,G8592
重庆西
成都东
重庆西,06:30:00,06:30:00,true
璧山,06:42:30,06:42:30,true
永川东,06:48:50,06:48:50,true
隆昌北,07:02:25,07:02:25,true
内江北,07:10:45,07:12:45,true
资阳北,07:30:15,07:30:15,true
成都东,07:54:05,07:54:05,true

备注

从trf导入车次时,每个文件都作为一个新的车次导入。如果全车次与既有运行图中的车次冲突,则自动添加后缀。由于实现的原因,请确保导入的trf文件之中不存在重复的全车次。

时刻表基本编辑

qETRC提供了 列车编辑时刻表编辑 两种停靠面板,皆可用于列车时刻表的(无附加限制的)基本编辑。本节以 时刻表编辑 为例作说明,下节将说明 列车编辑 。除此之外,关于列车时刻表的调整,已有较多的小功能适用于不同场景,请参阅 修订与微调

时刻表编辑 面板提供了最简洁、最基本的时刻表编辑功能,不包含其他设置项,以最大化利用空间。此功能的主要入口为:

运行图资源管理器

列车 具体项目 | 右键菜单 | 编辑时刻表

工具栏

上下文页面 列车编辑(7) | 时刻表

时刻表编辑

表中每一行为时刻表中的一个车站,其中站名、到点、开点为必填项,其他为选填项。修改到达或者出发时刻, 停时 列的数据自动更新。 营业 列(原则上)指出列车在该站是否营业,对于客车也简称“办客”,对于货车简称“办货” (关于客车/货车部分参见 列车类型系统 )。 股道 列指出列车在该站停车的图定股道名称(参见 运行图分析 )。 备注 列可以给出一些注记信息,在车站事件表等场合会直接展示出来。

通过下方的按钮可以增加/减少车站,或调整车站顺序。

列车信息编辑

这里所说的列车信息主要是指列车(除了时刻表之外的)车次名、始发终到站等数据。在当前的qETRC实现中,主要有两种方式对这些数据进行(全面的)查看和编辑,一是在工具栏上下文页面 列车编辑(7) ,二是在(pyETRC风格的) 列车编辑 停靠面板,两者的内容基本完全一致。在 列车编辑(7) 面板中,(为节省空间)没有写出各个字段的名称,可将鼠标放在编辑框上,看弹出的提示(tooltip)。下图是工具栏上相关编辑部分。

列车编辑-工具栏

列车编辑 停靠面板除了提供上述信息编辑外,还提供时刻表编辑,因此实质上是对列车的较为全面的数据编辑面板;可以完全用pyETRC的停靠面板操作逻辑使用。从以下方式可以打开本面板:

运行图资源管理器

列车 具体项目 | 右键菜单 | 编辑列车

运行图资源管理器

列车 具体项目 | 双击

列车管理

双击

列车管理

编辑

工具栏

上下文页面 列车编辑(7) | 编辑

列车编辑-停靠面板

下面以 列车编辑 面板的字段名,逐个解释各字段。

全车次下行/上行 设置本次列车的车次名。在本系统中,全车次是列车的唯一识别标记,在每个运行图文件中,每趟列车的全车次必须非空且唯一。下行/上行车次,或称为分方向车次,主要用于复车次的情况,可以是空的。在默认情况下,下行运行线的标签优先使用下行车次标注,如果下行车次为空则用全车次标注,上行亦然。

始发终到 站,填任意站名即可,亦可留空。始发终到站主要在列车标签、交路连线及交路图等场景使用。参见 始发终到站匹配规则

列车种类 指定当前列车所属类型。下拉列表列出的是本运行图文件当前存在的列车类型名称,但也可以手动输入(当前不存在的)列车类型名,这将自动创建新的列车类型。

旅客列车 选项是三状态(tristate)的,勾选、不勾选状态分别表示该列车是客车或不是客车(在本系统论域内,也可以直接简称货车);而半勾选(half-checked)状态(图上的状态)表示根据列车类型做判断。

运行线设置 规定当前列车运行线的格式。属于同一列车的所有运行线的形式总是相同的。如果勾选 自动 ,则根据列车类型的设置来规定;否则可以在此处设置运行线的颜色、线宽、线形。关于以上几项,以及列车类型规则相关内容,参见 列车类型系统

列车类型系统

小技巧

关于列车类型系统的逻辑设计及一些实现,可以参见专栏文章:https://zhuanlan.zhihu.com/p/464281123

原来pyETRC的文档中,我写过这样一段话:

相比ETRC,pyETRC系统的一大特色是所有数据都要有依据,不会随意为用户指定参数,或者即使给了默认参数,也可以由用户调整。列车类型系统是这条原则的一个例子。列车的类型系统和是否为客车,都可以由用户规定。

这个表述现在同样适用于qETRC。qETRC的列车类型系统与pyETRC大同小异,但做了更多的整合,主要是(在代码实现层面)明确新增了“列车类型”这一实体,以承载相关的全部数据。因此操作上亦有些变化。类型管理系统的逻辑比较复杂,特别是中间可能涉及了多处具体含义不同的 默认 的表述。更多关于逻辑层次的内容,推荐阅读上面给的专栏文章。

备注

本系统已经预制了较为完整的中国铁路类型系统。正常情况下,无需用户修改。但如果用户需要添加自己的类型规则,或者不使用国铁类型系统(例如,用本系统来进行城市轨道交通运行图分析),则可以修改或重新设计类型系统,此时可以参阅本部分内容。

概述

在qETRC中,每趟列车都要属于某个列车类型,例如 快速 动车组 等。列车类型除了作为一般的属性来筛选列车外,还决定了列车(在默认情况下)的运行线样式(包括颜色、线宽、线型)。所有的列车类型还可以分为两个大类,即 客车非客车 。其中,非客车有时直接简称为 货车 (在qETRC论域内,“客车”和“货车”是二元对立的,是所有列车集合的一个划分)。

备注

在pyETRC中,列车类型和是否属于客车是两个相对独立的部分,这是由历史原因以及pyETRC的实现造成的。qETRC对这个逻辑做了调整,“是否客车”成为“列车类型”的一个属性。

出于一些实际工作中客货二分的考虑以及与pyETRC继承和兼容的原因,qETRC中仍有一些场景直接应用了是否客车的属性。此时可能需要注意逻辑的变化。使用qETRC解释原pyETRC保存的运行图文件时,列车类型系统也是容易出现问题的部分之一,如有问题可以反馈。

对于每趟列车而言,有下列两种方式决定该列车所属的类型:

  • 根据列车的车次名直接确定类型。例如,在国铁系统内,以 K 开头的车次为 快速 类型,以 T 开头的车次为 特快 类型,等。一般地,程序中以车次名的正则表达式(regular expression) 规定满足一定格式的车次所属的类型。这是常用的、推荐的方案。参见 类型判定规则

  • 对具体的列车,可以直接指定列车所属的类型名称,参见 列车信息编辑

类型管理器

备注

下述的类型管理和类型规则皆有软件级别的默认设置和运行图文件级别的设置两个层次。两者的编辑界面一致,但用途有所不同。运行图级别的规则是直接生效的规则;软件级的规则用于运行图规则缺省时的补充(通常是作为新建运行图或者导入ETRC运行图时的默认规则)。

以下是以运行图级的设置为例。如果希望编辑软件级的默认设置,可在功能入口处的下拉菜单中找到相应的功能。

前面说过,在qETRC中,“列车类型”被作为独立的一个实体存在。类型管理器就用于管理各个类型实体的数据。目前每个类型的属性主要包括是否为旅客列车类型以及运行线样式。在工具栏 显示(4) | 类型管理 中可以查看、编辑当前运行图的类型管理系统,如下图所示:

类型管理系统

其中每行表示一个类型,可以设定类型名称及其各种属性。需注意列车类型名称必须是非空且不重复的。

备注

类型表第一行固定为 其他_ ,这是默认的类型,也就是当列车车次名无法匹配到任何类型时的兜底规则。表中可以修改默认类型的运行线属性,但请不要修改类型名称,不要删除默认类型,且始终保持它在类型表的第一行。否则可能导致意外的行为。

警告

这里的类型管理器并不能绝对地控制类型系统。特别是,删除类型的操作并不总是有效的。因为每趟列车必须属于一个类型,(举例来说,)如果存在列车属于类型A,但在这里的表中删除类型A,则这个删除操作是无效的。建议谨慎使用增删的功能,并仔细阅读窗口上方所给的说明,再做修改。

类型判定规则

为了支持从列车车次名到类型的转换,qETRC设计了一套类型判定规则,它是一组规则的有序序列,每条规则由描述车次格式的正则表达式(regex expression)和对应的类型名组成。在工具栏 显示(4) | 类型规则 可以打开编辑窗口,如下图所示。

类型规则

其中每一行是一条规则。匹配每个车次名时,总是从前到后依次匹配每一条规则,直到找到第一个能够匹配的规则为止,即为匹配结果。如果没有能够匹配的规则,则列车类型为默认的 其他_ 。类型规则中的类型名是可以重复的;也就是说可以有多条规则来指向同一种类型。

小技巧

上述从前到后依次匹配的逻辑是程序严格保证的。因此编写规则时可以利用这一条特性,一定程度地简化规则。

小技巧

此处使用的正则表达式是Qt的 QRegExp 类实现,关于正则表达式的具体规则可以查阅Qt文档或者其他相关资料:https://doc.qt.io/qt-5/qregexp.html

列车的类型

我们已经指出过,qETRC中每一趟列车总是属于一个类型:列车既不能不属于任何类型,也不能同时属于多个类型。现在我们进一步指出,列车总是属于一个确定的类型,也即它不能是悬而未决的。

在编辑列车信息时,如果列车类型一栏留空,系统将根据类型判定规则决定列车所属类型。注意这个决策是立即以当前规则设置进行的;当类型判定规则改变时,不会自动重新推断所有列车的类型,除非用户显式地使用工具栏 列车(3) | 批量操作 | 自动推断所有列车类型 功能。

除了对单一列车指定其所属类型外,我们还提供了对一组列车批量设置类型的功能,位于 列车管理 停靠面板 | 批量 | 批量分类 。在列表中选中一组列车后,输入或选择其所属的类型即可,如下图所示。

批量分类

最后,作为对pyETRC相应功能的兼容性考虑,我们仍然设置了对单个列车(在其所属类型之外)强制设置其是否属于旅客列车的功能,由一个三状态的复选框设置(参见 列车信息编辑 )。默认情况下,此复选框处于部分选中状态,即根据列车所述的类型,决定它是否属于客车。这个设置是动态的:如果列车类型的是否旅客列车属性发生变化,则其下的列车的是否客车属性也相应变化。这也是推荐的设置状态。用户也可以将此复选框改为勾选或不选的状态,则表示该列车是或不是旅客列车(无论其所属类型的设置如何)。