gpt4 book ai didi

c# - 改进 Winforms 中的 HitTest ; GraphicsPath.IsVisible 的任何替代方案?

转载 作者:行者123 更新时间:2023-11-30 20:35:12 31 4
gpt4 key购买 nike

在自定义控件上,我有一系列 LED 对象,它们应该根据给定的 GraphicsPath 打开(例如,见下图)。目前我正在使用 graphicsPath.IsVisible(ledPoint),但是因为我有很多 LED,所以遍历所有 LED 的速度可能会非常慢,尤其是在路径复杂的情况下(例如路径的逆向)在示例中)。

你们有没有想出更聪明的方法来加速迭代?如果举个例子太复杂,它可能会把我重定向到适当的资源。请考虑该控件位于 GDI+ 中,无法将其重新设计到另一个引擎中。

enter image description here

编辑


在我的 PC (i7 3.6GHz) 上,当 GraphicsPath 时,我只有一个简单的 100x100 像素矩形,然后我在我的 Control 上计算大小约为 500x500 像素的逆(因此,结果GraphicsPath 将是一个 500x500 的矩形,其中有一个 100x100 的“孔”),测试 6000 个 LED 大约需要 1.5 秒,这将非常影响用户体验。

在 Matthew Watson 回复之后,我将详细说明我的示例:

//------ Base path test
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new Rectangle(100, 100, 100, 100));

var sw = System.Diagnostics.Stopwatch.StartNew();
for (int x = 0; x < 500; ++x)
for (int y = 0; y < 500; ++y)
path.IsVisible(x, y);
Console.WriteLine(sw.ElapsedMilliseconds);

//------ Inverse path test
GraphicsPath clipRect = new GraphicsPath();
clipRect.AddRectangle(new Rectangle(0, 0, 500, 500));
GraphicsPath inversePath = Utility.CombinePath(path, clipRect, CombineMode.Complement);

sw.Restart();
for (int x = 0; x < 500; ++x)
for (int y = 0; y < 500; ++y)
inversePath.IsVisible(x, y);
Console.WriteLine(sw.ElapsedMilliseconds);

在我的 PC 上,第一次测试大约有 725 毫秒,第二次测试大约有 5000 毫秒。这只是一条相当简单的路径。 GraphicsPath 由用户的鼠标移动生成,用户可以执行多个路径组合(反转、并集、交集……我为此使用 GPC)。因此,通过测试 GraphicsPath.IsVisible() 的否定来测试反转可能很棘手。

Utility.CombinePath 返回的 inversePath 非常简单,有以下几点(左 PathPoints,右 PathTypes):

enter image description here

最佳答案

一个优化是只在有效边界矩形内进行测试:

Rectangle r = Rectangle.Round( path.GetBounds() );
for (int x = r.X; x < r.Width; ++x)
for (int y = r.Y; y < r.Height; ++y)
if (path.IsVisible( x, y ))..

另一个技巧flatten路径,因此它仅由线段组成:

Matrix m = new Matrix();
path.Flatten(m, 2);

选择较大的平坦度也有帮助。我发现 12 的速度很容易翻倍。

我没有使用你的测试平台,但结果应该有所帮助:

测试这条路径:

enter image description here

时间过去了:

25781(无边界)

7929(仅在范围内)

3067(在范围内并平整 2)

请注意,第一个只有在您没有通过客户端矩形开始反转时才有用,第二个只有在路径实际包含曲线时才有用。

更新:

采纳 Hans 的建议,这是迄今为止最有效的“优化”:

Region reg = new Region(path);
for (int x = r.X; x < r.Width; ++x)
for (int y = r.Y; y < r.Height; ++y)
reg.IsVisible(x, y);

它将我的时间缩短到 10-20 毫秒 (!)

所以这不仅仅是一个“优化”;它避免了最可怕的浪费时间,阅读:基本上没有时间进入测试,所有时间都进入了设置测试地区。

来自 Hans Passant 的评论:

GraphicsPath.IsVisible requires the path to be converted to a region under the hood. Do that up front with the Region(GraphicsPath) constructor so you don't pay that cost for every single point.

请注意,与其他路径相比,我的路径非常复杂;因此,我的积蓄远大于,这比您从带有长方形孔的长方形或类似物中得到的积蓄要多。 用户绘制的路径像我的(或来自 OP 的路径)很容易由数百段组成,而不仅仅是 4-8..

关于c# - 改进 Winforms 中的 HitTest ; GraphicsPath.IsVisible 的任何替代方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38322900/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com