计算平面上二条线段的相交点
在GDI+时,需要用到的一些图片算法片段,网上关于这些计算的比较难找到.因此特放到网上,便于大家参考.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace DrawLibrary
{
public enum EndPoint : short
{
Start = 0,
End = 1
}
public class Line {
Point _BeginPoint;
Point _EndPoint;
public Line(Point BeginPoint, Point EndPoint)
{
_BeginPoint = BeginPoint;
_EndPoint = EndPoint;
}
public Point BeginPoint
{
get { return _BeginPoint; }
}
public Point EndPoint
{
get { return _EndPoint; }
set
{
_EndPoint = value;
}
}
}
public class Utils
{
public static PointF PointToF(Point p)
{
return new PointF(p.X, p.Y);
}
public static Point PointFromF(PointF p)
{
return new Point((int)p.X, (int)p.Y);
}
public static EndPoint OtherEndpoint(EndPoint which)
{
return (which == EndPoint.Start) ? EndPoint.End : EndPoint.Start;
}
public static float Distance(Point p1, Point p2)
{
return (float)Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
}
public static int Area(Rectangle rect)
{
return rect.Width * rect.Height;
}
public static Point CenterOfRectangle(Rectangle rect)
{
return new Point(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2));
}
//计算一条线段与一个矩形的相交点
public static Point CalculateIntersection(Line line, Rectangle rect)
{
if (rect.IsEmpty)
throw new ArgumentException("不能与空区域进行计算.");
// corners
Point topLeft = new Point(rect.Left, rect.Top);
Point topRight = new Point(rect.Right, rect.Top);
Point bottomLeft = new Point(rect.Left, rect.Bottom);
Point bottomRight = new Point(rect.Right, rect.Bottom);
// boundaries
Line top = new Line(topLeft, topRight);
Line left = new Line(topLeft, bottomLeft);
Line right = new Line(topRight, bottomRight);
Line bottom = new Line(bottomLeft, bottomRight);
// calculate intersection between line and any boundary
Point intersection = new Point();
if (intersection.IsEmpty) intersection = CalculateIntersection(line, top);
if (intersection.IsEmpty) intersection = CalculateIntersection(line, left);
if (intersection.IsEmpty) intersection = CalculateIntersection(line, right);
if (intersection.IsEmpty) intersection = CalculateIntersection(line, bottom);
return intersection;
}
//计算二条线段的相交点
public static Point CalculateIntersection(Line line1, Line line2)
{
Point p1, p2, p3, p4;
p1 = NormalizeBeginPoint(line1.BeginPoint, line1.EndPoint);
p2 = NormalizeEndPoint(line1.BeginPoint, line1.EndPoint);
p3 = NormalizeBeginPoint(line2.BeginPoint, line2.EndPoint);
p4 = NormalizeEndPoint(line2.BeginPoint, line2.EndPoint);
int ua_num = (p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X);
int ub_num = (p2.X - p1.X) * (p1.Y - p3.Y) - (p2.Y - p1.Y) * (p1.X - p3.X);
int denom = (p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y);
if (denom == 0)
{
if (ua_num == 0 && ub_num == 0)
{
Point begin1 = NormalizeBeginPoint(line1.BeginPoint, line1.EndPoint);
Point begin2 = NormalizeBeginPoint(line2.BeginPoint, line2.EndPoint);
return NormalizeEndPoint(begin1, begin2);
}
else
{
return Point.Empty;
}
}
double ua = ua_num / (double)denom;
double ub = ub_num / (double)denom;
if (0 <= ua && ua <= 1 && // does line segment line1 contain intersecting pt?
0 <= ub && ub <= 1) // does line segment line2 contain intersecting pt?
{
// line segments intersect
Point intersection = new Point();
intersection.X = (int)(p1.X + ua * (p2.X - p1.X));
intersection.Y = (int)(p1.Y + ua * (p2.Y - p1.Y));
return intersection;
}
else
{
return Point.Empty;
}
}
public static double CalculateAngleInRadians(Line line)
{
if (line.BeginPoint.IsEmpty || line.EndPoint.IsEmpty) throw new ArgumentException("Invalid line end points");
double hyp = Utils.Distance(line.BeginPoint, line.EndPoint);
if (hyp == 0) throw new ArgumentException("Can't calculate angle for zero-length line");
double theta = (float)Math.Asin((line.EndPoint.Y - line.BeginPoint.Y) / hyp);
if (line.EndPoint.X < line.BeginPoint.X) theta = Math.PI - theta;
return theta;
}
public static double DegreesToRadians(double degrees)
{
return (degrees / 360) * (2 * Math.PI);
}
public static double RadiansToDegrees(double radians)
{
return 360 * (radians / (2 * Math.PI));
}
private static Line NormalizeLine(Line line)
{
return new Line(
NormalizeBeginPoint(line.BeginPoint, line.EndPoint),
NormalizeEndPoint(line.BeginPoint, line.EndPoint)
);
}
private static Point NormalizeBeginPoint(Point p1, Point p2)
{
if (p1.X < p2.X) return p1;
if (p1.X > p2.X) return p2;
if (p1.Y < p2.Y) return p1;
if (p1.Y > p2.Y) return p2;
return p1; // p1 == p2
}
private static Point NormalizeEndPoint(Point p1, Point p2)
{
if (p1.X < p2.X) return p2;
if (p1.X > p2.X) return p1;
if (p1.Y < p2.Y) return p2;
if (p1.Y > p2.Y) return p1;
return p2; // p1 == p2
}
}
}