本项目是基于Python语言和PyQt5的非官方性质、简易的中国铁路列车运行图系统。本代码的发布遵循GPLv3
协议。在协议允许范围内,作者保留一切权利和最终解释权。
作者联系方式:[email protected]
本项目在Windows 10 操作系统下开发和测试。
pyETRC
项目的最初灵感来源和很多功能设置都来自由LGuo等前辈基于java语言开发的ETRC
列车运行图系统。为致敬开发ETRC
项目的前辈,本项目定名为**pyETRC
列车运行图系统**,简称为pyETRC
。
本系统支持读取和导出ETRC
列车运行图系统的运行图文件(*.trc
)。但由于两软件支持的功能有差异,读取和导出过程可能造成一定的信息损失。
本系统与ETRC
列车运行图系统的实现各有侧重。相比本系统,ETRC
列车运行图系统有如下的特色比较突出:
- 动态运行图。本系统不支持此功能。
- 对于精确到客运时刻的需求,自带较完善的线路数据库和车次时刻数据库。而本系统的线路和车次数据库依赖外部文件,且目前很不完整。
- 较完善的车次切片功能。
- 更简洁的操作和数据,或者说需要用户提供的数据更少。
相比ETRC
列车运行图系统,本系统主要有如下的特色:
- 更准确、完整的数据支持,包括精确到秒的时刻和精确到三位小数的里程,允许上下行分设不同站点,标尺,天窗,交路等。
- 做了一定的效率优化,对较大运行图的执行效果相对更好。
- 提供了一些运行图快速微调工具和分析工具,例如调整某一站名(同时修改所有列车数据中引用的改站名),对比两运行图等。
- 在
3.0.0
版本以后,提供了路网级的数据库管理模块,可以在更高层面上管理,更方便地查看、导出区段运行图。
两系统各有长短。因此我们建议,如果有需求,可以两套系统结合使用。
使用源代码方式运行本项目,需要具有以下环境。
-
Python
3.7及以上的版本。开发所用的版本是3.7.4.注:本项目使用了大量的
f-string
语法,该语法在Python
3.6以后的版本才被支持。一些较新的代码中利用了Python
3.7中dict
键值对顺序与添加顺序一致的特性。如果使用3.6.*版本,这部分代码可能出现一些问题。如果使用3.6以下版本,则会报错。 -
下列的
Python
第三方库,都可以用pip
安装。PyQt5
。必须。推荐使用5.10.1
版本。xlwt
。可选。在涉及输出.xls
的操作中需要用到。xlrd
。可选。在涉及读取.xls
的操作中需要用到。xpinyin
。可选。在本系统2.3.0
版本之前的线路数据库排序中用到。NetworkX
。可选。在3.0.0
版本引入的路网数据管理中,用于以图论算法计算经由给出的路径。
-
作者开发的另一支持库
Timetable_new
。该库需要使用github上的源代码安装。
在安装第三方库之前,需要配置好python
环境,并将安装目录添加到PATH
环境变量中,安装好pip
库。相关教程可借助搜索引擎找到。
在shell中依次执行以下命令,无报错即可。
pip install PyQt5==5.10.1
pip install xlwt
pip install xlrd
pip install xpinyin
pip install networkx
依次执行:
git clone https://github.com/CDK6182CHR/Timetable_new
cd Timetable_new
.\install.bat
如果不用git
,也可以在链接中下载并解压源代码,双击执行install.bat
。
注:
install.bat
文件适合windows操作系统。如果是其他操作系统,请自行更改相关代码。
install.bat
的代码如下。
python setup.py build
python setup.py sdist
python setup.py install
pause
运行main.py
文件即可。
python main.py
这部分作为简单的扩展开发指南。
本项目目前有3个可执行文件。
main.py
是主程序运行入口。LineDB.py
在2.3.0
版本之后添加,是线路数据库维护系统的运行入口。RailNetManager.py
在3.0.0
版本之后添加,相对独立的路网级运行图数据库管理系统。
本项目主要依赖的是train_graph
包。下面简要说明包结构。
以下类主要用于存储数据,一般不包含与PyQt
交互的过程,一般涉及文件读写。如果要基于本项目进行扩展开发,推荐直接调用这些类。自2.3.1
版本开始,这部分被封装为data
包(package)。
line.py
铁路线路数据对象。trainstation.py
2.3.2
版本开始新增的列车时刻表中车站类。继承dict
实现,并可以按需要新增功能。linestation.py
与trainstation.py
类似,是对应Line
中的车站数据。train.py
列车对象。ruler.py
标尺(时分标准)对象。forbid.py
天窗数据对象。graph.py
运行图对象,主要包括一条线路Line
和一组车次Train
。circuit.py
车底交路对象。每个交路包含若干车次Train
的序列,每个车次可以属于至多一个交路。route.py
尚未开发完成的列车运行径路对象。
从大约2.4.0
版本开始新增utility
包,主要是通用的工具,以及对Qt既有组件的改进。目的在于,通过引进面向对象设计模式,提高代码复用能力。模块名、类名的前缀pe
是pyETRC
的简写,以区分于Q
开头的Qt原生组件类。
-
peCellWidget.py
是对QTableWidget
中的(通过setCellWidget
方法设置的)单元格组件的改进。原生的CellWidget
从没有包含所处的单元格位置信息,不能在其获得焦点时,同步修改tableWidget.currentItem()
等属性。此模块用于解决这个问题。其中,
PECellWidget
类仅对RTTI有用,暂无其他意义。请不要直接实例化这个类。请使用CellWidgetFactory.new()
工厂方法创建实例控件。 -
peCelledTable.py
与PECellWidget
配套使用的支持单元格组件定位的表格。主要是重写了setCellWidget
方法。 -
peControlledTable.py
是对需要支持增删、上下移动行的表格的封装。引进Adapter设计模式。本身继承的是QWidget
,但将有关方法调用转发给内置的QTableWidget
实例对象。实例化时,也可以通过参数
meta
指定创建QTableWidget
的某个子类实例,本项目中目前用到的是PECelledTable
。
在调用了PyQt
的模块中,有一部分与底层的绘图(绘制运行线)直接相关,它们是本项目的核心,这里单独列出来。
GraphicWidget.py
核心绘图窗口。继承QGraphicsWidget
实现,运行图的铺画在本类中完成。trainItem.py
列车运行线对象。包含了主要的运行线铺画逻辑。是GraphicWidget
类中的图元。在2.0.0
版本之后,每一趟列车(一个Train
对象)允许拥有多个TrainItem
对象。
与运行图数据操作相关的类主要有两种形式,一是以停靠面板方式,长期显示和有效的面板;二是以对话框为主的操作交互界面。前者包含了本系统的核心操作功能,下面简要说明停靠面板类及其相关类。
circuitWidget.py
交路编辑停靠面板,快捷键为ctrl+4
。colorWidget.py
默认颜色设置面板。在1.4.0
之后的版本中,被集成到运行图设置
面板中。configWidget.py
运行图设置面板。包含关于运行图铺画比例、运行图备注等设置。快捷键为ctrl+G
currentWidget.py
当前车次编辑面板。包含对当前选中的列车的车次、运行线管理、时刻表编辑等功能。这是最集中的修改列车信息的面板。快捷键为ctrl+I
。forbidWidget.py
天窗编辑面板。快捷键为ctrl+1
。interactiveTimetable.py
交互式时刻表。与时刻表面板布局类似,但支持更改列车时刻表, 且更改立即生效,立即体现在运行图上。lineWidget.py
线路编辑面板,可编辑线路名称和站表。快捷键为ctrl+X
。rulerWidget.py
标尺编辑面板。可管理标尺(增删改)。标尺数据属于线路数据的一部分,但其编辑功能是独立的。快捷键为ctrl+B
。trainTimetable.py
当前车次时刻表面板。将当前车次时刻表以只读方式、占用宽度尽量小的形式展示,建议可以长期开启的停靠面板。快捷键为ctrl+Y
。trainWidget.py
车次列表面板。展示基本的车次信息,并可增删。快捷键为ctrl+C
。typeWidget.py
显示类型面板。提供简洁的界面来快速选择显示或不显示某一类列车的运行线。快捷键为ctrl+L
。typeDialog.py
是由ConfigWidget
调用的列车类型管理对话框。管理默认情况下用于识别列车种类的车次正则表达式,是否为客车。
其他文件名形如*Dialog.py
*Widget.py
的大多数是与操作相关的窗口。下面简单说明。
mainGraphWindow.py
主窗口类。程序启动后首先产生本类实例。batchChangeStationDialog.py
批量调整站名,快捷键为ctrl+shift+U
。changeStationDialog.py
修改站名。快捷键为ctrl+U
。changeTrainIntervalDialog.py
列车区间时刻表重排功能。快捷键为ctrl+shift+R
。correctionWidget.py
提供对当前车次时刻表重新排序的功能。快捷键为ctrl+V
。detectWidget.py
根据标尺,推定列车区间通过时刻。快捷键为ctrl+2
。exchangeIntervalDialog.py
区间换线。交换两车次指定区间的运行线。快捷键为ctrl+5
。helpDialog.py
内置的简明功能表。快捷键为F1
。importTrainDialog.py
导入车次对话框。快捷键为ctrl+D
。intervalCountDialog.py
区间对数表。快捷键为ctrl+3
。intervalTrainDialog.py
区间车次表。快捷键为ctrl+shift+3
。intervalWidget.py
当前车次区间性质计算。支持计算选定区间的停站次数,旅速等。快捷键为ctrl+shift+Q
。rulerPaint.py
标尺排图向导类。按标尺,指定开始站点和方向、各站停站时长,自动铺画运行线。这是本系统亮点功能之一。快捷键为ctrl+R
。stationTimetable.py
车站时刻表,快捷键为ctrl+E
。stationvisualize.py
车站时刻表可视化。根据车站时刻等信息,提供一种股道安排方案并可视化。trainComparator.py
两车次时刻对照。快捷键为ctrl+shift+W
。trainDatabase.py
为导入车次功能中的相关设定提供支持。功能快捷键为ctrl+D
。graphDiffDialog.py
提供两运行图数据对比功能。2.3.2
版本新增。trainDiffDialog.py
提供两车次对比功能,主要由GraphDiffDialog
调用。2.3.2
版本新增。
2.3.0
版本彻底的重构了线路数据库这个模块,因而重新设计了有关代码,写成一个包(package),名为linedb
。它主要包含这些类(文件)。
category.py
线路“分类”的类。新版本的线路数据库中支持对库中的线路做任意多级别的分类,其中分类的数据部分 由本类实现。本类继承dict
。lineLib.py
是Category
的派生类,在顶层分类的基础上添加了文件io部分,并作为与GUI部分通信的主要接口。lineTreeWidget.py
对话框左侧的文件树类。继承QtWidgets.QTreeWidget
实现。关于线路、类别的增删逻辑,全都在本类实现。lineLibDialog.py
线路数据库对话框。在主界面中由ctrl+H
快捷键直接打开的就是这个对话框。
自3.0.0
版本新增路网级数据库管理模块,简称“路网管理模块”。本模块提供比区段运行图高一个级别的运行图管理,可以直接管理线路数据库和车次数据库,并不局限于既有线路,而是可以(基于铁路网的有向图模型)导出有数据的任一区段运行图。本部分的代码构成 railnet
包,从根目录下的RailNetManager.py
可以运行。
考虑到NetworkX
编译代价问题,目前win64
发行版暂不包含这部分功能。
railnet.py
铁路网络的数据模型。主要基于第三方库NetworkX
建立有向图模型,并能导出区段运行图。线路(Line
)数据模型与主程序一致。trainManager.py
车次数据库管理页面,主要显示和维护*.pyetdb
文件包含的数据。sliceManager.py
区段(切片)运行图管理页面,显示当前程序打开的所有区段运行图,并可输入经由,生成新的区段运行图。mainNetWindow.py
路网管理模块的主窗口。
由于交路部分涉及到的窗口较多,现在将和交路有关的窗口都合并到circuitwidgets
包中,除circuitWidget.py
停靠面板类之外。
circuitDialog.py
单个交路数据的编辑对话框,在CircuitWidget
中发起编辑操作后弹出。circuitDiagram.py
绘制交路图的面板。在CircuitDialog
中发起查看交路图操作后产生。circuitDiagramWidget.py
绘制交路图的对话框。ParseTextDialog.py
解析交路文本的对话框。从CircuitDialog
中的按钮触发,只解析一个交路。BatchParseCircuit.py
批量解析交路文本的对话框。对应快捷键ctrl+P
。AddTrainWidget.py
添加车次的对话框,主要是封装的外层QTabWidget
。AddRealTrain.py
添加实体车次,是AddTrainWidget
中的一个页面。AddVirtualTrain.py
添加虚拟车次,是AddTrainWidget
中的一个页面。所谓虚拟车次,是指仅有车次,但不指向本线一个具体Train
对象的车次,它仅仅为了保持交路完整性而存在。但如果导入了那个车次的Train
对象,则可以尝试识别虚拟车次。
trainFilter.py
车次筛选器。在全局用快捷键ctrl+shift+L
启动“高级显示车次设置”时,会调用本类。在车次编辑、车站时刻表等处也有使用。
pyETRC
依赖的数据文件全部是基于JSON
格式的。所有文件,无论扩展名,都是基于UTF-8
的无签名(不带BOM
,否则会出错)编码。使用Python标准库json
读取和写入。下面简要说明本系统的各种文件所要求的格式、内容及其生成方法。
包含上次打开的文件,系统默认运行图文件,上次关闭时的停靠面板等。一般情况下不需要手动处理。
生成方法:程序每次正常退出时都会生成。参见:mainGraphWindow.py
中的函数mainGraphWindow._checkSystemSetting()
。
包含用户设置的系统默认参数,例如运行图铺画大小,颜色,列车种类等。当用户新创建或者打开的运行图中不包含配置数据时,将自动使用(并复制)这一套数据。当文件缺失或某些字段缺失时,系统配置由Graph.checkSysConfig()
函数补全,见graph.py
。
生成方式:当程序正常运行时,用户若在“系统默认设置”(ctrl+shift+G
)面板中保存数据,或者在“线路数据库”(ctrl+H
)中更改默认文件时,自动保存config.json
文件。
如果要手工读取,请使用Graph.readSysConfig()
,手工保存请使用Graph.saveSysConfig()
,调用其数据请使用Graph.sysConfigData()
,该函数返回dict
类型。
包含列车运行图所需的所有数据,此部分的支持见graph.py
。文件最核心的数据结构大致是:
{
"line":{
"name":"宁蓉线成渝段",
"stations":[
{
"zhanming":"重庆北渝利场",
"licheng":0.0,
"dengji":0,
},
]
},
"trains":[
{
"checi":[full,down,up],
"timetable":[
{
"zhanming":"成都东",
"ddsj":"00:00:00",
"cfsj":"00:01":
},
...
],
},
...
]
}
最基础的数据是line
和trains
两个字段,分别是线路基础数据和车次数据表。前者由Line
对象管理,后者由一系列Train
对象管理。
如果要通过代码调用,请使用Graph.loadGraph()
方法来读取文件,Graph.save()
方法来保存。数据的修改、使用,请参阅Graph
Line
Train
等数据类的类定义。
2.3.0
以后版本建议车次数据库文件使用*.pyetdb
后缀,但其结构与*.pyetgr
的列车运行图文件是完全一致的,这意味着完全可以用pyETRC
直接打开它们,但由于车次数据库往往有非常多的数据量和不完整的线路数据,打开它们通常是很慢且没有意义的过程,故新版本中予以区分。
这里只介绍2.3.0
以后版本所用的线路数据库文件。新版本可以读取老版本的文件,但反之一般不行。线路数据库文件为任意多级嵌套的js对象,或者Python字典。字段名是分类名或者线名,而字段值属于一条线,当且仅当它存在str
类型的name
字段和list
类型的stations
字段。这意味着,如果在同一个分类下给两个子线路或者分类其名为"name"
和"stations"
,将导致不可预知的后果。
正常运行时,使用“线路数据库”(ctrl+H
)功能中的“保存”将创建或者保存*.pyetlib
文件。
如果要通过代码操作,相关支持在linedb/lineLib.py
文件中。使用LineLib.loadLib()
方法来读取文件,使用LineLib.saveLib()
方法来保存文件;更多具体的操作,请阅读lineLib.py
和category.py
的源代码。
在3.0.0
版本后添加的网络数据库管理模块中使用。保存的是工作区配置的信息,具体包括:
- 打开的线路数据库文件名(
*.pyetlib
) - 打开的车次数据库文件名(
*.pyetdb
) - 打开的所有运行图切片的经由表。
但不会包含上述信息里的具体内容。
也就是说,只记录线路数据库文件名,但不包含线路数据库的内容。
一般情况下,没有必要编程处理这种数据格式。