【StreetGen】城市级交通路网生成算法

2024-04-28 19:20

本文主要是介绍【StreetGen】城市级交通路网生成算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

街道面积广阔、多样化,用于多种(可能相互冲突的)交通方式以及社会和文化活动。 适当的规划至关重要,并且需要数据。 手动制作代表街道的数据(街道重建)容易出错且耗时。 由于细节的多样性、大小和规模,自动化街道重建是一项挑战。

最先进的技术侧重于道路(没有环境,没有城市特征),并且很大程度上取决于每个应用程序(模拟、可视化、规划)。 我们提出了一个统一的框架,该框架适用于真实的地理信息系统(GIS)数据,并在可能的情况下使用强大而简单的建模假设来对城市级别或街道级别的街道进行稳健建模。 我们的方法产生了一个连贯的街道网络模型,其中包含拓扑交通信息、路面和街道对象。 我们通过重建整个巴黎市街道并探索其他类似的重建(机场车道)来证明我们方法的稳健性和通用性。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

1、简介

图 2:StreetGen 一目了然。 给定道路轴,重建网络,找到拐角弧,计算表面,添加车道和标记。

街道很复杂,具有多种用途,包括实用(步行、购物等)、社交(会议等)和文化(艺术、公共活动等)。 管理现有街道和规划新街道需要数据,因为规划通常在整个社区范围内进行。 这些数据可以手动制作(例如,通常是地籍数据)。 不幸的是,这样做需要大量的时间和人力资源。

事实上,一个中等规模的城市可能有数百公里的街道。 街道不仅在空间上很宽,而且具有很强的可塑性并且经常变化。 此外,街道数据必须精确,因为一些结构元素,如路沿石(它们将人行道与道路分开)只有几厘米高。 弯曲的街道也不适合曼哈顿假说,该假说认为城市是沿着三个主要的正交方向组织的 Coughlan 和 Yuille(1999)。

街道上物体的数量和多样性也特别具有挑战性。 由于街道数据可能用于非常不同的目的(规划、公共工程和交通设计),因此它应该是可访问和可扩展的。

传统上,街道重建方案更多的是道路重建,也很大程度上以重建数据的后续使用为导向。 例如,当使用交通模拟时 Wilkie et al., (2012); 阮等人,(2014); Yeh 等人 (2015) 的重点是重建道路轴线(有时是车道),而不一定是道路表面。 在此应用中,重建的数据是一个网络(具有拓扑属性)也很重要,因为交通模拟工具依赖于它。 然而,重点显然是重建道路而不是街道。 街道是比道路复杂得多的对象,因为它们表达了城市的复杂性,并且包含城市对象、地点、临时结构(如市场)。 就准确度而言,重建的精度最多在一米左右。

另一个应用是虚拟世界或驾驶模拟的道路建设。 在这种情况下,我们可能只是想创建逼真的道路。 为此,可以使用现实生活中的土木工程规则,例如使用回旋曲线作为高速公路 McCrae 和 Singh,2009a 的主曲线; 王等人,(2014)。 当尝试创建虚拟世界时,建造的道路必须很好地融入其环境。 例如,当道路被水包围时,道路应该通过桥梁。 我们还可以模仿现实世界的道路建设限制,并选择一条能够最大限度降低成本的道路路径 Galin 等人(2010)。 甚至可以创建道路以形成分层网络 Galin 等人(2011)。 这样生成的道路看起来很漂亮并且很好地融入地形,但它们与现实不符。 也就是说,它们只存在于虚拟世界中。

目标还可能是创建一个道路网络作为城市的基础布局。 事实上,源于 Parish 和 Müller (2001) 的开创性工作,一整套方法首先按程序创建道路网络,然后创建地块并挤压它们以创建虚拟城市。 这些方法非常强大且富有表现力,但它们可能难以控制(即调整方法以获得所需的结果)。 其他工作集中于控制方法 Chen 等人,(2008); 利普等人,(2011); 贝内斯等人,(2014)。 这些方法都有同样的缺点; 它们并不直接适应模型现实。

更一般地说,在给定程序生成方法的情况下,找到参数以使生成的模型与所需结果相匹配仍然是一个持续存在的问题(例如,逆过程建模,如 Martinovic 和 Van Gool(2013)中的立面)。

在这项工作中,我们提出了一种街道程序建模的原始方法:StreetGen。 我们从粗略的 GIS 数据(巴黎路轴)开始; 因此,我们的建模基于真实的道路网络。 然后,我们使用基本假设和简单的道路模型来生成更详细的数据。 此时,我们生成一个大城市(巴黎)的街道数据; 结果是一个街道网络模型。 我们使用广泛的街道网络模型,其中骨架由形成网络的街道轴和交叉口形成。 然后其他组成部分(车道、人行横道、标记等)都链接到该网络。 我们所有的工作都基于关系数据库管理系统(RDBMS),用于存储输入、结果、拓扑和处理方法。

在第 2 节中,我们解释了为什么我们选择将我们的工作基于 RDBMS,并解释了假设、我们如何生成路面以及如何编辑生成模型的参数。 在第 3 节中,我们提供了街道生成的结果和编辑的结果。 在第 4 节中,我们讨论结果并提出局限性和可能的改进。

2、方法

2.1StreetGen简介

图 3:StreetGen 工作流程

StreetGen的设计是理论和实践考虑之间折衷的结果。 StreetGen 使用简单而有力的假设来放大数据。 因此,该方法是在假设看似正确时获得正确的结果,并在假设看似错误时将方法更改为更稳健的方法,以便始终获得最佳猜测结果。

其次,StreetGen 被设计为在不同级别独立工作。 它可以生成城市级别的街道数据。 完全相同的方法还在街道级别交互式地生成街道数据。

最后,StreetGen 结果被不同的应用程序使用(可视化、交通模拟和空间分析)。 因此,结果是一个具有强制约束的连贯街道数据模型,并且我们还保持与输入数据的链接(可追溯性)。

