以下提供了关于实现新网络导入器的建议——
实现自己的网络导入模块非常简单。需要执行以下步骤:
- 编写从原始文件读取和解析信息的方法
- 将解析后的值插入网络构建容器
- 让网络导入器知晓并使用你的代码
- 提交你的代码
是的,仅此而已。尽管如此,以下章节将更详细地描述这三个步骤。
构建读取器#
初步考虑#
关于网络导入器有一些我们试图遵循的约定。它们不是强制性的,但假定它们可以确保代码的可扩展性并强制提高代码质量。
在开始编写自己的导入器时,你应该考虑基于现有的导入器进行开发。NIImporter_OpenStreetMap.*、NIXML...Handler.* 是从 XML 文件读取网络描述的示例。NIImporter_VISUM.* 和 NIImporter_DlrNavteq.* 读取以不同方式格式化的纯文本文件。所有这些模块都位于 <SUMO_HOME>/src/netimport 中,当然,你的导入器也应该放在这里。
Convention
网络导入器代码位于 <SUMO_HOME>/src/netimport/ 中
Convention
网络导入器应命名为 NIImporter_<FORMAT_NAME>
调用读取器#
在添加对网络导入器 init 函数的调用之前,你必须添加相应的选项;否则,第一次调用将因访问未知选项而以错误结束。选项必须添加到 void NIFrame::fillOptions() 中。
然后,你可以通过在 NILoader.cpp 中包含解析器的 .h 文件,并在 void NILoader::load(OptionsCont &oc) 中添加对其 loadNetwork 方法的调用,使导入设施知道你的解析器。
导入顺序#
在大多数情况下,边、节点、交通灯、边之间的连接以及其他道路网络属性是显式给出且分离的。信息必须以正确的顺序导入。以下顺序是正确的:
- 节点
- 边(需要引用源节点和目标节点)
- 边之间的连接(通常需要引用边)
- 交通灯(需要引用节点)
一些更激进的程序员可能会尝试稍微优化顺序,如果原始数据的排列方式不同。在某些情况下这可能是可行的。
如果节点、边和其他信息是从多个文件解析的,则必须考虑导入顺序。当然,也可以将数据存储在临时容器中。但这应该尽量避免,因为它会增加内存消耗,而内存消耗确实是网络构建过程的主要问题之一。如果使用了临时容器,在从导入返回之前当然必须清除它们。
Convention
尽量避免使用静态容器
Convention
如果使用了静态容器,请清理它们
开始解析#
所有导入器都有一个名为 "loadNetwork" 的静态方法,用于启动解析。此方法负责在设置了相应选项时启动导入,并确保读取的值存储在相应的网络构建容器中以供进一步处理。为此,必须将选项和网络构建结构提供给导入器,使得调用具有以下签名:
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb);
首先,此方法询问是否设置了使 netconvert 读取相应格式文件的选项,以及设置的值是否正确。目前,这仅意味着检查给定的文件是否确实存在,而不是检查其格式是否良好或是否有效。方法 FileHelpers::exists(<FILE>) 返回给定文件是否存在。
Convention
所有导入器都有一个静态成员,用于检查是否设置了具有有效值的相应选项
检查文件存在后,将构建并启动解析器。
你可能已经注意到,某些导入解析器允许通过 ',' 分隔来给出多个文件。这在某些时候非常有帮助,但这不是强制性的。这取决于你决定你的导入器是否应该能够处理多个文件。
错误处理#
不同的格式有不同的错误来源。在某些情况下,可能需要在解析期间应用启发式方法。在所有情况下,如果出现奇怪的情况——而且并不是每次导入给定格式的网络都会出现奇怪的情况——应该生成警告。这通过调用宏来完成:
WRITE_WARNING(<TEXT>);
如果异常行为完全不允许进一步处理导入的文件,或者读取的值格式不正确(例如,读取了字符串,但预期的是浮点数),则应抛出 ProcessError。异常必须包含有关错误的信息,例如:
throw ProcessError("Number of lanes is <0");
是的,决定奇怪的值是错误还是警告有时是很困难的。
Convention
在发生错误时抛出 ProcessError
Convention
对异常行为发出警告
Convention
警告和错误异常都必须提供有关原因的解释
将读取的值添加到网络构建容器#
在节点、边或其他任何内容的定义解析之后,必须构建相应的结构并将其插入到相应的网络构建容器中。
| 类 | 道路元素 |
|---|---|
| NBNode | 节点(交叉口,路口) |
| NBEdge | 边(道路,街道) |
下表显示了哪些定义存储在哪些容器中:
在大多数情况下,这些方法返回添加是否成功。如果不成功,很可能已经存在同名的对象。通常,我们处理过的导入网络不包含重复项——除了可能是双向的边。如果无法添加对象,你必须显式删除它。如果你的格式已知包含重复项,你应该询问是否已经构建了重复项,仅在没有构建时才构建实例。
Convention
尽量避免构建和删除重复项
测试#
提交代码#
如果你没有仓库的写入权限,我们将非常高兴如果你能发出拉取请求或将针对最新版本的补丁发送到 sumo-dev 邮件列表。
