一组点,怎么求轮廓最小外接矩形??C#实现

要在C#中实现一组点的最小外接矩形,可以使用旋转卡壳(Rotating Calipers)算法来解决。该算法的基本思想是,在点集上绕着一个点旋转卡尺,保持卡尺间距不变,直到卡尺夹住点集边界上的两个点,记录此时卡尺的长度。然后,将卡尺旋转一定角度,直到卡尺夹住另外两个点,再记录此时的卡尺长度。重复这个过程直到卡尺夹住了所有的点,最终得到的最小卡尺长度就是最小外接矩形的对角线长度。

using System;
using System.Collections.Generic;
using System.Drawing;

public class RotatingCalipers
{
    public static double Distance(PointF p1, PointF p2)
    {
        double dx = p1.X - p2.X;
        double dy = p1.Y - p2.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }

    public static double AngleBetween(PointF v1, PointF v2)
    {
        double dotProduct = v1.X * v2.X + v1.Y * v2.Y;
        double cosAngle = dotProduct / (Distance(v1, new PointF(0, 0)) * Distance(v2, new PointF(0, 0)));
        return Math.Acos(cosAngle);
    }

    public static List<PointF> GetConvexHull(List<PointF> points)
    {
        // 这里使用 Jarvis 步进法来计算凸包
        List<PointF> hull = new List<PointF>();

        int n = points.Count;
        if (n < 3) return hull;

        int leftMost = 0;
        for (int i = 1; i < n; i++)
        {
            if (points[i].X < points[leftMost].X)
                leftMost = i;
        }

        int p = leftMost, q;
        do
        {
            hull.Add(points[p]);
            q = (p + 1) % n;
            for (int i = 0; i < n; i++)
            {
                if (CrossProduct(points[p], points[i], points[q]) < 0)
                    q = i;
            }
            p = q;
        } while (p != leftMost);

        return hull;
    }

    public static double CrossProduct(PointF p1, PointF p2, PointF p3)
    {
        return (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
    }

    public static RectangleF FindMinimumBoundingRectangle(List<PointF> points)
    {
        List<PointF> hull = GetConvexHull(points);

        double minArea = double.MaxValue;
        RectangleF minBoundingRect = RectangleF.Empty;

        for (int i = 0; i < hull.Count; i++)
        {
            PointF p1 = hull[i];
            PointF p2 = hull[(i + 1) % hull.Count];

            PointF edge = new PointF(p2.X - p1.X, p2.Y - p1.Y);
            PointF perpendicular = new PointF(-edge.Y, edge.X);

            double edgeLength = Distance(p1, p2);
            double maxProjection = 0;
            PointF maxPoint = PointF.Empty;

            foreach (var point in hull)
            {
                double projection = (point.X - p1.X) * perpendicular.X + (point.Y - p1.Y) * perpendicular.Y;
                if (projection > maxProjection)
                {
                    maxProjection = projection;
                    maxPoint = point;
                }
            }

            double height = maxProjection;
            double width = Distance(maxPoint, p1);

            double area = width * height;
            if (area < minArea)
            {
                minArea = area;
                minBoundingRect = new RectangleF(p1, new SizeF((float)width, (float)height));
            }
        }

        return minBoundingRect;
    }
}

How to use

using System;
using System.Collections.Generic;
using System.Drawing;

class Program
{
    static void Main()
    {
        // 生成一组随机点
        List<PointF> points = GenerateRandomPoints(10);

        // 找到这些点的最小外接矩形
        RectangleF minBoundingRect = RotatingCalipers.FindMinimumBoundingRectangle(points);

        Console.WriteLine("最小外接矩形:" + minBoundingRect);
    }

    static List<PointF> GenerateRandomPoints(int count)
    {
        Random rand = new Random();
        List<PointF> points = new List<PointF>();
        for (int i = 0; i < count; i++)
        {
            points.Add(new PointF(rand.Next(0, 100), rand.Next(0, 100)));
        }
        return points;
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值