图 3 总结了 StreetGen 流程。

2.2 关系型数据库管理系统简介

出于多种原因,我们选择在 StreetGen 的核心使用 RDBMS(*PostgreSQL 团队,2014 年 - 与 PostGIS 团队,2014 年 -)。

首先,RDBMS 是经典且广泛使用的,这意味着任何使用我们的结果的应用程序都可以轻松访问它,无论操作系统 (OS) 或编程语言如何。

其次,RDBMS 的用途非常广泛,可以在一个通用框架中重新组合我们输入的 GIS 数据、道路网络(具有拓扑)、生成的街道模型,甚至创建它的方法。 与基于文件的解决方案不同,我们将所有数据关联起来并强制执行这些关系。 例如,我们的模型包含与相应街道轴关联的街道表面。 如果删除一根轴,则相应的曲面也会自动删除。 我们将这一概念进一步推进,并将结果表与输入表链接起来,以便输入数据的任何更改都会自动导致结果更新。

最后,使用 RDBMS 提供了多操作系统、多 GIS(可能有许多客户端)、多用户功能,并且已被证明可以轻松扩展。 我们强调,StreetGen 的整体是自包含在 RDBMS 中的(输入数据、处理方法和结果)。

2.3 StreetGen设计原则

  • StreetGen的输入

我们使用很少的输入数据,并接受这些数据是模糊的并且可能包含错误。

第一个输入是由折线组成的道路轴网络(road axis network),每个轴都有估计的道路宽度。 我们在实验中使用巴黎的 BDTopo1 产品,但这种数据在许多国家/地区都可用。 它还可以根据航空图像 Montoya-Zegarra 等人 (2014)、激光雷达数据 Poullis 和 You (2010) 或跟踪数据(GPS 和/或手机)Ahmed 等人 (2014) 进行重建。

使用道路轴网络,我们使用 GRASS GIS (Neteler et al., (2012)) 或直接使用 PostGIS Topology 团队 PostGIS Topology, 2014- 来重建网络拓扑,使其达到容差。 我们通过 PostGIS 拓扑存储和使用具有有效拓扑的网络。

第二个输入是粗略估计的每个轴的平均速度。 我们可以简单地从道路重要性或道路宽度得出(当道路较宽时,平均速度更有可能更高)。

第三个输入是我们对街道的建模和我们创建的假设。

由于我们需要的数据是可以重建的,并且对数据质量的要求很低,所以我们的方法几乎可以在任何地方使用。 特别是,道路属性可能非常基本,如果需要的话仍然可以进行修正。

  • 街道数据模型

图 4:街道数据模型

现实生活中的街道极其复杂多样; 我们的目标并不是对所有可能的街道的所有微妙之处进行建模,而是旨在使用合理数量的参数对典型街道进行建模。

首先,我们观察到街道和城市物体是由街道轴线构成的。 例如,人行横道是相对于街道轴线定义的。 因此,我们将模型以街道轴为中心。

其次,我们观察到街道可以分为两种类型:形态不变的部分(相同的道路宽度、相同的人行道数量等)和过渡部分(交叉口,当道路宽度增加或减少时的过渡)。
我们遵循这种划分,以便我们的街道模型由形态恒定的部分(截面)和过渡部分(交叉口)组成。 过渡部分和恒定部分之间的间隔是截面限制,并以曲线横坐标的街道轴表示。

第三,经典街道适应交通,这意味着典型的车辆可以以给定的速度安全地沿着街道行驶。 这意味着十字路口的基石不会形成对车辆轮胎造成危险的急右转弯。 在这种情况下,最广泛的基石路径似乎是圆弧,因为它是公共工程期间最容易建造的形式。 因此,我们认为基石路径是一段或一段圆弧。 这种选择与 Wilkie 等人 (2012) 类似,并且非常适合城市,但不太适合城郊道路,其中选择的曲线通常是回旋曲线(如 McCrae 和 Singh,2009b) ,因为它实际上是用来修建高速公路和快速路的曲线。

然后,交集面由边界曲线起始处的每个轴上最远的点定义。 在此基本模型中,我们添加车道、标记等。

  • 运动学经验法则

图 5:不同重要性街道的 3 个不同半径大小(3m、4.9m、7.6m),来自真实的巴黎数据

我们提出基本假设来尝试估计交叉口拐角的半径。 我们强调,这些是给出合理最佳猜测结果的经验法则,并不意味着街道实际上是遵循这些规则的(例如,对于巴黎来说,这是错误的)。

我们的第一个假设是,街道经过改造,以便车辆可以根据街道类型以给定的速度 s 方便地行驶。 例如,车辆在狭窄的住宅区街道上行驶往往比在城市快车道上行驶得更慢。
我们的第二个假设是,给定速度,车辆的转弯受到限制。 考虑到车辆遵循圆弧轨迹,半径太小会产生危险的加速度并且会不舒服。 因此,我们可以通过经验函数f(s0)->r找到与行驶速度s相关的半径r。 该函数基于法国组织 SETRA (SETRA,, 2006) 的真实观察(函数见第 1 节)。

根据我们的街道数据模型和这些运动学经验法则,我们推断,如果我们大致了解道路的类型,我们也许能够粗略地估计其上车辆的速度。 根据速度,我们可以估计转弯半径,从而得出道路几何形状(见图 5)。

示意性地讲,我们认为道路边界是由车辆以给定速度沿其行驶,同时进行舒适转弯来定义的。

2.4 稳健高效的弧计算

上一节中的假设使我们能够根据道路类型猜测转弯半径。 该转弯半径用于重建限制交汇点的圆弧。 该方法必须是稳健的,因为我们的假设只是最好的猜测,有时是完全错误的。

给定两个道路轴(a1,a2),每个轴都是折线,而不是线段),每个轴都有一个近似宽度(w1,w2)和一个近似转弯半径(r = min(r1,r2),或其他选择规则) ,我们想要找到行驶车辆将遵循的圆弧的中心。

