(文字墙,如果信息不够请告诉我!)
我正在开发一个可以制作很多圆圈的程序(少至 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。不幸的是,这并没有快多少。希望有任何性能建议。如果对此有任何疑问,请告诉我!
谢谢! :)
首先尝试使用并行
这就是我要尝试的:
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%。