OpenDRIVE地图中Geometry线段对应x/y坐标的计算

OpenDrive地图解析代码可以参考,https://github.com/liuyf5231/opendriveparser


在OpenDRIVE地图的解析和绘制过程中,最关键的一点:在x/y坐标系下,利用起点(x,y)、曲线的相对长度(s坐标,该点距离起点的线段长度)计算出相应长度处所对应的x/y坐标。目前使用较多的Geometry类型为直线line、arc、spiral。

1.直线line的解析最简单,知道起点(x,y),直线角度hdg,距离起点的线段长度s,既可以计算出相对起点的dx,dy。

dx = s * cos(hdg)
dy = s * sin(hdg)

2.对于arc,有一个恒定的参数曲率curvature,dx,dy计算方式如下,

 c = curvature
 hdg = heading - PI / 2

 a = 2 / c * sin(s * c / 2)
 alpha = (PI - s * c) / 2 - hdg

 dx = -1 * a * cos(alpha)
 dy = a * sin(alpha)

3.spiral最复杂,不过OpenDRIVE官网给出了一个计算的例子(Sample code for the calculation of spirals),关键代码如下(c语言),可以按照原理利用具体的编程语言实现,

/**
* compute the actual "standard" spiral, starting with curvature 0
* @param s      run-length along spiral
* @param cDot   first derivative of curvature [1/m2]
* @param x      resulting x-coordinate in spirals local co-ordinate system [m]
* @param y      resulting y-coordinate in spirals local co-ordinate system [m]
* @param t      tangent direction at s [rad]
*/

void odrSpiral( double s, double cDot, double *x, double *y, double *t )
{
    double a;

    a = 1.0 / sqrt( fabs( cDot ) );
    a *= sqrt( M_PI );
    
    fresnel( s / a, y, x );
    
    *x *= a;
    *y *= a;
    
    if ( cDot < 0.0 )
        *y *= -1.0;

    *t = s * s * cDot * 0.5;
}

将地图中的所有线段都解析为x/y坐标后,我们很容易利用一些画图工具绘制出相应的地图,下图为利用python matplotlib绘制的地图,地图数据基于OpenDRIVE官网的Crossing8Course.xodr。只绘制了lane type为driving的车道线。
这里写图片描述

下图为官方工具OpenDRIVE Viewer绘制的地图(linux下运行,不开源)。
这里写图片描述

### OSM路网街景采样点数据获取方法 #### 预处理OSM路网数据 为了准备用于生成街景采样点的OSM路网数据,需要先进行一系列预处理工作。具体来说,城市道路网络和兴趣点(POIs)的数据是从OpenStreetMap(OSM)中获取的[^1]。这些数据包含了研究区域内各类可行驶的道路信息,包括但不限于主干道、次干道以及居住区内部的小巷子。 对于原始下载下来的OSM数据集而言,其中可能含有冗余或不准确的信息,因此有必要对其进行清理与优化。这一步骤涉及移除那些带有明显错误标签的道路记录,并通过计算双向车道间的几何平均位置来代替实际存在的两条平行线段表示法,从而减少后续算法复杂度并提高效率。 经过上述调整之后,最终得到一个精简版的城市交通图谱——它由2,004条连接节点构成边界的路径组成;与此同时还额外搜集到了3,459处具有代表性的地标建筑作为补充说明材料,用以更好地理解该地区的功能布局特征。 ```python import osmnx as ox G = ox.graph_from_place('Chengdu, China', network_type='drive') ox.plot_graph(G) ``` #### 投影转换至UTM坐标系 当准备好干净整洁的地图框架后,则可以着手考虑如何将之映射到适合进一步操作的空间参照体系内去了。通常情况下会选择采用统一横轴墨卡托投影(Universal Transverse Mercator Projection),也就是常说的UTM坐标系统来进行这项任务。这是因为相比于地理经纬度表达方式而言,前者能够提供更加直观且易于量化的平面直角坐标描述形式[^4]。 利用GIS软件包如ArcGIS中的`Projection`工具即可轻松完成这一过程:只需指定好源文件路径及其对应的输出格式参数选项即可实现自动化批量化作业流程。值得注意的是,在选择具体的带号时要依据目标地点所在的地理位置做出适当的选择,比如成都市就位于北半球第48个分区内。 ```python from pyproj import Transformer transformer = Transformer.from_crs("EPSG:4326", "EPSG:32648") # WGS84 to UTM Zone 48N lon, lat = transformer.transform(latitudes, longitudes) ``` #### 对路网数据进行增密采样 一旦完成了从WGS84椭球面模型向局部笛卡尔坐标的转变以后,就可以针对新产生的矢量图形执行下一步动作了——即按照预定间距沿每一段连线上均匀分布若干个离散化样本点位。这样的做法不仅有助于增加空间分辨率而且还能确保所选取的位置具备足够的代表性以便于后期分析使用[^3]。 借助ESRI ArcToolbox里的`Densify`命令行接口便能快速达成目的:用户只需要设置好待处理的对象层名还有期望达到的最大步长阈值就可以了。这样一来就能自动生成满足条件的一系列中间结点集合供后续调用了。 ```python def densify_road_network(shp_file_path, distance_interval=50): """ Densifies road segments by adding points at specified intervals. :param shp_file_path: Path of the shapefile containing roads data. :param distance_interval: Distance between consecutive sample points (meters). :return: List of sampled point coordinates [(lat1, lon1), ...]. """ from geopandas import read_file gdf = read_file(shp_file_path) samples = [] for line in gdf.geometry: length = int(line.length / distance_interval) + 1 for i in range(length): pt = line.interpolate(i * distance_interval).coords[0] samples.append(pt[::-1]) # Reverse tuple order to match latitude/longitude convention return samples ```
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值