求两个矩形是否相交

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;
        }

这里计算相交用的是最笨的计算方法,所以计算时间较长,需要考虑优化问题。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值