using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WIDESEAWCS_DTO.PlacedBlockDTO; using WIDESEAWCS_IBasicInfoService; namespace WIDESEAWCS_BasicInfoService { public class PlaceBlockService2 { public const int SPACING = 5; /// /// 容器尺寸 /// public ContainerSize ContainerSize { get; private set; } /// /// 已放置货物 /// public List PlacedBlocks { get; private set; } private readonly PlacedBlock containerFloor; public PlaceBlockService2(ContainerSize containerSize, List? placedBlocks = null) { containerSize.Length = containerSize.Length + 2 * SPACING; containerSize.Width = containerSize.Width + 2 * SPACING; ContainerSize = containerSize; if (placedBlocks == null || placedBlocks.Count == 0) { PlacedBlocks = new List(); } else { PlacedBlocks = placedBlocks; } containerFloor = new PlacedBlock(new Point3D(SPACING, SPACING, 0), ContainerSize.Length - 2 * SPACING, ContainerSize.Width - 2 * SPACING, 0); } /// /// 主放置方法:尝试放置指定尺寸的货物 /// /// 货物长度(X轴方向) /// 货物宽度(Y轴方向) /// 货物高度(Z轴方向) /// /// 成功:返回可放置位置的左下前角Point3D坐标 /// 失败:返回null(尺寸无效或空间不足) /// public Point3D? PlaceBlock(int length, int width, int height) { if (!IsValidBlock(length, width, height)) return null; return FindStackablePosition(length, width, height); } /// /// 验证货物尺寸有效性 /// 校验规则: /// 1. 各维度尺寸必须大于等于50mm /// 2. 各维度尺寸不得超过容器对应维度(扣除间隔后) /// 3. 高度必须 <= 容器剩余高度 /// /// /// /// /// private bool IsValidBlock(int l, int w, int h) { return l > 0 && w > 0 && h > 0 && l <= ContainerSize.Length - 2 * SPACING && w <= ContainerSize.Width - 2 * SPACING && h < ContainerSize.Height; } /// /// 在现有货物顶部寻找叠放位置(堆叠模式) /// 叠放条件: /// - 支撑面积 >= 被支撑面面积的70% /// - 新货物完全位于支撑货物上方 /// - 满足间隔要求 /// /// 长度 /// 宽度 /// 高度 /// private Point3D? FindStackablePosition(int l, int w, int h) { // 生成候选支撑层(包含容器底部) var candidateLayers = PlacedBlocks .Select(b => b.Position.Z + b.Height) .Append(0) .Distinct() .OrderBy(z => z) .ToList(); foreach (var baseZ in candidateLayers) { if (baseZ + h > ContainerSize.Height) continue; // 获取当前层的支撑块(包含虚拟容器底部) var supports = GetSupportBlocks(baseZ); foreach (var support in supports) { // 计算实际接触面积 int overlapX = Math.Min(support.Position.X + support.Length, l) - Math.Max(support.Position.X, 0); int overlapY = Math.Min(support.Position.Y + support.Width, w) - Math.Max(support.Position.Y, 0); int contactArea = overlapX * overlapY; int blockArea = l * w; if (contactArea < blockArea * 0.7) continue; // 计算有效叠放区域(修正间隔逻辑) int xStart = support.Position.X; int yStart = support.Position.Y; // 容器底部支撑必须内缩间隔(即使尺寸相同) if (support == containerFloor) { xStart = support.Position.X; yStart = support.Position.Y; } int xEnd = support.Position.X + support.Length - l; int yEnd = support.Position.Y + support.Width - w; // 普通支撑块仅在尺寸不同时加间隔 if (support != containerFloor && (l != support.Length && w != support.Width)) { xStart += SPACING; yStart += SPACING; xEnd -= SPACING; yEnd -= SPACING; } // 最终容器边界约束 xEnd = Math.Min(xEnd, ContainerSize.Length - l - SPACING); yEnd = Math.Min(yEnd, ContainerSize.Width - w - SPACING); // 验证支撑面积 //int supportArea = support.Length * support.Width; //int requiredSupportArea = (int)(l * w * 0.7); // 支撑面积 >= 被支撑面面积的70% //if (supportArea < requiredSupportArea) continue; if (xStart > xEnd || yStart > yEnd) continue; // 优化搜索:优先角落位置 for (int y = yStart; y <= yEnd; y += 10) { for (int x = xStart; x <= xEnd; x += 10) { var candidate = new Point3D(x, y, baseZ); if (IsPositionValid(candidate, l, w, h)) { var placed = new PlacedBlock(candidate, l, w, h); //PlacedBlocks.Add(placed); return candidate; } } } } } return null; } /// /// 获取支撑当前货物的底层货物列表 /// 特殊处理:当baseZ=0时返回虚拟容器底部作为支撑 /// 支撑条件:货物底面与支撑货物顶面接触且Z坐标匹配 /// /// 支撑块高度 /// private IEnumerable GetSupportBlocks(int baseZ) { var blocks = PlacedBlocks .Where(b => b.Position.Z + b.Height == baseZ) .OrderByDescending(b => b.Length * b.Width).ToList(); // 当baseZ=0时添加容器底部支撑 if (baseZ == 0 && blocks.Count == 0) { return new List { containerFloor }; } return blocks; } private bool IsPositionValid(Point3D pos, int l, int w, int h) { // 容器边界校验(原有逻辑) if (pos.X + l > ContainerSize.Length || pos.Y + w > ContainerSize.Width) return false; // 碰撞检测(原有逻辑) var newBlock = new PlacedBlock(pos, l, w, h); foreach (var existing in PlacedBlocks) { if (existing.Intersects(newBlock)) return false; } // 新增支撑面积校验(需要与FindStackablePosition中的计算保持同步) if (pos.Z > 0) { var contactArea = GetContactArea(pos, l, w); if (contactArea < l * w * 0.7) return false; } return true; } // 新增接触面积计算方法 private int GetContactArea(Point3D pos, int l, int w) { return PlacedBlocks .Where(b => b.Position.Z + b.Height == pos.Z) .Sum(b => { int overlapX = Math.Min(b.Position.X + b.Length, pos.X + l) - Math.Max(b.Position.X, pos.X); int overlapY = Math.Min(b.Position.Y + b.Width, pos.Y + w) - Math.Max(b.Position.Y, pos.Y); return overlapX * overlapY; }); } } }