2.2.10 电子海图系统解析及开发 海图显示 - 符号、复杂线型、图案

S-52标准中,所用到的符号、复杂线型及填充图案,都用矢量符号描述符号记录在相应的数据文件中。数据文件的编排规则相同,每一行数据的前四个字符,表示字段的名称;第5到10个字符,表示字段的长度;第10个字符之后的内容,表示字段的内容。

1. 符号文件S52Symbols

[
SYMB   10SY02035NIL
SYMD   39ACHARE02V012670105200402005030106100789
SXPO   90anchorage area as a point at small scale, or anchor points of mooring trot at large scale�
SCRF    6ACHMGD
SVCT   32SPA;SW1;PU1264,789;PD1264,1291;�
SVCT   31SPA;SW1;PU1108,938;PD1412,938;�
SVCT   57SPA;SW1;PU1061,1188;PD1167,1292;PD1365,1292;PD1463,1191;�
],
// ......
[
SYMB   10SY02038NIL
SYMD   39WRECKS05V007500075000590004100045300540
SXPO   31dangerous wreck, depth unknown�
SCRF   12ADEPVSCCHBLK
SVCT  196SPA;SW1;ST0;PU453,700;PM0;PD512,625;PD600,575;PD687,550;PD800,540;PD900,575;PD981,625;PD1040,700;PD1040,800;PD987,859;PD900,915;PD800,950;PD700,950;PD600,915;PD525,865;PD453,800;PD453,700;PM2;FP;�
SVCT   29SPC;SW1;PU600,650;PD600,850;�
SVCT   29SPC;SW1;PU900,650;PD900,850;�
SVCT   30SPC;SW1;PU500,750;PD1000,750;�
SVCT   29SPC;SW1;PU750,600;PD750,900;�
SVCT   22SPC;SW1;PU453,700;PD;�
SVCT   22SPC;SW1;PU512,625;PD;�
SVCT   22SPC;SW1;PU600,575;PD;�
SVCT   22SPC;SW1;PU687,550;PD;�
SVCT   22SPC;SW1;PU800,540;PD;�
SVCT   22SPC;SW1;PU900,575;PD;�
SVCT   22SPC;SW1;PU981,625;PD;�
SVCT   23SPC;SW1;PU1040,700;PD;�
SVCT   22SPC;SW1;PU453,800;PD;�
SVCT   22SPC;SW1;PU525,865;PD;�
SVCT   22SPC;SW1;PU600,915;PD;�
SVCT   22SPC;SW1;PU700,950;PD;�
SVCT   22SPC;SW1;PU800,950;PD;�
SVCT   22SPC;SW1;PU900,915;PD;�
SVCT   22SPC;SW1;PU987,859;PD;�
SVCT   23SPC;SW1;PU1043,793;PD;�
]

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

  • SYMB
    • 2个字符 'SY' 表示符号
    • 5个字符 02035 表示符号ID
    • 3个字符 NIL=新版;ADD=新增;MOD=替换;DEL=删除
  • SYMD
    • 8个字符 'ACHARE02' 表示字符名
    • 1个字符 符号类型 'V'=矢量;‘R’=光栅
    • 5个字符 01267=转心横坐标
    • 5个字符 01052=转心纵坐标
    • 5个字符 00402=绘制区宽度
    • 5个字符 00503=绘制区高度
    • 5个字符 01061=绘制区起点横坐标
    • 5个字符 00789=绘制区起点纵坐标
  • SXPO
    • 符号的描述及说明
  • SCRF
    • 颜色引用表(长度为6的倍数,首字母为缩写,后5个字符为颜色标记):A=CHMGD
  • SVCT
    • 具体的符号化指令(可分多行)

在类S52Tools里,添加如下常量:

    //一英尺 = 96像素 = 25.4 毫米, 每毫米像素数
    public const double MPP = 96 / 25.4;
    //画布上每单位像素数,一单位 = 001mm
    public const float UPP = (float)MPP * 0.01f;

