Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2817-BinPackingSpeedup/HeuristicLab.Problems.BinPacking/3.3/3D/BinPacking3D.cs @ 15488

Last change on this file since 15488 was 15488, checked in by rhanghof, 6 years ago

#2817:

  • Added line projection based bin packing
  • Added residual spaces to the view
File size: 14.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Joseph Helm and Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
26using HeuristicLab.Core;
27using HeuristicLab.Common;
28using HeuristicLab.Problems.BinPacking;
29using HeuristicLab.Problems.BinPacking3D.Geometry;
30using HeuristicLab.Collections;
31
32namespace HeuristicLab.Problems.BinPacking3D {
33  [Item("BinPacking3D", "Represents a single-bin packing for a 3D bin-packing problem.")]
34  [StorableClass]
35  public class BinPacking3D : BinPacking<PackingPosition, PackingShape, PackingItem> {
36
37    [Storable]
38    public Dictionary<PackingPosition, Tuple<int, int, int>> ResidualSpace { get; set; }
39
40
41
42
43    public BinPacking3D(PackingShape binShape)
44      : base(binShape) {
45      ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
46     
47      ExtremePoints.Add(binShape.Origin);
48      ResidualSpace.Add(binShape.Origin, new Tuple<int, int, int>(BinShape.Width, BinShape.Height, BinShape.Depth));
49
50//      AddExtremePoint(binShape.Origin);
51    }
52    [StorableConstructor]
53    protected BinPacking3D(bool deserializing) : base(deserializing) { }
54    protected BinPacking3D(BinPacking3D original, Cloner cloner)
55      : base(original, cloner) {
56      this.ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
57      foreach (var o in original.ResidualSpace)
58        this.ResidualSpace.Add(cloner.Clone(o.Key), Tuple.Create(o.Value.Item1, o.Value.Item2, o.Value.Item3));
59    }
60    public override IDeepCloneable Clone(Cloner cloner) {
61      return new BinPacking3D(this, cloner);
62    }
63
64
65    [StorableHook(HookType.AfterDeserialization)]
66    private void AfterDeserialization() {
67      // BackwardsCompatibility3.3
68      #region Backwards compatible code, remove with 3.4
69      if (ResidualSpace == null)
70        ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
71      #endregion
72    }
73
74
75
76
77    /// <summary>
78    /// Puts a given item into the bin packing at the given position.
79    /// </summary>
80    /// <param name="itemID">Offset in the internal item array</param>
81    /// <param name="item">Item</param>
82    /// <param name="position">Position of the item in the bin packing</param>
83    public override void PackItem(int itemID, PackingItem item, PackingPosition position) {
84      Items[itemID] = item;
85      Positions[itemID] = position;
86      ExtremePoints.Remove(position);
87      ResidualSpace.Remove(position);
88    }
89
90    /*
91    /// <summary>
92    /// Updates the extreme points of the bin
93    /// </summary>
94    /// <param name="item"></param>
95    /// <param name="position"></param>
96    /// <param name="stackingConstraints"></param>
97    public void UpdateExtremePoints(PackingItem item, PackingPosition position, bool stackingConstraints) {
98      if (stackingConstraints) {
99        UpdateExtremePointsWithStackingConstriants(item, position);
100      } else {
101        UpdateExtremePointsWithoutStackingConstriants(item, position);
102      }
103    }*/
104
105
106      /*
107    /// <summary>
108    /// Updates the extreme points of the bin.
109    /// As there is no need to project the extreme points to the next side of an item, the extreme points are only generated for the current item.
110    /// </summary>
111    /// <param name="item"></param>
112    /// <param name="position"></param>
113    private void UpdateExtremePointsWithStackingConstriants(PackingItem newItem, PackingPosition position) {
114      int newWidth = position.Rotated ? newItem.Depth : newItem.Width;
115      int newDepth = position.Rotated ? newItem.Width : newItem.Depth;
116      var ep1 = new PackingPosition(position.AssignedBin, position.X + newWidth, position.Y, position.Z);
117      var ep2 = new PackingPosition(position.AssignedBin, position.X, position.Y + newItem.Height, position.Z);
118      var ep3 = new PackingPosition(position.AssignedBin, position.X, position.Y, position.Z + newDepth);
119      AddExtremePoint(ep1);
120      AddExtremePoint(ep2);
121      AddExtremePoint(ep3);
122    }*/
123
124     
125
126    #region Position feasability
127
128    /// <summary>
129    /// In this case feasability is defined as following:
130    /// 1. the point is supported by something;
131    /// 2. the item does not collide with another already packed item
132    /// </summary>
133    /// <param name="item"></param>
134    /// <param name="position"></param>
135    /// <param name="stackingConstraints"></param>
136    /// <returns></returns>
137    public override bool IsPositionFeasible(PackingItem item, PackingPosition position, bool stackingConstraints) {
138      //var b1 = CheckItemDimensions(item, position);
139      var b2 = ItemCanBePlaced(item, position);
140      var b3 = CheckStackingConstraints(item, position, stackingConstraints);
141
142      return b2 && b3;
143    }
144
145    /// <summary>
146    /// Returns true if a given item can be placed in the current bin
147    /// </summary>
148    /// <param name="givenItem"></param>
149    /// <param name="givenItemPosition"></param>
150    /// <returns></returns>
151    private bool ItemCanBePlaced(PackingItem givenItem, PackingPosition givenItemPosition) {
152      var width = givenItemPosition.Rotated ? givenItem.Depth : givenItem.Width;
153      var depth = givenItemPosition.Rotated ? givenItem.Width : givenItem.Depth;
154      // Check if the boundings of the bin would injured
155      if (givenItemPosition.X + width > BinShape.Width ||
156          givenItemPosition.Y + givenItem.Height > BinShape.Height ||
157          givenItemPosition.Z + depth > BinShape.Depth) {
158        return false;
159      }
160
161      //if the given item collides with any other item, it can not be placed
162      foreach (var item in Items) {
163        if (ItemsCollides(new Tuple<PackingPosition, PackingItem>(Positions[item.Key], item.Value),
164                          new Tuple<PackingPosition, PackingItem>(givenItemPosition, givenItem))) {
165          return false;
166        }
167      }
168      return true;
169    }
170
171    /// <summary>
172    /// Checks if two given items in a space collides
173    /// </summary>
174    /// <param name="t1"></param>
175    /// <param name="t2"></param>
176    /// <returns></returns>
177    private bool ItemsCollides(Tuple<PackingPosition, PackingItem> t1, Tuple<PackingPosition, PackingItem> t2) {
178      var position1 = t1.Item1;
179      var item1 = t1.Item2;
180      var position2 = t2.Item1;
181      var item2 = t2.Item2;
182      var cx = (position2.X == position1.X) || (position2.X < position1.X && position2.X + item2.Width > position1.X) || (position2.X > position1.X && position1.X + item1.Width > position2.X);
183      var cy = (position2.Y == position1.Y) || (position2.Y < position1.Y && position2.Y + item2.Height > position1.Y) || (position2.Y > position1.Y && position1.Y + item1.Height > position2.Y);
184      var cz = (position2.Z == position1.Z) || (position2.Z < position1.Z && position2.Z + item2.Depth > position1.Z) || (position2.Z > position1.Z && position1.Z + item1.Depth > position2.Z);
185      return cx && cy && cz;
186    }
187
188    /// <summary>
189    /// Checks the stacking constraints. This method depends that the given item can be placed at this position
190    /// </summary>
191    /// <param name="item"></param>
192    /// <param name="position"></param>
193    /// <param name="stackingConstraints"></param>
194    /// <returns></returns>
195    private bool CheckStackingConstraints(PackingItem item, PackingPosition position, bool stackingConstraints) {
196      if (position.Y == 0 || !stackingConstraints && HasOnePointWithAnItemBelow(item, position)) {
197        return true;
198      }
199
200      return IsStaticStable(item, position) && IsWeightSupported(item, position);
201    }
202
203    /// <summary>
204    /// Checks if a given item has any point lieing on another item.
205    /// </summary>
206    /// <param name="item"></param>
207    /// <param name="position"></param>
208    /// <returns></returns>
209    private bool HasOnePointWithAnItemBelow(PackingItem item, PackingPosition position) {
210      bool p1, p2, p3, p4;
211      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
212
213      return p1 || p2 || p3 || p4;
214    }
215
216    /// <summary>
217    /// Checks if a given item is static stable.
218    /// A item is static stable if all edges have an object below.
219    /// </summary>
220    /// <param name="item"></param>
221    /// <param name="position"></param>
222    /// <returns></returns>
223    public override bool IsStaticStable(PackingItem item, PackingPosition position) {
224      bool p1, p2, p3, p4;
225      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
226      return p1 && p2 && p3 && p4;
227    }
228
229    /// <summary>
230    /// This method sets the out parameters p1 ... p4 if the point lies on another item.
231    /// p1 ... p3 represents one point on the bottom side of an given item.
232    /// +---------+
233    /// |p1     p2|
234    /// |         |
235    /// |p4     p3|
236    /// +---------+
237    /// </summary>
238    /// <param name="item">Given item</param>
239    /// <param name="position">Given item position</param>
240    /// <param name="p1"></param>
241    /// <param name="p2"></param>
242    /// <param name="p3"></param>
243    /// <param name="p4"></param>
244    private void PointsLiesOnAnItem(PackingItem item, PackingPosition position, out bool p1, out bool p2, out bool p3, out bool p4) {
245      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
246      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
247      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
248      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
249
250      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
251
252      p1 = itemsP1.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z < x.Item1.Z + x.Item2.Depth).Any();
253      p2 = itemsP2.Where(x => position.X + item.Width > x.Item1.X && position.Z < x.Item1.Z + x.Item2.Depth).Any();
254      p3 = itemsP3.Where(x => position.X + item.Width > x.Item1.X && position.Z + item.Depth > x.Item1.Z).Any();
255      p4 = itemsP4.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z + item.Depth > x.Item1.Z).Any();
256    }
257
258    /// <summary>
259    /// This method returns a collection for the out parameters itemsP1 ... itemsP4 with the items below
260    /// itemsP1 ... itemsP4 represents one point on the bottom side of an given item.
261    /// +---------+
262    /// |p1     p2|
263    /// |         |
264    /// |p4     p3|
265    /// +---------+
266    /// </summary>
267    /// <param name="item"></param>
268    /// <param name="position"></param>
269    /// <param name="itemsP1"></param>
270    /// <param name="itemsP2"></param>
271    /// <param name="itemsP3"></param>
272    /// <param name="itemsP4"></param>
273    private void GetItemsUnderItemWithContact(PackingItem item, PackingPosition position,
274                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1,
275                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2,
276                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3,
277                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4) {
278      itemsP1 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z, false));
279      itemsP2 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z, false));
280      itemsP3 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z + item.Depth - 1, false));
281      itemsP4 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z + item.Depth - 1, false));
282
283    }
284
285    /// <summary>
286    /// Returns a collection of items which are below a given point.
287    /// The top side of every item is at the same level as the Y-coordinate of the given position.
288    /// </summary>
289    /// <param name="position"></param>
290    /// <returns></returns>
291    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelowForPosition(PackingPosition position) {
292      return GetItemsBelow(position).Where(x => (x.Item1.Y + x.Item2.Height) == position.Y);
293    }
294
295    /// <summary>
296    /// Checks if a given the weight of an given item is supportet by the items below.
297    /// </summary>
298    /// <param name="item"></param>
299    /// <param name="position"></param>
300    /// <returns></returns>
301    private bool IsWeightSupported(PackingItem item, PackingPosition position) {
302      if (position.Y == 0) {
303        return true;
304      }
305      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
306      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
307      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
308      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
309
310      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
311
312      return itemsP1.Where(x => x.Item2.SupportsStacking(item)).Any() &&
313        itemsP2.Where(x => x.Item2.SupportsStacking(item)).Any() &&
314        itemsP3.Where(x => x.Item2.SupportsStacking(item)).Any() &&
315        itemsP4.Where(x => x.Item2.SupportsStacking(item)).Any();
316    }
317
318    #endregion
319
320    protected override void GenerateNewExtremePointsForNewItem(PackingItem newItem, PackingPosition position) {
321      throw new NotImplementedException();
322    }
323
324    #region Get items
325   
326    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelow(PackingPosition pos) {
327      var line = new Line3D(pos, new Vector3D(0, 1, 0));
328      return Items.Select(x => new {
329        Item = x.Value,
330        Position = Positions[x.Key],
331        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Top))
332      }).Where(x => x.Intersection != null && x.Intersection.Y <= pos.Y)
333        .Select(x => Tuple.Create(x.Position, x.Item));
334    }
335
336    #endregion
337  }
338}
Note: See TracBrowser for help on using the repository browser.