当 Look-up 表变成程序:拆解 S-101 的 215 条渲染规则

发布时间:2026/9/30 20:45:36

当 Look-up 表变成程序:拆解 S-101 的 215 条渲染规则 上一篇拆 PC 分发件时留了个坑目录里登记着 215 个规则文件的引用但解开包只看到数据——符号怎么画有 XML颜色怎么配有 colorProfile唯独没有什么条件下画什么的逻辑。S-52 时代的 Look-up 表好歹是一张能读的表S-101 把它变成了 215 个 Lua 文件——210 个物标规则外加 5 个PortrayalAPI、S100Scripting之类的框架与公共文件。这些文件不在图示表达包里而是以 CSPConditional Symbology Procedure条件制图程序源码的形式随产品规范发布——IHO 官网上各产品规范的 Portrayal 附件里就能下到。本文拆的这批对应S-101 Ed 2.0.0 配套的图示表达目录 v2.0.0——215 个 Lua 文件逐个实读数目正好与目录登记对上。这件事的分量值得单独说一句条件制图从给人读的文档变成了给机器跑的程序。S-52 PresLib 时代PL 3.4 / PL 4.0 里的条件逻辑是伪代码每家渲染器自己翻译成 C——翻译过程就是实现分歧的温床。S-101 干脆把官方实现Lua连同文档一起发你要做的不是照着文档写而是把这段 Lua 嵌进去跑。这篇挑三个代表拆开最小的——锚泊船规则四十来行当入门样本最烧脑的——深度区和它的邻居们管安全等深线怎么画最后一族干脆不用 Lua——换 XSLT 引擎的规则。最小的规则锚泊船AnchorBerth.lua全文 43 行是理解 CSP 结构的好样本。核心判断只有两处local symbol ACHBRT07 -- default for categoryOfCargo ! 7 if contains(7, feature.categoryOfCargo) then symbol ANCBDNG2 end第一个条件就值得停下属性直接改写符号。锚泊船装的是危险品categoryOfCargo 含 7符号从普通锚泊换成危险品锚泊标——船员扫一眼符号就知道这片锚地里混着危险品船。这行代码在 S-52 里对应 Look-up 表里的一条带条件的行语义没变只是载体从表行变成了 if。几何类型分支是第二处if feature.PrimitiveType PrimitiveType.Point then ... elseif feature.PrimitiveType PrimitiveType.Surface then ... featurePortrayal:SimpleLineStyle(dash,0.64,CHMGF) featurePortrayal:AddInstructions(LineInstruction:_simple_)点要素给符号面要素除了符号还要画边界——边界不引用外部线样式文件而是用SimpleLineStyle内联一条简单的虚线0.64 宽、CHMGF 浅品红。S-52 里这个区分写在 Look-up 表的两个不同条目里现在变成了显式的 if-else。还有一处容易被忽略但很关键if contextParameters.RadarOverlay then featurePortrayal:AddInstructions(ViewingGroup:26220;DrawingPriority:15;DisplayPlane:OverRadar) else featurePortrayal:AddInstructions(...DisplayPlane:UnderRadar)contextParameters是船员设置不是要素属性。雷达叠加开着锚泊符号画在雷达图像上层关着就画在下层。同一个物标画面层级跟着用户参数走——这就是为什么渲染器没法把画在哪层写死也是 CSP 签名里带contextParameters的原因。要素属性、几何类型、用户上下文三股输入在这里汇合。最后一个小细节要素带名字时规则追加一条文本注记且内容走模板——EncodeString(GetFeatureName(feature, contextParameters), Nr %s)。图上Nr 7这样的锚泊编号格式是规则里定的不是渲染器拼的。连一个前缀字符串的归属都被规范收走了。顺带看一眼指令协议本身AddInstructions吃一个分号分隔的字符串ViewingGroup:26220;DrawingPriority:15;DisplayPlane:UnderRadar——分组、优先级、显示面一条指令流。渲染器要做的只是实现这个指令集的解释器规则怎么写它一概不关心。最烧脑的规则深度区和它的邻居们DEPARE03.lua有 150 余行处理的是海图上最要命的问题安全等深线到底画在哪。前文讲过安全等深线是船员按吃水设的参数改一个数整张图的填色分布重算。重算在 S-101 里的实体就是这段 Luaif depthRangeMinimumValue contextParameters.SafetyContour then unsafe true else safe true end水深小于安全等深线这片深度区标记为 unsafe——但真正的重头戏在后面。深度区画边界时要判断我这条边是不是安全等深线而判断依据不是自己的属性是邻居是谁for curveAssociation in feature:GetFlattenedSpatialAssociations() do local associatedFeatures curveAssociation.AssociatedFeatures ...DEPARE03 遍历自己每条共享边把共边的要素捞出来分堆共边的是DepthContour看它的深度值是不是恰好等于安全等深线loc_safety。是LandArea、UnsurveyedArea那要看对方的水线效果waterLevelEffect——陆地和未测量区贴着的边按 unsafe 处理。连内陆水域都有特判River、Lake、Canal、DockArea、LockBasin 算一组还要看线性建筑物的水线效果属性。这段代码里埋着一句真实工程味的注释-- NOTE: S-52 PL 3.4 disagrees with PL 4.0.1 on the inlandWaterShared and watlev. -- Going with 3.4 since 4.0.1 doesnt apply the proper weight when safe water is -- next to a land area.S-52 预库 3.4 版和 4.0.1 版在内陆水域的判定上标准自己打架了官方实现选边站 3.4理由写在注释里。条件制图程序化的一个意外好处就在这实现分歧没法再藏在各家 C 里它被显式地摆在了代码注释中型式认可时审的就是这一行。DEPARE03 里还有两处值得圈出来。其一位置质量直接映射到线型if qualityOfPosition and qualityOfPosition ~ 1 and qualityOfPosition ~ 10 and qualityOfPosition ~ 11 then featurePortrayal:SimpleLineStyle(dash,0.64,DEPSC)这条边如果位置测量质量不达标qualityOfPosition 不在可信值列表里安全等深线画成虚线——测得不准的等深线在图上就该长得不确定。数据质量参与渲染决策这是 S-100 系列相对 S-57 最实质的进步之一而它就落在这几行里。其二规则是可组合的。文件头require RESCSP03、require SAFCON01、require SEABED01——管制区注记、安全水深标注、海床显示各是独立的 CSP被 DEPARE03 按需调用。215 个规则文件不是 215 个孤立函数是一张调用网。连性能桩都标准化了Debug.StartPerformance(Lua Code - DEPARE03)官方实现自带计时。顺带一提长度上的冠军另有其人——碍航物 OBSTRN07.lua 有 188 行沉船、适淹礁、水线效果的多层嵌套判成迷宫不过读懂了深度区其它规则都是它的变奏。另一族不用 Lua 的 XSLTLua 不是唯一载体。S-111 表面流、S-123 海上无线电服务这批产品规范的图示表达用的是XSLT——规则文件长这样S-123 的海警站42 行xsl:template matchCoastguardStation[primitivePoint] priority1 pointInstruction ... viewingGroup12310/viewingGroup displayPlaneOVERRADAR/displayPlane symbol referenceCostGuardStattion/ /pointInstruction xsl:if testcommunicationChannel! textInstruction.../textInstruction /xsl:if /xsl:transform对比 AnchorBerth 那段 Lua语义一一对应模板匹配管几何类型[primitivePoint]xsl:if管条件注记输出的是指令 XML 而不是指令流字符串。一个是命令式Lua 主动 AddInstructions一个是声明式XSLT 匹配后产出 XML条件制图的语义是同一套。顺带一个彩蛋注意引用里那个CostGuardStattion——双写的 t官方分发件原样带着这个拼写错误。同一个包里还有拼错的Meterorological文件名少个 o 的版本和正确版本并存——一个 S-123 包贡献两处拼写彩蛋标准是工程产物这件事在细节里到处都是实锤。为什么两套并存XSLT 是 S-52 预库时代就确立的技术路线这批产品规范延续了它S-101 较新规则换成了 Lua。但血统是一致的——S-131 的线样式文件头里照样写着sourceS52Preslib4.0下一篇细看这个文件PresLib 的符号资产在新框架里继续服役。对我们做渲染器的人实际含义是解析器要么支持两种规则引擎要么在接入不同产品规范前先做一层转换。我们的做法是工具里双引擎并列同一个 S-131 分发包实测吃下 41 个 Lua 规则S-123 分发包实测吃下 26 个 XSLT 规则文件87 个 XML、657 个符号覆盖 11 个物标两条管道各自出渲染预览。这件事的真正含义把逻辑标准化成可执行程序改变的不只是写法渲染器退化成解释器。指令集ViewingGroup / PointInstruction / LineInstruction / …成为唯一稳定接口规则包整体可替换——IHO 发新版 PC换包不换码。对照 S-52 时代每家把 Look-up 翻译进 C升级一次预库等于重新翻译一次。实现分歧无处可藏。3.4 对 4.0.1 的取舍写在官方源码注释里谁跟谁不一致、跟了谁全都可查。型式认可审显示对不对时审的不再是你按文档理解对了吗而是你跑的是不是这段代码。测试有了锚点。S-64 的官方测试数据集为什么能当标准答案前文说过现在补上另一半——数据集喂进来规则跑出去两侧都是标准件对不对得上逐条可比。规则文件、绘图资源、颜色配置三样凑齐渲染器才算拿到了完整的画法。想亲手翻这 215 个规则工具页的 PC 解析器支持上传整个分发包目录每个物标的渲染预览、规则源码、符号实图都在里面S-101 和 S-123 的包都能直接吃。下一篇进 S-131港口基础设施产品——S-100 的产品谱系从航海走向港口运营连系船柱和岸电设施都成了物标。图示表达规则换到新场景里怎么组织本篇双引擎实测用的那个 S-131 PC 2.0.0 分发包到时候正好登场。我是夜航海图做海图与地图渲染开发的工程师。博客「航图笔记」同步更新全部文章欢迎 RSS 订阅这个系列持续更新S-100 全家族拆解中关注博主不迷路完整在线工具与最新文章见 nightchart.cn。
延伸阅读