图6:寻找圆心问题。 左为经典问题,中、右为使用真实世界数据的问题。

实现方法说明如下:

图 7:使用几何运算稳健地找到圆心的方法。

在上图中,计算轴的缓冲区,然后缓冲区外环的交集返回一组候选点。 在候选者中,最接近交点中心的那个是最终的圆心。

我们的第一种方法基于显式计算,如 Wang 等人(2014),图 13 所示。但是,这种方法并不稳健,并且存在特殊情况(平角、零度角、一条道路完全包含在另一条道路中) ,是复杂的二维 (2D),最重要的是,不能在多段线上使用。 然而,由于数据规范或错误,现实世界的数据精确地由折线组成。

我们选择使用形态和布尔运算来克服这些限制。 我们的主要运算符是正缓冲区和负缓冲区(正式来说,输入与给定大小的磁盘的 Minkowski 和)以及表面交集、并集等。

我们正在寻找圆弧的中心。 因此,根据定义,中心可以是距a1 d1=w1+r 和距a2 d2=w2+r 的所有位置。

我们将其转化为几何运算:

  • buffer_i,a_i 与 d_i 的缓冲区
  • inter,缓冲区边界的交集,通常是一组点,但也可以是一组点和曲线。 所有这些地方都可以是圆的中心。
  • 最接近,距离交汇点中心最近的交点。 我们必须在候选者中进行过滤,以便只保留根据我们的假设最有意义的一个。

在某些情况下,最近的点可能是空的(例如,考虑到其宽度,当一条道路在几何上包含在另一条道路中时)。 在这种情况下,我们的方法失败了,没有造成任何损坏,因为没有创建弧。

半径可能不适合当地路网拓扑。 当道路轴线相对于建议的半径太短时,这种情况主要发生。 在这种情况下,我们通过显式计算最大半径(如果可能)将猜测半径减小到其最大可能值。

也有可能关于半径的假设是错误的,这会产生明显错位的弧。 我们选择了一个非常简单的选项来估计圆弧是否错位,并简单地使用圆弧与交点中心之间的距离阈值。 在本例中,我们将半径设置为与巴黎车道分隔石半径 (0.15 m) 相对应的最小值。

2.5 从圆弧中心计算曲面

图8:从圆心出发,通过投影和过滤找到限制相交的边界点(距相交中心最远)

当找到圆心时,我们可以计算相关的弧并找到交点限制(见图8)。 我们通过将圆心投影到 wi 缓冲的两个轴上来创建相应的圆弧。 事实上,我们不使用投影,因为折线上的投影可能定义不明确(例如,投影在最近的线段上可能不起作用)。 相反,我们采用最近的点。

同样,我们将圆心“投影”到道路轴线上。 我们将这些投影称为候选边界点。 每个交点的每个轴有两个或更少的边界点。 根据我们的相交表面模型,我们只保留每个相交的每个轴的候选者之一,选择距相交中心最远的候选者。 我们使用曲线横坐标来定义距交点中心的距离,这是必要的,因为在某些奇怪的情况下,欧几里得距离可能会产生误导。

截面和相交面:

图 9:通过根据法线的局部估计切割部分来创建边界线


我们通过首先在边界点之外的每个截面的末端创建边界线来计算截面表面。 边界线垂直于道路轴线的局部直线近似。 然后,我们使用这些线切割缓冲的道路轴线以获得交叉口内的道路轴线表面。

此时,可以通过将边界线连接到圆弧来构建交叉面,必要时经过缓冲道路轴。 我们发现很难稳健地做到这一点,因为由于错误的输入数据、错误的假设或计算精度问题,之前的一些结果可能会丢失或稍微错误。

图 10:函数 ST_BuildArea 根据切割的轴曲面和圆弧构建可能的最大区域

我们更喜欢一种不太具体的方法。 我们使用“ST_BuildArea”函数(见图10)。 给定一组几何图形,它将所有几何图形分解为折线,然后从这些折线创建最大可能的表面。 我们在切割道路和弧线上使用它。

可变缓冲器:

图 11:用于稳健道路宽度过渡的可变缓冲区

在交叉口仅改变道路宽度的特殊情况下,圆弧过渡不如线性过渡真实。 我们使用可变缓冲区来稳健地完成此操作。 它还提供了能够仅使用街道轴来控制三种最经典的过渡(对称、左和右)和过渡长度的优势。

我们将变量缓冲区定义为半径在每个顶点(即线串的点)处定义的缓冲区。 半径在顶点之间线性变化。 计算它的一种简单但低效的解决方案是构建圆形和等腰梯形,然后合并这些基元的表面。 我们使用简单版本。

  • 车道、标记、街道物体

根据街道断面,我们可以构建车道和车道分隔线。 为此,我们不能简单地平移中心轴,因为轴是折线(见图 12)。 相反,必须使用类似于缓冲区的函数(“ST_OffsetCurve”)。

图 12:从中心线(黑色)开始,平移不会创建正确的车道(红色)。 我们必须使用缓冲区(绿色)

我们的输入数据包含车道数量的估计。 即使此类数据缺失,仍然可以利用启发式方法从道路宽度、道路平均速度等进行猜测。 车道数量也可以从各种遥感数据中检索。 例如,Jin 等人(2009)建议使用航空图像。 我们还可以沿着边界线修建人行横道。

使用交叉面和道路断面,我们构建城市街区(见图 13)。 我们粗略地将城市街区表面定义为其边界道路表面和道路交叉口的补充表面。 然而,由于城市街区周围的所有路面可能尚未生成,因此当路面缺失时,我们使用道路轴线代替路面作为城市街区界限。

由于道路轴网络已存储为拓扑,因此可以立即获得由围绕所需街区的道路轴形成的表面。 然后,我们使用布尔运算从面上减去街道和交叉面。 这样做的优点是,当限制街区的一些街道尚未计算时,这仍然可以提供结果,这在实践中经常出现。 根据定义,通用面(“外部”)不用作城市街区!

