487 lines
10 KiB
Markdown
487 lines
10 KiB
Markdown
# CM95 — CM93 → MySQL Importer
|
||
|
||
CM95 当前仓库的已验证基线,是一个将 CM93 数据解析、标准化并保存到 MySQL 5.7 的 importer。
|
||
|
||
当前基线:
|
||
|
||
```text
|
||
commit: 9d56592cadf7e047fb059e5a8746188595a08b43
|
||
tag: cm93-mysql-importer-baseline-v1
|
||
date: 2026-09-02
|
||
```
|
||
|
||
本阶段只覆盖:
|
||
|
||
```text
|
||
CM93 source
|
||
→ binary parse
|
||
→ dictionary decode
|
||
→ geometry build / normalization
|
||
→ MySQL 5.7
|
||
→ audit / traceability
|
||
```
|
||
|
||
本文 importer 冻结基线本身不因下游 PBF 工作而改变;PBF 已在后续独立阶段单独启动,见本文末尾。
|
||
|
||
---
|
||
|
||
## 1. 当前状态
|
||
|
||
CM93JAPAN / Dataset ID=1 已完成两套独立全库验收:
|
||
|
||
```text
|
||
Geometry Audit: OVERALL: PASS
|
||
Non-Geometry Audit: OVERALL: PASS
|
||
```
|
||
|
||
最终基线:
|
||
|
||
| 项目 | 数量 / 结果 |
|
||
|---|---:|
|
||
| Cells | 784 |
|
||
| Features | 322465 |
|
||
| Attributes | 405153 |
|
||
| Sounding points | 275700 |
|
||
| Coverages | 1156 |
|
||
| Area | 81080 |
|
||
| Area valid | 81080 / 81080 |
|
||
| Coverage valid | 1156 / 1156 |
|
||
| Feature repaired | 55 |
|
||
| Coverage repaired | 3 |
|
||
| Feature geometry issues | 0 |
|
||
| Coverage geometry issues | 0 |
|
||
| raw_geotype=16 | 4406 |
|
||
| raw_geotype=16 issues | 0 |
|
||
| Area bbox mismatch | 0 |
|
||
| Source files checked | 784 |
|
||
| Source files missing | 0 |
|
||
| Source size mismatch | 0 |
|
||
| Source SHA-256 mismatch | 0 |
|
||
|
||
---
|
||
|
||
## 2. 主要能力
|
||
|
||
Importer 当前处理并保存:
|
||
|
||
- CM93 Cell 扫描;
|
||
- CM93OBJ / CM93ATTR 字典;
|
||
- Cell header;
|
||
- vector / edge;
|
||
- 2D point;
|
||
- 3D sounding;
|
||
- Feature;
|
||
- Attribute;
|
||
- Point / Line / Area;
|
||
- Coverage;
|
||
- WGS offset;
|
||
- Sounding point;
|
||
- Feature bbox;
|
||
- raw feature / raw attribute;
|
||
- Cell 原始 table 分块;
|
||
- source SHA-256;
|
||
- import job / event;
|
||
- geometry issue / repaired 状态。
|
||
|
||
每个 Feature 必须保持:
|
||
|
||
```text
|
||
dataset_id
|
||
cell_id
|
||
source_record_index
|
||
```
|
||
|
||
从数据库记录可追溯回原始 CM93 Cell 和 source record。
|
||
|
||
---
|
||
|
||
## 3. 生产代码
|
||
|
||
核心生产文件:
|
||
|
||
```text
|
||
src/cm93db/cm93_binary.py
|
||
src/cm93db/cell_parser.py
|
||
src/cm93db/geometry.py
|
||
src/cm93db/importer.py
|
||
src/cm93db/audit.py
|
||
sql/001_schema_mysql57.sql
|
||
```
|
||
|
||
Geometry 和 importer 的当前行为已经通过全量数据验收。后续没有明确任务时,不应重写其主流程。
|
||
|
||
---
|
||
|
||
## 4. 数据库
|
||
|
||
目标数据库:
|
||
|
||
```text
|
||
MySQL 5.7
|
||
```
|
||
|
||
Schema:
|
||
|
||
```text
|
||
sql/001_schema_mysql57.sql
|
||
```
|
||
|
||
Importer 的 normalized SRID 为:
|
||
|
||
```text
|
||
EPSG:4326
|
||
```
|
||
|
||
MySQL geometry 通过 WKB 写入,坐标使用 double precision。
|
||
|
||
不要假设 MySQL 8 的 Spatial / SRID 行为适用于本项目。
|
||
|
||
数据库连接配置以项目现有 `.env.example` / 配置模块为准。
|
||
|
||
---
|
||
|
||
## 5. 导入
|
||
|
||
Windows 项目环境示例:
|
||
|
||
```powershell
|
||
cd D:\React\cm93-mysql-importer-starter
|
||
|
||
& ".\.venv\Scripts\cm93db.exe" import D:\Ship\CM93V2\CM93JAPAN
|
||
```
|
||
|
||
普通导入会根据:
|
||
|
||
```text
|
||
chart_cell.import_status
|
||
source_size
|
||
source_sha256
|
||
```
|
||
|
||
跳过已经成功导入且源文件 SHA-256 未变化的 Cell。
|
||
|
||
典型输出:
|
||
|
||
```text
|
||
SKIP ... (SHA-256 unchanged)
|
||
```
|
||
|
||
需要强制重新解析并写入所有选中 Cell 时:
|
||
|
||
```powershell
|
||
& ".\.venv\Scripts\cm93db.exe" import D:\Ship\CM93V2\CM93JAPAN --reimport
|
||
```
|
||
|
||
`--reimport` 会清理每个 Cell 已有 payload 后重新生成,因此只应在明确需要全量重导时使用。
|
||
|
||
如果单个 Cell 因临时数据库连接错误等原因处于 `FAILED`,普通 import 默认会重试失败 Cell,同时跳过其余未变化的 DONE Cell。
|
||
|
||
---
|
||
|
||
## 6. Geometry 语义
|
||
|
||
### 6.1 坐标
|
||
|
||
CM93 raw coordinate 按 Cell header 参数转换到 Mercator 坐标,再转换为经纬度。
|
||
|
||
Coverage 的 `_wgsox / _wgsoy` 用于最终 geometry 的 WGS offset 修正。
|
||
|
||
最终数据库 geometry 使用 SRID 4326。
|
||
|
||
### 6.2 Line
|
||
|
||
Line 必须保留断开的多个 line parts,不得为了得到单条 LineString 而跨 discontinuity 人为连接。
|
||
|
||
### 6.3 Area / Coverage
|
||
|
||
当前冻结规则:
|
||
|
||
#### 已经 OGC-valid
|
||
|
||
```text
|
||
PASS-THROUGH
|
||
```
|
||
|
||
已经 valid 的 Polygon / MultiPolygon 不重新 normalization,不为了统一 ring 顺序而重建。
|
||
|
||
#### OGC-invalid
|
||
|
||
只有 invalid Area / Coverage 才执行:
|
||
|
||
```text
|
||
boundary noding
|
||
→ polygonize_full
|
||
→ odd-even face selection
|
||
→ union selected faces
|
||
→ GEOS normalize
|
||
→ valid Polygon / MultiPolygon
|
||
```
|
||
|
||
该规则来自 CM93 实际 topology / fill semantics 的完整审计。
|
||
|
||
生产规则明确禁止直接使用:
|
||
|
||
```text
|
||
make_valid()
|
||
ST_MakeValid()
|
||
buffer(0)
|
||
```
|
||
|
||
来覆盖原始 CM93 Polygon 语义。
|
||
|
||
Normalization 不允许创造原始 CM93 boundary linework 之外的新边界。
|
||
|
||
open ring、断裂 contour 等真实结构异常不能静默“修好”;无法安全 normalization 的 Coverage 必须阻止错误 Cell 落库。
|
||
|
||
### 6.4 raw_geotype=16
|
||
|
||
`raw_geotype=16` 是 CM93 正常的 parent/no-geometry 对象。
|
||
|
||
当前正确语义:
|
||
|
||
```text
|
||
geometry_type = META
|
||
geometry = NULL
|
||
geometry_issue = NULL
|
||
geometry_repaired = 0
|
||
```
|
||
|
||
它不是 `"geometry missing"` 错误,也不进入 `geometry_invalid_count`。
|
||
|
||
当前 Dataset ID=1 共验证:
|
||
|
||
```text
|
||
4406 / 4406
|
||
```
|
||
|
||
全部为正常 parent/no-geometry。
|
||
|
||
### 6.5 bbox
|
||
|
||
Area 发生 normalization 后:
|
||
|
||
```text
|
||
feature bbox = final normalized geometry.bounds
|
||
```
|
||
|
||
不能继续使用 normalization 前可能包含 retraced connector 的 bounds。
|
||
|
||
---
|
||
|
||
## 7. geometry_repaired / geometry_issue
|
||
|
||
`geometry_repaired=1` 表示 importer 对原 OGC-invalid CM93 polygon 执行冻结 normalization,并得到了最终 valid Polygon/MultiPolygon。
|
||
|
||
`geometry_issue` 只用于:
|
||
|
||
- geometry 真正缺失但该 primitive 应存在 geometry;
|
||
- geometry empty;
|
||
- open ring / 结构异常;
|
||
- normalization 无法安全完成;
|
||
- 其他真实 geometry 异常。
|
||
|
||
正常 META parent/no-geometry 不属于 issue。
|
||
|
||
当前已验证:
|
||
|
||
```text
|
||
Feature repaired = 55
|
||
Coverage repaired = 3
|
||
Feature issues = 0
|
||
Coverage issues = 0
|
||
```
|
||
|
||
Coverage 同时也是 `_m_sor` Feature,所以不要简单把 `55 + 3` 当作 58 个独立 CM93 source Feature。
|
||
|
||
---
|
||
|
||
## 8. Raw source 保留
|
||
|
||
标准化 geometry 不得破坏原始输入证据。
|
||
|
||
必须长期保留:
|
||
|
||
```text
|
||
chart_feature.raw_feature_blob
|
||
chart_feature.raw_attribute_blob
|
||
chart_raw_record
|
||
source_record_index
|
||
```
|
||
|
||
`chart_raw_record` 使用分块保存原始 Cell table,并在 metadata 中记录:
|
||
|
||
```text
|
||
chunk_index
|
||
chunk_count
|
||
total_bytes
|
||
```
|
||
|
||
这保证后续仍可重新核对 parser 与 CM93 原始二进制。
|
||
|
||
---
|
||
|
||
## 9. 长期回归验收
|
||
|
||
正式长期验收工具:
|
||
|
||
```text
|
||
tools/cm93_mysql_final_geometry_audit.py
|
||
tools/cm93_mysql_non_geometry_final_audit.py
|
||
```
|
||
|
||
### Geometry 全库验收
|
||
|
||
```powershell
|
||
& ".\.venv\Scripts\python.exe" .\tools\cm93_mysql_final_geometry_audit.py `
|
||
--host 127.0.0.1 `
|
||
--port 3306 `
|
||
--user root `
|
||
--database cm93_chart `
|
||
--dataset-id 1
|
||
```
|
||
|
||
当前 CM93JAPAN 基线应得到:
|
||
|
||
```text
|
||
Cells : 784
|
||
Features : 322465
|
||
Feature repaired : 55
|
||
Coverage repaired : 3
|
||
Feature issues : 0
|
||
Coverage issues : 0
|
||
Geotype16 total : 4406
|
||
Geotype16 issues : 0
|
||
Area total : 81080
|
||
Area valid : 81080
|
||
Area bbox mismatch : 0
|
||
Coverage total : 1156
|
||
Coverage valid : 1156
|
||
Failure count : 0
|
||
OVERALL: PASS
|
||
```
|
||
|
||
### 非 Geometry 全库验收
|
||
|
||
```powershell
|
||
& ".\.venv\Scripts\python.exe" .\tools\cm93_mysql_non_geometry_final_audit.py `
|
||
--host 127.0.0.1 `
|
||
--port 3306 `
|
||
--user root `
|
||
--database cm93_chart `
|
||
--dataset-id 1 `
|
||
--source-root "D:\Ship\CM93V2\CM93JAPAN"
|
||
```
|
||
|
||
当前 CM93JAPAN 基线应得到:
|
||
|
||
```text
|
||
Cells : 784
|
||
Features : 322465
|
||
Attributes : 405153
|
||
Soundings : 275700
|
||
Coverages : 1156
|
||
|
||
Cell count mismatch : 0
|
||
Feature check failures : 0
|
||
Dictionary failures : 0
|
||
Attribute failures : 0
|
||
Coverage failures : 0
|
||
Sounding failures : 0
|
||
JSON/relation failures : 0
|
||
Raw failures : 0
|
||
|
||
Source files checked : 784
|
||
Source files missing : 0
|
||
Source size mismatch : 0
|
||
Source SHA256 mismatch : 0
|
||
|
||
Failure count : 0
|
||
OVERALL: PASS
|
||
```
|
||
|
||
任何实质性修改以下部分后,都应重新执行对应验收:
|
||
|
||
- binary parser;
|
||
- dictionary decode;
|
||
- geometry build;
|
||
- Area/Coverage normalization;
|
||
- WGS offset;
|
||
- importer DB mapping;
|
||
- raw preservation;
|
||
- Feature / Attribute / Sounding / Coverage 关系;
|
||
- bbox;
|
||
- schema。
|
||
|
||
---
|
||
|
||
## 10. 历史调查脚本
|
||
|
||
仓库中保留了本次 importer 调查过程中产生的 V 系列审计脚本。
|
||
|
||
它们用于记录问题定位过程,不再作为日常回归入口。
|
||
|
||
日常回归只使用:
|
||
|
||
```text
|
||
tools/cm93_mysql_final_geometry_audit.py
|
||
tools/cm93_mysql_non_geometry_final_audit.py
|
||
```
|
||
|
||
历史调查脚本不要被新的生产代码 import,也不要把历史审计结果作为运行时依赖。
|
||
|
||
---
|
||
|
||
## 11. Git 冻结基线
|
||
|
||
当前正式可回退点:
|
||
|
||
```text
|
||
commit 9d56592cadf7e047fb059e5a8746188595a08b43
|
||
tag cm93-mysql-importer-baseline-v1
|
||
```
|
||
|
||
该 tag 表示:
|
||
|
||
```text
|
||
CM93 → MySQL importer validated baseline
|
||
```
|
||
|
||
tag 应保持不可变。
|
||
|
||
后续改动在 `main` 上正常提交;需要对比时,以此 tag 作为 importer normalization 前后已验证基线。
|
||
|
||
---
|
||
|
||
## 12. 当前不做的事情
|
||
|
||
当前 importer 阶段不包括:
|
||
|
||
- PBF 生成;
|
||
- PBF schema;
|
||
- PBF renderer;
|
||
- PBF API;
|
||
- 为 PBF 改写 MySQL importer;
|
||
- 为了下游显示而损失 raw CM93 数据;
|
||
- 对原始 CM93 文件进行写回。
|
||
|
||
该限制针对 importer 冻结阶段;后续 PBF 阶段已由用户明确启动,但 PBF 实现不得反向破坏已冻结的 importer / MySQL / raw 数据模型。
|
||
|
||
|
||
---
|
||
|
||
## 13. 后续独立 PBF 阶段
|
||
|
||
CM95 → NavSea 的 PBF 下游阶段已经单独启动;importer 冻结基线继续保持不变。
|
||
|
||
2026-10-01 新增独立 bathymetry PBF 首批 build:
|
||
|
||
```text
|
||
config/bathymetry/cm95_bathymetry_north_kyushu_v1.yaml
|
||
tools/cm95_bathymetry_build_v1.py
|
||
web/bathymetry_test.html
|
||
web/bathymetry_test_server.py
|
||
docs/CM95_Bathymetry独立PBF_v1.md
|
||
```
|
||
|
||
该 bathymetry PBF 是第二个独立 vector source,等深线由 SOUNDG 测深点派生,标记为 `reliability=reference_low`,不与基础 PBF 合并。
|