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));
}
}
}
经测试,复杂线型文件解析及绘制正常: