在c#中圈出问题
本文关键字:出问题 | 更新日期: 2023-09-27 18:21:31
我需要这部分的帮助
旁注:我有两个圆圈。
- 我需要创建5种方法来找到一个圆:
相交(圆c),
切线输出(圆c),
切线In(圆),
不相交(圆)
和包含(圆圈),
(基本上,我需要决定另一个圆c是否与该圆相交,是否从外部与该圆相切,是否在该圆内部但在某个点相交,是否在没有任何接触的情况下在该圆外部,或是否完全在该圆内。)
为了确定它是否与另一个圆相交,我制作了以下代码:
public bool intersect(Circle c)
{
Point p = new Point(), myCenter = new Point();
p.setPoint(c.x, c.y);
myCenter.setPoint(x, y);
return myCenter.dist(p) < radius + c.radius;
}
但是当我做两个圆(0,0,1)和(0,0,5)时。这表明圆相交。难道它不应该表明它不相交吗?
我还需要其他方法的帮助。
提前感谢!
这是我的代码:
public static void Main(string[] args)
{
Circle c1 = new Circle(0, 0, 1), c2 = new Circle(1, 0, 1);
Point p1 = new Point();
p1.setPoint(0, 1);
p1.print();
Console.Write(", ");
c1.print();
Console.WriteLine();
if (c1.onCircle(p1))
{
// Console.Write(" Point ");
p1.print();
Console.Write (" on ");
c1.print();
Console.WriteLine();
}
else
Console.WriteLine("Point NOT on circle");
if (c1.intersect(c2))
{
// Console.WriteLine("Two circles intersect");
c1.print();
Console.Write(" intersects ");
c2.print();
Console.WriteLine();
}
else
Console.WriteLine("Two circles do NOT intersect");
}
我的班级:
class Circle : Point
{
private double radius;
public Circle(double xV, double yV, double r)
{
this.x = xV;
this.y = yV;
this.radius = r;
}
public void setRadius(double r)
{
radius = r > 0 ? radius : 0;
}
public bool onCircle(Point p)
{
return dist(p) == radius;
}
public bool intersect (Circle c)
{
Point p = new Point (), myCenter = new Point();
p.setPoint (c.x, c.y);
myCenter.setPoint (x, y);
return myCenter.dist(p) < radius + c.radius;
}
public void print()
{
Console.Write("Circle: ({0}, {1}, {2})", x, y, radius);
}
}
点的类别:
public class Point
{
protected double x; // x coordiate of Point
protected double y; // y coordinate of Point
public void setPoint (double xCoor, double yCoor) {
x = xCoor;
y = yCoor;
}
public double dist(Point p) // compute the distance of point p to the current point
{
double distance;
distance = Math.Sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
return distance;
}
public void print()
{
Console.Write("Point: ({0}, {1})", x, y);
}
}
您的编码风格看起来不确定-我只会在数学上帮助您。
取两个圆,A(中心c1
,半径r1
)和B(中心c2
,半径r2
)。设d = c1.dist(c2)
。
tangentOut
:条件是d = r1 + r2
tangentIn
:d = abs(r2 - r1)
disjoint
:d > r1 + r2
contained
:d < abs(r2 - r1)
此外,考虑到数值精度,将任何等式更改为deltaε比较。例如,a = b
变为abs(a - b) < e
,其中e
是某个最大阈值。
您应该重新检查您的逻辑是否存在交集。现在的方法只适用于当一个圆没有完全包围另一个圆时不相交的圆。你选择测试的情况,同心圆,显示为中心之间的距离为0,实际上小于半径的总和。另一种可能不会被发现的情况是单个退化交点的情况。
我建议阅读Wolfram Alpha关于Circle Circle Intersection的文章,以找到更好的测试方法。
您的intersect
方法看起来应该会产生准确的结果,但由于Circle
源自Point
,因此可以大大简化:
public bool intersect(Circle c)
{
return dist(c) < radius + c.radius;
}
所有其他操作都类似:
public bool tangentOut(Circle c)
{
return dist(c) == radius + c.radius;
}
public bool tangentIn(Circle c)
{
return dist(c) == Math.Abs(c.radius - radius);
}
public bool disjoint(Circle c)
{
return dist(c) > radius + c.radius;
}
public bool contains(Circle c)
{
return dist(c) <= radius - c.radius
}
关于Epsilon值的漫谈如下
CCD_ 20和CCD_ 21中的比较需要稍微改变以解决准确性问题。在使用较大的值时,使用静态epsilon数字(如您与willywonka的评论交流中所示)会带来麻烦。相反,您可以根据所比较的数字来缩放ε。
ε的基数是1和下一个可能的数字之间的差,通过设置值的二进制表示中的最低位。根据维基百科上关于双精度浮点格式的条目(我通过测试证实了这一点),这大约是2E-16。这对0到2-E之间的数字来说很好,但当你超出这个范围时就不起作用了。同样,使用更大的值会给你更大的范围,但会在某个时候停止工作。
因此,与其使用静态数字,不如将最大值缩小一个有用的量,比如10^9的一部分,并将其用作ε。一个示例扩展方法:
public static class Extensions
{
public static bool EpsilonEqual(this double l, double r, double eScale = 1e+9)
{
double d = Math.Abs(l - r);
double e = Math.Abs(Math.Max(l, r)) / 1e+9;
return d <= e;
}
}
调整比例因子以满足您的精度要求。然后你可以这样做:
public bool tangentOut(Circle c)
{
return dist(c).EpsilonEquals(radius + c.radius);
}
public bool tangentIn(Circle c)
{
return dist(c).EpsilonEquals(Math.Abs(c.radius - radius));
}