Make road mark from road shapefile.
Project description
roadmark-maker
从 3D 道路 Shapefile 生成沿路排布的立体路名标牌(Wavefront OBJ)或实例化贴图用的 Billboard 位姿(CSV)。核心为 Python(GeoPandas / Shapely / Matplotlib)与 C++(OpenMP、可选 AVX2)混合的 Maplex 风格 避让与网格管线。
构建
chcp 65001 && uv build --wheel --out-dir dist
依赖与构建说明见 pyproject.toml;C++ 求解器声明在 src/roadmark_maker/roadmark_core.hpp,Cython 绑定在 src/roadmark_maker/roadmark_accel.pyx。
对外接口与能力
| 接口 | 作用 | 典型下游 |
|---|---|---|
generate(...) |
完整管线:读 SHP → 采样与排版 → C++ OBB 碰撞解算 → 逐字或整段 挤出网格 → 写 OBJ | Cesium、OSG、Blender 等需三角网格的场景 |
generate_csv(...) |
与 generate 共用 _prepare_data(同样的采样、CRS、density / repeat_mode、碰撞),但 不建网格;在引擎内固定 curved_text=False,将每条标注的 整体 位姿(平移 + 旋转)写出为 CSV |
UE、Cesium 等用 实例化 Quad + 贴图 画路名 |
二者均在 src/roadmark_maker/__init__.py 中导出;优先加载 roadmark_accel_avx2,不可用时回退 roadmark_accel。
核心逻辑(文字从哪来、模型 / CSV 怎么来)
- 文字内容:来自 Shapefile 中由
name_field指定的字段(默认name),经strip后跳过空、none、nan。 - 字体与字形:
_FontManager.get_chinese_font_path()依次尝试常见中文字体;失败则下载 Noto Sans SC 到临时目录。_TextMeshEngine用matplotlib.textpath.TextPath将字符转为多边形,单字用symmetric_difference处理字内孔洞,整段用union合并字间形状;三角化使用mapbox_earcut,再挤出顶/底与侧墙。 - 三维模型(OBJ):对每个未
hidden的标注,build_tbn_matrix在弧长distance处建立局部 TBN(切线 / 副法线 / 法线) 齐次矩阵;curved_text=True时按字符沿线的弧长位置逐字建矩阵并变换顶点;curved_text=False时整段网格用 一个 采样点的矩阵整体放置。separate_objects控制是否每个标注单独o object_name。 - CSV:
generate_csv在_prepare_data之后遍历存活标注,取矩阵的平移(x,y,z),将3×3旋转经 C++MathUtils.matrix_to_rotations转为四元数与/或 ZYX 欧拉角,可按target_crs再投影;列为x,y,z+ 角度 +name。不包含逐字几何,适合整条路名一张纹理的实例化。
参数如何控制「分布」与外观
| 参数 | 控制点 |
|---|---|
text_count |
若为正整数,在每条线段上 等分弧长 生成该数量的候选(忽略 distance_interval)。 |
distance_interval |
未设 text_count 时,沿弧长每隔约该距离(与当前 CRS 单位一致;UTM 下为米)放一个候选。 |
add_at_endpoints |
为 true 时在弧长 0 与 line_len 处额外各加一个候选。 |
density |
仅当 curved_text=True 时参与 auto_place_labels:档位决定 全局最小间距、同组重复最小间距、每组最多保留条数、全局贪心外层迭代次数(见下表);可用 max_global_iterations 覆盖迭代次数。 |
repeat_mode / connect_eps |
name_connected(默认)下按 路名 + 线段端点距离 ≤ eps 并查集合并连通分量,同组共享 max_labels_per_group 配额;feature / name 为其它分组策略。 |
font_size / letter_spacing |
世界空间大致字高与字距;碰撞体宽度用 effective_text_len 与 effective_char_width_est(自动压缩时变化)。 |
curved_text |
True:自动适配线长、全局选点、逐字贴合折线;False:整段文本一块网格、不做 auto_place_labels 筛选。 |
auto_fit_text / min_font_scale / min_letter_spacing / overflow_strategy |
在 curved_text=True 时,apply_autofit 按线长比例缩小字号与字距,仍过长则 truncate 策略下二分保留长度并加 …。 |
posture |
flat:法线朝上贴地;billboard:以世界 Z 为参考的立式朝向。 |
use_utm |
True:以数据质心经度推算 UTM 带并 to_crs,XY/Z 比例更接近真实米制;False(默认):工作 CRS 为 EPSG:3857。 |
weight_field |
碰撞时 权重大者不滑动;权重相同则 文本更长者 作为 yielder 被推动。 |
separate_objects |
仅影响 OBJ 是否分 o 组。 |
全局迭代优化(auto_place_labels)与 C++ 碰撞
全局阶段(仅 curved_text=True):
- 对每个要素在「线长能放下估计跨度」的候选里,选弧长最接近 线段中点 的一个作为 锚点。
- 外层循环最多
iterations次(由density决定,或由max_global_iterations覆盖);每轮对当前已选集合调用_fast_resolve_collisions(..., 3, ...),去掉被标为hidden的。 - 在剩余候选中贪心加入下一个:需满足 全局与其它已选中心的平面距离 ≥
global_min_sep、同group_id内 ≥repeat_min_interval、且组内个数小于max_labels_per_group;得分优先 离已选集合最远。 - 未被选中的候选最终
hidden=True,不再导出。
density 默认档位(font_size 取中位数有效字号参与比例,代码见 _density_profile)
| 档位 | global_min_sep |
repeat_min_interval |
max_labels_per_group |
外层迭代 iterations |
|---|---|---|---|---|
very_dense |
6×fs | 10×fs | 5 | 10 |
dense |
8×fs | 14×fs | 4 | 9 |
moderate |
10×fs | 18×fs | 3 | 8 |
sparse |
14×fs | 26×fs | 2 | 7 |
very_sparse |
18×fs | 34×fs | 1 | 6 |
C++ 碰撞(MaplexSolver::resolve_collisions,Python 侧 max_iterations 固定为 3,非用户参数):
- 根据当前 OBB 最大宽度建 均匀网格,格内两两做 分离轴 SAT(四个轴:两边 OBB 的方向与法向)。
- 冲突时对 yielder 做 同线级联滑动:步长约
2 * char_width_est,沿切向推进并可能推动后方同线标注;超出line_len则hidden。 - 固定轮次结束后仍有重叠则 一方直接 hidden(权重与字长规则同上)。
推荐:城市密集路网可先用 moderate 或 dense;希望同一路名少重复、留白大可 sparse / very_sparse。若仍过密,可增大 distance_interval 或设置较小的 text_count,或略减小 font_size。
注意:generate_csv 将 curved_text 置为 False,因此 不会 执行上述全局 auto_place_labels 筛选;CSV 与 OBJ(curved_text=True)在「候选数量」上可能不一致。
处理流程图(与实现一致)
flowchart TB
subgraph API["入口"]
G["generate() → OBJ"]
C["generate_csv() → CSV<br/>内部固定 curved_text=False"]
end
subgraph S1["1. 数据与坐标系"]
A[读取 Shapefile<br/>GeoPandas] --> B{name_field 存在?}
B -->|否| W[警告并返回空结果]
B -->|是| CRS{use_utm}
CRS -->|true| U[质心经纬度 → 推算 UTM EPSG]
CRS -->|false 默认| M[EPSG:3857]
U --> T[to_crs 工作 CRS]
M --> T
end
subgraph S2["2. 沿几何采样候选 Label"]
T --> L[拆分 LineString / MultiLineString]
L --> S[text_count 或 distance_interval<br/>+ 可选端点 add_at_endpoints]
S --> K[每条记录: text / weight≥1 / line_len / distance 等]
end
subgraph S3["3. 曲线模式预处理"]
K --> CT{curved_text?}
CT -->|False| SK[跳过 autofit / auto_place]
CT -->|True| AF{auto_fit_text?}
AF -->|是| AF2[apply_autofit:<br/>按线长缩放 + truncate …]
AF -->|否| AP
AF2 --> AP[auto_place_labels:<br/>锚点 + 全局贪心 + 组约束<br/>每轮子集 _fast_resolve ×3]
AP --> SK
end
subgraph S4["4. 局部坐标架与 C++ 碰撞"]
SK --> MX[为各候选 build_tbn_matrix<br/>差分弧长得 T; auto_flip 可读性]
MX --> COL["_fast_resolve_collisions<br/>C++ 网格 + SAT-OBB<br/>固定 max_iterations=3"]
COL --> MD[distance 变化则 matrix_dirty]
end
subgraph S5["5a. OBJ 导出 generate"]
MD --> OBJ{导出分支}
OBJ -->|curved_text=True| CV[逐字 TextPath + earcut 挤出<br/>沿线分布弧长]
OBJ -->|curved_text=False| FL[整段 generate_mesh 一次<br/>单矩阵变换]
CV --> WOBJ[写 v/f; separate_objects 控制 o 分组]
FL --> WOBJ
end
subgraph S5b["5b. CSV 导出 generate_csv"]
MD --> CSVM[矩阵平移 + matrix_to_rotations<br/>可选 target_crs 变换]
CSVM --> WCSV[UTF-8-SIG CSV<br/>x,y,z + 四元数/欧拉 + name]
end
G --> A
C --> A
一次运行只调用 generate 或 generate_csv 之一;上图中 5a / 5b 为两种出口,不会在同一次执行里同时发生。
逻辑关系简图(阶段依赖)
graph LR
IO[SHP + CRS] --> SP[弧长采样]
SP --> GF{curved_text?}
GF -->|是| AP[autofit + 全局选点]
GF -->|否| MX[建 TBN]
AP --> MX
MX --> CPP[C++ 碰撞 3 轮]
CPP --> OUT{输出}
OUT -->|generate| MESH[网格 + OBJ]
OUT -->|generate_csv| TBL[位姿 + CSV]
以上流程与 src/roadmark_maker/roadmark_accel.pyx 中 _RoadMaplexEngine._prepare_data、export_obj、export_csv 的实现顺序一致,便于对照阅读源码。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 188.2 kB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f646f26624b6f93910e9e939c4ed9a9fbad059c86469aa2e452222e0aff73021
|
|
| MD5 |
46a92cbe04e7ccc6919dbb77f5b553c8
|
|
| BLAKE2b-256 |
e3bd876da36a5539074ee4f5af1642a462d89dd288ac759502d9971249417efa
|
File details
Details for the file roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 427.8 kB
- Tags: CPython 3.14, manylinux: glibc 2.24+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c98ab46f46988722f6537935dd53f78b9158ff88178a0864c06fe1dd909378dc
|
|
| MD5 |
273e4b0f992f66180854593d1a7ff25e
|
|
| BLAKE2b-256 |
0405be6c703479ed0aeb4d5231ea168ba355a816aff7ac59c7ebbf2319b93707
|
File details
Details for the file roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 184.1 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14195588d13ff06f56c68049bdd1ef1f9608c9784f1291e195e68c7ae923c5d3
|
|
| MD5 |
755199a25421e12c83f2c6c11fdf7d97
|
|
| BLAKE2b-256 |
f82e2fbbe35307e1714aa0b3656d1f957834bbba34fad6444606b9bedd22a309
|
File details
Details for the file roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 429.5 kB
- Tags: CPython 3.13, manylinux: glibc 2.24+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bd92d2e73cdd2197b00ddf0857af8b0f1105ab753529a23b7d811f89c25dea8
|
|
| MD5 |
0bd4eb59db3943bc0fd4700f24c80853
|
|
| BLAKE2b-256 |
af945d247f8377ea93078e5b8ded3f9c981b15c9c225fecf19cc7312a6deca4f
|
File details
Details for the file roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 183.7 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6f8664749d779110e91cebcde275d932d049ff53984fb13ae7fceba88197e12
|
|
| MD5 |
8750757051d496b90bdbbc94a28df6d0
|
|
| BLAKE2b-256 |
54628cc49b6e12ace648084a06b1d2a3fc049b4c0a1558bc5673dc46d86d9ad9
|
File details
Details for the file roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 429.0 kB
- Tags: CPython 3.12, manylinux: glibc 2.24+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa2a0f6a1b4f374050b8c663cd6b6661470d27a5239644529128de807f5c0da7
|
|
| MD5 |
0014267a39f5d49d35facb56fd92e7b9
|
|
| BLAKE2b-256 |
bc517bd383767e235e9c19bf903e66429f1d2e42ae7280aa039bd12783190c08
|
File details
Details for the file roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 186.3 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f684a3a06acdbd9bd95433d7d0e145f81bef61aee864ee11b6f963c735df680
|
|
| MD5 |
bea8337eeeb3e460b4458fa4a41c9ac0
|
|
| BLAKE2b-256 |
8731cd7560bc5126f9f297c776c0473c0e9c71eb61b21b07b625472d80dfc113
|
File details
Details for the file roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 437.4 kB
- Tags: CPython 3.11, manylinux: glibc 2.24+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2f2a6b62ed4d76fd952661fd73d153de8a7e695e61e9c77fc5e71a7e6a56bbc
|
|
| MD5 |
21fe2b999ec266ecc703cf99fc9a983b
|
|
| BLAKE2b-256 |
9a969a30ea3c89e5770419d2d3d84945a21dddee2bc4bfe07577a586682b3701
|