ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

当 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。
返回列表