GetRegion(double x1, double y1, double x2, double y2, double dir, double allowShift = 3 * Math.PI / 180)
{
dir = RouteMathExtend.TurnToFixedRegion(dir, 0, 2 * Math.PI);
List<PointD> regionPoints = new List<PointD>();
double xl, xr, yu, yd;
xl = xLeft ;
xr = xright ;
yu = yUpper ;
yd = yDown ;
double minX = Math.Min(x1, x2);
double maxX = Math.Max(x1, x2);
double minY = Math.Min(y1, y2);
double maxY = Math.Max(y1, y2);
double width = xl + xr;
double height = yu + yd;
if (Math.Abs(dir) < allowShift || Math.Abs(dir - Math.PI * 2) < allowShift)
{
RectangleF rec = new RectangleF((float)(minX - yd), (float)(minY - xr), (float)(maxX - minX + height), (float)(maxY - minY + width));
regionPoints.Add(new PointD(rec.Left, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Bottom));
regionPoints.Add(new PointD(rec.Left, rec.Bottom));
}
else if (Math.Abs(dir - Math.PI / 2) < allowShift)
{
RectangleF rec = new RectangleF((float)(minX - xl), (float)(minY - yd), (float)(maxX - minX + width), (float)(maxY - minY + height));
regionPoints.Add(new PointD(rec.Left, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Bottom));
regionPoints.Add(new PointD(rec.Left, rec.Bottom));
}
else if (Math.Abs(dir - Math.PI) < allowShift)
{
RectangleF rec = new RectangleF((float)(minX - yu), (float)(minY - xl), (float)(maxX - minX + height), (float)(maxY - minY + width));
regionPoints.Add(new PointD(rec.Left, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Bottom));
regionPoints.Add(new PointD(rec.Left, rec.Bottom));
}
else if (Math.Abs(dir - Math.PI / 2 * 3) < allowShift)
{
RectangleF rec = new RectangleF((float)(minX - xr), (float)(minY - yu), (float)(maxX - minX + width), (float)(maxY - minY + height));
regionPoints.Add(new PointD(rec.Left, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Top));
regionPoints.Add(new PointD(rec.Right, rec.Bottom));
regionPoints.Add(new PointD(rec.Left, rec.Bottom));
}
else
{
double k1 = Math.Tan(dir);
double k2 = -1 / k1;//与当前线段垂直的斜率
double cosA = Math.Cos(dir);
double sinA = Math.Sin(dir);
double b1, b2, b3, b4, c1, c2, c3, c4, p, q;
b1 = b3 = y1 - x1 * k1;
b2 = y1 < y2 ? y1 - x1 * k2 : y2 - x2 * k2;
b4 = y1 > y2 ? y1 - x1 * k2 : y2 - x2 * k2;
if (cosA > 0) p = 1; else p = -1;
if (sinA > 0) q = 1; else q = -1;
c1 = b1 + p * xl * Math.Pow((1 + k1 * k1), 0.5);
c3 = b3 - p * xr * Math.Pow((1 + k1 * k1), 0.5);
if (q > 0)
{
c2 = b2 - yd * Math.Pow((1 + k2 * k2), 0.5);
c4 = b4 + yu * Math.Pow((1 + k2 * k2), 0.5);
}
else
{
c2 = b2 - yd * Math.Pow((1 + k2 * k2), 0.5);
c4 = b4 + yu * Math.Pow((1 + k2 * k2), 0.5);
}
double x, y;
if (CalCrossPoint(k1, k2, c1, c2, out x, out y))
regionPoints.Add(new PointD(Math.Ceiling(x), Math.Ceiling(y)));
else
Debug.WriteLine("求取路径顶点时有误");
if (CalCrossPoint(k1, k2, c3, c2, out x, out y))
regionPoints.Add(new PointD(Math.Floor(x), Math.Ceiling(y)));
else
Debug.WriteLine("求取路径顶点时有误");
if (CalCrossPoint(k1, k2, c3, c4, out x, out y))
regionPoints.Add(new PointD(Math.Floor(x), Math.Floor(y)));
else
Debug.WriteLine("求取路径顶点时有误");
if (CalCrossPoint(k1, k2, c1, c4, out x, out y))
regionPoints.Add(new PointD(Math.Ceiling(x), Math.Floor(y)));
else
Debug.WriteLine("求取路径顶点时有误");
}
if (regionPoints.Count > 0)
regionPoints.Add(regionPoints[0]);
return new CommonRegion(0, regionPoints, null, null, 0, null);
}
bool CalCrossPoint(double k1, double k2, double b1, double b2, out double x, out double y)
{
x = 0;
y = 0;
if (k1!=k2)
{
x = (b2 - b1) / (k1 - k2);
y = (b2 * k1 - b1 * k2) / (k1 - k2);
return true;
}
return false;
}
/// <summary>
/// 计算两个区域是否相交,
/// 需要考虑的情形有:
/// 1、一个区域包含在另一个区域内,此时可用点在区域内的算法计算
/// 2、一个区域与另一个区域由部分重叠,且重叠区域不包括边界点
/// </summary>
/// <param name="region"></param>
/// <returns></returns>
public bool IsIntersect(List<PointD>BoundaryPoints)
{
for (int i = 0; i < this.BoundaryPoints.Count - 1; i++)
{
PointD p = this.BoundaryPoints[i];
if (IsInTheRegion(p.X, p.Y))
return true;
}
for (int i = 0; i < BoundaryPoints.Count - 1; i++)
{
PointD p = region.BoundaryPoints[i];
if (this.IsInTheRegion(p.X, p.Y))
return true;
}
for (int i = 1; i < BoundaryPoints.Count; i++)
{
for (int j = 1; j < this.BoundaryPoints.Count; j++)
{
if (CheckLineCross(BoundaryPoints[i].X, region.BoundaryPoints[i].Y, BoundaryPoints[i - 1].X, BoundaryPoints[i - 1].Y,
this.BoundaryPoints[j].X, this.BoundaryPoints[j].Y, this.BoundaryPoints[j - 1].X, this.BoundaryPoints[j - 1].Y))
return true;
}
}
return false;
}
bool IsInTheRegion(List<PointD> BoundaryPoints, double x, double y)
{
var pts = new List<PointD>(BoundaryPoints);
double offset = 20;
if (pts.Count == 0) return false;
else if (pts.Count == 1)
{
return NearPoint(pts[0], (new PointD(x, y)), offset);
}
else if (pts.Count == 2)
{
if (pts[0].Equals(pts[1]))
{
return NearPoint(pts[0], (new PointD(x, y)), offset);
}
else
{
return DisPointToLineSegment(x, y, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y) < offset;
}
}
else if (pts.Count == 3)
{
if (NearPoint(pts[0], pts[2], offset))
{
if (NearPoint(pts[0], pts[1], offset))
{
return NearPoint(pts[0], (new PointD(x, y)), offset);
}
else
{
return DisPointToLineSegment(x, y, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y) < offset;
}
}
}
if (!NearPoint(pts[0], pts.Last(), offset)) pts.Add(pts[0]);
if (pts == null || pts.Count == 0)
return false;
double minx = pts[0].X;
double maxx = pts[0].X;
double miny = pts[0].Y;
double maxy = pts[0].Y;
for (int i = 1; i < pts.Count - 1; i++)
{
if (pts[i].X < minx)
minx = pts[i].X;
if (pts[i].X > maxx)
maxx = pts[i].X;
if (pts[i].Y < miny)
miny = pts[i].Y;
if (pts[i].Y > maxy)
maxy = pts[i].Y;
}
Rectangle MaxRectangle = new Rectangle((int)minx, (int)miny, (int)(maxx - minx), (int)(maxy - miny));
if (x < MaxRectangle.Left || x > MaxRectangle.Right || y < MaxRectangle.Top || y > MaxRectangle.Bottom)
return false;
int[] index = new int[4];
for (int i = 0; i < pts.Count - 1; i++)
{
if (Math.Abs(pts[i].X - x) < 20 && Math.Abs(pts[i].Y - y) < 20)
return true;
if (CheckPointAboveLine(x, y, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y) == 0 &&
OnLineSegment(x, y, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y))
return true;
if (CheckLineCross(x, y, x + MaxRectangle.Width, y, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y))
{
index[0]++;
}
if (RouteMath.CheckLineCross(x, y, x - MaxRectangle.Width, y, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y))
{
index[1]++;
}
if (CheckLineCross(x, y, x, y + MaxRectangle.Height, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y))
{
index[2]++;
}
if (CheckLineCross(x, y, x, y - MaxRectangle.Height, pts[i].X, pts[i].Y, pts[i + 1].X, pts[i + 1].Y))
{
index[3]++;
}
}
foreach (int i in index)
{
if (i % 2 != 1)
return false;
}
return true;
}
这里计算相交用的是最笨的计算方法,所以计算时间较长,需要考虑优化问题。