图 13:当没有可用路面时,我们通过计算由相关路面、道路交叉口和道路轴线界定的表面来生成城市街区(插图顶部)


2.6 并发和扩展

这项工作的目的是以并发方式为整个城市建模街道(即多个进程可以同时生成同一条街道)。 我们对方法的选择很大程度上受到这些因素的影响,并且我们使用特定的设计来实现这些目标,这些目标不是附属的而是必要的。

  • 单一大型查询

我们强调 StreetGen 是一个大型 SQL 查询(使用各种 PL/pgSQL 和 Python 函数)。

它提供的第一个优点是它完全封装在一个 RDBMS 事务中。这意味着,如果出于任何原因输出不遵守街道数据模型的约束,结果将回滚(即,我们回到 就好像交易从未发生过一样)。 这为生成的街道模型以及输入数据的状态提供了强有力的保证。

其次,StreetGen 使用 SQL,它自然地适用于集合(内在的 SQL 原理)。 这意味着计算n个路面并不是计算n次1个路面。 这是至关重要的,因为计算一个路面实际上需要使用其在道路网络图中的一个邻居。 因此,单独计算每条道路会重复大量工作。

第三,我们受益于 PostgreSQL 高级查询规划器,它收集和使用有关所有表的统计信息。 这意味着网络的一小部分或大部分上的相同查询不会以相同的方式执行。 查询计划器优化执行计划以估计最有效的计划。 这一点,再加上索引的广泛使用,是使 StreetGen 在不同规模上无缝工作的关键。

  • 一个连贯的街道模型结果

使用 RDBMS 的优点之一是并发性(多个用户同时处理相同数据的能力)。
默认情况下,StreetGen 输入(道路网络)也是如此。 多个用户可以同时编辑路轴网络,完全保证数据的完整性。

然而,我们提出了更多建议,并利用 RDBMS 功能,以便 StreetGen 不会返回一组街道,而是创建或更新街道建模。

这意味着我们可以在整个巴黎路轴网络上使用 StreetGen,它将创建最终的街道建模。 仅在一个道路轴上第二次使用 StreetGen 将简单地更新与该轴关联的街道模型的参数。 因此,我们可以随时保证输出街道模型是一致且最新的。

第一次计算街道模型对应于使用“insert”SQL 语句。 创建街道模型后,我们使用“更新”SQL 语句。 在实践中,我们自动混合这两个语句,以便在计算输入道路轴网络的一部分时,自动更新现有的街道模型,并自动插入不存在的街道模型。 这种逻辑的简称(如果结果尚不存在,则插入,否则更新)是“upsert”。

这种机制对于一个用户来说完美无缺,但对于多个用户来说却受到竞争条件的影响。 我们用这个综合例子来说明这个问题。 全球街道模型是空的。 User1和User2都计算对应于道路轴r_i的街道模型s_i。 现在,两个用户都将他们的结果更新到街道表中。 竞争条件会产生错误(相同的结果被插入两次)。

图 14:左,经典的 upsert。 是的,竞争条件会产生错误

我们可以通过两种策略来解决这个竞争问题。 第一个策略是,当upsert失败时,我们重试,直到upsert成功。 这一策略没有提供任何理论上的保证,即使在实践中它运作良好。 我们选择第二种策略,它基于信号量,并通过避免计算已经计算的街道来工作。

在一组道路轴上使用 StreetGen 时,我们使用信号量来标记正在处理的道路轴。 StreetGen 仅考虑处理尚未标记的路轴。 当计算完成后,StreetGen 释放信号量。 因此,只要其他 StreetGen 用户已经在计算这些街道,任何想要计算相同道路轴的其他用户就什么也不做。 该策略在理论上提供了可靠的保证,但会使用大量内存。

2.7 生成基本交通信息

StreetGen 基于 RDBMS 中的表。 因此,它的模型非常灵活且适应性强。 我们利用这种能力来生成交通模拟所需的基本几何信息。 交通模拟的世界很复杂,不同的方法可能需要截然不同的数据,具体取决于模拟的方法和规模。

例如,模拟全国范围内的交通(宏观模拟)的方法不需要与尝试模拟城市交通的方法相同的数据,也不需要与模拟一个交叉路口的车辆精确轨迹的方法相同的数据。

此外,交通模拟可能需要语义数据。 例如,普通车道和公共汽车保留的同一车道可能在几何上相同,但在模拟中具有非常不同的影响。

交通模拟可能需要交通灯排序、有关汽车速度和密度的统计、物体的可见性、照明等。

因此,我们并不假装为各种交通模拟提供数据,而是提供城市尺度的基本几何数据。 我们选择提供的基本几何信息是车道和车道互连。 由于车道和互连已集成到 StreetGen 中,因此如有必要,车道、互连和道路网络(道路轴线、交叉口)之间的链接始终可用。

我们将车道定义为车辆在路段中可以遵循的几何路径。 车道是严格定向的并且只能单向使用。 交叉路口是车辆在交叉路口时可以遵循的轨迹,从一个路段(车道)行驶到另一路段(车道)。 同样,互连也是单向的。

  • 生成车道

我们的数据包含每个道路轴的大概车道数。 即使没有此类数据,也可以根据道路宽度和重要性进行估计。

我们使用缓冲区运算(正式称为 Minkowsky 磁盘求和)来计算轴的通道,因为简单的平移不会产生正确的结果(见图 12)。 我们创建车道轴和车道分隔符,第二个是有用的表示形式,也是生成车道分隔标记的潜在基础。 然后,通道生成取决于通道数量的奇偶校验,并且是迭代的(见图 15)。 必须特别小心,以便生成的所有折线都具有一致的几何方向。

图 15:生成不同数量的车道,在 QGIS 中以虚线显示

