using System.Collections;
using System;
using Utility;
public class Line
{
public enum ExpressionType
{
ETYPE_NULL = 0,
ETYPE_NORMAL = 1,
ETYPE_KXY = 2,
}
private ExpressionType _Type = ExpressionType.ETYPE_NULL;
private float _Def_A = 1;
private float _Def_B = 0;
private float _Def_C = 0;
private Point _Def_Pos = new Point(0,0);
private float _Def_K = 0;
private bool _isVerticalWithX = false;
public Line(float A, float B, float C)
{
if (A == 0 && B == 0)
{
throw new Exception("can't to create a line");
}
_Def_A = A;
_Def_B = B;
_Def_C = C;
_Type = ExpressionType.ETYPE_NORMAL;
}
public Line(float k, Point pos, bool isVerticalWithX = false)
{
_Type = ExpressionType.ETYPE_KXY;
_Def_Pos = pos.Clone();
_Def_K = k;
_isVerticalWithX = isVerticalWithX;
}
public static Line GetLine(float A, float B, float C)
{
Line TLine = null;
try
{
TLine = new Line(A, B, C);
}
catch (System.Exception ex)
{
return null;
}
return TLine;
}
public static Line GetLine(float k, Point pos, bool isVerticalWithX = false)
{
return new Line(k, pos, isVerticalWithX);
}
public bool CheckPointIsInLine(Point pos)
{
if (_Type == ExpressionType.ETYPE_NORMAL)
{
if (((_Def_A * pos.x) + (_Def_B * pos.y) + _Def_C) == 0)
{
return true;
}
}
else if (_Type == ExpressionType.ETYPE_KXY)
{
if ((_Def_K * (pos.x - _Def_Pos.x)) == (pos.y - _Def_Pos.y))
{
return true;
}
}
return false;
}
public Point getInLinePointByX(float x)
{
Point point = new Point();
point.x = x;
if (_Type == ExpressionType.ETYPE_NORMAL)
{
if (_Def_B == 0)
return null;
point.y = (-_Def_C - _Def_A * x) / _Def_B;
}
else if (_Type == ExpressionType.ETYPE_KXY)
{
if (_isVerticalWithX)
return null;
point.y = _Def_K * (x - _Def_Pos.x) + _Def_Pos.y;
}
return point;
}
public Point getInLinePointByY(float y)
{
Point point = new Point();
point.y = y;
if (_Type == ExpressionType.ETYPE_NORMAL)
{
if (_Def_A == 0f)
return null;
point.x = (-_Def_C - _Def_B * y) / _Def_A;
}
else if (_Type == ExpressionType.ETYPE_KXY)
{
if (_Def_K == 0f)
return null;
point.x = (y - _Def_Pos.y) / _Def_K + _Def_Pos.x;
}
return point;
}
public LineWithSegmentRetins CheckSegmentIsCrossLine(Segment segment)
{
if (segment == null)
return LineWithSegmentRetins.LSR_Independent;
float flag0 = 1;
float flag1 = 1;
if (_Type == ExpressionType.ETYPE_NORMAL)
{
flag0 = (_Def_A * segment._start.x) + (_Def_B * segment._start.y) + _Def_C;
flag1 = (_Def_A * segment._end.x) + (_Def_B * segment._end.y) + _Def_C;
}
else if (_Type == ExpressionType.ETYPE_KXY)
{
flag0 = _isVerticalWithX ? segment._start.x - _Def_Pos.x : _Def_K * (segment._start.x - _Def_Pos.x) - (segment._start.y - _Def_Pos.y);
flag1 = _isVerticalWithX ? segment._end.x - _Def_Pos.x : _Def_K * (segment._end.x - _Def_Pos.x) - (segment._end.y - _Def_Pos.y);
}
if(flag0 == 0 && flag1 == 0)
return LineWithSegmentRetins.LSR_Cross_Coincide;
else if(flag0 == 0 || flag1 == 0)
return LineWithSegmentRetins.LSR_Cross_In;
else if(flag0 * flag1 < 0)
return LineWithSegmentRetins.LSR_Cross;
return LineWithSegmentRetins.LSR_Independent;
}
public ExpressionType GetType()
{
return _Type;
}
public bool GetXYKLineIsVerticalWithX()
{
return (_Type == ExpressionType.ETYPE_KXY) && _isVerticalWithX;
}
}
using System.Collections;
using Utility;
using System;
public class Segment {
public Point _start;
public Point _end;
public Segment(Point start, Point end)
{
if (start == end)
{
throw new Exception("can't to create a segment");
}
_start = start.Clone();
_end = end.Clone();
}
public static bool CheckSegment(Point start, Point end)
{
return !(start == end);
}
public bool CheckPointIsInSegment(Point point)
{
return Utility.Utility.CrossMultiply(point, _start, _end) == 0f && (point.x >= Utility.Utility.getMin(_start.x, _end.x) && point.x <= Utility.Utility.getMax(_start.x, _end.x));
}
}
using System.Collections;
using System.Collections.Generic;
using System;
using Utility;
public class Polygon {
public List<Point> _Pos_list = new List<Point>();
public Polygon(List<Point> pos_list, bool checkLegal = true)
{
if(pos_list.Count < 3)
{
throw new Exception("can't to create a polygon");
}
if(checkLegal && !ChackIsPolygon(pos_list))
throw new Exception("can't to create a polygon");
else if(!checkLegal)
{
}
_Pos_list.Clear();
for(int index = 0; index < pos_list.Count; index++)
{
_Pos_list.Add(pos_list[index].Clone());
}
}
public static bool ChackIsPolygon(List<Point> pos_list)
{
if (pos_list.Count < 3)
return false;
List<Segment> segment_list = new List<Segment>();
for (int index = 0; index < pos_list.Count; index++)
{
segment_list.Add(new Segment(pos_list[index].Clone(), pos_list[index == pos_list.Count - 1 ? 0 : index + 1].Clone()));
}
for (int x = 0; x < segment_list.Count; x++)
{
for (int y = x + 1; y < segment_list.Count; y++)
{
SegmentsRelations flag = Utility.Utility.CheckSegmentsIntersect(segment_list[x], segment_list[y]);
if ((y - x > 1 && !(x == 0 && y == segment_list.Count - 1)) && flag > SegmentsRelations.SR_Independent)
return false;
}
}
return true;
}
public List<Segment> getSegments()
{
List<Segment> segment_list = new List<Segment>();
for (int index = 0; index < _Pos_list.Count; index++)
{
segment_list.Add(new Segment(_Pos_list[index].Clone(), _Pos_list[index == _Pos_list.Count - 1 ? 0 : index + 1].Clone()));
}
return segment_list;
}
}
using System.Collections;
using System.Collections.Generic;
using System;
namespace Utility
{
public enum SegmentsRelations
{
SR_Independent = -1,
SR_Cross = 0,
SR_Cross_In = 1,
SR_Cross_Coincide = 3,
}
public enum LineWithSegmentRetins
{
LSR_Independent = -1,
LSR_Cross = 0,
LSR_Cross_In = 1,
LSR_Cross_Coincide = 3,
}
public class Point
{
public Point()
{
}
public Point(float tx, float ty)
{
x = tx;
y = ty;
}
public float x = 0;
public float y = 0;
public Point Clone()
{
return new Point(x,y);
}
public string ToString()
{
return "Point( " + x.ToString() + " , " + y.ToString() + " )";
}
}
public static class Utility
{
public static float getAbs(float src)
{
return src < 0 ? (-src) : src;
}
public static float getMax(float arg0, float arg1)
{
return arg0 > arg1 ? arg0 : arg1;
}
public static float getMin(float arg0, float arg1)
{
return arg0 > arg1 ? arg1 : arg0;
}
public static LineWithSegmentRetins CheckSegmentIsCrossLine(Line line, Segment segment)
{
if (line == null || segment == null)
return LineWithSegmentRetins.LSR_Independent;
return line.CheckSegmentIsCrossLine(segment);
}
public static bool CheckPointIsInSegment(Segment se, Point point)
{
if (se == null || point == null)
return false;
return se.CheckPointIsInSegment(point);
}
public static bool CheckRectanglesIntersect(Point Rect0_p0, Point Rect0_p1, Point Rect1_p0, Point Rect1_p1)
{
if (getAbs((Rect0_p0.x + Rect0_p1.x) - (Rect1_p0.x + Rect1_p1.x)) <= getAbs(Rect0_p0.x - Rect0_p1.x) + getAbs(Rect1_p0.x - Rect1_p1.x) && getAbs((Rect0_p0.y + Rect0_p1.y) - (Rect1_p0.y + Rect1_p1.y)) <= getAbs(Rect0_p0.y - Rect0_p1.y) + getAbs(Rect1_p0.y - Rect1_p1.y))
return true;
return false;
}
/*********************************************************************************************
*
* 判断 2条线段是否相交
*
* 原理 1快速排除 (排除2条线段在同一直线上时 不相交)
* 2 两条线段相交 必然相互 相交, 两条线段的两个端点各自在另一线段的两侧或有一端点在另一线段上
*
**********************************************************************************************/
public static SegmentsRelations CheckSegmentsIntersect(Segment s0, Segment s1)
{
if (!CheckRectanglesIntersect(s0._start, s0._end, s1._start, s1._end))
return SegmentsRelations.SR_Independent;
/***********************************************************************************************************************************
* 向量的叉乘 几何意义垂直与两向量的向量(实际运算得出的是伪向量,绝对值为垂直与两向量的模,也等于以两向量为2边组成的平行四边形的面积)
* 设向量P(A1,A2) 向量Q (B1,B2)
* P X Q = -(Q X P)
* P X Q = A1*B2 - A2*B1 //(A1*B2 - A2*B1 的绝对值为平行四边形的面积)
* 右手原理 右手半握,大拇指垂直向上,四指右向量P握向Q,大拇指的方向就是叉积的方向
* 当 A1*B2 - A2*B1 大于 0 时 P 在 Q的顺时针方向 (右手原理 )
*
* !!!!!!!!!!!!!以上大一数学有学!!!!!!!!!!!!!!
*
* 当P X Q > 0 //P在Q的顺时针方向 拇指向下
* 当P X Q < 0 //P在Q的逆时针方向 拇指向上
* 当P X Q = 0 //p Q 共线 方向不确定是否相同 拇指范围为垂直与共线的平面的圆
*
* p 跨立 Q (A1 - B1) X (B2 - B1) (A2 - B1) X (B2 - B1) 得出的值正负相反时 跨立
* 所以 (A1 - B1) X (B2 - B1) *(A2 - B1) X (B2 - B1) < 0 当 = 0 时 因为已通过快速排除 2线段必然重合
* 简化为 (A1 - B1) X (B2 - B1) * (B2 - B1) X (A2 - B1) >= 0
***********************************************************************************************************************************/
float flag0 = CrossMultiply(s0._start, s1._end, s1._start);
float flag1 = CrossMultiply(s1._end, s0._end, s1._start);
if (flag0 == 0f && flag1 == 0f)
return SegmentsRelations.SR_Cross_Coincide;
else if (flag0 == 0 || flag1 == 0)
{
if (s0.CheckPointIsInSegment(s1._start) || s0.CheckPointIsInSegment(s1._end) || s1.CheckPointIsInSegment(s0._start) || s1.CheckPointIsInSegment(s0._end))
return SegmentsRelations.SR_Cross_In;
else
return SegmentsRelations.SR_Independent;
}
else if (flag0 * flag1 > 0)
{
float flag2 = CrossMultiply(s1._start, s0._end, s0._start);
float flag3 = CrossMultiply(s0._end, s1._end, s0._start);
if (flag2 * flag3 > 0)
return SegmentsRelations.SR_Cross;
else
return SegmentsRelations.SR_Independent;
}
return SegmentsRelations.SR_Independent;
}
public static float CrossMultiply(Point A, Point B, Point C)
{
return (A.x - C.x) * (B.y - C.y) - (A.y - C.y) * (B.x - C.x);
}
/******************************************************************
*
* 判断一个点是否在多边形内
*
* 以该点做平行与x轴直线 当且仅当 直线在点两侧与矩形的交点个数为奇数时
* 该点在多边形内
*
* 当一侧的交点为奇数时,另一侧肯定也为奇数 所以只用证明一侧即可
*
******************************************************************/
public static bool CheckPointInPolygon(Point point, Polygon polygon)
{
if (point == null || polygon == null)
return false;
List<Segment> segment_list = polygon.getSegments();
for (int index = 0; index < segment_list.Count; index++)
{
if (segment_list[index].CheckPointIsInSegment(point))
return true;
}
Line lineX = new Line(0f,1f,-point.y);
int crossCount = 0;
for (int index = 0; index < segment_list.Count; index++)
{
LineWithSegmentRetins type = CheckSegmentIsCrossLine(lineX, segment_list[index]);
if (type == LineWithSegmentRetins.LSR_Independent || type == LineWithSegmentRetins.LSR_Cross_Coincide)
{
continue;
}
else if (type == LineWithSegmentRetins.LSR_Cross)
{
Point hPoint = null;
Point lPoint = null;
if (segment_list[index]._start.y > segment_list[index]._end.y)
{
hPoint = segment_list[index]._start;
lPoint = segment_list[index]._end;
}
else
{
hPoint = segment_list[index]._end;
lPoint = segment_list[index]._start;
}
if (CrossMultiply(point, lPoint, hPoint) > 0f)
{
crossCount++;
}
}
else if (type == LineWithSegmentRetins.LSR_Cross_In)
{
if ((segment_list[index]._start.y == point.y && segment_list[index]._end.y < point.y) || (segment_list[index]._end.y == point.y && segment_list[index]._start.y < point.y))
{
Point hPoint = null;
Point lPoint = null;
if (segment_list[index]._start.y > segment_list[index]._end.y)
{
hPoint = segment_list[index]._start;
lPoint = segment_list[index]._end;
}
else
{
hPoint = segment_list[index]._end;
lPoint = segment_list[index]._start;
}
if (CrossMultiply(point, lPoint, hPoint) > 0f)
{
crossCount++;
}
}
}
}
return crossCount % 2 == 1;
}
}
}