using System;
using System.Collections.Generic;
using System.Linq;
using WIDESEAWCS_Common;
public class ContainerPlacer
{
// 容器尺寸常量
private const int ContainerY = 2800; // 长度方向(Y轴)
private const int ContainerX = 600; // 宽度方向(X轴)
private const int ContainerZ = 500; // 高度方向(Z轴)
// 系统参数
private const int SafetySpacing = 10; // 安全间距
private const int YAxisMaxPlace = 880;// 放置Y坐标最大值
private const int SuctionSpacing = 660; // 吸盘间距
// 吸盘尺寸配置(横向/纵向)
private static readonly (int x, int y)[] SuctionSizes =
{
(530, 130), // 0度横向
(130, 530) // 90度纵向
};
///
/// 主计算方法
///
public SuctionInfo CalculatePlacement(Block newBlock, List existingBlocks)
{
// 获取所有支撑面并按高度排序
var supportSurfaces = GetSupportSurfaces(existingBlocks)
.OrderBy(s => s.Z)
.ToList();
foreach (var surface in supportSurfaces)
{
// 尝试所有有效旋转组合
foreach (var rotation in GetValidRotations(newBlock))
{
// 计算实际放置尺寸
//var (placeW, placeL) = GetPlacementDimensions(newBlock, rotation);
// 跳过尺寸不符的表面
if (!CanPlaceOnSurface(newBlock.W, newBlock.L, surface, newBlock.H)) continue;
// 搜索可用位置
var position = FindPosition(newBlock.W, newBlock.L, surface, existingBlocks);
if (!position.HasValue) continue;
// 计算吸盘参数
var suction = CalculateSuctionParams(newBlock, position.Value,
surface.Z, rotation, newBlock.W, newBlock.L);
suction.Point = position.Value;
// 最终验证
if (ValidatePlacement(suction, existingBlocks))
{
return suction;
}
}
}
return null;
}
///
/// 获取支撑面列表(容器底部+现有木块顶面)
///
private List GetSupportSurfaces(List blocks)
{
var surfaces = new List {
new SupportSurface { // 容器底部
Z = 0, X = 0, Y = 0,
AvailableX = ContainerX, AvailableY = ContainerY
}
};
// 添加现有木块顶面
surfaces.AddRange(blocks.Select(b => new SupportSurface
{
Z = b.Z + b.H,
X = b.X,
Y = b.Y,
AvailableX = b.W,
AvailableY = b.L
}));
return surfaces;
}
///
/// 表面可行性检查
///
private bool CanPlaceOnSurface(int placeW, int placeL,
SupportSurface surface, int blockH)
{
return surface.AvailableX >= placeW &&
surface.AvailableY >= placeL &&
surface.Z + blockH <= ContainerZ;
}
///
/// 获取有效旋转角度(考虑规则5)
///
private IEnumerable GetValidRotations(Block block)
{
// 0°/180°横向双吸盘(规则5)
if (block.L > 920 && block.W >= 100 || block.L < 450)
{
yield return 0;
yield return 180;
}
// 90°/270°纵向双吸盘(无条件允许)
yield return 90;
yield return 270;
}
///
/// 计算实际放置尺寸(考虑旋转)
///
private (int w, int l) GetPlacementDimensions(Block b, int rotation)
{
return rotation % 180 == 0 ? (b.W, b.L) : (b.L, b.W);
}
///
/// 位置搜索算法(带安全间距)
///
private Point? FindPosition(int placeW, int placeL,
SupportSurface surface, List existing)
{
// 搜索步长设置为安全间距
const int step = 10;
for (int x = surface.X; x + placeW <= surface.X + surface.AvailableX; x += step)
{
for (int y = surface.Y; y + placeL <= surface.Y + surface.AvailableY; y += step)
{
if (IsPositionValid(x, y, placeW, placeL, surface.Z, existing))
{
return new Point(x, y);
}
}
}
return null;
}
///
/// 位置有效性验证(含安全间距)
///
private bool IsPositionValid(int x, int y, int w, int l,
int z, List existing)
{
// 创建带安全间距的检测区域
var newArea = new Rectangle(
x - SafetySpacing,
y - SafetySpacing,
x + w + SafetySpacing,
y + l + SafetySpacing);
var a = existing.Where(block =>
block.Z + block.H - z > 1).ToList();
// 碰撞检测
foreach (var b in a)
{
var existArea = new Rectangle(
b.X - SafetySpacing,
b.Y - SafetySpacing,
b.X + b.W + SafetySpacing,
b.Y + b.L + SafetySpacing);
if (newArea.Intersects(existArea)) return false;
}
// 容器边界检查
return x >= 0 && x + w <= ContainerX &&
y >= 0 && y + l <= ContainerY;
}
///
/// 计算吸盘参数(核心算法)
///
private SuctionInfo CalculateSuctionParams(Block block, Point position,
int surfaceZ, int rotation, int placeW, int placeL)
{
var info = new SuctionInfo { Rotation = rotation };
var suctionType = rotation % 180 == 0 ? 0 : 1;
// 计算理论放置中心
info.PlaceCenter = new int[3] {
position.X + placeW/2,
position.Y + placeL/2,
surfaceZ + block.H
};
// 先应用规则6:放置位置调整
if (ApplyRule6Adjustment(info, suctionType))
{
// 调整后需要重新计算抓取点
ApplyRule7Adjustment(info, block, suctionType);
}
else
{
// 未触发规则6时直接应用规则7
ApplyRule7Adjustment(info, block, suctionType);
}
// 应用旋转调整
//ApplyRotationAdjustment(info, rotation, block);
return info;
}
///
/// 应用规则6调整:放置位置超过880mm时边缘抓取
///
private bool ApplyRule6Adjustment(SuctionInfo info, int suctionType)
{
if (info.PlaceCenter[1] <= YAxisMaxPlace) return false;
// 计算吸盘尺寸
int suctionSize = SuctionSizes[suctionType].y;
// 计算调整后的放置位置(规则6)
info.PlaceCenter[1] = YAxisMaxPlace - suctionSize / 2;
info.Rotation += 180; // 添加旋转标记
return true;
}
///
/// 应用规则7调整:抓取点尽量靠近中心
///
private void ApplyRule7Adjustment(SuctionInfo info, Block block, int suctionType)
{
// 计算理论最大行程
int maxTravel = YAxisMaxPlace - SuctionSizes[suctionType].y / 2;
// 计算理想抓取点
info.PickCenter = new int[3] {
block.W / 2,
Math.Min(block.L / 2, maxTravel), // Y方向尽量接近中心
block.H
};
}
///
/// 应用旋转调整(180/270度)
///
private void ApplyRotationAdjustment(SuctionInfo info, int rotation, Block block)
{
if (rotation == 180 || info.Rotation == 180)
{
// Y轴镜像
info.PickCenter[1] = block.L - info.PickCenter[1];
info.PlaceCenter[1] = ContainerY - info.PlaceCenter[1];
}
else if (rotation == 270 || info.Rotation == 270)
{
// X轴镜像
info.PickCenter[0] = ContainerX - info.PickCenter[0];
info.PlaceCenter[0] = ContainerX - info.PlaceCenter[0];
}
}
///
/// 最终放置验证
///
private bool ValidatePlacement(SuctionInfo info, List existing)
{
// 空间边界检查
if (info.PlaceCenter[0] < 0 || info.PlaceCenter[0] > ContainerX) return false;
if (info.PlaceCenter[1] < 0 || info.PlaceCenter[1] > YAxisMaxPlace) return false;
if (info.PlaceCenter[2] > ContainerZ) return false;
// 吸盘投影覆盖检查
var suctionType = info.Rotation % 180 == 0 ? 0 : 1;
var (sx, sy) = SuctionSizes[suctionType];
var projection = new Rectangle(
info.PlaceCenter[0] - sx / 2,
info.PlaceCenter[1] - sy / 2,
info.PlaceCenter[0] + sx / 2,
info.PlaceCenter[1] + sy / 2
);
// 检查是否完全在支撑面内
return existing.All(b => !projection.Intersects(new Rectangle(
b.X - SafetySpacing,
b.Y - SafetySpacing,
b.X + b.W + SafetySpacing,
b.Y + b.L + SafetySpacing
)));
}
}
// 辅助类定义--------------------------------------------
public class SupportSurface
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public int AvailableX { get; set; }
public int AvailableY { get; set; }
}
public class Rectangle
{
public int Left { get; }
public int Top { get; }
public int Right { get; }
public int Bottom { get; }
public Rectangle(int x1, int y1, int x2, int y2)
{
Left = Math.Min(x1, x2);
Right = Math.Max(x1, x2);
Top = Math.Min(y1, y2);
Bottom = Math.Max(y1, y2);
}
public bool Intersects(Rectangle other)
{
return !(Right < other.Left ||
Left > other.Right ||
Bottom < other.Top ||
Top > other.Bottom);
}
}
#region
//using System;
//using System.Collections.Generic;
//using System.Linq;
//using WIDESEAWCS_Common;
//public class ContainerPlacer
//{
// // 容器尺寸常量
// private const int ContainerY = 2800; // 长度方向(Y轴)
// private const int ContainerX = 700; // 宽度方向(X轴)
// private const int ContainerZ = 500; // 高度方向(Z轴)
// // 系统参数
// private const int SafetySpacing = 10; // 安全间距
// private const int YAxisMax = 880; // Y坐标最大值
// private const int SuctionSpacing = 660; // 吸盘间距
// // 吸盘尺寸配置(横向/纵向)
// private static readonly (int x, int y)[] SuctionSizes =
// {
// (530, 130), // 0度横向
// (130, 530) // 90度纵向
// };
// ///
// /// 主计算方法
// ///
// public SuctionInfo CalculatePlacement(Block newBlock, List existingBlocks)
// {
// // 获取所有支撑面并按高度排序
// var supportSurfaces = GetSupportSurfaces(existingBlocks)
// .OrderBy(s => s.Z)
// .ToList();
// foreach (var surface in supportSurfaces)
// {
// // 尝试所有有效旋转组合
// foreach (var rotation in GetValidRotations(newBlock))
// {
// // 计算实际放置尺寸
// var (placeW, placeL) = GetPlacementDimensions(newBlock, rotation);
// // 跳过尺寸不符的表面
// if (!CanPlaceOnSurface(placeW, placeL, surface, newBlock.H)) continue;
// // 搜索可用位置
// var position = FindPosition(placeW, placeL, surface, existingBlocks);
// if (!position.HasValue) continue;
// // 计算吸盘参数
// var suction = CalculateSuctionParams(newBlock, position.Value,
// surface.Z, rotation, placeW, placeL);
// // 最终验证
// if (ValidatePlacement(suction, existingBlocks))
// {
// return suction;
// }
// }
// }
// return null;
// }
// ///
// /// 获取支撑面列表(容器底部+现有木块顶面)
// ///
// private List GetSupportSurfaces(List blocks)
// {
// var surfaces = new List {
// new SupportSurface { // 容器底部
// Z = 0, X = 0, Y = 0,
// AvailableX = ContainerX, AvailableY = ContainerY
// }
// };
// // 添加现有木块顶面
// surfaces.AddRange(blocks.Select(b => new SupportSurface
// {
// Z = b.Z + b.H,
// X = b.X,
// Y = b.Y,
// AvailableX = b.W,
// AvailableY = b.L
// }));
// return surfaces;
// }
// ///
// /// 表面可行性检查
// ///
// private bool CanPlaceOnSurface(int placeW, int placeL,
// SupportSurface surface, int blockH)
// {
// return surface.AvailableX >= placeW &&
// surface.AvailableY >= placeL &&
// surface.Z + blockH <= ContainerZ;
// }
// ///
// /// 获取有效旋转角度(考虑规则5)
// ///
// private IEnumerable GetValidRotations(Block block)
// {
// // 0°/180°横向双吸盘(规则5)
// if (block.L > 920 && block.W >= 300)
// {
// yield return 0;
// yield return 180;
// }
// // 90°/270°纵向双吸盘(无条件允许)
// yield return 90;
// yield return 270;
// }
// ///
// /// 计算实际放置尺寸(考虑旋转)
// ///
// private (int w, int l) GetPlacementDimensions(Block b, int rotation)
// {
// return rotation % 180 == 0 ? (b.W, b.L) : (b.L, b.W);
// }
// ///
// /// 位置搜索算法(带安全间距)
// ///
// private Point? FindPosition(int placeW, int placeL,
// SupportSurface surface, List existing)
// {
// // 搜索步长设置为安全间距
// const int step = 10;
// for (int x = surface.X; x + placeW <= surface.X + surface.AvailableX; x += step)
// {
// for (int y = surface.Y; y + placeL <= surface.Y + surface.AvailableY; y += step)
// {
// if (IsPositionValid(x, y, placeW, placeL, surface.Z, existing))
// {
// return new Point(x, y);
// }
// }
// }
// return null;
// }
// ///
// /// 位置有效性验证(含安全间距)
// ///
// private bool IsPositionValid(int x, int y, int w, int l,
// int z, List existing)
// {
// // 创建带安全间距的检测区域
// var newArea = new Rectangle(
// x - SafetySpacing,
// y - SafetySpacing,
// x + w + SafetySpacing,
// y + l + SafetySpacing);
// // 碰撞检测
// foreach (var b in existing.Where(block =>
// Math.Abs(block.Z + block.H - z) < 0.001)) // 同平面检测
// {
// var existArea = new Rectangle(
// b.X - SafetySpacing,
// b.Y - SafetySpacing,
// b.X + b.W + SafetySpacing,
// b.Y + b.L + SafetySpacing);
// if (newArea.Intersects(existArea)) return false;
// }
// // 容器边界检查
// return x >= 0 && x + w <= ContainerX &&
// y >= 0 && y + l <= ContainerY;
// }
// ///
// /// 计算吸盘参数(核心算法)
// ///
// private SuctionInfo CalculateSuctionParams(Block block, Point position,
// int surfaceZ, int rotation, int placeW, int placeL)
// {
// var info = new SuctionInfo { Rotation = rotation };
// var suctionType = rotation % 180 == 0 ? 0 : 1;
// // 计算理论中心点
// info.PlaceCenter = new int[3] {
// position.X + placeW/2,
// position.Y + placeL/2,
// surfaceZ + block.H
// };
// // 计算初始抓取中心
// CalculateInitialPickCenter(info, block, rotation, suctionType);
// // 应用行程调整(规则6、7)
// ApplyTravelAdjustment(info, suctionType);
// // 应用旋转调整(180/270度)
// ApplyRotationAdjustment(info, rotation, block);
// return info;
// }
// ///
// /// 计算初始抓取中心点
// ///
// private void CalculateInitialPickCenter(SuctionInfo info, Block block,
// int rotation, int suctionType)
// {
// switch (rotation % 360)
// {
// case 0: // 横向双吸盘
// case 180:
// info.PickCenter = new int[3] {
// block.W / 2, // X中心
// block.L / 2, // Y中心
// block.H // Z坐标
// };
// break;
// case 90: // 纵向双吸盘
// case 270:
// info.PickCenter = new int[3] {
// block.W / 2, // X中心
// block.L / 2, // Y中心
// block.H // Z坐标
// };
// break;
// }
// }
// ///
// /// 应用行程调整(规则6、7)
// ///
// private void ApplyTravelAdjustment(SuctionInfo info, int suctionType)
// {
// // 计算理论行程需求
// int requiredTravel = info.PickCenter[1];
// // 当超过最大允许行程时进行调整
// if (requiredTravel > YAxisMax)
// {
// // 计算吸盘尺寸
// int suctionSize = SuctionSizes[suctionType].y;
// // 计算调整后的抓取位置(尽量靠近中心)
// int adjustedPickY = info.PlaceCenter[1] > YAxisMax
// ? YAxisMax - suctionSize / 2 // 抓取远端
// : suctionSize / 2; // 抓取近端
// // 更新抓取中心并标记旋转
// info.PlaceCenter[1] = adjustedPickY;
// info.Rotation += 180;
// }
// }
// ///
// /// 应用旋转调整(180/270度)
// ///
// private void ApplyRotationAdjustment(SuctionInfo info, int rotation, Block block)
// {
// if (rotation == 180)
// {
// // Y轴镜像
// info.PickCenter[1] = block.L - info.PickCenter[1];
// info.PlaceCenter[1] = ContainerY - info.PlaceCenter[1];
// }
// else if (rotation == 270)
// {
// // X轴镜像
// info.PickCenter[0] = ContainerX - info.PickCenter[0];
// info.PlaceCenter[0] = ContainerX - info.PlaceCenter[0];
// }
// }
// ///
// /// 最终放置验证
// ///
// private bool ValidatePlacement(SuctionInfo info, List existing)
// {
// // 空间边界检查
// if (info.PlaceCenter[0] < 0 || info.PlaceCenter[0] > ContainerX) return false;
// if (info.PlaceCenter[1] < 0 || info.PlaceCenter[1] > YAxisMax) return false;
// if (info.PlaceCenter[2] > ContainerZ) return false;
// // 投影覆盖检查
// var projection = new Rectangle(
// info.PlaceCenter[0] - SuctionSizes[info.Rotation % 180 == 0 ? 0 : 1].x / 2,
// info.PlaceCenter[1] - SuctionSizes[info.Rotation % 180 == 0 ? 0 : 1].y / 2,
// info.PlaceCenter[0] + SuctionSizes[info.Rotation % 180 == 0 ? 0 : 1].x / 2,
// info.PlaceCenter[1] + SuctionSizes[info.Rotation % 180 == 0 ? 0 : 1].y / 2
// );
// // 检查是否完全在支撑面内
// return existing.All(b => !projection.Intersects(new Rectangle(
// b.X - SafetySpacing,
// b.Y - SafetySpacing,
// b.X + b.W + SafetySpacing,
// b.Y + b.L + SafetySpacing
// )));
// }
//}
//// 辅助类定义--------------------------------------------
//public class SupportSurface
//{
// public int X { get; set; }
// public int Y { get; set; }
// public int Z { get; set; }
// public int AvailableX { get; set; }
// public int AvailableY { get; set; }
//}
//public struct Point
//{
// public int X { get; }
// public int Y { get; }
// public Point(int x, int y) => (X, Y) = (x, y);
//}
//public class Rectangle
//{
// public int Left { get; }
// public int Top { get; }
// public int Right { get; }
// public int Bottom { get; }
// public Rectangle(int x1, int y1, int x2, int y2)
// {
// Left = Math.Min(x1, x2);
// Right = Math.Max(x1, x2);
// Top = Math.Min(y1, y2);
// Bottom = Math.Max(y1, y2);
// }
// public bool Intersects(Rectangle other)
// {
// return !(Right < other.Left ||
// Left > other.Right ||
// Bottom < other.Top ||
// Top > other.Bottom);
// }
//}
#endregion