我们的数据集还给出了每个道路轴的大致信息方向。 道路轴线方向可以是“正向”、“反向”或“双向”。 “直接”和“反向”均适用于单向道路,全局方向相对于道路轴几何方向(即点的顺序)。 在“两者”的情况下,我们只知道这条路不是单向的。

请注意,这一简单信息不足以描述即使是中等复杂的真实道路(例如,一个方向有 3 条车道,另一个方向有 1 条车道)。 由于缺乏更好的解决方案,我们不得不做出强有力的假设。

在“反向”或“直接”的情况下,所有车道应具有相同的方向。 在“两者”情况下,道路轴线右侧的车道应与道路轴线方向相同,左侧车道的方向应相反。 在奇怪的情况下,中央车道将被视为位于道路轴线的右侧。 车道按距道路轴线的距离、侧面(从右侧开始)进行编号。 图 16 概述了可能的车道方向。

图 16:车道的默认可能方向

  • 互连中生成轨迹

我们的数据集缺乏有关车道互连的任何信息,即车道之间的哪些连接是可能的以及这些连接具有什么轨迹。 例如,位于 X 街的右车道,是否可以在下一个路口转到 Y 街的右车道,并遵循哪条轨迹?

强有力的假设是必要的。 我们使用车道的方向,并认为互连只能连接交叉口中具有相反输入方向的车道。 考虑到交叉路口,每条车道要么进入或离开该交叉路口(交叉路口输入方向)。 此外,我们认为同一路段的车道不是直接相连的(不掉头)。 请注意,在现实生活中,这样的轨迹是可能的。 我们根据这些条件为每对车道创建互连。

十字路口的实际车辆轨迹非常复杂,取决于运动学参数、驾驶员感知参数、驾驶员资料、车辆、天气条件等。例如,Wolfermann 等人 (2011) 研究了一个简单的情况,仅对速度曲线进行建模。

我们使用贝塞尔曲线生成合理且简单的轨迹。 此外,我们隔离了负责轨迹计算的部分,因此可以轻松地用比贝塞尔曲线更合适的解决方案替换它。

图 17:互连轨迹,受起点/终点和可能的交叉中心影响的贝塞尔曲线

贝塞尔控制点是车道中心进入/离开交叉路口的点。 第三个控制点视情况而定。 它通常是车道交叉口和交叉口中心的重心。 然而,当车道平行时,车道交叉口被进入/出口重心取代。 在车道平行且相对的特殊情况下,不考虑交叉口中心以获得直线轨迹。 图 17 显示了各种情况下的互连轨迹生成。

2.8 环岛检测

StreetGen 已用于交通模拟。 StreetGen 不考虑任何交叉路口的语义差异。 然而,交通模拟工具在交叉路口和环岛之间存在很大差异。

尽管如此,环形交叉口和经典交叉口之间的交通建模仍然存在很大差异。 因此我们需要一种检测环岛的方法。 我们面临着类似于(Touya,(2010),第 3.1 节)的问题。 主要问题是环岛定义基于交叉路口的驾驶规则(优先类型、无红绿灯……)。 然而,我们使用的路轴网络上没有这些详细信息。 如果我们使用严格的几何定义(周围都是圆形),我们可以尝试从航空图像(Ravanbakhsh 和 Fraser,(2009))或车辆轨迹 Zinoune 等(2012)中提取信息。 然而,这两个例子都不是在街道环境中,那里的环形交叉路口可能要小得多,并且在航拍图像上更难看到。 此外,由于建筑物掩盖了 GPS,车辆轨迹的精确度也会降低。

当然,我们还远远没有达到这种水平的信息,因此我们使用了现有的很少的信息,即街道轴线的几何形状和街道名称。 我们需要一种方法来表征可用于检测的环形交叉口。 我们不能仅仅根据道路网络的拓扑结构(例如:一个小环路)来定义环岛,也不能纯粹根据几何形状(道路轴线形成一个圆)来定义环岛,因为环岛不一定是圆形的。 我们注意到环岛中的道路轴线往往具有相同的名称,和/或包含单词“PL”或“RPT”(IGN 是“Place”和“Rond-Point”(环岛)的缩写)。

因此,我们使用两个标准来定义潜在的环岛:其道路轴线可能是圆形的(几何标准),并且道路轴线可能具有相同的名称或在名称中包含“PL”或“RPT”(地名标准)。 我们使用霍夫变换(Duda 和 Hart,(1972))来检测道路轴上连续点的四元组,这些点是对圆弧的良好支持,然后通过 DBSCAN 算法执行无监督聚类(Pedregosa 等人,(2011), 埃斯特等人,(1996))。 为了利用道路名称,我们面对面地探索道路网络,同时考虑一个面上的所有道路是否具有相同的名称和/或某些道路包含特殊的“PL”或“RPT”关键字。

最终结果经过加权,供用户用来快速检测环岛(见图 18)。

图 18:环岛检测可减少用户工作

2.9 街道对象:从道路到街道

到目前为止,我们主要考虑了道路建模(道路轴线、路面、交叉口中心、交叉口表面、车道、互连等)。 然而,街道的特点是其中存在大量且多样化的物体。 我们在广义上使用街道对象,包括街道设施以及标记、树木等。图 19 给出了 StreetGen 中街道对象建模的示例。

图 19:StreetGen 中的街道对象。 

街道对象是在 QGIS 中查看的具有高级符号系统的语义点。 每个对象都可以相对于街道轴线或街道边界进行定位和定向。

  • 通用街道对象

街道包含大量不同的物体。 我们建议通过可扩展的机制将它们添加到StreetGen中,以便将来可以轻松地完成复杂的语义或层次结构。

我们观察到,许多街道物体无论是位置还是方向都与街道轴线和路面相关。 例如,人行横道是相对于街道轴线和人行道定义的。 它的方向通常也与街道轴线方向相关(尽管情况并非总是如此)。

然后,我们设计一个系统,其中对象可以链接到街道轴,以便能够相应地计算方向和位置。 每个对象位置都可以根据街道轴或人行道位置以绝对坐标定义。 如果对象相对于街道轴或人行道定位,则对象位置由其沿街道轴的曲线横坐标定义。

