Algorithm 确定一个矩形是否比另一个矩形更接近一个圆
假设我们有两个矩形A,B和一个圆R。我们想确定,对于任意三个点R,A,B,“R\in R,A\in A,B\in B”,“dist(R,A)Algorithm 确定一个矩形是否比另一个矩形更接近一个圆,algorithm,computational-geometry,geometry,rectangles,Algorithm,Computational Geometry,Geometry,Rectangles,假设我们有两个矩形A,B和一个圆R。我们想确定,对于任意三个点R,A,B,“R\in R,A\in A,B\in B”,“dist(R,A)那么代码> A-R
PS:测试应该是可靠和完整的,即没有假阳性或真阴性首先,你可以考虑你的圆的中心。如果中心更接近一个矩形,则圆更接近。接下来,将您的中心点与定义矩形的平面进行比较,以将其分割为几个可能的体积之一(基本上,矩形的多少个平面位于其正确的一侧)。对于其余平面(它不位于其正确的一侧),找到沿每个轴从点到平面的距离,并将其视为距离向量。它的范数是从圆心到矩形的欧几里得距离。这个解决方案应该是O(d),并且很容易实现,因为矩形是轴对齐的。首先,因为我们在N维空间中工作,所以我们将这些对象称为
NBox
和NBall
。这些定义了N维体积
假设长方体的轴与欧几里德空间的标准单位向量对齐,则NBox
可以表示为沿坐标轴的两个N维双数组Min
和Max
,或者表示为坐标轴上的单个N维Range
投影列表。NBall
可以表示为单个N维双数组Center
和双Radius
。一个NPoint
,一个单一的N维点,像这样(在c#中):
既然我们知道了如何计算长方体和点之间的最近点,那么就很容易得到长方体、点和球之间的距离。两点和/或长方体之间的距离是最近点之间的距离,如果它们相交,则为零。NBall
与方框或点之间的距离是最近点之间的距离,小于半径,如果差值为负值(交点),则为零
我可以想到一个算法,它涉及所有的面和矩形(或超立方体)的顶点。因此,不幸的是,它在维数上是指数型的。但至少它应该是正确的 引理1 给定点p。给定矩形内最近的点是p本身或重角边界/曲面上的另一点 引理2 给定点p。给定矩形内最远的点是其中一个顶点(角) 所以,如果我们想检查矩形A是否比矩形B更接近圆R,那么我们搜索一个反例。如果我们找不到,A就更近了 假设存在这样一个反例(r,a,b)。然后我们可以将点a移得更远,b移得更近,得到一个更“强大”的反例。 我们只检查这些“最强”的潜在反例。 因此,如果r中有一个点r,a中最远的点不比B中最近的点近,那么a就不比r近。但是如果我们找不到这样的点r,那么a就更接近r,根据jojer的条件 如引理1所述,我们只检查b的每个曲面(2d中的边)上的b点。 根据引理2,我们只检查a顶点的a点 如果我们现在检查所有这些a点和所有这些b点,将空间分成两半,并显示圆完全位于靠近a的那一半,那么就没有反例了 空间分割是2个超平面和一个超抛物线的合成(如果我们将a的顶点与B的曲面进行对比),请参见示例: 因此,我们构造所有这些分割平面/抛物面,并测试圆心的方向距离是否大于其半径。 如果是这样的话,那么就不可能有三元组(r,a,b)构成反例
整个过程应该只是对一些二次型的求值,主要是顶点对和顶点曲面对的数量,它们在维数上是指数级的。嗨,我不太明白“如果中心更靠近一个矩形,那么圆就更近。”实际上,距离(a,r)及(b,r)区因为A和B应该连接到同一点R。我的意思是,你不需要考虑你的圆的半径。如果你知道你的圆的中心,只需要从中心到每个矩形的距离,并且减去你的半径,得到实际的距离。但是,既然你只关心哪个更近,你就不知道。如果是<代码> a < b>代码>那么代码> A-R
public interface INDimensional
{
int Dimension { get; }
}
public class NPoint : INDimensional
{
readonly double[] point;
public NPoint(double[] point)
{
if (point == null)
throw new ArgumentNullException();
if (point.Length < 1)
throw new ArgumentException();
this.point = point.ToArray(); // copy
}
public int Dimension { get { return point.Length; } }
public double this[int i] { get { return point[i]; } }
public IList<double> Coordinates { get { return Array.AsReadOnly(point); } }
}
public class NBall : INDimensional
{
readonly NPoint center;
readonly double radius;
public NBall(double[] center, double radius)
{
if (Math.Abs(radius) < Accuracy.AbsoluteDoubleTolerance)
this.radius = 0;
else if (radius < 0)
throw new ArgumentException();
else
this.radius = radius;
this.center = new NPoint(center);
this.radius = radius;
}
public int Dimension { get { return center.Dimension; } }
public double this[int i] { get { return center[i]; } }
public NPoint Center { get { return center; } }
public double Radius { get { return radius; } }
}
public class NBox : INDimensional
{
readonly double[] min;
readonly double[] max;
static void ComputeExtremes(double[] point1, double[] point2, out double[] min, out double[] max)
{
if (point1 == null || point2 == null)
throw new NullReferenceException();
if (point1.Length != point2.Length)
throw new ArgumentException();
min = new double[point1.Length];
max = new double[point1.Length];
for (int i = 0; i < point1.Length; i++)
{
// Handle double-precision rounding issues where point1[i] and point2[i] so nearly equal that they somehow got inverted.
min[i] = Math.Min(point1[i], point2[i]);
max[i] = Math.Max(point1[i], point2[i]);
}
}
public NBox(double[] min, double[] max)
{
ComputeExtremes(min, max, out this.min, out this.max);
}
public int Dimension { get { return min.Length; } }
public Range<double> this[int i] { get { return new Range<double>(min[i], max[i]); } }
public IList<double> Min { get { return Array.AsReadOnly(min); } }
public IList<double> Max { get { return Array.AsReadOnly(max); } }
}
public static class NDimensionalExtensions
{
public static bool FindClosest(this Range<double> range, double other, out double closestParameter)
{
if (other <= range.Min)
{
closestParameter = range.Min;
return false;
}
if (other >= range.Max)
{
closestParameter = range.Max;
return false;
}
closestParameter = other;
return true;
}
}
public class NBox
{
public bool FindClosest(NPoint other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
}
public static class NDimensionalExtensions
{
public static bool FindClosest(this Range<double> range, Range<double> other, out double closestParameter)
{
if (other.Max <= range.Min)
{
closestParameter =range.Min;
return false;
}
else if (other.Min >= range.Max)
{
closestParameter = range.Max;
return false;
}
// return in the middle of the overlap
closestParameter = 0.5 * Math.Max(range.Min, other.Min) + 0.5 * Math.Min(range.Max, other.Max);
return true;
}
}
public class NBox
{
public bool FindClosest(NBox other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
}
public interface INDimensional
{
double GetDistance(NBox other);
}
public class NPoint : INDimensional
{
public double GetDistance(NPoint other)
{
if (Dimension != other.Dimension)
throw new ArgumentException();
double distSq = 0;
for (int i = 0; i < Dimension; i++)
{
var dot = (this[i] - other[i]);
distSq += dot * dot;
}
return Math.Sqrt(distSq);
}
public double GetDistance(NBox other)
{
NPoint closestPoint;
if (other.FindClosest(this, out closestPoint))
return 0;
return GetDistance(closestPoint);
}
}
public class NBall : INDimensional
{
public double GetDistance(NBox other)
{
NPoint closestPoint;
var allInside = other.FindClosest(Center, out closestPoint);
if (allInside)
return 0;
double distance = closestPoint.GetDistance(Center) - Radius;
if (distance < 0)
distance = 0;
return distance;
}
}
public class NBox : INDimensional
{
public bool FindClosest(NBox other, out NPoint closestPoint)
{
if (other.Dimension != Dimension)
throw new ArgumentException();
double[] closest = new double[other.Dimension];
bool allInside = true;
for (int i = 0; i < Dimension; i++)
{
allInside = allInside && this[i].FindClosest(other[i], out closest[i]);
}
closestPoint = new NPoint(closest);
return allInside;
}
public double GetDistance(NBox other)
{
NPoint myClosest, boxClosest;
if (FindClosest(other, out myClosest))
return 0;
if (other.FindClosest(this, out boxClosest))
return 0;
return myClosest.GetDistance(boxClosest);
}
}
public static class Accuracy
{
public static double AbsoluteDoubleTolerance
{
get
{
return 100 * double.Epsilon;
}
}
}