更多相关文章

2026/9/30 20:45:36

离线芯片焊接自动化改造:3个节奏点决定回本周期

跟几位做功率器件和传感器封装的朋友聊天,发现一个共性:离线芯片焊接设备买了好几年,上下料还是靠人守。一人看两台机,夜班人手一紧,稼动率就往下掉;基板划伤、物料混批的索赔单也隔三差五冒出来。自动化改…

2026/9/30 21:46:01

UltraEdit 设置默认打开格式:用 TaoToken 统一管理配置文件关联

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/30 21:41:01

零基础 Vibe Coding 教程:MCP 服务介绍与 TaoToken 统一 Key 接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/29 11:07:23

东莞市品牌网站建设报价常见报错与解决

东莞品牌网站建设报价单背后:一份保姆级建站教程避坑实录 网站做好了没人访问,这大概是很多老板最头疼的事。花了大几万做的品牌站,上线后流量惨淡,比路边摊还冷清。别急着骂外包公司,很多“东莞品牌网站建设报价”里藏着不少猫腻,比如用模板站冒充定制…

2026/9/29 21:48:03

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 7:00:49

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 0:01:22

MATLAB+Yalmip+CPLEX实战:综合能源系统优化调度全流程解析

做综合能源系统优化调度这活儿,最痛苦的不是建模本身,而是模型写完之后不知道该怎么求解。看论文里轻飘飘一句“采用Yalmip调用CPLEX求解”,自己上手时却往往卡在环境配置、变量声明、约束写法和求解状态判读上,一耗就是两三天。这…

2026/9/30 0:01:22

I3C比I2C快10倍?RK3576实战:速率、DTS配置与混合总线避坑指南

I3C 比 I2C 快 10 倍?这句话在嵌入式群里传了很久,每次都能吵出一堆截图。前段时间我正好在 RK3576 上调板级 I3C 接口,从控制器寄存器一路摸到 Linux DTS 配置,踩了不少坑,也把这笔速度账彻底算明白了。本文就用 RK35…

2026/9/30 0:01:22

字符串转对象:JSON.parse、new Function与URLSearchParams

“字符串转对象”这几个字,我在技术群里见过的问法至少有十几种:有人拿着一串{a:1,b:2}说 JSON.parse 直接报错,有人要从 URL 里抠出参数,还有人只是想把abc变成能挂属性的东西。js 这门语言里,字符串和对象之间的转换…

2026/9/29 3:53:39

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/30 18:00:04

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/30 10:28:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