图 20:可以相对于道路模型定义对象位置和方向

每个对象方向也可以定义为绝对方向或根据街道轴。 可能对象的列表在可以轻松扩展的表中定义,并且还用于构建更复杂的信息(例如,层次结构)。 三重商店格式将是很好的选择。

图20示出了对象相对于街道轴线和/或街道边界的定位和定向的原理。 让我们以安全屏障为例。 在巴黎,这些通常用于人行道上,距离道路几厘米,与街道轴线平行。

在我们当前的实现中,通用街道对象底层表示是具有语义和可能的相对定位和方向信息的点。 这种通用表示可以专门用于专门的街道对象。

  • 特殊街道物体

街道中的通用街道对象数量众多,但许多对象需要比点更具体的参数和/或不同的表示。 我们证明可以将专门的街道对象作为通用对象的专门化来引入。 这个概念是从对象编程设计中的继承借用的。 需要为每个专门的街道对象创建一个新表。 该表通过外键和add-oc 触发器链接到通用表。 专用表存储附加参数和附加表示,并与通用表的相关对象保持同步。

我们通过对象人行横道来演示此功能(见图 21)。

图 21:可以添加专用对象,并具有足够的参数(此处为宽度)和表示形式(此处以 qgis 虚线图案显示表面)

人行横道可以通过其沿道路轴线(曲线横坐标)的位置及其相对于道路轴线的方向进行参数化。 这两个参数已为通用对象定义。 然而,人行横道还需要一个宽度参数,定义道路轴线水平上人行横道的宽度。 此外,人行横道最好不要用点和符号表示,而是用表面表示,从人行道到人行道,这意味着特殊的几何形状(表面而不是点)和基于行人生成该表面的函数 交叉口参数和路面。

图 22:根据参数以及道路轴线和路面构建人行横道表面

创建人行横道表面并不立即,因为道路轴是一条折线。 我们通过首先创建在道路轴线上界定人行横道的点来创建这样的功能。 然后这些点以一定角度向左和向右投影到路面上。 然后提取点之间的路面边界并将其缝合在一起形成平行四边形。 图 22 说明了人行横道表面的创建。

3、结果评估

本节致力于测试我们的街道建模方法。 我们的道路模型依赖于转弯半径,因此我们从估计这些转弯半径的实验开始。 然后,我们通过结果质量、稳健性、扩展性、并发性和并行性方面的实验来测试 StreetGen 的核心。 我们测试现实世界交通模拟应用程序中生成的交通信息。 最后,我们通过生成具有挑战性的道路、另一个国家的道路和机场跑道来测试 StreetGen 的通用性。

3.1估计默认转弯半径

由于缺乏有关转弯半径的信息,我们不得不假设转弯半径取决于道路类型(参见第 2.3 节)。 尽管这个假设是一个好的开始,并且已经在城市之外得到了实证验证,但据我们所知,它还没有在城市中得到检验。

图 23:测试半径假设的工作流程

遗憾的是,巴黎没有半径数据,因此我们提出了一个框架来估计巴黎的这一假设。该测试框架如图 23 所示。

首先,我们使用一种霍夫变换(Duda 和 Hart,(1972))和过滤从开放数据巴黎“trotoir”(人行道)层中提取圆弧。 结果很嘈杂,因为“trotoir”层包含许多不是基石的圆形物体。 我们获得大约 14000 个圆弧。 然后我们将包含近似行驶速度的GPS路网数据库与包含道路重要性、道路宽度、车道数量等的BDTopo路网映射。我们使用模糊几何(道路轴扩大几米所共享的空间) 和模糊语义距离(使用三元组比较两个轴街道名称)。 参见图 24。

图 24:通过各种数据集合并获得的半径检测和平均道路速度

基于道路数据,我们尝试了多种方法来预测转弯半径。 第一种方法“猜测”是手动设计一个简单的函数“radius = f_guess(道路重要性)”。 第二种方法是使用法国 SETRA 的结果,该结果将平均车速与城郊道路的转弯半径联系起来,其中“半径 = f_speed(车辆平均速度)”,使用等式 1。

最后,我们使用机器学习来训练随机森林回归器,使用道路重要性、速度和道路宽度来预测半径,从而得到“半径 = f_rforest(重要性、速度、道路宽度)”。 随机森林预测旨在与其他两种方法进行比较。 结果如表 1 所示,并如图 25 所示。

表1:各种半径预测方法的误差

|公制 ( m )| f_guess| f_speed| f_rforest|
|-|-|-|
|平均绝对误差| 2.41| 2.18| 1.97|
|中位绝对误差| 1.9| 1.91| 1.69|

图 25:说明使用各种方法预测的主要道路和住宅区的半径

3.2 街道生成

在本节中,我们对 StreetGen 核心进行测试。

  • 鲁棒性

总体而言,StreetGen 生成了整个巴黎道路网。 我们首先生成几条街道,然后是几个街区,然后是巴黎第六区,然后是巴黎第四区,然后是巴黎的整个南部,然后是整个巴黎。 每次我们改变规模时,我们都会遇到新的特殊情况和例外。 每次我们都必须增强 StreetGen。 我们认为它很好地说明了一些现实生活中街道的复杂性以及输入数据中可能存在的错误。

  • 质量

总体而言,巴黎的大部分街道似乎都适合我们的街道数据模型。 即使在非常复杂的交叉路口或重叠的交叉路口,StreetGen 结果看起来也基本真实。

图 26:日益复杂的交集结果示例

在一些边缘情况下,由于假设或方法的局限性,结果不切实际(参见图 27)。 然而,这些案件很容易被发现,并且可以单独解决。

图 27:各种失败案例,从严重到不太严重(1、2、3)。1:循环,2:缓冲区使用不当,3:半径对于网络来说太大

