2.2.17 电子海图系统解析及开发 海图显示 - 符号指令查询表 Look-Up Tables

通过矢量符号描述语言,可以知道符号具体形状;通过符号化指令,可以对指定的位置对点、线、面物标进行绘制;那落实到S-57数据中的一条条记录而言,具体调用哪些符号化指令,这就需要用到符号指令查询表(Look-Up Tables)。S-57物标目录中的每一类物标,都可以通过查询表获取其符号化指令。

若对于某物标获取不到其符号化指令,缺省值为:NODTA颜色填充,NODATA03图案填充,显示级别为0,被雷达图像覆盖,基本显示,组别为11050。

查询表结构

查询文件的编排规则为每一行数据的前四个字符,表示字段的名称;第5到10个字符,表示字段的长度;第10个字符之后的内容,表示字段的内容。

[
LUPT   29LU00491NILCONVYRL00008OLINES�
ATTC   16CATCON1�CONRAD3�
INST   83LS(DASH,4,CHGRD);SY(RACNSP01);TE(clr {0:0.0},VERCLR,3,1,2,15110,1,0,CHBLK,11)�
DISC   12DISPLAYBASE�
LUCM    612210�
],
// ......
[
LUPT   40LU00009NILACHAREA00003SPLAIN_BOUNDARIES�
ATTC    8CATACH8�
INST   43SY(ACHARE02);LS(DASH,2,CHMGF);CS(RESTRN01)�
DISC    9STANDARD�
LUCM    626220�
],

上面包含两条记录的相关说明,每个符号指令由如下字段构成(以首条记录为例):

  • LUPT
    • 2个字符 'LU' 表示查询表
    • 5个字符 00491 表示标识符
    • 3个字符 NIL=新版;ADD=新增;MOD=替换;DEL=删除
    • 6个字符 物标目录类别 ‘CONVYR’(传送带)
    • 1个字符 物标几何类别 'A'=面物标;'L'=线物标;'P'=点物标
    • 5个字符 显示优先级 00008
    • 1个字符 雷达优先级 'O'=在雷达图像上;'S'=在雷达图像下
    • 最后其他字符 显示设置
       面物标可以是:'PLAIN_BOUNDARIES'(简单边界)或 'SYMBOLIZED_ BOUNDARIES'(符号化边界)
       点物标可以是:'SIMPLIFIED'(简单符号)或 'PAPER_CHART'(纸质海图符号)
       线物标只能是:'LINES'

      简单边界是用实线、虚线、点线去给区域描边;而符号化边界是用复杂线型填充区域边界。
      简单符号是用简单的几何图形加颜色当作灯标、沉船等点物标的符号;而纸质海图符号则是用与纸质海图一样的符号标注点物标。

  • ATTC 属性组合(可重复,也可空)
    • 6个字符 表示属性
    • 1~15个字符 表示属性性

      不同属性之间由单元分隔符隔开,属性值可为空,也可用'?'表示。
      示例中存在两组属性值:CATCON=1和CONRAD=3

  • INST
    • 符号指令 示例中为:用虚线描绘,线中点设置符号RACNSP01,同时显示格式文本
  • DISC
    • 显示模式 ‘DISPLAYBASE’=基础显示;�‘STANDARD’=标准显示;�‘OTHER’=其他显示
  • LUCM
    • 描述与说明

综上可知:对于线物标CONVYR(传送带),如果其包含属性值CATCON=1(传送带类型=带式)和CONRAD=3(雷达显著物标=安装雷达反射器),那么用虚线描边,线段中点设置符号RACNSP01,同时显示格式文本VERCLR(净空高度)。

读取查询表

仿照上述查询表记录结构,新建类S52LookUp

    //查询表 单条记录
    public class S52LookUp
    {
        //LUPT              
        public int RCID;                    //标识符
        public UInt16 ObjectClassCode;      //物标目录类别
        public char ObjectType;             //几何类别 'A' Area 'L' Line 'P' Point
        public int Priority;                //优先级
        public char RaderPriority;          //雷达优先级 'O'=在雷达图像上;'S'=在雷达图像下
        //PLAIN_BOUNDARIES;SYMBOLIZED_BOUDARIES (Areas)
        //SIMPLIFIED; PAPER_CHART (Points)
        //LINES (Lines)
        public string DisplaySet;           //显示设置

        //ATTC
        public UInt16[] AttrCodes;
        public string[] AttrValues;

        //INST
        public string[][] Instruction;         //符号指令 拆分成二维数组

        //DISC
        public string DisplayCategory;        //显示模式

        //LUCM
        public string ViewingGroup;           //组号

        //缺省值
        public static S52LookUp Default
        {
            get
            {
                return new S52LookUp()
                {
                    Priority = 0,
                    RaderPriority = 'S',
                    DisplayCategory = "DISPLAYBASE",
                    ViewingGroup = "11050",
                    Instructions = new string[][]
                    {
                        new string[] { "AC", "NODTA" },
                        new string[] { "AP", "PRTSUR01" }
                    }
                };
            }
        }
    }

将查询表文件S52LookupTable添加进项目S57Parser,新建单例模式的类S52LookUps存储整个查询表,让其继承至List<S52LookUp>

    public class S52LookUps : List<S52LookUp>
    {
        private static readonly S52LookUps instance = new S52LookUps();

        //显示的static 构造函数
        static S52LookUps() { }

        private S52LookUps()
        {
            var lines = Encoding.ASCII.GetString(Properties.Resources.S52LookupTable).Split('\n');

            S52LookUp obj = null;
            for (int i = 0; i < lines.Length; i++)
            {
                if (string.IsNullOrWhiteSpace(lines[i])) continue;
                if (lines[i][0] == '[')  //开始
                {
                    obj = new S52LookUp();
                    continue;
                }
                if (lines[i][0] == ']') //结束
                {
                    this.Add(obj);
                    continue;
                }

                var line = lines[i];
                var tag = line.Substring(0, 4);
                var lastUtIndex = line.LastIndexOf(Helper.UT);

                if (tag == "LUPT")
                {
                    obj.RCID = int.Parse(line.Substring(11, 5));
                    obj.ObjectClassCode = S57Objects.Instance[line.Substring(19, 6)].Code;
                    obj.ObjectType = line[25];
                    obj.Priority = int.Parse(line.Substring(26, 5));
                    obj.RaderPriority = line[31];
                    obj.DisplaySet = line.Substring(32, lastUtIndex-32);
                }
                else if (tag == "ATTC")
                {
                    var attc = line.Substring(9, lastUtIndex - 9);
                    if (string.IsNullOrWhiteSpace(attc)) continue;
                    var ats = attc.Split(Helper.UT);
                    obj.AttrCodes = new UInt16[ats.Length];
                    obj.AttrValues = new string[ats.Length];
                    for (int j = 0; j < ats.Length; j++)
                    {
                        obj.AttrCodes[j] = S57Attributes.Instance[ats[j].Substring(0, 6)].Code;
                        obj.AttrValues[j] = ats[j].Substring(6);
                    }
                }
                else if (tag == "INST")
                {
                    string[] inst = line.Substring(9, lastUtIndex - 9).Split(';');
                    obj.Instructions = new string[inst.Length][];
                    for (int j = 0; j < inst.Length; j++)
                    {
                        obj.Instructions[j] = inst[j].Split('(', ',', ')');
                    }
                }
                else if (tag == "DISC") obj.DisplayCategory = line.Substring(9, lastUtIndex - 9);
                else if (tag == "LUCM") obj.ViewingGroup = line.Substring(9, lastUtIndex - 9);
            }
        }

        public static S52LookUps Instance => instance;
    }

使用查询表

查询表中规定了物标的显示优先级、显示指令,是否被雷达图像覆盖等。海图绘制时,先遍历各物标,通过物标类别、几何类型,用户显示设置(对于面物标和点物标有两个显示方式)为查找条件,找到查询表匹配的记录。若匹配记录为0,则使用缺省指令;若匹配记录为1,则直接使用该指令;若匹配记录大于1,则需要利用属性值进一步筛选。

利用属性筛选的规则:

  • 物标需包含查询表记录中所含有的属性,并且值和顺序也需要一样。如:查询表中属性值4,3,4与物标中对应属性值3,4,3或4,3是不匹配的,但与4,3,4,7一致,因为7不需要被符号化。
  • 如果查询表中属性值缺失,则表明任何属性值(除了unknown)都匹配。
  • 如果查询表中属性值为‘?’,则只有物标属性值=unknown才匹配。
查询表使用流程

编码实现

新增用户设置,记录面物标是显示符号化边界还是简单边界,点物标是显示简单符号还是纸质海图符号。

    public static class MySettings
    {
        // ...
        public static bool SYMBOLIZED_BOUDARIES = true;                 //显示符号化边界
        public static bool PAPER_CHART = true;                          //显示纸质海图符号
        public static string DisplayMode = "STANDARD";                  //海图模式
    }

修改类S57Feature,添加字段public S52LookUp LookUp及比例尺范围。

    public class S57Feature : S57Record
    {
        // ......
        public S52LookUp LookUp;
        public int ScaleMinium => GetAttrValue(133, 0);
        public int ScaleMaximum => GetAttrValue(132, 0);
    }

工具类中S52Tools中,新增静态方法S52LookUp FindLookUpEntry(S57Feature f),为特征记录设置符号指令:

    public static S52LookUp FindLookUpEntry(S57Feature f)
    {
        //几何类型
        var objType = f.PRIM == 1 ? 'P' : f.PRIM == 2 ? 'L' : 'A';
        //物标类别+显示模式
        var entries = S52LookUps.Instance.Where(x => x.ObjectClassCode == f.OBJL
                        && x.ObjectType == objType && x.DisplayCategory == MySettings.DisplayMode);

        if (entries.Count() == 0) return S52LookUp.Default;
        if (entries.Count() == 1) return entries.First();

        if (f.PRIM == 1)
        {
            entries = entries.Where(x => x.DisplaySet == (MySettings.PAPER_CHART ? "PAPER_CHART" : "SIMPLIFIED"));
        }
        else if (f.PRIM == 3)
        {
            entries = entries.Where(x => x.DisplaySet == (MySettings.SYMBOLIZED_BOUDARIES ? "SYMBOLIZED_BOUDARIES" : "PLAIN_BOUNDARIES"));
        }

        if (entries.Count() == 0) return S52LookUp.Default;
        if (entries.Count() == 1 || f.AttrCodes == null) return entries.First();

        var lookup = entries.First();  //默认第一项
        foreach (var en in entries)
        {
            if (en.AttrCodes == null) continue;
            var isOk = true;
            for (int i = 0; i < en.AttrCodes.Length; i++)
            {
                var index = -1;
                for (var m = 0; m < f.AttrCodes.Length; m++)
                {
                    if (f.AttrCodes[m] == en.AttrCodes[i])
                    {
                        index = m;
                        break;
                    }
                }
                if (index >= 0)
                {
                    if (en.AttrValues[i] == "" && f.AttrValues[index] == "") //缺失
                    {
                        isOk = false;
                        break;
                    }
                    if (en.AttrValues[i] == "?" && f.AttrValues[index] != "")
                    {
                        isOk = false;
                        break;
                    }
                    //属性的值不匹配
                    if (!f.AttrValues[index].StartsWith(en.AttrValues[i]))
                    {
                        isOk = false;
                        break;
                    }
                }
                else
                {
                    //没找到对应的属性
                    isOk = false;
                    break;
                }
            }
            if (isOk)
            {
                lookup = en;
                break;
            }
        }

        return lookup;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容