151 lines
3.2 KiB
Markdown
151 lines
3.2 KiB
Markdown
# CM93 解析与审计设计 v1
|
||
|
||
## 1. 原始格式解析
|
||
|
||
独立 Python 实现依据已公开的 OpenCPN CM93 行为进行互操作核对,但不复制 OpenCPN 的类结构或 GUI/S52 代码。
|
||
|
||
核心数据顺序:
|
||
|
||
1. 10-byte prolog
|
||
2. 128-byte header
|
||
3. vector records
|
||
4. 3D point descriptors
|
||
5. 2D points
|
||
6. feature records
|
||
|
||
完整性条件:
|
||
|
||
`word0 + table1_length + table2_length == file_size`
|
||
|
||
且 `word0 == 138`。
|
||
|
||
进一步核对:
|
||
|
||
- vector point 总数 = header `n_vector_record_points`
|
||
- 3D point 总数 = header `m_50`
|
||
- feature 总数 = header `usn_feature_records`
|
||
- attribute payload bytes = header `m_78`
|
||
- feature geometry refs = header `m_46 + m_4a`
|
||
- related object pointers = header `m_nrelated_object_pointers`
|
||
- 最终 cursor = EOF
|
||
|
||
任何一项不成立,该 cell 解析失败,不允许“尽量导入”。
|
||
|
||
## 2. 属性
|
||
|
||
按 `CM93ATTR.DIC/ATTRLUT.DIC`:
|
||
|
||
- B: 1-byte integer
|
||
- W: uint16 / 10.0
|
||
- G: int32
|
||
- R: float32,标准化后以 Python double/MySQL DOUBLE 保存
|
||
- S: NUL-terminated string
|
||
- C: 3-byte prefix + NUL-terminated string,prefix 与 text 均保留
|
||
- L: count byte + count 个 byte values
|
||
|
||
raw value bytes 始终另存。
|
||
|
||
## 3. Geometry
|
||
|
||
Feature geotype 低 4 bit:
|
||
|
||
- 1 Point
|
||
- 2 Line
|
||
- 4 Area
|
||
- 8 3D Sounding
|
||
|
||
Line/Area edge index:低 13 bit 是 edge index,高位是 usage;`usage & 4` 表示反向遍历 edge。
|
||
|
||
Area 按 edge chain 闭合形成 contour/ring。系统不会调用 `make_valid` 或改变原始顶点坐标。
|
||
|
||
## 4. 坐标
|
||
|
||
CM93 raw X/Y:0..65535。
|
||
|
||
Cell 变换:
|
||
|
||
`easting = raw_x * x_rate + easting_min`
|
||
|
||
`northing = raw_y * y_rate + northing_min`
|
||
|
||
CM93 半长轴:`6378388.0 m`。
|
||
|
||
若 coverage 给出 `_wgsox/_wgsoy`,标准化母数据采用:
|
||
|
||
`easting -= wgsox`
|
||
|
||
`northing -= wgsoy`
|
||
|
||
然后执行 CM93 Mercator → lon/lat。
|
||
|
||
Coverage polygon 自身保留未偏移坐标,用于判断 feature 属于哪个 coverage;offset 元数据独立保存。
|
||
|
||
## 5. Sounding
|
||
|
||
CM93 Z:
|
||
|
||
- `z >= 12000` → `depth = z - 12000`
|
||
- 否则 → `depth = z / 10.0`
|
||
|
||
每个 sounding point 同时保存 raw_x/raw_y/raw_z、depth 和 WGS84 Point。
|
||
|
||
## 6. Raw preservation
|
||
|
||
每个 cell 保存 decoded:
|
||
|
||
- prolog
|
||
- header
|
||
- vector table
|
||
- point3d table
|
||
- point2d table
|
||
- feature table
|
||
|
||
较大的 table 按 512 KiB 分块写入 `chart_raw_record`,避免 MySQL `max_allowed_packet` 造成单大包问题。
|
||
|
||
审计要求所有 raw chunk `OCTET_LENGTH` 总和 = 原 cell 文件字节数。
|
||
|
||
## 7. 审计分层
|
||
|
||
### Source parser audit
|
||
|
||
重新读取原 CM93,验证所有结构计数和 EOF。
|
||
|
||
### Database completeness audit
|
||
|
||
逐 cell 对比源数据与:
|
||
|
||
- chart_feature
|
||
- chart_feature_attribute
|
||
- point/line/area geometry
|
||
- chart_coverage
|
||
- chart_sounding_point
|
||
|
||
### Raw preservation audit
|
||
|
||
比较 raw chunk 总字节数与原文件长度。
|
||
|
||
### Hash audit
|
||
|
||
比较数据库 `source_sha256` 与当前原文件。
|
||
|
||
### Precision audit
|
||
|
||
从 Z/A~G 分层抽样,重新从 CM93 raw geometry 生成 WKB,然后从 MySQL `ST_AsWKB()` 回读,使用 `equals_exact` 比较。
|
||
|
||
默认 tolerance:`1e-12 degree`。
|
||
|
||
该标准比最初讨论的 `1e-9 degree` 更严格。
|
||
|
||
## 8. 不做的事情
|
||
|
||
第一阶段不做:
|
||
|
||
- PBF
|
||
- zoom selection
|
||
- simplify
|
||
- topology repair
|
||
- scale 去重
|
||
- cartographic style 映射
|
||
|
||
这些都属于第二阶段。
|