[英]Maximum and Minimum values in a PointF[] array
我有一个PointF数组,我想用它来绘制一个使用Graphics.DrawCurve方法的曲线。
为此,我需要现在X和Y的最大值和最小值,以便我可以正确地缩放我的位图图像框。
如何在PointF数组中找到X和Y的最大值和最小值?
我想出了这个想法,但我不确定这是不是最好的方法!
//Find the max value on X axis (Time) and Y axis (Current)
float xMax = 0;
float yMax = 0;
foreach (PointF point in points)
{
if (point.X > xMax)
{
xMax = point.X;
}
if (point.Y > yMax)
{
yMax = point.Y;
}
}
您需要迭代数组中的所有元素并针对边界框测试每个元素,在当前项目位于其外时增加边界框。 像这样:
Point
min = first item in array,
max = first item in array;
foreach (item in array of points)
{
min.x = Math.Min (min.x, item.x)
min.y = Math.Min (min.y, item.y)
max.x = Math.Max (max.x, item.x)
max.y = Math.Max (max.y, item.y)
}
(min,max) are now the opposite corners of an axis aligned bounding box
编辑:你有正确的想法,但有一个.Net框架API来进行最小/最大测试:Math.Min和Math.Max。 除非有关于可用于减少测试数量的点数组的其他信息,否则您将不得不测试数组中的每个点。 不幸的是,那里没有捷径。 我想知道JIT编译器是否足够聪明,可以使用SIMD吗?
此外,如果数组中的所有点都小于零,则使用值0初始化可能会导致错误。
如果找到最小值(左上角)和最大值(右下角),则可以计算图形的大小。
首先,您需要一种比较Point值的方法 - 如果Point类(struct?)实现IComparable,您已经很好了,否则您可能需要编写自定义IComparer类。
接下来,您可以在IEnumerable上编写一个简单的扩展方法,以从集合中获取最小值或最大值:
static class ExtensionsClass
{
/// <summary>
/// Returns the mimimum value within the collection.
/// </summary>
static public T Min(this IEnumerable<T> values) where T : IComparable<T>
{
T min = values.First();
foreach(T item in values)
{
if (item.CompareTo(min) < 0)
min = item;
}
return min;
}
/// <summary>
/// Returns the maximum value within the collection.
/// </summary>
static public T Max(this IEnumerable<T> values) where T : IComparable<T>
{
T max= values.First();
foreach(T item in values)
{
if (item.CompareTo(min) > 0)
max= item;
}
return max;
}
}
使用这些扩展方法,可以更容易地找到最小/最大点,从而找到图形的大小。
var minX = points.Min().x;
var minY = points.Min().y;
var maxX = points.Max().x;
var maxY = points.Max().y;
使用RyuJIT和SIMD ,可以大大加速这些操作。
void MinMax(int[] a, out int minimum, out int maximum) {
int simdLength = Vector<int>.Length;
Vector<int> vmin = new Vector<int>(int.MaxValue);
Vector<int> vmax = new Vector<int>(int.MinValue);
for (int i = 0; i < a.Length; i += simdLength) {
Vector<int> va = new Vector<int>(a, i);
Vector<int> vLessThan = Vector.LessThan(va, vmin);
vmin = Vector.ConditionalSelect(vLessThan, va, vmin);
Vector<int> vGreaterThan = Vector.GreaterThan(va, vmax);
vmax = Vector.ConditionalSelect(vGreaterThan, va, vmax);
}
int min = int.MaxValue, max = int.MinValue;
for (int i = 0; i < simdLength; ++i) {
min = Math.Min(min, vmin[i]);
max = Math.Max(max, vmax[i]);
}
minimum = min;
maximum = max;
}
显然用PointF数组替换int数组。 基本上,这里发生的是SIMD能够在每次循环迭代中处理最小值和最大值4-8个项目。 从理论上讲,这将提供4-8倍的加速,具体取决于您的CPU。 使用支持AVX2的CPU可以提供最快的性能提升。
资料来源: http : //blogs.microsoft.co.il/sasha/2014/04/22/c-vectorization-microsoft-bcl-simd/
你的代码不好。 如果你有点(2,4)和(3,1),那么xMax将是3,而yMax将是4,这不是一个点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.