2.2.17 電子海圖系統(tǒng)解析及開發(fā) 海圖顯示 - 符號指令查詢表 Look-Up Tables

通過矢量符號描述語言,可以知道符號具體形狀;通過符號化指令,可以對指定的位置對點、線、面物標進行繪制;那落實到S-57數(shù)據(jù)中的一條條記錄而言,具體調用哪些符號化指令,這就需要用到符號指令查詢表(Look-Up Tables)。S-57物標目錄中的每一類物標,都可以通過查詢表獲取其符號化指令。

若對于某物標獲取不到其符號化指令,缺省值為:NODTA顏色填充,NODATA03圖案填充,顯示級別為0,被雷達圖像覆蓋,基本顯示,組別為11050。

查詢表結構

查詢文件的編排規(guī)則為每一行數(shù)據(jù)的前四個字符,表示字段的名稱;第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個字符 顯示優(yōu)先級 00008
    • 1個字符 雷達優(yōu)先級 'O'=在雷達圖像上;'S'=在雷達圖像下
    • 最后其他字符 顯示設置
      ?面物標可以是:'PLAIN_BOUNDARIES'(簡單邊界)或 'SYMBOLIZED_ BOUNDARIES'(符號化邊界)
      ?點物標可以是:'SIMPLIFIED'(簡單符號)或 'PAPER_CHART'(紙質海圖符號)
      ?線物標只能是:'LINES'

      簡單邊界是用實線、虛線、點線去給區(qū)域描邊;而符號化邊界是用復雜線型填充區(qū)域邊界。
      簡單符號是用簡單的幾何圖形加顏色當作燈標、沉船等點物標的符號;而紙質海圖符號則是用與紙質海圖一樣的符號標注點物標。

  • 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;                //優(yōu)先級
        public char RaderPriority;          //雷達優(yōu)先級 '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;         //符號指令 拆分成二維數(shù)組

        //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 構造函數(shù)
        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;
    }

使用查詢表

查詢表中規(guī)定了物標的顯示優(yōu)先級、顯示指令,是否被雷達圖像覆蓋等。海圖繪制時,先遍歷各物標,通過物標類別、幾何類型,用戶顯示設置(對于面物標和點物標有兩個顯示方式)為查找條件,找到查詢表匹配的記錄。若匹配記錄為0,則使用缺省指令;若匹配記錄為1,則直接使用該指令;若匹配記錄大于1,則需要利用屬性值進一步篩選。

利用屬性篩選的規(guī)則:

  • 物標需包含查詢表記錄中所含有的屬性,并且值和順序也需要一樣。如:查詢表中屬性值4,3,4與物標中對應屬性值3,4,3或4,3是不匹配的,但與4,3,4,7一致,因為7不需要被符號化。
  • 如果查詢表中屬性值缺失,則表明任何屬性值(除了unknown)都匹配。
  • 如果查詢表中屬性值為‘?’,則只有物標屬性值=unknown才匹配。
查詢表使用流程

編碼實現(xiàn)

新增用戶設置,記錄面物標是顯示符號化邊界還是簡單邊界,點物標是顯示簡單符號還是紙質海圖符號。

    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中,新增靜態(tài)方法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;
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容