点、线、面物标都存在需要显示相关文本(如:物标名称)的情况。文本虽然不是符号库的一部分,但它却是电子海图数据的一部分。S-52标准规定,显示文本的字体只能是标准的“sans serif”。值得注意的是,水深点处的水深不是以文本方式出现,而是以符号的方式出现的。
为了阅读方便,电子海图显示文本时,一般不会旋转。文本的转心应该位于面物标的中心,或位于单个线段的中点,或位于多个线段的长度各的中心处。
文本显示涉及到两个命令:TX
和TE
1. TX
纯文本显示,不需要格式控制
参数说明:
-
STRING 待显示的文本
可传入固定文本,或物标的六字母属性(如:OBJNAM表示物标名称)。如果属性所对应的值为枚举或列表型,需要将其编号所代表的含义输出。 -
HJUST 水平对齐
’1‘ 表示居中
’2‘ 表示靠右
’3‘ 表示靠左(默认值) -
VJUST 垂直对齐
’1‘ 表示靠下(默认值)
’2‘ 表示居中
’3‘ 表示靠上 -
SPACE 字符间距
’1‘ 两端对齐(调整字符间距,使文本填满物标的显示空间)
’2‘ 标准间距(默认值)
’3‘ 标准间距,但允许换行,单行字符不超过8个 -
CHARS 字符说明(字体,粗细、宽度(直体/斜体),字号等)
字体
’1‘ 标准 sans serif (唯一选项)
粗细
’4‘ 表示加细(对应值300)
’5‘ 表示中等(对应值500)
’6‘ 表示加粗(对应值700)
宽度
’1‘ 表示直体,对于属性$CHARS的值,必须用直体表示
字号
单位为pica point(1 pica point = 0.351mm),最小值为10,同时也是默认值 -
XOFFS x方向的偏移量
单位为pica point,表示x方向上的偏移量,向右为正 -
YOFFS y方向的偏移量
单位为pica point,表示x方向上的偏移量,向下为正 -
COLOUR 文本的颜色
用颜色标记指定的颜色 -
DISPLAY 文本的分组
航海人员可按组选中文本
示例:TX(OBJNAM,1,2,3,’15110’,0,0,CHBLK,26)
含义:纯文本显示物标名称,水平居中,垂直居中,标准间距、允许换行,标准字体、加粗、直体、10号字,无偏移、颜色为CHBLK,组别为26。
2. TE
格式文本显示,其格式控制符合C语言标准
与TX不同之处是,TE的文本显示是按照一定格式输出。该输出格式是符合C语言标准的,而本项目采用的C#编程,C#与C的格式控制是不兼容的,因此有两种方法解决:
- 修改查询表中TE的格式控制字符串,使其满足C#标准,如: 将
"clr cl %4.1lf"
改为clr cl {0:f1}
。 - 用C#编写工具类以实现C格式输出,有个现成的方案A printf implementation in C#。
示例:TE('clr cl %4.1lf','VERCCL',3,1,2,'15110',1,0,CHBLK,11)
含义:若物标属性VERCCL=16.2,最后显示的结果为:clr cl 16.2,其他含义与TX一样。
3. 编码实现
- 对于
TE
指令,先将第一个参数(格式)和第二个参数内容读取出来,组合成纯文本,然后调用方法与TE
一样。var txt = PrintFTools.sprintf("clr cl %4.1lf", 16.2);
-
SPACE 字符间距
1. 对于两端对齐方式,Skia并没有现成的现实方案。需要的流程较为复杂:计算物标的地理长度⇒屏幕长度⇒确定文本中单个字符的宽度⇒确定每个字符的绘制位置⇒依次绘制字符。考虑实际作用较小,而暂不考虑。
2. 标准间距,对应SKFontStyleWidth.Normal
3. 允许换行的标准间距,当文本长度超过8字符时,进行拆分,然后多行输出。考虑实际作用较小,而暂不考虑。 -
CHARS 字段编程
字体SKTypeface FromFamilyName("sans serif")
粗细 4,5,6 对应SKFontStyleWeight
中的Light
,Normal
,Bold
宽度 1,2对应SKFontStyleSlant
中的Upright
,Italic
字号 1 pica point = = 0.351mm = 96 / 25.4 * 0.351 像素//chars 形如 15110 var fontWeight = SKFontStyleWeight.Normal; if (chars[1] == '4') fontWeight = SKFontStyleWeight.Light; else if (chars[1] == '6') fontWeight = SKFontStyleWeight.Bold; var fontSlant = SKFontStyleSlant.Upright; if (chars[2] != '1') fontSlant = SKFontStyleSlant.Italic; var textSize = PicaPoint * int.Parse(chars.Substring(3)); var font = SKTypeface.FromFamilyName("sans serif", fontWeight, SKFontStyleWidth.Normal, fontSlant); var paint = new SKPaint(){ Typeface = font, TextSize = textSize };
-
COLOUR 字体颜色
paint.Color = S52Colors.Instance[colour];
- ** HJUST/VJUST** 对齐方式
Skia文本的基点位于文本基线左侧,对于水平对齐可直接设置TextAlign
,若要改变垂直对齐方式,需要获取字体信息,然后设置基点的位置。
//水平对齐 if (hjust == "2") paint.TextAlign = SKTextAlign.Right; else if(hjust == "1") paint.TextAlign = SKTextAlign.Center; //垂直对齐 var fontMetrics = paint.FontMetrics; if (vjust == "3") y = y - fontMetrics.CapHeight; //Top: else if (hjust == "1") y = y - fontMetrics.CapHeight/2; //Center
-
XOFFS/YOFFS 偏移量
if (xoffs != 0) x += PicaPoint * xoffs; if (yoffs != 0) y += PicaPoint * yoffs;
如果需要对文本进行理更为复杂的格式控制,可考虑使用第三方库RichTextKit,它是SkiaSharp的富文本布局,测量和渲染库。
- 显示文本的完整代码如下:
//字体大小单位 1 pica point = 0.351mm
public const float PicaPoint = (float)MPP * 0.351f;
//在屏幕指定坐标处绘制文本
public static void DrawTextAtXY(SKCanvas ca, float x, float y, string txt,
string hjust, string vjust, string space, string chars, int xoffs, int yoffs, string colour)
{
if (string.IsNullOrEmpty(txt)) return;
//chars 形如 15110
var fontWeight = SKFontStyleWeight.Normal;
if (chars[1] == '4') fontWeight = SKFontStyleWeight.Light;
else if (chars[1] == '6') fontWeight = SKFontStyleWeight.Bold;
var fontSlant = SKFontStyleSlant.Upright;
if (chars[2] != '1') fontSlant = SKFontStyleSlant.Italic;
var textSize = PicaPoint * int.Parse(chars.Substring(3));
var font = SKTypeface.FromFamilyName("sans serif", fontWeight, SKFontStyleWidth.Normal, fontSlant);
var paint = new SKPaint() { Typeface = font, TextSize = textSize };
//颜色
paint.Color = S52Colors.Instance[colour];
//水平对齐
if (hjust == "2") paint.TextAlign = SKTextAlign.Right;
else if (hjust == "1") paint.TextAlign = SKTextAlign.Center;
var fontMetrics = paint.FontMetrics;
if (vjust == "3") y = y - fontMetrics.CapHeight; //Top:
else if (hjust == "1") y = y - fontMetrics.CapHeight / 2; //Center
if (xoffs != 0) x += PicaPoint * xoffs;
if (yoffs != 0) y += PicaPoint * yoffs;
ca.DrawText(txt, x, y, paint);
}
}