You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

矩形零件装箱适配判断逻辑优化求助

矩形零件装箱问题的优化方案

问题根源

你当前使用的ComponentFitsInBin函数中,最后两个基于Sum的判断逻辑完全错误:

  • bin.SizeX - bin.PackedComponents.Sum(p => p.SizeX)计算的是所有零件X尺寸总和与Bin宽度的差值,这和Bin内实际剩余的可用空间布局毫无关系。比如Bin为10×10,放入一个8×8的零件后,SumX=8,剩余X差值为2,但实际Bin内存在2×10和8×2的空隙,完全可以放下2×10或旋转后的3×2零件,但你的逻辑会因为零件X尺寸3>2而错误拒绝。
  • 这种只看总长度的判断,既会错过可用空隙,又无法真正防止零件超出Bin边界(形状不匹配时,即使总长度足够,也可能重叠或超出)。

核心优化思路

要解决这个问题,必须:

  1. 记录已放置零件的位置信息:Bin内的PackedComponent不能只存储尺寸,还要记录每个零件的左上角坐标和实际摆放的尺寸(因为支持90度旋转,实际尺寸可能和原始尺寸不同)。
  2. 替换Sum判断为碰撞检测:通过检查零件(含两种旋转状态)是否能放入Bin内的某个空位,且不与已放置零件重叠、不超出Bin边界,来判断是否适配。

代码实现示例

1. 更新PackedComponent类,增加位置和实际尺寸属性

public class PackedComponent
{
    // 原始尺寸
    public int OriginalSizeX { get; set; }
    public int OriginalSizeY { get; set; }
    // 实际摆放的尺寸(考虑旋转)
    public int Width { get; set; }
    public int Height { get; set; }
    // 摆放位置(左上角坐标,以Bin的左上角为原点)
    public int X { get; set; }
    public int Y { get; set; }

    // 计算表面积
    public int GetSurfaceArea() => Width * Height;
}

2. 重写ComponentFitsInBin函数

private bool ComponentFitsInBin(PackedComponent component, Bin bin)
{
    // 快速过滤:剩余面积不足直接返回
    if (bin.RemainingSurfaceArea < component.GetSurfaceArea())
        return false;

    // 生成两种可能的摆放方向:原始方向、旋转90度
    var possibleOrientations = new List<(int Width, int Height)>
    {
        (component.OriginalSizeX, component.OriginalSizeY),
        (component.OriginalSizeY, component.OriginalSizeX)
    };

    foreach (var (width, height) in possibleOrientations)
    {
        // 当前方向下零件尺寸超过Bin,直接跳过
        if (width > bin.SizeX || height > bin.SizeY)
            continue;

        // Bin为空时直接可以放入
        if (bin.PackedComponents.Count == 0)
            return true;

        // 尝试在已放置零件的右侧或下方放置(基础填充策略)
        foreach (var placed in bin.PackedComponents)
        {
            // 放在当前零件右侧
            int newX = placed.X + placed.Width;
            int newY = placed.Y;
            if (CanPlaceAt(newX, newY, width, height, bin))
                return true;

            // 放在当前零件下方
            newX = placed.X;
            newY = placed.Y + placed.Height;
            if (CanPlaceAt(newX, newY, width, height, bin))
                return true;
        }

        // 尝试紧贴Bin边缘的空位(比如已放零件上方、右方的整行/整列空位)
        int maxUsedY = bin.PackedComponents.Max(p => p.Y + p.Height);
        if (maxUsedY + height <= bin.SizeY && CanPlaceAt(0, maxUsedY, width, height, bin))
            return true;

        int maxUsedX = bin.PackedComponents.Max(p => p.X + p.Width);
        if (maxUsedX + width <= bin.SizeX && CanPlaceAt(maxUsedX, 0, width, height, bin))
            return true;
    }

    // 所有方向和位置都尝试后仍无法放置
    return false;
}

// 辅助函数:检查指定位置是否可以放置零件(不超出边界、不重叠)
private bool CanPlaceAt(int x, int y, int width, int height, Bin bin)
{
    // 检查是否超出Bin边界
    if (x + width > bin.SizeX || y + height > bin.SizeY)
        return false;

    // 检查是否与已放置零件重叠
    foreach (var placed in bin.PackedComponents)
    {
        bool isOverlapping = !(placed.X + placed.Width <= x || 
                               x + width <= placed.X || 
                               placed.Y + placed.Height <= y || 
                               y + height <= placed.Y);
        if (isOverlapping)
            return false;
    }

    return true;
}

补充说明

  • 上述代码使用的是基础的"紧邻填充"策略,你可以根据需求替换为更高效的装箱算法(比如Best Fit Decreasing、First Fit Decreasing,或专门针对矩形装箱的空位分割算法)。
  • RemainingSurfaceArea的检查保留作为快速过滤,避免不必要的碰撞检测,提升性能。
  • 旋转逻辑通过生成两种尺寸组合实现,确保不会错过可以通过旋转适配的空位。

内容的提问来源于stack exchange,提问作者Parrotmaster

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:44:53