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

Last change on this file since 15554 was 15554, checked in by rhanghof, 21 months ago

#2817:

  • Unittests
  • Bugfixes on the line projection based extreme point creation method
File size: 14.3 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 IDictionary<PackingPosition, IEnumerable<ResidualSpace>> ExtremePoints { get; protected set; }
39
40
41    public BinPacking3D(PackingShape binShape)
42      : base(binShape) {
43      ExtremePoints = new SortedList<PackingPosition, IEnumerable<ResidualSpace>>();
44     
45      ExtremePoints.Add(binShape.Origin, new List<ResidualSpace>() {ResidualSpace.Create(binShape.Width, binShape.Height, binShape.Depth)});
46    }
47
48    [StorableConstructor]
49    protected BinPacking3D(bool deserializing) : base(deserializing) { }
50
51    protected BinPacking3D(BinPacking3D original, Cloner cloner)
52      : base(original, cloner) {
53
54      this.ExtremePoints = new SortedList<PackingPosition, IEnumerable<ResidualSpace>>();
55      foreach (var extremePoint in original.ExtremePoints) {
56        var residualSpaces = new List<ResidualSpace>();
57        foreach (var residualSpace in extremePoint.Value) {
58          residualSpaces.Add(cloner.Clone(residualSpace));
59        }
60        ExtremePoints.Add(cloner.Clone(extremePoint.Key), residualSpaces);
61      }
62    }
63
64    public override IDeepCloneable Clone(Cloner cloner) {
65      return new BinPacking3D(this, cloner);
66    }
67
68   
69
70    /// <summary>
71    /// Puts a given item into the bin packing at the given position.
72    /// </summary>
73    /// <param name="itemID">Offset in the internal item array</param>
74    /// <param name="item">Item</param>
75    /// <param name="position">Position of the item in the bin packing</param>
76    public override void PackItem(int itemID, PackingItem item, PackingPosition position) {
77      Items[itemID] = item;
78      Positions[itemID] = position;
79      ExtremePoints.Remove(position);
80    }
81
82    /*
83    /// <summary>
84    /// Updates the extreme points of the bin
85    /// </summary>
86    /// <param name="item"></param>
87    /// <param name="position"></param>
88    /// <param name="stackingConstraints"></param>
89    public void UpdateExtremePoints(PackingItem item, PackingPosition position, bool stackingConstraints) {
90      if (stackingConstraints) {
91        UpdateExtremePointsWithStackingConstriants(item, position);
92      } else {
93        UpdateExtremePointsWithoutStackingConstriants(item, position);
94      }
95    }*/
96
97
98      /*
99    /// <summary>
100    /// Updates the extreme points of the bin.
101    /// 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.
102    /// </summary>
103    /// <param name="item"></param>
104    /// <param name="position"></param>
105    private void UpdateExtremePointsWithStackingConstriants(PackingItem newItem, PackingPosition position) {
106      int newWidth = position.Rotated ? newItem.Depth : newItem.Width;
107      int newDepth = position.Rotated ? newItem.Width : newItem.Depth;
108      var ep1 = new PackingPosition(position.AssignedBin, position.X + newWidth, position.Y, position.Z);
109      var ep2 = new PackingPosition(position.AssignedBin, position.X, position.Y + newItem.Height, position.Z);
110      var ep3 = new PackingPosition(position.AssignedBin, position.X, position.Y, position.Z + newDepth);
111      AddExtremePoint(ep1);
112      AddExtremePoint(ep2);
113      AddExtremePoint(ep3);
114    }*/
115
116     
117
118    #region Position feasability
119
120    /// <summary>
121    /// In this case feasability is defined as following:
122    /// 1. the point is supported by something;
123    /// 2. the item does not collide with another already packed item
124    /// </summary>
125    /// <param name="item"></param>
126    /// <param name="position"></param>
127    /// <param name="stackingConstraints"></param>
128    /// <returns></returns>
129    public override bool IsPositionFeasible(PackingItem item, PackingPosition position, bool stackingConstraints) {
130      //var b1 = CheckItemDimensions(item, position);
131      var b2 = ItemCanBePlaced(item, position);
132      var b3 = CheckStackingConstraints(item, position, stackingConstraints);
133
134      return b2 && b3;
135    }
136
137    /// <summary>
138    /// Returns true if a given item can be placed in the current bin
139    /// </summary>
140    /// <param name="givenItem"></param>
141    /// <param name="givenItemPosition"></param>
142    /// <returns></returns>
143    private bool ItemCanBePlaced(PackingItem givenItem, PackingPosition givenItemPosition) {
144      var width = givenItemPosition.Rotated ? givenItem.Depth : givenItem.Width;
145      var depth = givenItemPosition.Rotated ? givenItem.Width : givenItem.Depth;
146      // Check if the boundings of the bin would injured
147      if (givenItemPosition.X + width > BinShape.Width ||
148          givenItemPosition.Y + givenItem.Height > BinShape.Height ||
149          givenItemPosition.Z + depth > BinShape.Depth) {
150        return false;
151      }
152
153      //if the given item collides with any other item, it can not be placed
154      foreach (var item in Items) {
155        if (ItemsCollides(new Tuple<PackingPosition, PackingItem>(Positions[item.Key], item.Value),
156                          new Tuple<PackingPosition, PackingItem>(givenItemPosition, givenItem))) {
157          return false;
158        }
159      }
160      return true;
161    }
162
163    /// <summary>
164    /// Checks if two given items in a space collides
165    /// </summary>
166    /// <param name="t1"></param>
167    /// <param name="t2"></param>
168    /// <returns></returns>
169    private bool ItemsCollides(Tuple<PackingPosition, PackingItem> t1, Tuple<PackingPosition, PackingItem> t2) {
170      var position1 = t1.Item1;
171      var item1 = t1.Item2;
172      var position2 = t2.Item1;
173      var item2 = t2.Item2;
174      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);
175      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);
176      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);
177      return cx && cy && cz;
178    }
179
180    /// <summary>
181    /// Checks the stacking constraints. This method depends that the given item can be placed at this position
182    /// </summary>
183    /// <param name="item"></param>
184    /// <param name="position"></param>
185    /// <param name="stackingConstraints"></param>
186    /// <returns></returns>
187    private bool CheckStackingConstraints(PackingItem item, PackingPosition position, bool stackingConstraints) {
188      if (position.Y == 0 || !stackingConstraints && HasOnePointWithAnItemBelow(item, position)) {
189        return true;
190      }
191
192      return IsStaticStable(item, position) && IsWeightSupported(item, position);
193    }
194
195    /// <summary>
196    /// Checks if a given item has any point lieing on another item.
197    /// </summary>
198    /// <param name="item"></param>
199    /// <param name="position"></param>
200    /// <returns></returns>
201    private bool HasOnePointWithAnItemBelow(PackingItem item, PackingPosition position) {
202      bool p1, p2, p3, p4;
203      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
204
205      return p1 || p2 || p3 || p4;
206    }
207
208    /// <summary>
209    /// Checks if a given item is static stable.
210    /// A item is static stable if all edges have an object below.
211    /// </summary>
212    /// <param name="item"></param>
213    /// <param name="position"></param>
214    /// <returns></returns>
215    public override bool IsStaticStable(PackingItem item, PackingPosition position) {
216      bool p1, p2, p3, p4;
217      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
218      return p1 && p2 && p3 && p4;
219    }
220
221    /// <summary>
222    /// This method sets the out parameters p1 ... p4 if the point lies on another item.
223    /// p1 ... p3 represents one point on the bottom side of an given item.
224    /// +---------+
225    /// |p1     p2|
226    /// |         |
227    /// |p4     p3|
228    /// +---------+
229    /// </summary>
230    /// <param name="item">Given item</param>
231    /// <param name="position">Given item position</param>
232    /// <param name="p1"></param>
233    /// <param name="p2"></param>
234    /// <param name="p3"></param>
235    /// <param name="p4"></param>
236    private void PointsLiesOnAnItem(PackingItem item, PackingPosition position, out bool p1, out bool p2, out bool p3, out bool p4) {
237      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
238      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
239      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
240      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
241
242      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
243
244      p1 = itemsP1.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z < x.Item1.Z + x.Item2.Depth).Any();
245      p2 = itemsP2.Where(x => position.X + item.Width > x.Item1.X && position.Z < x.Item1.Z + x.Item2.Depth).Any();
246      p3 = itemsP3.Where(x => position.X + item.Width > x.Item1.X && position.Z + item.Depth > x.Item1.Z).Any();
247      p4 = itemsP4.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z + item.Depth > x.Item1.Z).Any();
248    }
249
250    /// <summary>
251    /// This method returns a collection for the out parameters itemsP1 ... itemsP4 with the items below
252    /// itemsP1 ... itemsP4 represents one point on the bottom side of an given item.
253    /// +---------+
254    /// |p1     p2|
255    /// |         |
256    /// |p4     p3|
257    /// +---------+
258    /// </summary>
259    /// <param name="item"></param>
260    /// <param name="position"></param>
261    /// <param name="itemsP1"></param>
262    /// <param name="itemsP2"></param>
263    /// <param name="itemsP3"></param>
264    /// <param name="itemsP4"></param>
265    private void GetItemsUnderItemWithContact(PackingItem item, PackingPosition position,
266                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1,
267                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2,
268                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3,
269                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4) {
270      itemsP1 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z, false));
271      itemsP2 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z, false));
272      itemsP3 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z + item.Depth - 1, false));
273      itemsP4 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z + item.Depth - 1, false));
274
275    }
276
277    /// <summary>
278    /// Returns a collection of items which are below a given point.
279    /// The top side of every item is at the same level as the Y-coordinate of the given position.
280    /// </summary>
281    /// <param name="position"></param>
282    /// <returns></returns>
283    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelowForPosition(PackingPosition position) {
284      return GetItemsBelow(position).Where(x => (x.Item1.Y + x.Item2.Height) == position.Y);
285    }
286
287    /// <summary>
288    /// Checks if a given the weight of an given item is supportet by the items below.
289    /// </summary>
290    /// <param name="item"></param>
291    /// <param name="position"></param>
292    /// <returns></returns>
293    private bool IsWeightSupported(PackingItem item, PackingPosition position) {
294      if (position.Y == 0) {
295        return true;
296      }
297      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
298      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
299      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
300      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
301
302      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
303
304      return itemsP1.Where(x => x.Item2.SupportsStacking(item)).Any() &&
305        itemsP2.Where(x => x.Item2.SupportsStacking(item)).Any() &&
306        itemsP3.Where(x => x.Item2.SupportsStacking(item)).Any() &&
307        itemsP4.Where(x => x.Item2.SupportsStacking(item)).Any();
308    }
309
310    #endregion
311
312    protected override void GenerateNewExtremePointsForNewItem(PackingItem newItem, PackingPosition position) {
313      throw new NotImplementedException();
314    }
315
316    #region Get items
317   
318    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelow(PackingPosition pos) {
319      var line = new Line3D(pos, new Vector3D(0, 1, 0));
320      return Items.Select(x => new {
321        Item = x.Value,
322        Position = Positions[x.Key],
323        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Top))
324      }).Where(x => x.Intersection != null && x.Intersection.Y <= pos.Y)
325        .Select(x => Tuple.Create(x.Position, x.Item));
326    }
327
328    #endregion
329  }
330}
Note: See TracBrowser for help on using the repository browser.