直线和线段与圆交点计算方法参考

直接上代码:

首先是线段类和圆类的定义:

using UnityEngine;

public class Circle
{
	Vector2 c;
	float r;
	public Vector2 center { get { return c; } }
	public float radius { get { return r; } }
	public Circle(Vector2 center, float radius)
	{
		SetCenter(center);
		SetRadius(radius);
	}

	public void SetCenter(Vector2 center) { c = center; }
	public void SetRadius(float radius) { r = radius; }
}

public class Segment2D
{
	Vector2 _pointA = Vector2.zero;
	public Vector2 pointA
	{
		get { return _pointA; }
		set
		{
			if (_pointA != value)
			{
				_pointA = value;
				Update();
			}
		}
	}

	Vector2 _pointB = Vector2.zero;
	public Vector2 pointB
	{
		get { return _pointB; }
		set
		{
			if (_pointB != value)
			{
				_pointB = value;
				Update();
			}
		}
	}

	float _length = 0;
	public float length { get { return _length; } }
	Vector2 _normal = Vector2.zero;
	public Vector2 normal { get { return _normal; } }

	public Segment2D(Vector2 pointA, Vector2 pointB)
	{
		SetPoints(pointA, pointB);
	}

	public void SetPoints(Vector2 pointA, Vector2 pointB)
	{
		bool updateEnabled = false;
		if (_pointA != pointA)
		{
			_pointA = pointA;
			updateEnabled = true;
		}
		if (_pointB != pointB)
		{
			_pointB = pointB;
			updateEnabled = true;
		}
		if (updateEnabled) Update();
	}

	void Update()
	{
		_length = Vector2.Distance(_pointA, _pointB);
		_normal = _length > 0 ? (_pointB - pointA) / _length : Vector2.zero;
	}
}

然后是计算类:

public class Calculate
{
    //计算直线和圆的交点
	static public Vector2[] GetLineCircleIntersections(Segment2D seg, Circle circle)
	{
		float cR = circle.radius;

		if (Mathf.Approximately(seg.length, 0)) return new Vector2[0];
		if (Mathf.Approximately(cR, 0)) return new Vector2[0];

		float pAx = seg.pointA.x;
		float pAy = seg.pointA.y;
		float pBx = seg.pointB.x;
		float pBy = seg.pointB.y;
		float ccx = circle.center.x;
		float ccy = circle.center.y;

		float discriminant;

		bool isSegSlopeLegal = !Mathf.Approximately(pAx, pBx);

		if (!isSegSlopeLegal)
		{
			discriminant = cR * cR - (pAx - ccx) * (pAx - ccx);
			if (Mathf.Approximately(discriminant, 0))
			{
				return new Vector2[] { new Vector2(pAx, ccy) };
			}
			else
			{
				if (discriminant < 0) return new Vector2[0];
				//
				float sqrtDisc = Mathf.Sqrt(discriminant);
				float yA = ccy + sqrtDisc;
				float yB = ccy - sqrtDisc;
				return new Vector2[] { new Vector2(pAx, yA), new Vector2(pAx, yB) };
			}
		}

		float lineA = (pAy - pBy) / (pAx - pBx);
		float lineB = (pAy * pBx - pBy * pAx) / (pBx - pAx);
		float a = lineA * lineA + 1;
		float b = 2 * lineA * (lineB - ccy) - 2 * ccx;
		float c = ccx * ccx + (lineB - ccy) * (lineB - ccy) - cR * cR;
		discriminant = b * b - 4 * a * c;

		if (!Mathf.Approximately(discriminant, 0))
		{
			if (discriminant < 0) return new Vector2[0];
			//
			float sqrtDisc = Mathf.Sqrt(discriminant);
			float xA = (-b + sqrtDisc) / (2 * a);
			float yA = lineA * xA + lineB;
			float xB = (-b - sqrtDisc) / (2 * a);
			float yB = lineA * xB + lineB;
			return new Vector2[] { new Vector2(xA, yA), new Vector2(xB, yB) };
		}
		else
		{
			float x = -b / (2 * a);
			float y = lineA * x + lineB;
			return new Vector2[] { new Vector2(x, y) };
		}
	}

    //计算线段和圆的交点
	static public Vector2[] GetSegmentCircleIntersections(Segment2D seg, Circle circle)
	{
		float cR = circle.radius;

		if (Mathf.Approximately(seg.length, 0)) return new Vector2[0];
		if (Mathf.Approximately(cR, 0)) return new Vector2[0];

		float sqrtRadius = cR * cR;
		bool aInC = (seg.pointA - circle.center).sqrMagnitude < sqrtRadius;
		bool bInC = (seg.pointB - circle.center).sqrMagnitude < sqrtRadius;
		if (aInC && bInC) return new Vector2[0];

		float pAx = seg.pointA.x;
		float pAy = seg.pointA.y;
		float pBx = seg.pointB.x;
		float pBy = seg.pointB.y;
		float ccx = circle.center.x;
		float ccy = circle.center.y;

		float discriminant;

		bool isSegSlopeLegal = !Mathf.Approximately(pAx, pBx);

		if (!isSegSlopeLegal)
		{
			discriminant = cR * cR - (pAx - ccx) * (pAx - ccx);
			if (Mathf.Approximately(discriminant, 0))
			{
				if ((pAy - ccy) * (pBy - ccy) > 0) return new Vector2[0];

				return new Vector2[] { new Vector2(pAx, ccy) };
			}

			if (discriminant < 0) return new Vector2[0];
			//
			float sqrtDisc = Mathf.Sqrt(discriminant);
			float yA = ccy + sqrtDisc;
			float yB = ccy - sqrtDisc;
			if (aInC) return new Vector2[] { new Vector2(pAx, yB) };
			if (bInC) return new Vector2[] { new Vector2(pAx, yA) };
			return new Vector2[] { new Vector2(pAx, yA), new Vector2(pAx, yB) };
		}

		float lineA = (pAy - pBy) / (pAx - pBx);
		float lineB = (pAy * pBx - pBy * pAx) / (pBx - pAx);
		float a = lineA * lineA + 1;
		float b = 2 * lineA * (lineB - ccy) - 2 * ccx;
		float c = ccx * ccx + (lineB - ccy) * (lineB - ccx) - cR * cR;
		discriminant = b * b - 4 * a * c;

		if (!Mathf.Approximately(discriminant, 0))
		{
			if (discriminant < 0) return new Vector2[0];
			//
			float sqrtDisc = Mathf.Sqrt(discriminant);
			float xA = (-b + sqrtDisc) / (2 * a);
			float yA = lineA * xA + lineB;
			float xB = (-b - sqrtDisc) / (2 * a);
			float yB = lineA * xB + lineB;
			if (aInC) return new Vector2[] { new Vector2(xA, yA) };
			if (bInC) return new Vector2[] { new Vector2(xB, yB) };
			return new Vector2[] { new Vector2(xA, yA), new Vector2(xB, yB) };
		}
		else
		{
			float x = -b / (2 * a);
			float y = lineA * x + lineB;
			Vector2 point = new Vector2(x, y);
			if (Vector2.Dot(seg.pointA - point, seg.pointB - point) > 0) return new Vector2[0];
			return new Vector2[] { point };
		}
	}
}

猜你喜欢

转载自blog.csdn.net/ttod/article/details/131729964