故障1是由于1轴和2轴形成环路造成的。 因此,在某些特殊情况下,整个块被认为是一个交叉点。 这种情况很少见,而且很容易被发现。

故障2是由我们计算相交面的方法引起的。 在 T 字路口,一条与小街道正交的大街道会产生凹凸。 可以使用变量缓冲区来处理。

故障 3 更为微妙,当一根轴相对于半径太短时就会发生。 在这种情况下,圆弧的末端远离交点,因为交点很短。 它可以通过考虑具有大致相同方向的下一个轴来修复,但它会引入特殊情况。

我们将 StreetGen 的结果与巴黎的实际道路进行了比较,这些道路可通过 Open Data Paris2 获得。 它清楚地显示了输入数据的限制,主要是在道路宽度估计方面。

图 28:估计参数可能与实际情况相差甚远(左)。 但是,可以通过编辑模型参数来手动或自动拟合街道模型。

使用交互式工具(见图 28),可以更新输入数据,使其更接近现实,直到达到非常好的匹配。 如果道路模型的参数不适应现实,就不可能对 StreetGen 结果进行定性评估,这在进一步的工作中手动或自动执行。

  • 缩放

整个巴黎街道网络在 10 分钟内生成(1 个核心)。 使用完全相同的方法,一条街道(及其邻居)在~200ms内生成,因此低于~300ms的人类交互极限。

  • SQL集合操作

我们通过测试两个场景来说明 SQL(在集合上工作)的特殊性。 在第一个场景(无设置)中,我们在巴黎路轴上逐一使用StreetGen,这将需要2个多小时才能完成。 在第二个场景(设置)中,我们一次在所有轴上使用 StreetGen,这大约需要 10 分钟。

  • 并发性

我们测试 StreetGen,让两个用户同时计算在 100% 和 0% 的道路轴之间共享的两个道路轴集。 竞争条件被有效修复,我们得到了预期的结果。

  • 并行性

我们在路轴质心上使用 K 均值算法3 将巴黎路轴网络分为八个簇(见图 29)。 这会在几秒钟内发生在数据库中。 然后K个用户使用StreetGen计算一个集群(并行性),从而将整体计算时间减少到一分钟左右。

图 29:使用 K-Means 聚类道路轴质心,K=20,(黑色部分是凸包)

3.3 利用Streetgen进行交通模拟

在本节中,我们设计了一个实验来测试 StreetGen 生成的交通信息的有用性。

从视觉上看,生成的车道和互连似乎在大多数情况下都是经过调整的。 然而,计算成本显着增加,因为通道和互连是由触发器生成的,而不是在全局级别生成的。 而且互连使用PLPython和shapely,这引入了很大的开销。

我们通过导出交通模拟工具 SymuVia 的模型来测试 StreetGen 在交通模拟方面的可用性(Leclercq 等人,(2007))。 这项工作由 Lionel Atty(IGN、SIDT)为 TrafiPollu 项目(Soheilian 和 Atty,(2016))执行,混合使用了 QGIS 插件中编排的 sql 查询和 python 模块。

图 30:将 StreetGen 流量模型转换为 SymuVia 流量模型

主要困难是对交叉口的不同处理(SimuVia 交叉口模型需要语义,如经典交叉口的环岛,请参阅第 2.8 节)、将具有相同方向的车道重新分组为同质车道组的必要性(见图 30)、几何图形和 XML 的简化 导出为自定义 SymuVia 格式。

导出速度并不快 (10分钟一百条街道),但导出的数据已成功用于 SymuVia 交通模拟工具。

图 31 给出了在自定义 Symuvia 工具中手动创建的道路网络交通信息以及使用 StreetGen 自动创建的相同数据的示例。 自动化结果成功地用于 SYmuvia 交通模拟工具,尽管它概述了 StreetGen 输入数据(关于车道数量)的不精确性。

图 31:手动创建的交通信息和 StreetGen 自动交通信息

3.4 扩展Streetgen应用

StreetGen 的设计考虑了巴黎这座城市,即许多遗产道路。 事实上,世界各地的街道布局和特征差异很大,有关城市类型的专业知识极大地有助于创建适应性假设。 例如,类似曼哈顿的网格布局更容易处理。

我们仍然可以测试 StreetGen 的通用性和稳健性。 为此,我们在不同的异常场景中使用 StreetGen。

市内快速通道(里尔):

图 32:StreetGen 通用性实验:法国里尔市内高速道路

第一个场景是使用 StreetGen 对里尔现代部分快速道路的道路进行建模(见图 32)。 我们强调,此示例不包含桥梁或立交桥,因为 StreetGen 无法管理这些。 这些道路具有现代设计,因此不必遵循 StreetGen 假设。 然而,StreetGen 模型足够通用,可以很好地模拟道路。 该道路模型是使用基地内交互从头开始编辑的。

  • 基于网格的布局(马里)

图 33:StreetGen 通用性实验:主要基于网格的城市布局,马里

第二种场景是将 StreetGen 用于基于网格的道路网络(见图 33)。 我们无法获得该领域的真实情况。 然而,结果证明对于在 3D 世界构建中的进一步使用是令人满意的。

  • 机场(卑尔根)

图 34:StreetGen 用于挪威卑尔根机场跑道和辅助道路

最后一个场景更加延伸,建议使用 StreetGen 生成机场跑道和服务道路(见图 34)。 除极少数例外,StreetGen 都能够对机场的失控路面(和服务道路)进行建模。

然而,由于所有尺寸与巴黎街道相差甚远(40 米的跑道宽度在机场并不罕见),这种情况凸显了能够轻松更改默认设置的需求。 为了满足这一需求,我们将所有 StreetGen 设置更改为存储在全局设置表中。 然后这个全局设置表可以适应每种情况。

4、讨论

4.1 估计默认转弯半径

在 3.1 节中,我们尝试评估如何估计转弯半径。

