如何在 C# 位图中高效地创建圆形或形状?

问题描述 投票:0回答:1

(文字墙,如果信息不够请告诉我!)

我正在开发一个可以制作很多圆圈的程序(少至 10 个,但可以呈指数级扩展)。我正在寻找一种方法来提高此过程的性能。以一个圆为“底”,每隔一个圆从底上“减去”。举个例子,想象一块饼干或其他圆形物体,其边缘有小口。

最初,我使用 Vector2 数组或列表来定义每个圆的面积和周长,然后找到与基圆面积匹配的向量并减去圆,然后将它们从基圆中删除。当圆圈数到 100 甚至 1000 时,速度会很快,但到了 10000 时,速度会变得非常慢(几分钟),超过这个速度可能需要一个多小时。

周长定义方法:

public override void DefinePerimeter()
        {
            perimeter = new List<Vector2>();

            //Find one quadrant worth of perimeter
            //Mirror x,y values to form full circle

            for(float i = 0; i < 90; i += resolutionFactor)
            {
                float cos = radius * MathF.Cos(i);
                float sin = radius * MathF.Sin(i);

                perimeter.Add(new Vector2((int)(center.X + cos), (int)(center.Y - sin)));
                perimeter.Add(new Vector2((int)(center.X - cos), (int)(center.Y - sin)));
                perimeter.Add(new Vector2((int)(center.X - cos), (int)(center.Y + sin)));
                perimeter.Add(new Vector2((int)(center.X + cos), (int)(center.Y + sin)));
            }
            perimeter = RemoveDuplicates(perimeter);//Removes duplicate Vector2

区域定义:

if (perimeterDefined == true && perimeter.Count>1)
            {
                Vector2 yBounds = Bounding.GetYBounds(perimeter);
                if(yBounds.Y-yBounds.X>0)
                {
                    List<Vector2> yLevel = new List<Vector2>();
                    for (int i = (int)yBounds.X; i < (int)yBounds.Y; i++)
                    {
                        yLevel.Clear();
                        yLevel = perimeter.FindAll(x => x.Y == i);
                        //Instead, define perimeter and area simultaneously in one method
                        //Define perimeter already finds bounds for each y level, just add area between them each loop
                        if (yLevel.Count > 0)
                        {
                            Vector2 xBounds = Bounding.GetXBounds(yLevel);
                            for (int j = (int)xBounds.X; j < (int)xBounds.Y; j++)
                            {
                                area.Add(new Vector2(j, i));
                            }
                        }
                    }
                    areaDefined = true;
                }
                else if(yBounds.Y-yBounds.X==0)
                {
                    area.Add(new Vector2(yBounds.Y, yBounds.Y));
                }
            }
            else if (perimeterDefined == true && perimeter.Count == 1)
            {
                area.Add(perimeter[0]);
            }
            else
            {
                Console.WriteLine("Error: Perimeter not defined!");
            }

YBounds 和 XBounds 方法是相同的,只是分别将 x 替换为 y:

public static Vector2 GetYBounds(List<Vector2> range)
        {
                return new Vector2(range.Min(x => (int)x.Y), range.Max(x => (int)x.Y));
        }

如您所见,区域定义对于性能来说非常重要。我尝试了一种新方法,其中我只计算要减去的圆的半径,并使用它们的位置确定需要删除基础区域中的哪些向量2。不幸的是,这并没有快多少。希望有任何性能建议。如果对此有任何疑问,请告诉我!

谢谢! :)

c# performance optimization bitmap rendering
1个回答
0
投票

首先尝试使用并行

这就是我要尝试的:

public override void DefinePerimeter()
    {
        perimeter = new List<Vector2>();

        //Find one quadrant worth of perimeter
        //Mirror x,y values to form full circle

        // this helps to get the value to the stack wich is faster to call
        int CenterX = center.x;
        int CenterY = center.y;
        
        Parallel.ForEach(Iterate(0,90,resolutionFactor).ToArray(), (value, state,index) => 
        {
            float cos = radius * MathF.Cos(value);
            float sin = radius * MathF.Sin(value);
            // do the calculations once then just callit
            int CenterXPluszCos = (int)(CenterX + cos);
            int CenterXMinusCos = (int)(CenterX - cos);
            int CenterYMinusSin = (int)(CenterY - sin);
            int CenterYPluszSin = (int)(CenterY + sin);
            perimeter.Add(new Vector2(CenterXPluszCos, CenterYMinusSin));
            perimeter.Add(new Vector2(CenterXMinusCos , CenterYMinusSin));
            perimeter.Add(new Vector2(CenterXMinusCos, CenterYPluszSin));
            perimeter.Add(new Vector2(CenterXPluszCos , CenterYPluszSin));
        });
        perimeter = RemoveDuplicates(perimeter);//Removes duplicate Vector2
}
private static IEnumerable<double> Iterate(double FromInclusive, double toExclusive, double step)
{
   for(double d = fromInclusive; d < toExclusive; d+= step yield return d;
}

A 如果您愿意,可以尝试创建周长数组列表,并使用索引添加计算出的向量。如果 Add 方法减慢循环速度,这可能会很好。但如果将数组转换回列表,从长远来看,这会更难做到,而且速度会快 100%。

© www.soinside.com 2019 - 2024. All rights reserved.