Skip to main content

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 怎么来)

  1. 文字内容:来自 Shapefile 中由 name_field 指定的字段(默认 name),经 strip 后跳过空、none、nan。
  2. 字体与字形:_FontManager.get_chinese_font_path() 依次尝试常见中文字体;失败则下载 Noto Sans SC 到临时目录。_TextMeshEngine 用 matplotlib.textpath.TextPath 将字符转为多边形,单字用 symmetric_difference 处理字内孔洞,整段用 union 合并字间形状;三角化使用 mapbox_earcut,再挤出顶/底与侧墙。
  3. 三维模型(OBJ):对每个未 hidden 的标注,build_tbn_matrix 在弧长 distance 处建立局部 TBN(切线 / 副法线 / 法线) 齐次矩阵;curved_text=True 时按字符沿线的弧长位置逐字建矩阵并变换顶点;curved_text=False 时整段网格用 一个 采样点的矩阵整体放置。separate_objects 控制是否每个标注单独 o object_name。
  4. 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 的实现顺序一致,便于对照阅读源码。

Metadata

Release files for roadmark-maker 0.2.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for roadmark-maker 0.2.8
File Actions
roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl CPython 3.14 CPython 3.14 Windows x86-64 Details for roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl
roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details for roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl CPython 3.13 CPython 3.13 Windows x86-64 Details for roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl
roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details for roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details for roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl
roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details for roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl CPython 3.11 CPython 3.11 Windows x86-64 Details for roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl
roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details for roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Total release size: 2.5 MB

Release files / roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl

Download URL roadmark_maker-0.2.8-cp314-cp314-win_amd64.whl
Size 188.2 kB
Tags CPython 3.14 Windows x86-64
SHA-256 checksum
How to use checksums
f646f26624b6f93910e9e939c4ed9a9fbad059c86469aa2e452222e0aff73021
BLAKE2b-256 checksum
How to use checksums
e3bd876da36a5539074ee4f5af1642a462d89dd288ac759502d9971249417efa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL roadmark_maker-0.2.8-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 427.8 kB
Tags CPython 3.14 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
c98ab46f46988722f6537935dd53f78b9158ff88178a0864c06fe1dd909378dc
BLAKE2b-256 checksum
How to use checksums
0405be6c703479ed0aeb4d5231ea168ba355a816aff7ac59c7ebbf2319b93707
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl

Download URL roadmark_maker-0.2.8-cp313-cp313-win_amd64.whl
Size 184.1 kB
Tags CPython 3.13 Windows x86-64
SHA-256 checksum
How to use checksums
14195588d13ff06f56c68049bdd1ef1f9608c9784f1291e195e68c7ae923c5d3
BLAKE2b-256 checksum
How to use checksums
f82e2fbbe35307e1714aa0b3656d1f957834bbba34fad6444606b9bedd22a309
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL roadmark_maker-0.2.8-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 429.5 kB
Tags CPython 3.13 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
3bd92d2e73cdd2197b00ddf0857af8b0f1105ab753529a23b7d811f89c25dea8
BLAKE2b-256 checksum
How to use checksums
af945d247f8377ea93078e5b8ded3f9c981b15c9c225fecf19cc7312a6deca4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl

Download URL roadmark_maker-0.2.8-cp312-cp312-win_amd64.whl
Size 183.7 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
f6f8664749d779110e91cebcde275d932d049ff53984fb13ae7fceba88197e12
BLAKE2b-256 checksum
How to use checksums
54628cc49b6e12ace648084a06b1d2a3fc049b4c0a1558bc5673dc46d86d9ad9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL roadmark_maker-0.2.8-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 429.0 kB
Tags CPython 3.12 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
fa2a0f6a1b4f374050b8c663cd6b6661470d27a5239644529128de807f5c0da7
BLAKE2b-256 checksum
How to use checksums
bc517bd383767e235e9c19bf903e66429f1d2e42ae7280aa039bd12783190c08
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl

Download URL roadmark_maker-0.2.8-cp311-cp311-win_amd64.whl
Size 186.3 kB
Tags CPython 3.11 Windows x86-64
SHA-256 checksum
How to use checksums
4f684a3a06acdbd9bd95433d7d0e145f81bef61aee864ee11b6f963c735df680
BLAKE2b-256 checksum
How to use checksums
8731cd7560bc5126f9f297c776c0473c0e9c71eb61b21b07b625472d80dfc113
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Release files / roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL roadmark_maker-0.2.8-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 437.4 kB
Tags CPython 3.11 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
b2f2a6b62ed4d76fd952661fd73d153de8a7e695e61e9c77fc5e71a7e6a56bbc
BLAKE2b-256 checksum
How to use checksums
9a969a30ea3c89e5770419d2d3d84945a21dddee2bc4bfe07577a586682b3701
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.4

Security for roadmark-maker 0.2.8

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.8 This release

8 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page