新建类S52Symbol存储符号的相关信息:

    public class S52Symbol
    {
        public int RCID;                    //标识符
        public string Name;                 //名称
        public string Description;          //描述
        public int PivotPointX;             //转心坐标
        public int PivotPointY; 
        public int BoundingBoxWidth;        //绘制区宽度
        public int BoundingBoxHeight;       //绘制区高度
        public int BoundingBoxX;            //绘制区起点坐标
        public int BoundingBoxY;
        public Dictionary Colors = new Dictionary(); //颜色
        public List Instructions = new List();   //绘图指令

        //偏移量
        public int OffsetX => (int)((PivotPointX - BoundingBoxX) * S52Tools.UPP);
        public int OffsetY => (int)((PivotPointY - BoundingBoxY) * S52Tools.UPP);

        private SKBitmap img;
        public SKBitmap Image              //绘制后的符号
        {
            get
            {
                if(img == null)
                {
                    //图片大小
                    var width = (int)(BoundingBoxWidth * S52Tools.UPP) + 2;
                    var height = (int)(BoundingBoxHeight * S52Tools.UPP) + 2;

                    img = new SKBitmap(width, height);
                    using (var ca = new SKCanvas(img))
                    {
                        ca.Clear();
                        ca.Scale(S52Tools.UPP, S52Tools.UPP);  //缩放
                        ca.Translate(-BoundingBoxX + 13, -BoundingBoxY + 13); //平移

                        //使用矢量符号描述语言绘制
                        S52Tools.DrawSymbol(ca, Colors, Instructions);
                    }
                }

                return img;
            }
        }
    }

新建符号目录,将符号文件添加进项目S57Viewer,新建单例模式的类S52Symbols,对外提供符号名称的索引器,以快速获取相应符号。如:获取缩写为"ACHARE02"的符号S52Symbols.Instance["ACHARE02"]

    //符号目录
    public sealed class S52Symbols
    {
        private static readonly S52Symbols instance = new S52Symbols();

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

        private S52Symbols() { }

        public static S52Symbols Instance => instance;

        Dictionary nameObjs = new Dictionary();

        public S52Symbol this[string acronym]
        {
            get
            {
                LoadResource();
                return nameObjs[acronym];
            }
        }

        private void LoadResource()
        {
            if (nameObjs.Count > 0) return;  //首次才需要加载资源文件

            var lines = Encoding.ASCII.GetString(Properties.Resources.S52Symbols).Split('\n');

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

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

                if (tag == "SYMB") obj.RCID = int.Parse(line.Substring(11, 5));
                else if (tag == "SYMD")
                {
                    obj.Name = line.Substring(9, 8);
                    obj.PivotPointX = int.Parse(line.Substring(18, 5));
                    obj.PivotPointY = int.Parse(line.Substring(23, 5));
                    obj.BoundingBoxWidth = int.Parse(line.Substring(28, 5));
                    obj.BoundingBoxHeight = int.Parse(line.Substring(33, 5));
                    obj.BoundingBoxX = int.Parse(line.Substring(38, 5));
                    obj.BoundingBoxY = int.Parse(line.Substring(43, 5));
                }
                else if (tag == "SXPO") obj.Description = line.Substring(9);
                else if (tag == "SCRF")
                {
                    for (int j = 9; j <= line.Length - 6; j += 6)
                    {
                        obj.Colors.Add(line[j], S52Colors.Instance[line.Substring(j + 1, 5)]);
                    }
                }
                else if (tag == "SVCT") obj.Instructions.Add(line.Substring(9));
            }
        }
    }

经测试,符号文件解析及绘制正常:

符号示例

2. 复杂线型文件S52ComplexLines