表 1 中的结果相当不确定。 无论使用什么函数来预测半径,结果都很差。 提取的半径噪音太大,而且我们从道路速度数据库中提取的平均速度信息缺乏细节(只有 4 个可能的值)。 即使随机森林回归器也无法正常工作。 直观上,半径可能还取决于道路建设日期、历史数据、邻里或其他数据。 然而,SETRA 函数 f_speed (1) 结果在处理主要道路时相关(参见图 25),但一般情况下不相关。

我们测试了这样的假设:该函数可能是正确的,但参数化得很糟糕。 为此,我们尝试使用非线性最小二乘优化和损失函数来找到 f_speed 的最佳参数,以减少异常值权重。 我们找不到更好的值。 我们以此作为证据,证明我们没有足够的数据来得出该函数整体是否适合我们的需求的结论。

使用调整后的 StreetGen 结果可以更好地执行此实验。

4.2 街道数据模型

我们的街道数据模型很简单,可以很好地代表道路,但在某些方面需要详细说明。
首先,停车位在巴黎街道布局中非常丰富且重要,但我们的模型无法专门处理这些。

车道不能有不同的宽度或类型(公交车道、自行车道等)。

我们的模型只是街道建模的第一步。 因为我们对街道进行建模,所以我们的模型无法处理桥梁、隧道、立交桥等。 这种限制源于我们用于拓扑管理的工具:PostGIS Topology。

4.3 动力学假说

总体而言,动力学假设提供了看起来很现实的结果,但在巴黎这样的老城区远非如此。 事实上,许多街道的历史早于汽车的发明。 我们试图找到现实世界的拐角半径(通过霍夫圆弧检测分析 OpenDataParis)与道路类型或道路平均速度(来自 GPS 数据库)之间的相关性。 除了快速道路之外,我们找不到明显的相关性。 在这些道路上,平均速度较高,并且它们是为遵循经典工程规则的车辆设计的。

4.4 精度问题

我们所有的几何运算(缓冲区、布尔运算、距离等)都依赖于 PostGIS(因此是 GEOS4)。 然后我们面临计算精度问题,尤其是在处理弧时。 弧形类型是一种并不总是受支持的数据类型,因此它必须通过段来近似。

图 35:精度问题示例。 左边,我们用线段来近似圆弧,这会引入误差。 是的,该错误足以错误地合并相交曲面

StreetGen 使用各种策略来尝试解决这些问题。 然而,唯一真正的解决方案是使用精确的计算工具,例如 CGAL The CGAL Project, (2015)。 它还允许我们计算 3D 圆心。 最近一个名为 SFCGAL5 的插件将部分 CGAL 集成到 PostGIS 中,使用精确计算

4.5 Streetgen 交通

导出成功,但有点慢,尽管慢主要是由于 simuvia XML 格式造成的。 主要问题之一是产生了太多的互连。 事实上,我们生成所有可能的互连,我们将从仅生成看似合理的互连的启发式中受益匪浅。

4.6 街道物体

StreetGen 中添加的街道对象极大地提高了建模的可能性。 然而,该系统并未经过全面测试。 在城市规模上,将所有对象存储在一个表中可能会被证明是一种限制(巴黎包含数千万个街道对象)。 我们演示了基于点和基于表面的对象,但是基于线的对象(例如标记)也非常突出。

然而,主要的限制是我们没有测试基于规则和模式的自动对象生成。 我们确实认为正确解决对象问题需要语法或类似的高级语义工具,但我们没有尝试过。

4.7 扩展 StreetGen 的使用

使用稍微偏离其预期功能的工具总是很有趣的。 其中限制之一是里尔道路拥有一条道路宽度线性增加的道路,无法使用 StreetGen 进行建模。 当输入道路轴拓扑不正确时,马里数据集揭示了一个问题。 机场建模显然是 StreetGen 功能的延伸。 特别是,机场跑道拥有大量语义对象,如灯光、信标等。将 StreetGen 结果与实际机场模型进行比较时,差异非常明显(图 36,由 Thales TTS 提供)。

图 36:真实机场模型,由 Thales TTS 提供

4.8 街道模型与现实的拟合

StreetGen 从一开始就被设计为基于很少的信息来提供对街道的最佳猜测。 然而,在某些情况下,我们希望结果更符合现实。

为此,我们创建了一种交互式行为,以便多个用户可以拟合自动 StreetGen 结果以更好地匹配现实(例如使用航空图像作为地面实况)。

我们没有创建图形用户界面 (GUI),而是创建了一组自动基础行为,以便编辑输入数据或特殊交互层可以交互地更改 StreetGen 结果。 这样做可以确保任何可以读取和写入 PostGIS 矢量的 GIS 软件都可以用作 StreetGen GUI。

在某些情况下,我们可能有对街道物体或人行道的观察,可能是从航空图像或激光雷达中自动提取的,因此不精确且包含错误。 我们测试了一种优化算法,该算法会扭曲最佳猜测 StreetGen 的街道模型,以更好地匹配这些观察结果。

这个主题与逆过程建模类似,我们认为它提供了很多机会。

5、结束语

作为结论,我们基于一些假设提出了一个相对简单的街道模型。 这种街道数据模型似乎适合巴黎这样复杂的城市。 我们提出了各种策略来稳健地使用该模型。 我们表明,除了存储数据和并发设施之外,RDBMS 还提供了有趣的可能性。

我们的方法 StreetGen 有足够的改进空间。 我们可以使用更复杂的方法来预测半径,更好地处理特殊情况,并扩展数据模型以更好地使用车道并添加由语法管理的复杂街道对象。

在我们未来的工作中,我们还希望利用StreetGen交互的可能性来进行大规模的协作编辑。 这样完成的街道建模可以用作下一步的基本事实,这将是一种基于人行道、标记等观察结果检测的自动方法。然后找到最佳参数将涉及执行逆过程建模。


原文链接:StreetGen城市级路网生成 - BimAnt

这篇关于【StreetGen】城市级交通路网生成算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944051

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];