处理点与线的关系,线与线的关系的算法等等,如有错误,欢迎指正。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PointLinePositionRelation
{
#region Entity
/// <summary>
/// Entity Point
/// </summary>
public class Point
{
public Point(double x, double y)
{
this.x = x;
this.y = y;
}
private double x;
public double X
{
get { return x; }
set { x = value; }
}
private double y;
public double Y
{
get { return y; }
set { y = value; }
}
}
/// <summary>
/// Entity of line
/// </summary>
public class Line
{
public Line()
{
}
public Line(List<Point> _points)
{
this.points = _points;
}
private List<Point> points = new List<Point>();
public List<Point> Points
{
get { return points; }
}
public bool AddPoint(Point p)
{
bool success = false;
if (!points.Contains(p))
{
points.Add(p);
success = true;
}
return success;
}
public bool RemovePoint(Point p)
{
bool success = false;
if (points.Contains(p))
{
points.Remove(p);
success = true;
}
return success;
}
public bool UpdatePoint(Point src_p, Point tar_p)
{
bool success = false;
if (points.Contains(src_p))
{
src_p.X = tar_p.X;
src_p.Y = tar_p.Y;
success = true;
}
return success;
}
}
/// <summary>
/// Position Status
/// </summary>
enum Position
{
LEFT = 0,
RIGHT = 1,
ON_K = 2,
UP = 3,
DOWN = 4,
ON = 5,
ERROE = 6
}
#endregion
#region Function
public static class PointLineAlgorithems
{
#region Algorithems
/// <summary>
/// return the traingle degree
/// </summary>
/// <param name="tupe"></param>
/// tuple item1:the first point
/// tuple item2:the last point
/// tuple item3:the middle point
/// <returns></returns>
public static double GetTraingleDegree(Tuple<Point, Point, Point> tupe)
{
double distance1 = GetDistance(tupe.Item1, tupe.Item2);
double distance2 = GetDistance(tupe.Item1, tupe.Item3);
double distance3 = GetDistance(tupe.Item2, tupe.Item3);
return Math.Acos(Math.Pow(distance1,2)+Math.Pow(distance2,2)-Math.Pow(distance3,2)/2*distance1*distance2);
}
/// <summary>
/// to judage point and line position
/// </summary>
/// <param name="l"></param>
/// <param name="p"></param>
/// <returns></returns>
public static string JudgePointLineRelation(Line l, Point p)
{
//y = kx + b
//the k of line combine with two points
double k;
//the b of line
double b;
//the result
string POSITION = string.Empty;
//this function is to deal with one point with a line with two points
//if line point is not 2,you should split to two or more lines with
//two points,so here we return string.Empty
if (l.Points.Count != 2 || p == null) return string.Empty;
//if the X value of two points are the same
//wo can not get k,then we can deal it as follows
if (l.Points[0].X == l.Points[1].X)
{
if (p.X > l.Points[0].X) POSITION = "LEFT";
else if (p.X < l.Points[0].X) POSITION = "RIGHT";
else if (p.X == l.Points[0].X) POSITION = "ON";
//else POSITION = "ERROR_K";
}
//if the k is not zero,we can deal it as follows
else
{
k = (l.Points[0].Y - l.Points[1].Y) / (l.Points[0].X - l.Points[1].X);
b = ((l.Points[0].X * l.Points[1].Y) - (l.Points[0].Y * l.Points[1].X)) / (l.Points[0].X - l.Points[1].X);
if (p.Y > k * p.X + b) POSITION = "UP";
else if (p.Y < k * p.X + b) POSITION = "DOWN";
else if (p.Y == k * p.X + b) POSITION = "ON";
//else POSITION = "ERROR_N";
}
return POSITION;
}
/// <summary>
/// to judage if two line clips
/// </summary>
/// <param name="src"></param>
/// <param name="tar"></param>
/// <returns></returns>
public static int? JudageLinesRelation(Line src, Line tar)
{
//if point count of line is less then 2,we do not
//deal with this
if (src.Points.Count < 2 || tar.Points.Count < 2)
return null;
Point p = null;
Line l = null;
string flag = string.Empty;
//falg of clip,if not clip 1,else 0
int? clip = 1;
for (int i = 0; i < src.Points.Count; i++)
{
//the first loop point
p = new Point(src.Points[i].X, src.Points[i].Y);
//the loop for tar line
for (int j = 0; j + 1 < tar.Points.Count; j++)
{
//temp line with two points
l = new Line();
l.AddPoint(tar.Points[j]);
l.AddPoint(tar.Points[j + 1]);
//if the value of flag is Null or Empty,means flag has not been given value
if (string.IsNullOrEmpty(flag))
flag = JudgePointLineRelation(l, p);
else
{
//if the new point position is not the same as the old point,the two line cliped
//there is no need to contine the loop,we change the flag value to 0(means two line cliped)
if (flag != JudgePointLineRelation(l, p))
{
clip = 0;
break;
}
}
}
}
return clip;
}
/// <summary>
/// get distance of two points
/// </summary>
/// <param name="src"></param>
/// <param name="tar"></param>
/// <returns></returns>
public static double GetDistance(Point src, Point tar)
{
if (src.X == tar.X && src.Y == tar.Y) return 0;
return Math.Sqrt(Math.Pow(Math.Abs(src.X - tar.X), 2) + Math.Pow(Math.Abs(src.Y - tar.Y), 2));
}
/// <summary>
/// To get min distance of two lines
/// </summary>
/// <param name="src"></param>
/// <param name="tar"></param>
/// <returns></returns>
public static Tuple<double?, int?, int?> CalcMinDistance(Line src, Line tar)
{
//if the point count less than 2,we do not think it is a line.
if (src.Points.Count < 2 || tar.Points.Count < 2) return null;
//if the two line cliped,we do not deal with this situation
if (0 == JudageLinesRelation(src, tar)) return null;
#region Params
//the min distance point src_index
int? src_index = null;
//the min distance point tar_index
int? tar_index = null;
//the temp value to keep the distance
double? temp = null;
//the min distance
double dist = 0;
#endregion
//loop for the src line
for (int i = 0; i < src.Points.Count; i++)
{
//loop for tar line
for (int j = 0; j < tar.Points.Count; j++)
{
//the distance
dist = GetDistance(src.Points[i], tar.Points[j]);
//if the temp has not been given value
if (null == temp)
{
temp = dist;
src_index = i;
tar_index = j;
}
else
{
//if the new value < temp,then keep the min value
if (temp > dist)
{
temp = dist;
src_index = i;
tar_index = j;
}
}
}
}
return new Tuple<double?, int?, int?>(temp, src_index, tar_index);
}
/// <summary>
/// to judage the two line direction
/// </summary>
/// <param name="src_line"></param>
/// <param name="tar_line"></param>
/// <returns></returns>
public static bool? JudageLineDirection(Line src_line, Line tar_line)
{
//if the point count of line less than 2,we do not deal with this
if (src_line.Points.Count < 2 || tar_line.Points.Count < 2)
return null;
//the boolean flag,if the two line are the same direction,then true
//else the flag will be false.Note:if the exception has occoured
//the value null will be returned
bool flag = false;
//the line temp value.
//Note:this line is not always represent the min distance line
Line line = null;
//the temp value to recored the result that the position of point on
//src_line position and temp line(mostly min distance line)
string src_temp = string.Empty;
//the temp value to recored the result that the position of point on
//tar_line position and temp line(mostly min distance line)
string tar_temp = string.Empty;
//the temp tuple value that recored the min distance line information
//item1:min distance value
//item2:the index of the point on src_line
//item3:the index of the point on tar_line
Tuple<double?, int?, int?> tuple = CalcMinDistance(src_line, tar_line);
//if the min diatance information is not null
if (tuple != null)
{
//the index of src_line or tar_line type is int?,if index has not been given value
//the value will be null,else will be the index of point,which combine the min distance line
if (tuple.Item2.HasValue && tuple.Item3.HasValue)
{
#region different situation
//if the index of point which combine the min distance line is less than count
if ((tuple.Item2.Value < src_line.Points.Count - 1) && (tuple.Item2.Value < tar_line.Points.Count - 1))
{
line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value] });
src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value + 1]);
tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value + 1]);
}
//if the index of point of src_line equals count-1
else if (tuple.Item2.Value == src_line.Points.Count - 1)
{
line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value - 1], tar_line.Points[tuple.Item3.Value] });
src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value]);
tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value + 1]);
}
//if the index of point of tar_line equals count-1
else if (tuple.Item3.Value == tar_line.Points.Count - 1)
{
line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value - 1] });
src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value + 1]);
tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value]);
}
//both of them are equals count - 1
else
{
line = new Line(new List<Point> { src_line.Points[tuple.Item2.Value], tar_line.Points[tuple.Item3.Value] });
src_temp = JudgePointLineRelation(line, src_line.Points[tuple.Item2.Value - 1]);
tar_temp = JudgePointLineRelation(line, tar_line.Points[tuple.Item3.Value - 1]);
}
#endregion
}
else
{
//if did not get min distance information,return null
return null;
}
//if the result are different,different direction
//else the same direction
if ((src_temp != tar_temp) && (src_temp != "ON" && tar_temp != "ON"))
{
flag = false;
}
else
{
flag = true;
}
}
return flag;
}
#endregion
}
#endregion
}