[
LNST   10LS03346NIL
LIND   38ACHARE51001080082003030005030030600568
LXPO   30boundary of an anchorage area�
LCRF    6ACHMGD
LVCT   32SPA;SW1;PU1429,568;PD1429,1070;�
LVCT   31SPA;SW1;PU1273,717;PD1577,717;�
LVCT   55SPA;SW1;PU1226,967;PD1332,1071;PD1530,1071;PD1628,970;�
LVCT   29SPA;SW1;PU306,815;PD906,815;�
LVCT   31SPA;SW1;PU2732,815;PD3336,815;�
LVCT   42SPA;SW1;PU2868,813;PD3030,975;PD3199,807;�
LVCT   31SPA;SW1;PU1928,814;PD2528,814;�
LVCT   42SPA;SW1;PU2068,812;PD2233,976;PD2397,812;�
LVCT   39SPA;SW1;PU390,812;PD546,974;PD713,813;�
],
//......
[
LNST   10LS02034NIL
LIND   38UNITMTR1002760064401109004470027600644
LXPO   49change of depth unit line, bounds 'metre depths'�
LCRF    6ACHGRD
LVCT   30SPA;SW1;PU276,644;PD1385,644;�
LVCT   61SPA;SW1;PU701,782;PD701,1089;PD804,786;PD908,1091;PD908,786;�
]

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

  • LNST
    • 2个字符 'LS' 表示复杂线型
    • 5个字符 03346 表示符号ID
    • 3个字符 NIL=新版;ADD=新增;MOD=替换;DEL=删除
  • LIND
    • 8个字符 'ACHARE51' 表示字符名
    • 5个字符 00108=转心横坐标
    • 5个字符 00820=转心纵坐标
    • 5个字符 03030=绘制区宽度
    • 5个字符 00503=绘制区高度
    • 5个字符 00306=绘制区起点横坐标
    • 5个字符 00568=绘制区起点纵坐标
  • LXPO
    • 复杂线型的描述及说明
  • LCRF
    • 颜色引用表(长度为6的倍数,首字母为缩写,后5个字符为颜色标记):A=CHMGD
  • LVCT
    • 具体的符号化指令(可分多行)

新建复杂线型目录,将复杂线型文件添加进项目S57Viewer,新建单例模式的类S52ComplexLines,对外提供符号名称的索引器,以快速获取相应符号。如:获取缩写为"ACHARE51"的复杂线型S52ComplexLines.Instance["ACHARE51"]

    //复杂线型目录
    public sealed class S52ComplexLines
    {
        private static readonly S52ComplexLines instance = new S52ComplexLines();

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

        private S52ComplexLines() { }

        public static S52ComplexLines Instance => instance;

        Dictionary nameObjs = new Dictionary();

        public S52Symbol this[string acronym]
        {
            get
            {
                LoadResource();
                return nameObjs[acronym];
            }
        }

        private void LoadResource()
        {
            if (nameObjs.Count > 0) return;  //首次才需要加载资源文件

            var lines = Encoding.ASCII.GetString(Properties.Resources.S52ComplexLines).Split('\n');

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

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

                if (tag == "LNST") obj.RCID = int.Parse(line.Substring(11, 5));
                else if (tag == "LIND")
                {
                    obj.Name = line.Substring(9, 8);
                    obj.PivotPointX = int.Parse(line.Substring(17, 5));
                    obj.PivotPointY = int.Parse(line.Substring(22, 5));
                    obj.BoundingBoxWidth = int.Parse(line.Substring(27, 5));
                    obj.BoundingBoxHeight = int.Parse(line.Substring(32, 5));
                    obj.BoundingBoxX = int.Parse(line.Substring(37, 5));
                    obj.BoundingBoxY = int.Parse(line.Substring(42, 5));
                }
                else if (tag == "LXPO") obj.Description = line.Substring(9);
                else if (tag == "LCRF")
                {
                    for (int j = 9; j <= line.Length - 6; j += 6)
                    {
                        obj.Colors.Add(line[j], S52Colors.Instance[line.Substring(j + 1, 5)]);
                    }
                }
                else if (tag == "LVCT") obj.Instructions.Add(line.Substring(9));
            }
        }
    }

经测试,复杂线型文件解析及绘制正常:

复杂线型中的基本元素

3. 图案文件S52Patterns

