1
z8018
2025-06-10 e46aa927d231af83724683c7286d9db503e24cf7
ÏîÄ¿´úÂë/WCS/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/PlaceBlockService.cs
@@ -3,13 +3,76 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_DTO.PlacedBlockDTO;
using WIDESEAWCS_DTO.TaskInfo;
using WIDESEAWCS_IBasicInfoService;
namespace WIDESEAWCS_BasicInfoService
{
    /// <summary>
    /// è´§ç‰©æ”¾ç½®æœåŠ¡ï¼Œæä¾›é›†è£…ç®±å†…è´§ç‰©æ‘†æ”¾ä½ç½®è®¡ç®—åŠŸèƒ½
    /// </summary>
    /// <remarks>
    /// ä¸»è¦åŠŸèƒ½åŒ…æ‹¬ï¼š <br/>
    /// 1. æ ¹æ®è´§ç‰©å°ºå¯¸è‡ªåŠ¨è®¡ç®—æœ€ä¼˜æ‘†æ”¾ä½ç½® <br/>
    /// 2. æ”¯æŒæ¨ªå‘/纵向两种摆放方式 <br/>
    /// 3. è€ƒè™‘吸盘尺寸、容器边界等物理限制 <br/>
    /// 4. æä¾›ä»»åŠ¡ä½ç½®åæ ‡è½¬æ¢åŠŸèƒ½ <br/>
    ///  <br/>
    /// æ ¸å¿ƒå‚数: <br/>
    /// - SPACING: è´§ç‰©é—´æœ€å°é—´è· <br/>
    /// - MaxRotateLength: æœ€å¤§æ—‹è½¬é•¿åº¦é™åˆ¶ <br/>
    /// - MaxY/MinY: Y轴坐标限制 <br/>
    /// - SuctionLength/Width: å¸ç›˜å°ºå¯¸å‚æ•°
    /// </remarks>
    public class PlaceBlockService
    {
        public const int SPACING = 5;
        /// <summary>
        /// èŽ·å–é…ç½®æ–‡ä»¶ä¸­"Spacing"键对应的整数值,表示间距值
        /// </summary>
        public static int SPACING = AppSettings.GetValue("Spacing").ObjToInt();
        /// <summary>
        /// èŽ·å–æˆ–è®¾ç½®æœ€å¤§æ—‹è½¬é•¿åº¦é…ç½®å€¼
        /// </summary>
        public static int MaxRotateLength = AppSettings.GetValue("MaxRotateLength").ObjToInt();
        /// <summary>
        /// æœ€å¤§Y坐标限制(毫米)
        /// </summary>
        public const int MaxY = 600;
        /// <summary>
        /// æœ€å°æ¨ªå‘Y坐标限制(毫米)
        /// </summary>
        public static int MinY = AppSettings.GetValue("MinY").ObjToInt();
        /// <summary>
        /// æ—‹è½¬æŠ“取Y轴偏移量(毫米)
        /// </summary>
        public static int RotateYOffset = AppSettings.GetValue("RotateYOffset").ObjToInt();
        /// <summary>
        /// å¸ç›˜æ¨ªå‘长度
        /// </summary>
        public const int SuctionLengthH = 920;
        /// <summary>
        /// å¸ç›˜æ¨ªå‘宽度
        /// </summary>
        public const int SuctionWidthH = 530;
        /// <summary>
        /// å¸ç›˜çºµå‘长度
        /// </summary>
        public const int SuctionLengthZ = 530;
        /// <summary>
        /// å¸ç›˜çºµå‘宽度
        /// </summary>
        public const int SuctionWidthZ = 130;
        /// <summary>
        /// å®¹å™¨å°ºå¯¸
@@ -21,10 +84,25 @@
        /// </summary>
        public List<PlacedBlock> PlacedBlocks { get; private set; }
        /// <summary>
        /// å®¹å™¨åœ°æ¿çš„æ”¾ç½®å—实例
        /// </summary>
        private readonly PlacedBlock containerFloor;
        /// <summary>
        /// åˆå§‹åŒ–放置区块服务
        /// </summary>
        /// <param name="containerSize">容器尺寸</param>
        /// <param name="placedBlocks">已放置区块列表,可选参数</param>
        /// <remarks>
        /// æž„造函数会初始化容器尺寸和已放置区块列表。
        /// å¦‚果未提供placedBlocks或列表为空,将创建新的空列表。
        /// åŒæ—¶ä¼šåˆ›å»ºè¡¨ç¤ºå®¹å™¨åº•部的PlacedBlock对象。
        /// </remarks>
        public PlaceBlockService(ContainerSize containerSize, List<PlacedBlock>? placedBlocks = null)
        {
            containerSize.Length = containerSize.Length;
            containerSize.Width = containerSize.Width;
            ContainerSize = containerSize;
            if (placedBlocks == null || placedBlocks.Count == 0)
            {
@@ -34,22 +112,33 @@
            {
                PlacedBlocks = placedBlocks;
            }
            containerFloor = new PlacedBlock(new Point3D(0, 0, 0), ContainerSize.Length, ContainerSize.Width, 0);
            containerFloor = new PlacedBlock(new Point3D(SPACING, SPACING, 0), ContainerSize.Length - 2 * SPACING, ContainerSize.Width - 2 * SPACING, 0);
            //containerFloor = new PlacedBlock(new Point3D(SPACING, SPACING, 0), ContainerSize.Length - 2 * SPACING, ContainerSize.Width - 2 * SPACING, 0);
        }
        /// <summary>
        /// ä¸»æ”¾ç½®æ–¹æ³•:尝试放置指定尺寸的货物
        /// æ ¹æ®ç»™å®šçš„长宽高寻找合适的放置位置
        /// </summary>
        /// <param name="length">货物长度(X轴方向)</param>
        /// <param name="width">货物宽度(Y轴方向)</param>
        /// <param name="height">货物高度(Z轴方向)</param>
        /// <returns>
        /// æˆåŠŸï¼šè¿”å›žå¯æ”¾ç½®ä½ç½®çš„å·¦ä¸‹å‰è§’Point3D坐标
        /// å¤±è´¥ï¼šè¿”回null(尺寸无效或空间不足)
        /// </returns>
        /// <param name="length">块的长度</param>
        /// <param name="width">块的宽度</param>
        /// <param name="height">块的高度</param>
        /// <returns>可放置的3D坐标点,若无法放置则返回null</returns>
        /// <remarks>
        /// æ–¹æ³•会自动处理长宽参数,确保length >= width
        /// åœ¨æ”¾ç½®å‰ä¼šå…ˆæ£€æŸ¥å—的有效性
        /// </remarks>
        public Point3D? PlaceBlock(int length, int width, int height)
        {
            int tempLength = length;
            int tempWidth = width;
            if (length < width)
            {
                length = tempWidth;
                width = tempLength;
            }
            if (!IsValidBlock(length, width, height))
                return null;
@@ -57,35 +146,68 @@
        }
        /// <summary>
        /// éªŒè¯è´§ç‰©å°ºå¯¸æœ‰æ•ˆæ€§
        /// æ ¡éªŒè§„则:
        /// 1. å„维度尺寸必须大于等于50mm
        /// 2. å„维度尺寸不得超过容器对应维度(扣除间隔后)
        /// 3. é«˜åº¦å¿…é¡» <= å®¹å™¨å‰©ä½™é«˜åº¦
        /// æ ¹æ®ç»™å®šçš„长、宽、高和边缘值放置一个块,并返回可放置的位置
        /// </summary>
        /// <param name="l"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <returns></returns>
        private bool IsValidBlock(int l, int w, int h)
        /// <param name="length">块的长度</param>
        /// <param name="width">块的宽度</param>
        /// <param name="height">块的高度</param>
        /// <param name="edge">边缘值</param>
        /// <returns>可放置的位置信息,若块无效则返回null</returns>
        public TaskPosition? PlaceBlock(int length, int width, int height, int edge)
        {
            return l > 0 && w > 0 && h > 0 &&
                   l <= ContainerSize.Length - 2 * SPACING &&
                   w <= ContainerSize.Width - 2 * SPACING &&
                   h < ContainerSize.Height;
            int tempLength = length;
            int tempWidth = width;
            if (length < width)
            {
                length = tempWidth;
                width = tempLength;
            }
            if (!IsValidBlock(length, width, height))
                return null;
            return FindStackablePosition(length, width, height, edge);
        }
        /// <summary>
        /// åœ¨çŽ°æœ‰è´§ç‰©é¡¶éƒ¨å¯»æ‰¾å æ”¾ä½ç½®ï¼ˆå †å æ¨¡å¼ï¼‰
        /// å æ”¾æ¡ä»¶ï¼š
        /// - æ”¯æ’‘面积 >= è¢«æ”¯æ’‘面面积的70%
        /// - æ–°è´§ç‰©å®Œå…¨ä½äºŽæ”¯æ’‘货物上方
        /// - æ»¡è¶³é—´éš”要求
        /// æ£€æŸ¥ç»™å®šçš„长宽高是否构成有效的块体尺寸
        /// </summary>
        /// <param name="l">长度</param>
        /// <param name="w">宽度</param>
        /// <param name="h">高度</param>
        /// <returns></returns>
        /// <returns>如果尺寸有效返回true,否则返回false</returns>
        /// <remarks>
        /// æœ‰æ•ˆå—体需满足:长宽高都大于0,且长宽不超过容器尺寸减去两倍间距,高度不超过容器高度
        /// </remarks>
        private bool IsValidBlock(int l, int w, int h)
        {
            return l > 0 && w > 0 && h > 0 &&
                   l <= ContainerSize.Length &&
                   w <= ContainerSize.Width &&
                   h < ContainerSize.Height;
        }
        //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;
        //}
        /// <summary>
        /// åœ¨å®¹å™¨ä¸­æŸ¥æ‰¾å¯æ”¾ç½®æŒ‡å®šå°ºå¯¸å—体的有效位置
        /// </summary>
        /// <param name="l">块体长度</param>
        /// <param name="w">块体宽度</param>
        /// <param name="h">块体高度</param>
        /// <returns>可放置位置的3D坐标点,若无合适位置则返回null</returns>
        /// <remarks>
        /// 1. é€šè¿‡åˆ†æžå·²æ”¾ç½®å—体生成候选支撑层
        /// 2. è€ƒè™‘容器底部和支撑块的不同间隔规则
        /// 3. ä¼˜å…ˆæ£€æŸ¥è§’落位置以提高搜索效率
        /// </remarks>
        private Point3D? FindStackablePosition(int l, int w, int h)
        {
            // ç”Ÿæˆå€™é€‰æ”¯æ’‘层(包含容器底部)
@@ -133,23 +255,18 @@
                    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)
                    {
                        for (int x = xStart; x <= xEnd; x += 10)
                        for (int y = yStart; y <= yEnd; y += 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);
                                //PlacedBlocks.Add(placed);
                                return candidate;
                            }
                        }
@@ -160,81 +277,122 @@
        }
        /// <summary>
        /// èŽ·å–æ”¯æ’‘å½“å‰è´§ç‰©çš„åº•å±‚è´§ç‰©åˆ—è¡¨
        /// ç‰¹æ®Šå¤„理:当baseZ=0时返回虚拟容器底部作为支撑
        /// æ”¯æ’‘条件:货物底面与支撑货物顶面接触且Z坐标匹配
        /// åœ¨å®¹å™¨ä¸­æŸ¥æ‰¾å¯å †å ä½ç½®
        /// </summary>
        /// <param name="baseZ">支撑块高度</param>
        /// <returns></returns>
        /// <param name="l">物品长度</param>
        /// <param name="w">物品宽度</param>
        /// <param name="h">物品高度</param>
        /// <param name="edge">边缘类型</param>
        /// <returns>返回找到的有效任务位置,若找不到则返回null</returns>
        /// <remarks>
        /// 1. ç”Ÿæˆå€™é€‰æ”¯æ’‘层(包含容器底部)
        /// 2. éåŽ†æ¯å±‚æ”¯æ’‘å—è®¡ç®—æœ‰æ•ˆå æ”¾åŒºåŸŸ
        /// 3. è€ƒè™‘容器边界约束和间隔规则
        /// 4. ä¼˜å…ˆæ£€æŸ¥è§’落位置以提高搜索效率
        /// </remarks>
        private TaskPosition? FindStackablePosition(int l, int w, int h, int edge)
        {
            // ç”Ÿæˆå€™é€‰æ”¯æ’‘层(包含容器底部)
            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 xStart = support.Position.X;
                    int yStart = support.Position.Y;
                    int xEnd = support.Position.X + support.Length - l;
                    int yEnd = support.Position.Y + support.Width - w;
                    // æœ€ç»ˆå®¹å™¨è¾¹ç•Œçº¦æŸ
                    xEnd = Math.Min(xEnd, ContainerSize.Length - l);
                    yEnd = Math.Min(yEnd, ContainerSize.Width - w);
                    if (xStart > xEnd || yStart > yEnd) continue;
                    // ä¼˜åŒ–搜索:优先角落位置
                    for (int x = xStart; x <= xEnd; x += 10)
                    {
                        for (int y = yStart; y <= yEnd; y += 10)
                        {
                            var candidate = new Point3D(x, y, baseZ);
                            if (IsPositionValid(candidate, l, w, h))
                            {
                                TaskPosition taskPosition = GetTaskPosition(candidate, l, w, h, edge);
                                if (IsPositionValid(taskPosition))
                                {
                                    return taskPosition;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }
        /// <summary>
        /// èŽ·å–æŒ‡å®šé«˜åº¦å±‚çš„æ”¯æ’‘å—
        /// </summary>
        /// <param name="baseZ">需要支撑的高度层</param>
        /// <returns>按面积从大到小排序的支撑块集合,当baseZ=0且无支撑块时返回容器底部</returns>
        private IEnumerable<PlacedBlock> GetSupportBlocks(int baseZ)
        {
            var blocks = PlacedBlocks
                .Where(b => b.Position.Z + b.Height == baseZ)
                .OrderByDescending(b => b.Length * b.Width);
                .OrderBy(b => b.Position.X)
                .ThenBy(b => b.Position.Y)
                /*.OrderByDescending(b => b.Length * b.Width)*/
                .ToList();
            // å½“baseZ=0时添加容器底部支撑
            if (baseZ == 0 && !blocks.Any())
            if (baseZ == 0 && blocks.Count == 0)
            {
                return new List<PlacedBlock> { containerFloor };
            }
            return blocks;
            //// èŽ·å–æ‰€æœ‰åœ¨ baseZ é«˜åº¦çš„æ”¯æ’‘块
            //var blocks = PlacedBlocks
            //    .Where(b => b.Position.Z + b.Height == baseZ)
            //    .ToList();
            //// å½“ baseZ=0 æ—¶æ·»åŠ å®¹å™¨åº•éƒ¨æ”¯æ’‘
            //if (baseZ == 0 && !blocks.Any())
            //{
            //    return new List<PlacedBlock> { containerFloor };
            //}
            //// è®¡ç®—整体平面
            //if (blocks.Any())
            //{
            //    int minX = blocks.Min(b => b.Position.X);
            //    int minY = blocks.Min(b => b.Position.Y);
            //    int maxX = blocks.Max(b => b.Position.X + b.Length);
            //    int maxY = blocks.Max(b => b.Position.Y + b.Width);
            //    var overallSupport = new PlacedBlock(
            //        new Point3D(minX, minY, baseZ),
            //        maxX - minX,
            //        maxY - minY,
            //        0
            //    );
            //    return new List<PlacedBlock> { overallSupport };
            //}
            //return blocks;
        }
        /// <summary>
        /// éªŒè¯æŒ‡å®šä½ç½®æ˜¯å¦åˆæ³•
        /// æ ¡éªŒå†…容:
        /// 1. è¾¹ç•Œæ¡ä»¶ï¼šè´§ç‰©ä¸å¾—超出容器有效空间
        /// 2. ç¢°æ’žæ£€æµ‹ï¼šä¸Žå·²æ”¾ç½®è´§ç‰©æ— ç©ºé—´é‡å 
        /// 3. é—´éš”要求:保持最小间隔(SPACING常量)
        /// æ£€æŸ¥æŒ‡å®šä½ç½®æ˜¯å¦æœ‰æ•ˆï¼Œå³è¯¥ä½ç½®æ˜¯å¦å¯ä»¥æ”¾ç½®æŒ‡å®šå°ºå¯¸çš„块体
        /// </summary>
        /// <param name="pos">坐标</param>
        /// <param name="l">长度</param>
        /// <param name="w">宽度</param>
        /// <param name="h">高度</param>
        /// <returns></returns>
        /// <param name="pos">要检查的位置坐标</param>
        /// <param name="l">块体长度</param>
        /// <param name="w">块体宽度</param>
        /// <param name="h">块体高度</param>
        /// <returns>如果位置有效且不与其他已放置块体重叠则返回true,否则返回false</returns>
        /// <remarks>
        /// æ£€æŸ¥æ¡ä»¶åŒ…括:
        /// 1. æ˜¯å¦è¶…出容器尺寸限制
        /// 2. X坐标是否超过1600限制
        /// 3. å½“X坐标超过MaxY且长度超过MaxRotateLength时的限制
        /// 4. æ˜¯å¦ä¸Žå·²æ”¾ç½®çš„块体发生重叠(考虑SPACING间距)
        /// </remarks>
        private bool IsPositionValid(Point3D pos, int l, int w, int h)
        {
            // è¾¹ç•Œæ£€æŸ¥ï¼ˆå«å®¹å™¨è¾¹ç¼˜é—´éš”)
            if (pos.X < SPACING ||
                pos.Y < SPACING ||
                pos.X + l > ContainerSize.Length - SPACING ||
                pos.Y + w > ContainerSize.Width - SPACING)
            if (pos.X + l > ContainerSize.Length ||
                pos.Y + w > ContainerSize.Width)
                return false;
            // ä¸‰ç»´ç¢°æ’žæ£€æµ‹
            if (pos.X > 1600)
                return false;
            if (pos.X > MaxY && l > MaxRotateLength) return false;
            var newBlock = new PlacedBlock(pos, l, w, h);
            return !PlacedBlocks.Any(existing =>
            {
@@ -250,74 +408,205 @@
                return xOverlap && yOverlap && zOverlap;
            });
        }
    }
    /// <summary>
    /// ä¸‰ç»´åæ ‡ç»“构体
    /// è¡¨ç¤ºè´§ç‰©æ”¾ç½®ä½ç½®çš„左下前角坐标(X,Y,Z)
    /// åæ ‡ç³»è¯´æ˜Žï¼š
    /// - X轴:沿容器长度方向
    /// - Y轴:沿容器宽度方向
    /// - Z轴:垂直方向(高度)
    /// </summary>
    public struct Point3D
    {
        /// <summary>X轴坐标(毫米)</summary>
        public int X { get; }
        //private bool IsPositionValid(Point3D pos, int l, int w, int h)
        //{
        //    // è¾¹ç•Œæ£€æŸ¥ï¼ˆå«å®¹å™¨è¾¹ç¼˜é—´éš”)
        //    if (pos.X < SPACING ||
        //        pos.Y < SPACING ||
        //        pos.X + l > ContainerSize.Length - SPACING ||
        //        pos.Y + w > ContainerSize.Width - SPACING)
        //        return false;
        /// <summary>Y轴坐标(毫米)</summary>
        public int Y { get; }
        //    if (pos.X > 1600)
        //        return false;
        /// <summary>Z轴坐标(毫米)</summary>
        public int Z { get; }
        //    if (pos.X > MaxY && l > MaxRotateLength) return false;
        public Point3D(int x, int y, int z)
        //    // ä¸‰ç»´ç¢°æ’žæ£€æµ‹
        //    var newBlock = new PlacedBlock(pos, l, w, h);
        //    return !PlacedBlocks.Any(existing =>
        //    {
        //        bool xOverlap = newBlock.Position.X < existing.Position.X + existing.Length + SPACING &&
        //                      newBlock.Position.X + newBlock.Length + SPACING > existing.Position.X;
        //        bool yOverlap = newBlock.Position.Y < existing.Position.Y + existing.Width + SPACING &&
        //                      newBlock.Position.Y + newBlock.Width + SPACING > existing.Position.Y;
        //        bool zOverlap = newBlock.Position.Z < existing.Position.Z + existing.Height &&
        //                      newBlock.Position.Z + h > existing.Position.Z;
        //        return xOverlap && yOverlap && zOverlap;
        //    });
        //}
        /// <summary>
        /// æ£€æŸ¥ä»»åŠ¡ä½ç½®æ˜¯å¦æœ‰æ•ˆ
        /// </summary>
        /// <param name="pos">要检查的任务位置</param>
        /// <returns>如果Y轴坐标在有效范围内返回true,否则返回false</returns>
        private bool IsPositionValid(TaskPosition pos)
        {
            X = x;
            Y = y;
            Z = z;
            return pos.PutPositionY <= MaxY && pos.PutPositionY >= 0 && pos.TakePositionY >= 0;
        }
    }
    /// <summary>
    /// å·²æ”¾ç½®è´§ç‰©ä¿¡æ¯ç±»
    /// è®°å½•每个货物的位置和尺寸信息
    /// åæ ‡ç³»è¯´æ˜Žï¼šä½ç½®ç‚¹ä¸ºè´§ç‰©çš„左下前角坐标
    /// </summary>
    public class PlacedBlock
    {
        /// <summary>货物左下前角坐标</summary>
        public Point3D Position { get; }
        /// <summary>沿X轴方向长度(毫米)</summary>
        public int Length { get; }
        /// <summary>沿Y轴方向宽度(毫米)</summary>
        public int Width { get; }
        /// <summary>沿Z轴方向高度(毫米)</summary>
        public int Height { get; }
        public PlacedBlock(Point3D position, int length, int width, int height)
        /// <summary>
        /// æ ¹æ®ç»™å®šçš„三维坐标和尺寸参数计算任务位置信息
        /// </summary>
        /// <param name="point3D">起始三维坐标点</param>
        /// <param name="length">物体长度</param>
        /// <param name="width">物体宽度</param>
        /// <param name="height">物体高度</param>
        /// <param name="edge">边缘标识(0/1)</param>
        /// <returns>包含取放货位置信息的TaskPosition对象</returns>
        /// <remarks>
        /// è¯¥æ–¹æ³•根据物体尺寸自动选择单吸盘或双吸盘模式,
        /// å¹¶è®¡ç®—吸盘中心点位置,同时处理边界条件限制。
        /// æ¨ªå‘放置时最小Y坐标为155,纵向时为350,最大Y坐标为700。
        /// </remarks>
        public TaskPosition GetTaskPosition(Point3D point3D, int length, int width, int height, int edge)
        {
            Position = position;
            Length = length;
            Width = width;
            Height = height;
        }
    }
            //放货位置板材中心点
            Point3D putCenter = new Point3D(point3D.X + length / 2, point3D.Y + width / 2, point3D.Z + height / 2);
    public struct ContainerSize
    {
        public int Length { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
            //取货位置板材中心点
            Point3D takeCenter = new Point3D(length / 2, width / 2, height / 2);
        public ContainerSize(int length, int width, int height)
        {
            Length = length;
            Width = width;
            Height = height;
            //吸盘长530 é—´éš”660  æœ€å¤§920 å¸ç›˜å®½130
            int positionR = 1;
            int takePositionX = 0;
            int takePositionY = 0;
            int takePositionZ = 0;
            int putPositionX = 0;
            int putPositionY = 0;
            int putPositionZ = 0;
            //1.如果长度大于920,宽度大于等于300,则可以使用双吸盘横向吸取
            if (length > 920) //横向双吸
            {
                //吸盘尺寸
                Point3D deviceCenter = new Point3D(530 / 2, 920 / 2, 0);
                positionR = 1;
                takePositionX = (takeCenter.Y - deviceCenter.X);
                takePositionY = (takeCenter.X - deviceCenter.Y);
                takePositionZ = 10;
                putPositionX = (putCenter.Y - deviceCenter.X);
                putPositionY = (putCenter.X - deviceCenter.Y);
                putPositionZ = point3D.Z;
            }
            else//横向单吸
            {
                //吸盘尺寸
                Point3D deviceCenter = new Point3D(530 / 2, 130 / 2, 0);
                positionR = 1;
                takePositionX = (takeCenter.Y - deviceCenter.X);
                takePositionY = (takeCenter.X - deviceCenter.Y);
                takePositionZ = 10;
                putPositionX = (putCenter.Y - deviceCenter.X);
                putPositionY = (putCenter.X - deviceCenter.Y);
                putPositionZ = point3D.Z;
            }
            if (takePositionY <= MinY)
            {
                takePositionY = 0;
                putPositionY = point3D.X + MinY;
            }
            else
            {
                takePositionY -= MinY;
            }
            if (putPositionY > MaxY)
            {
                int moreY = putPositionY - MaxY;
                if (takePositionY - moreY > 0)
                {
                    takePositionY -= moreY;
                    putPositionY = MaxY;
                }
                else if (Math.Abs(takePositionY - moreY) < SPACING)
                {
                    takePositionY = 0;
                    putPositionY = Math.Abs(takePositionY - moreY) + MinY;
                }
                else
                {
                    int count = PlacedBlocks.Where(x => x.Position.Y == 10).Count();
                    putPositionY = point3D.X - 920 + 130 + RotateYOffset;
                    takePositionY = length - MinY - 130 - RotateYOffset;
                    if (putPositionY < 0 && takePositionY + putPositionY >= 0)
                    {
                        takePositionY += putPositionY;
                        putPositionY = 0;
                    }
                    positionR = 2;
                }
            }
            if (positionR == 2 && edge == 0)
            {
                takePositionX = width - 530;
                putPositionX = point3D.Y;
            }
            else if (positionR == 2 && edge == 1)
            {
                takePositionX = 0;
                putPositionX = point3D.Y + width - 530;
            }
            else if (positionR == 1 && edge == 1)
            {
                if(width > ContainerSize.Width)
                {
                    takePositionX = 0;
                    putPositionX = point3D.Y;
                }
                else
                {
                    takePositionX = width - 530;
                    putPositionX = point3D.Y + (width - 530);
                }
            }
            else if (positionR == 1 && edge == 0)
            {
                if (putPositionX < 0)
                {
                    takePositionX = 0;
                    putPositionX = point3D.Y;
                }
            }
            if (takePositionY < 0 && Math.Abs(takePositionY) < SPACING)
            {
                takePositionY = 0;
            }
            TaskPosition taskPosition = new TaskPosition()
            {
                PositionR = positionR,
                TakePositionX = takePositionX,
                TakePositionY = takePositionY,
                TakePositionZ = takePositionZ,
                PutPositionX = putPositionX,
                PutPositionY = putPositionY,
                PutPositionZ = putPositionZ,
                TakeCenterPositionX = takeCenter.X,
                TakeCenterPositionY = takeCenter.Y,
                TakeCenterPositionZ = takeCenter.Z,
                PutCenterPositionX = putCenter.X,
                PutCenterPositionY = putCenter.Y,
                PutCenterPositionZ = putCenter.Z,
                PositionX = point3D.X,
                PositionY = point3D.Y,
                PositionZ = point3D.Z
            };
            return taskPosition;
        }
    }
}