在游戏程序的上下文中,我有一个移动的圆圈和一个固定的线段。该段可以具有任意大小和方向。
我在尝试计算时遇到了困难:
答案 0 :(得分:6)
我将用伪算法回答 - 没有任何代码。我看到的方式有两种情况,我们可能返回true ,如下图所示:
这里的蓝色是你的圆圈,虚线是轨迹线,红线是你的给定线。
从轨迹中我们为每个点A和B构建法线。然后将这些线切割或扩展为辅助线(Ha
和Hb
),使其长度为{{1} }和A
正好是圆的半径。然后我们检查这些辅助线中的每一条是否与轨迹线相交。如果他们返回true。
答案 1 :(得分:3)
看这里:
Line segment / Circle intersection
如果在x或y的计算的平方根下得到的值为负,则该段不相交。除此之外,你可以在x和y之后停止计算(注意:你可能得到两个答案)
更新我已经修改了我的答案,非常专门解决您的问题。我赞成Doswa这个解决方案,因为我几乎跟着并为C#编写了它。基本策略是我们将您的线段的最近点定位到圆的中心。在此基础上,我们将查看最近点的距离,如果它在半径范围内,则将该点沿着方向定位到最靠近圆的半径的点。
// I'll bet you already have one of these.
public class Vec : Tuple<double, double>
{
public Vec(double item1, double item2) : base(item1, item2) { }
public double Dot(Vec other)
{ return Item1*other.Item1 + Item2*other.Item2; }
public static Vec operator-(Vec first, Vec second)
{ return new Vec(first.Item1 - second.Item1, first.Item2 - second.Item2);}
public static Vec operator+(Vec first, Vec second)
{ return new Vec(first.Item1 + second.Item1, first.Item2 + second.Item2);}
public static Vec operator*(double first, Vec second)
{ return new Vec(first * second.Item1, first * second.Item2);}
public double Length() { return Math.Sqrt(Dot(this)); }
public Vec Normalize() { return (1 / Length()) * this; }
}
public bool IntersectCircle(Vec origin, Vec lineStart,
Vec lineEnd, Vec circle, double radius, out Vec circleWhenHit)
{
circleWhenHit = null;
// find the closest point on the line segment to the center of the circle
var line = lineEnd - lineStart;
var lineLength = line.Length();
var lineNorm = (1/lineLength)*line;
var segmentToCircle = circle - lineStart;
var closestPointOnSegment = segmentToCircle.Dot(line) / lineLength;
// Special cases where the closest point happens to be the end points
Vec closest;
if (closestPointOnSegment < 0) closest = lineStart;
else if (closestPointOnSegment > lineLength) closest = lineEnd;
else closest = lineStart + closestPointOnSegment*lineNorm;
// Find that distance. If it is less than the radius, then we
// are within the circle
var distanceFromClosest = circle - closest;
var distanceFromClosestLength = distanceFromClosest.Length();
if (distanceFromClosestLength > radius) return false;
// So find the distance that places the intersection point right at
// the radius. This is the center of the circle at the time of collision
// and is different than the result from Doswa
var offset = (radius - distanceFromClosestLength) *
((1/distanceFromClosestLength)*distanceFromClosest);
circleWhenHit = circle - offset;
return true;
}
答案 2 :(得分:1)
这是一些计算从点到线的距离的Java(这不完整,但会给你基本的图片)。代码来自一个名为的类 '向量'。假设是矢量对象被初始化为线矢量。方法'distance'接受线矢量开始的点(当然称为'at')和感兴趣的点。它计算并返回从该点到该线的距离。
public class Vector
{
double x_ = 0;
double y_ = 0;
double magnitude_ = 1;
public Vector()
{
}
public Vector(double x,double y)
{
x_ = x;
y_ = y;
}
public Vector(Vector other)
{
x_ = other.x_;
y_ = other.y_;
}
public void add(Vector other)
{
x_ += other.x_;
y_ += other.y_;
}
public void scale(double val)
{
x_ *= val;
y_ *= val;
}
public double dot(Vector other)
{
return x_*other.x_+y_*other.y_;
}
public void cross(Vector other)
{
x_ = x_*other.y_ - y_*other.x_;
}
public void unit()
{
magnitude_ = Math.sqrt(x_*x_+y_*y_);
x_/=magnitude_;
y_/=magnitude_;
}
public double distance(Vector at,Vector point)
{
//
// Create a perpendicular vector
//
Vector perp = new Vector();
perp.perpendicular(this);
perp.unit();
Vector offset = new Vector(point.x_ - at.x_,point.y_ - at.y_);
double d = Math.abs(offset.dot(perp));
double m = magnitude();
double t = dot(offset)/(m*m);
if(t < 0)
{
offset.x_ -= at.x_;
offset.y_ -= at.y_;
d = offset.magnitude();
}
if(t > 1)
{
offset.x_ -= at.x_+x_;
offset.y_ -= at.y_+y_;
d = offset.magnitude();
}
return d;
}
private void perpendicular(Vector other)
{
x_ = -other.y_;
y_ = other.x_;
}
public double magnitude()
{
magnitude_ = Math.sqrt(x_*x_+y_*y_);
return magnitude_;
}
}