D3D标注动态避让
原来也思考了该如何实现标注动态避让,认为必须得计算字符串所占的大小。如果在屏幕上要计算屏幕象素之类的东西。
今天总算找到了实现方法,在C# WorldWind中的KMLImporter类中有。关键是Font的如下方法:
public Rectangle MeasureString(Sprite sprite, string text, DrawTextFormat format, Color color);
public Rectangle MeasureString(Sprite sprite, string text, DrawTextFormat format, int color);

1 if(icon.Name != null)
2 {
3 // Render name field
4 const int labelWidth = 1000; // Dummy value needed for centering the text
5 if(iconTexture==null)
6 {
7 // Center over target as we have no bitmap
8 Rectangle realrect = drawArgs.defaultDrawingFont.MeasureString(m_sprite, icon.Name, DrawTextFormat.WordBreak, color);
9 realrect.X = (int)projectedPoint.X - (labelWidth>>1);
10 realrect.Y = (int)(projectedPoint.Y - (drawArgs.defaultDrawingFont.Description.Height >> 1));
11
12 bool bDraw = true;
13
14 foreach (Rectangle drawnrect in labelRectangles)
15 {
16 if (realrect.IntersectsWith(drawnrect))
17 {
18 bDraw = false;
19 break;
20 }
21 }
22
23 if (bDraw)
24 {
25 labelRectangles.Add(realrect);
26 drawArgs.defaultDrawingFont.DrawText(m_sprite, icon.Name, realrect, DrawTextFormat.Center, color);
27 }
28 }
29 else
30 {
31 // Adjust text to make room for icon
32 int spacing = (int)(icon.Width * 0.3f);
33 if(spacing>10)
34 spacing = 10;
35 int offsetForIcon = (icon.Width>>1) + spacing;
36
37 // Text to the right
38 Rectangle rightrect = drawArgs.defaultDrawingFont.MeasureString(m_sprite, icon.Name, DrawTextFormat.WordBreak, color);
39 rightrect.X = (int)projectedPoint.X + offsetForIcon;
40 rightrect.Y = (int)(projectedPoint.Y - (drawArgs.defaultDrawingFont.Description.Height >> 1));
41
42 // Text to the left
43 Rectangle leftrect = drawArgs.defaultDrawingFont.MeasureString(m_sprite, icon.Name, DrawTextFormat.WordBreak, color);
44 leftrect.X = (int)projectedPoint.X - offsetForIcon - rightrect.Width;
45 leftrect.Y = (int)(projectedPoint.Y - (drawArgs.defaultDrawingFont.Description.Height >> 1));
46
47 bool bDrawRight = true;
48 bool bDrawLeft = true;
49
50 foreach (Rectangle drawnrect in labelRectangles)
51 {
52 if (rightrect.IntersectsWith(drawnrect))
53 {
54 bDrawRight = false;
55 }
56 if (leftrect.IntersectsWith(drawnrect))
57 {
58 bDrawLeft = false;
59 }
60 if (!bDrawRight && !bDrawLeft)
61 {
62 break;
63 }
64 }
65
66 if (bDrawRight)
67 {
68 labelRectangles.Add(rightrect);
69 drawArgs.defaultDrawingFont.DrawText(m_sprite, icon.Name, rightrect, DrawTextFormat.WordBreak, color);
70 }
71 else if (bDrawLeft)
72 {
73 labelRectangles.Add(leftrect);
74 drawArgs.defaultDrawingFont.DrawText(m_sprite, icon.Name, leftrect, DrawTextFormat.WordBreak, color);
75 }
76 }
77 }
这种方式实现简单,但是会造成先添加到标注字符串集合的文字优先显示。索引靠后的文字始终被隐藏。
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程