[
PATT   10PT02000NIL
PATD   55AIRARE02VSTGCON0200010000022590225600618005280043500452
PXPO   39pattern of symbols for an airport area�
PCRF    6ALANDF
PVCT  150SPA;SW1;PU623,980;PD859,980;PD790,901;PD790,801;PD1053,801;PD810,638;PD810,516;PD751,452;PD680,516;PD680,638;PD435,795;PD684,797;PD684,907;PD623,980;�
],
//......
[
PATT   10PT03001NIL
PATD   55VEGATN04VSTGCON0100010000007500075000400003000055000450
PXPO   33pattern of symbols for mangroves�
PCRF    6ALANDF
PVCT   25SPA;SW1;PU750,600;CI150;�
PVCT   29SPA;SW1;PU550,750;PD950,750;�
PVCT   29SPA;SW1;PU750,748;PD750,587;�
]

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

  • PATT
    • 2个字符 'PT' 表示图案
    • 5个字符 02000 表示符号ID
    • 3个字符 NIL=新版;ADD=新增;MOD=替换;DEL=删除
  • LIND
    • 8个字符 'AIRARE02' 表示字符名
    • 1个字符 符号类型 'V'=矢量;‘R’=光栅
    • 3个字符 填充方式 'STG'=交错式;‘LIN’=线性式
    • 3个字符 填充间距 'CON'=固定;‘SCL’=随比例尺而变化
    • 5个字符 02000=图案间最小距离(包含转心与绘制区)
    • 5个字符 10000=图案间最大距离(固定间距时,此值无意义)
    • 5个字符 00108=转心横坐标
    • 5个字符 00820=转心纵坐标
    • 5个字符 03030=绘制区宽度
    • 5个字符 00503=绘制区高度
    • 5个字符 00306=绘制区起点横坐标
    • 5个字符 00568=绘制区起点纵坐标
  • PXPO
    • 复杂线型的描述及说明
  • PCRF
    • 颜色引用表(长度为6的倍数,首字母为缩写,后5个字符为颜色标记):A=CHMGD
  • PVCT
    • 具体的符号化指令(可分多行)

相比于符号和复杂线型,图案新增了填充方式、填充间距、图案间最大/最小距离。图案文件中,填充间距都是固定的,因此图案间最大距离没有意义,图案间最小距离其实就是各图案在填充时的实际距离。新建类S52Pattern继承至S52Symbol

    public class S52Pattern: S52Symbol
    {
        public string TypeOfFillPattern;        //填充方式
        public int MinimumDistance;             //图案最小距离
    }

新建图案目录,将图案文件添加进项目S57Viewer,新建单例模式的类S52Patterns,对外提供符号名称的索引器,以快速获取相应符号。如:获取缩写为"AIRARE02"的图案S52Patterns.Instance["AIRARE02"]

    //图案填充目录
    public sealed class S52Patterns
    {
        private static readonly S52Patterns instance = new S52Patterns();

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

        private S52Patterns() { }

        public static S52Patterns Instance => instance;

        Dictionary nameObjs = new Dictionary();

        public S52Pattern this[string acronym]
        {
            get
            {
                LoadResource();
                return nameObjs[acronym];
            }
        }

        private void LoadResource()
        {
            if (nameObjs.Count > 0) return;  //首次才需要加载资源文件

            var lines = Encoding.ASCII.GetString(Properties.Resources.S52Patterns).Split('\n');

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

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

                if (tag == "PATT") obj.RCID = int.Parse(line.Substring(11, 5));
                else if (tag == "PATD")
                {
                    obj.Name = line.Substring(9, 8);
                    obj.TypeOfFillPattern = line.Substring(18, 3);
                    obj.MinimumDistance = int.Parse(line.Substring(24, 5));
                    obj.PivotPointX = int.Parse(line.Substring(34, 5));
                    obj.PivotPointY = int.Parse(line.Substring(39, 5));
                    obj.BoundingBoxWidth = int.Parse(line.Substring(44, 5));
                    obj.BoundingBoxHeight = int.Parse(line.Substring(49, 5));
                    obj.BoundingBoxX = int.Parse(line.Substring(54, 5));
                    obj.BoundingBoxY = int.Parse(line.Substring(59, 5));
                }
                else if (tag == "PXPO") obj.Description = line.Substring(9);
                else if (tag == "PCRF")
                {
                    for (int j = 9; j <= line.Length - 6; j += 6)
                    {
                        obj.Colors.Add(line[j], S52Colors.Instance[line.Substring(j + 1, 5)]);
                    }
                }
                else if (tag == "PVCT") obj.Instructions.Add(line.Substring(9));
            }
        }
    }

经测试,复杂线型文件解析及绘制正常:

面区域填充中的基本图案

你可能感兴趣的:(2.2.10 电子海图系统解析及开发 海图显示 - 符号、复杂线型、图案)