Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 15463 was 15462, checked in by rhanghof, 7 years ago

#2817
-Added unit tests for bin packing 3d.
-The items can now be sorted by the material.

File size: 33.1 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;
30
31namespace HeuristicLab.Problems.BinPacking3D {
32  [Item("BinPacking3D", "Represents a single-bin packing for a 3D bin-packing problem.")]
33  [StorableClass]
34  public class BinPacking3D : BinPacking<PackingPosition, PackingShape, PackingItem> {
35
36    [Storable]
37    public Dictionary<PackingPosition, Tuple<int, int, int>> ResidualSpace { get; protected set; }
38
39    public BinPacking3D(PackingShape binShape)
40      : base(binShape) {
41      ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
42      AddExtremePoint(binShape.Origin);
43      InitializeOccupationLayers();
44    }
45    [StorableConstructor]
46    protected BinPacking3D(bool deserializing) : base(deserializing) { }
47    protected BinPacking3D(BinPacking3D original, Cloner cloner)
48      : base(original, cloner) {
49      this.ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
50      foreach (var o in original.ResidualSpace)
51        this.ResidualSpace.Add(cloner.Clone(o.Key), Tuple.Create(o.Value.Item1, o.Value.Item2, o.Value.Item3));
52    }
53    public override IDeepCloneable Clone(Cloner cloner) {
54      return new BinPacking3D(this, cloner);
55    }
56
57
58    [StorableHook(HookType.AfterDeserialization)]
59    private void AfterDeserialization() {
60      // BackwardsCompatibility3.3
61      #region Backwards compatible code, remove with 3.4
62      if (ResidualSpace == null)
63        ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
64      #endregion
65    }
66
67    #region New methods for bin packer class
68
69    public override void PackItem(int itemID, PackingItem item, PackingPosition position) {
70      Items[itemID] = item;
71      Positions[itemID] = position;
72      ExtremePoints.Remove(position);
73      ResidualSpace.Remove(position);
74    }
75
76    /// <summary>
77    /// Updates the extreme points of the bin
78    /// </summary>
79    /// <param name="item"></param>
80    /// <param name="position"></param>
81    /// <param name="stackingConstraints"></param>
82    public void UpdateExtremePoints(PackingItem item, PackingPosition position, bool stackingConstraints) {
83      if (stackingConstraints) {
84        UpdateExtremePointsWithStackingConstriants(item, position);
85      } else {
86        UpdateExtremePointsWithoutStackingConstriants(item, position);
87      }
88    }
89
90    /// <summary>
91    /// Updates the extreme points of the bin.
92    /// 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.
93    /// </summary>
94    /// <param name="item"></param>
95    /// <param name="position"></param>
96    private void UpdateExtremePointsWithStackingConstriants(PackingItem newItem, PackingPosition position) {
97
98      //UpdateExtremePointsWithoutStackingConstriants(newItem, position);
99      //return;
100
101      int newWidth = position.Rotated ? newItem.Depth : newItem.Width;
102      int newDepth = position.Rotated ? newItem.Width : newItem.Depth;
103      var ep1 = new PackingPosition(position.AssignedBin, position.X + newWidth, position.Y, position.Z);
104      var ep2 = new PackingPosition(position.AssignedBin, position.X, position.Y + newItem.Height, position.Z);
105      var ep3 = new PackingPosition(position.AssignedBin, position.X, position.Y, position.Z + newDepth);
106      AddExtremePoint(ep1);
107      AddExtremePoint(ep2);
108      AddExtremePoint(ep3);
109
110      /*
111      ExtremePoints.Add(ep1);
112      ExtremePoints.Add(ep2);
113      ExtremePoints.Add(ep3);
114
115      var rs1 = CalculateResidualSpace(CreateRs(ep1));
116      var rs2 = CalculateResidualSpace(CreateRs(ep2));
117      var rs3 = CalculateResidualSpace(CreateRs(ep3));
118      ResidualSpace.Add(ep1, rs1);
119      ResidualSpace.Add(ep2, rs2);
120      ResidualSpace.Add(ep3, rs3);*/
121    }
122
123
124    /*private bool AddExtremePoint(PackingPosition position) {
125      if ()
126
127      return true;
128    }
129
130   
131    private bool AddExtremePoint(PackingPosition pos) {
132      if (ExtremePoints.Add(pos)) {
133        var rs = CalculateResidualSpace(new Vector3D(pos));
134        ResidualSpace.Add(pos, rs);
135        // Check if existing extreme points are shadowed by the new point
136        // That is, their residual space fit entirely into the residual space of the new point
137        foreach (var ep in ExtremePoints.Where(x => x != pos && new Vector3D(x).IsInside(pos, rs)).ToList()) {
138          if (IsWithinResidualSpaceOfAnotherExtremePoint(new Vector3D(ep), ResidualSpace[ep], pos, rs)) {
139            ExtremePoints.Remove(ep);
140            ResidualSpace.Remove(ep);
141          }
142        }
143        return true;
144      }
145      return false;
146    }*/
147
148
149    private Tuple<int, int, int> CalculateResidualSpace(Vector3D pos) {
150      var itemPos = Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] });
151      Vector3D limit = new Vector3D() { X = BinShape.Width, Y = BinShape.Height, Z = BinShape.Depth };
152      if (pos.X < limit.X && pos.Y < limit.Y && pos.Z < limit.Z) {
153        var rightLimit = ProjectRight(pos);
154        var upLimit = ProjectUp(pos);
155        var forwardLimit = ProjectForward(pos);
156        if (rightLimit.X > 0) {
157          limit.X = rightLimit.X;
158        }
159        if (upLimit.Y > 0) {
160          limit.Y = upLimit.Y;
161        }
162        if (forwardLimit.Z > 0) {
163          limit.Z = forwardLimit.Z;
164        }
165      }
166
167     
168     
169      if (limit.X - pos.X <= 0 || limit.Y - pos.Y <= 0  || limit.Z - pos.Z <= 0) {
170        return Tuple.Create(0, 0, 0);
171      }
172
173
174      return Tuple.Create(limit.X - pos.X, limit.Y - pos.Y, limit.Z - pos.Z);
175    }
176
177
178    private Vector3D CreateRs(PackingPosition position) {
179      return new Vector3D() { X = position.X, Y = position.Y, Z = position.Z };
180    }
181
182    private void UpdateExtremePointsWithoutStackingConstriants(PackingItem item, PackingPosition position) {
183      GenerateNewExtremePointsForNewItem(item, position);
184
185      // if an item is fit in below, before, or left of another its extreme points have to be regenerated
186      foreach (var above in GetItemsAbove(position)) {
187        GenerateNewExtremePointsForNewItem(above.Item2, above.Item1);
188      }
189      foreach (var front in GetItemsInfront(position)) {
190        GenerateNewExtremePointsForNewItem(front.Item2, front.Item1);
191      }
192      foreach (var right in GetItemsOnRight(position)) {
193        GenerateNewExtremePointsForNewItem(right.Item2, right.Item1);
194      }
195    }
196
197
198
199    /// <summary>
200    /// In this case feasability is defined as following:
201    /// 1. the item fits into the bin-borders;
202    /// 2. the point is supported by something;
203    /// 3. the item does not collide with another already packed item
204    ///
205    /// Unfortunatelly this method does not support item rotation
206    /// </summary>
207    /// <param name="item"></param>
208    /// <param name="position"></param>
209    /// <param name="stackingConstraints"></param>
210    /// <returns></returns>
211    public override bool IsPositionFeasible(PackingItem item, PackingPosition position, bool stackingConstraints) {
212      var b1 = CheckItemDimensions(item);
213      var b2 = ItemCanBePlaced(item, position);
214      var b3 = CheckStackingConstraints(item, position, stackingConstraints);
215
216      return b1 && b2 && b3;
217    }
218
219    /// <summary>
220    /// Compares the dimensions of a given item and the current bin.
221    /// </summary>
222    /// <param name="item"></param>
223    /// <returns>Returns true if the dimensions of an given item are less or equal to the bin.</returns>
224    private bool CheckItemDimensions(PackingItem item) {
225      return BinShape.Width >= item.Width && BinShape.Height >= item.Height && BinShape.Depth >= item.Depth;
226    }
227
228    /// <summary>
229    /// Returns true if a given item can be placed in the current bin
230    /// </summary>
231    /// <param name="givenItem"></param>
232    /// <param name="givenItemPosition"></param>
233    /// <returns></returns>
234    private bool ItemCanBePlaced(PackingItem givenItem, PackingPosition givenItemPosition) {
235      // Check if the boundings of the bin would injured
236      if (givenItemPosition.X + givenItem.Width > BinShape.Width ||
237          givenItemPosition.Y + givenItem.Height > BinShape.Height ||
238          givenItemPosition.Z + givenItem.Depth > BinShape.Depth) {
239        return false;
240      }
241
242      //if the given item collides with any other item, it can not be placed
243      foreach (var item in Items) {
244        if (ItemsCollides(new Tuple<PackingPosition, PackingItem>(Positions[item.Key], item.Value),
245                          new Tuple<PackingPosition, PackingItem>(givenItemPosition, givenItem))) {
246          return false;
247        }
248      }
249      return true;
250    }
251
252    /// <summary>
253    /// Checks if two given items in a space collides
254    /// </summary>
255    /// <param name="t1"></param>
256    /// <param name="t2"></param>
257    /// <returns></returns>
258    private bool ItemsCollides(Tuple<PackingPosition, PackingItem> t1, Tuple<PackingPosition, PackingItem> t2) {
259      var position1 = t1.Item1;
260      var item1 = t1.Item2;
261      var position2 = t2.Item1;
262      var item2 = t2.Item2;
263      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);
264      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);
265      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);
266      return cx && cy && cz;
267    }
268
269    /// <summary>
270    /// Checks the stacking constraints. This method depends that the given item can be placed at this position
271    /// </summary>
272    /// <param name="item"></param>
273    /// <param name="position"></param>
274    /// <param name="stackingConstraints"></param>
275    /// <returns></returns>
276    private bool CheckStackingConstraints(PackingItem item, PackingPosition position, bool stackingConstraints) {
277      if (position.Y == 0 || !stackingConstraints && HasOnePointWithAnItemBelow(item, position)) {
278        return true;
279      }
280
281      return IsStaticStable(item, position) && IsWeightSupported(item, position);
282    }
283
284
285    /// <summary>
286    /// Checks if a given item has any point lieing on another item.
287    /// </summary>
288    /// <param name="item"></param>
289    /// <param name="position"></param>
290    /// <returns></returns>
291    private bool HasOnePointWithAnItemBelow(PackingItem item, PackingPosition position) {
292      bool p1, p2, p3, p4;
293      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
294
295      return p1 || p2 || p3 || p4;
296    }
297
298    /// <summary>
299    /// Checks if a given item is static stable.
300    /// A item is static stable if all edges have an object below.
301    /// </summary>
302    /// <param name="item"></param>
303    /// <param name="position"></param>
304    /// <returns></returns>
305    public override bool IsStaticStable(PackingItem item, PackingPosition position) {
306      bool p1, p2, p3, p4;
307      PointsLiesOnAnItem(item, position, out p1, out p2, out p3, out p4);
308      return p1 && p2 && p3 && p4;
309    }
310
311    /// <summary>
312    /// This method sets the out parameters p1 ... p4 if the point lies on another item.
313    /// p1 ... p3 represents one point on the bottom side of an given item.
314    /// +---------+
315    /// |p1     p2|
316    /// |         |
317    /// |p4     p3|
318    /// +---------+
319    /// </summary>
320    /// <param name="item">Given item</param>
321    /// <param name="position">Given item position</param>
322    /// <param name="p1"></param>
323    /// <param name="p2"></param>
324    /// <param name="p3"></param>
325    /// <param name="p4"></param>
326    private void PointsLiesOnAnItem(PackingItem item, PackingPosition position, out bool p1, out bool p2, out bool p3, out bool p4) {
327      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
328      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
329      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
330      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
331
332      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
333
334      p1 = itemsP1.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z < x.Item1.Z + x.Item2.Depth).Any();
335      p2 = itemsP2.Where(x => position.X + item.Width > x.Item1.X && position.Z < x.Item1.Z + x.Item2.Depth).Any();
336      p3 = itemsP3.Where(x => position.X + item.Width > x.Item1.X && position.Z + item.Depth > x.Item1.Z).Any();
337      p4 = itemsP4.Where(x => position.X < x.Item1.X + x.Item2.Width && position.Z + item.Depth > x.Item1.Z).Any();
338    }
339
340
341    /// <summary>
342    /// This method returns a collection for the out parameters itemsP1 ... itemsP4 with the items below
343    /// itemsP1 ... itemsP4 represents one point on the bottom side of an given item.
344    /// +---------+
345    /// |p1     p2|
346    /// |         |
347    /// |p4     p3|
348    /// +---------+
349    /// </summary>
350    /// <param name="item"></param>
351    /// <param name="position"></param>
352    /// <param name="itemsP1"></param>
353    /// <param name="itemsP2"></param>
354    /// <param name="itemsP3"></param>
355    /// <param name="itemsP4"></param>
356    private void GetItemsUnderItemWithContact(PackingItem item, PackingPosition position,
357                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1,
358                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2,
359                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3,
360                                   out IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4) {
361      itemsP1 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z, false));
362      itemsP2 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z, false));
363      itemsP3 = GetItemsBelowForPosition(new PackingPosition(0, position.X, position.Y, position.Z + item.Depth - 1, false));
364      itemsP4 = GetItemsBelowForPosition(new PackingPosition(0, position.X + item.Width - 1, position.Y, position.Z + item.Depth - 1, false));
365
366    }
367
368    /// <summary>
369    /// Returns a collection of items which are below a given point.
370    /// The top side of every item is at the same level as the Y-coordinate of the given position.
371    /// </summary>
372    /// <param name="position"></param>
373    /// <returns></returns>
374    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelowForPosition(PackingPosition position) {
375      return GetItemsBelow(position).Where(x => (x.Item1.Y + x.Item2.Height) == position.Y);
376    }
377
378
379    /// <summary>
380    /// Checks if a given the weight of an given item is supportet by the items below.
381    /// </summary>
382    /// <param name="item"></param>
383    /// <param name="position"></param>
384    /// <returns></returns>
385    private bool IsWeightSupported(PackingItem item, PackingPosition position) {
386      if (position.Y == 0) {
387        return true;
388      }
389      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP1;
390      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP2;
391      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP3;
392      IEnumerable<Tuple<PackingPosition, PackingItem>> itemsP4;
393
394      GetItemsUnderItemWithContact(item, position, out itemsP1, out itemsP2, out itemsP3, out itemsP4);
395
396      return itemsP1.Where(x => x.Item2.SupportsStacking(item)).Any() &&
397        itemsP2.Where(x => x.Item2.SupportsStacking(item)).Any() &&
398        itemsP3.Where(x => x.Item2.SupportsStacking(item)).Any() &&
399        itemsP4.Where(x => x.Item2.SupportsStacking(item)).Any();
400    }
401
402
403
404    #endregion
405
406    /// <summary>
407    /// Generates new extreme points for a given item and its position.
408    /// It also recalcualtes the residual space and removes the extreme points which are not needed any more.
409    /// </summary>
410    /// <param name="newItem"></param>
411    /// <param name="position"></param>
412    protected override void GenerateNewExtremePointsForNewItem(PackingItem newItem, PackingPosition position) {
413      int newWidth = position.Rotated ? newItem.Depth : newItem.Width;
414      int newDepth = position.Rotated ? newItem.Width : newItem.Depth;
415
416      var itemPlacement = Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] }).ToList();
417      // Find ExtremePoints beginning from sourcepointX
418      var sourcePoint = new Vector3D() { X = position.X + newWidth, Y = position.Y, Z = position.Z };
419      if (sourcePoint.X < BinShape.Width && sourcePoint.Y < BinShape.Height && sourcePoint.Z < BinShape.Depth) {
420        // Projecting onto the XZ-plane
421        var below = ProjectDown(sourcePoint);
422        var residualSpace = CalculateResidualSpace(below);
423        if (IsNonZero(residualSpace)
424          && !IsWithinResidualSpaceOfAnotherExtremePoint(below, residualSpace)) {
425          // add only if the projected point's residual space is not a sub-space
426          // of another extreme point's residual space
427          var belowPoint = new PackingPosition(position.AssignedBin, below.X, below.Y, below.Z);
428          AddExtremePoint(belowPoint);
429        }
430        // Projecting onto the XY-plane
431        var back = ProjectBackward(sourcePoint);
432        residualSpace = CalculateResidualSpace(back);
433        if (IsNonZero(residualSpace)
434          && !IsWithinResidualSpaceOfAnotherExtremePoint(back, residualSpace)) {
435          // add only if the projected point's residual space is not a sub-space
436          // of another extreme point's residual space
437          var backPoint = new PackingPosition(position.AssignedBin, back.X, back.Y, back.Z);
438          AddExtremePoint(backPoint);
439        }
440      }
441
442      //Find ExtremePoints beginning from sourcepointY
443      sourcePoint = new Vector3D(position.X, position.Y + newItem.Height, position.Z);
444      if (sourcePoint.X < BinShape.Width && sourcePoint.Y < BinShape.Height && sourcePoint.Z < BinShape.Depth) {
445        // Projecting onto the YZ-plane
446        var left = ProjectLeft(sourcePoint);
447        var residualSpace = CalculateResidualSpace(left);
448        if (IsNonZero(residualSpace)
449          && !IsWithinResidualSpaceOfAnotherExtremePoint(left, residualSpace)) {
450          // add only if the projected point's residual space is not a sub-space
451          // of another extreme point's residual space
452          var leftPoint = new PackingPosition(position.AssignedBin, left.X, left.Y, left.Z);
453          AddExtremePoint(leftPoint);
454        }
455        // Projecting onto the XY-plane
456        var back = ProjectBackward(sourcePoint);
457        residualSpace = CalculateResidualSpace(back);
458        if (IsNonZero(residualSpace)
459          && !IsWithinResidualSpaceOfAnotherExtremePoint(back, residualSpace)) {
460          // add only if the projected point's residual space is not a sub-space
461          // of another extreme point's residual space
462          var backPoint = new PackingPosition(position.AssignedBin, back.X, back.Y, back.Z);
463          AddExtremePoint(backPoint);
464        }
465      }
466
467      //Find ExtremePoints beginning from sourcepointZ
468      sourcePoint = new Vector3D(position.X, position.Y, position.Z + newDepth);
469      if (sourcePoint.X < BinShape.Width && sourcePoint.Y < BinShape.Height && sourcePoint.Z < BinShape.Depth) {
470        // Projecting onto the XZ-plane
471        var below = ProjectDown(sourcePoint);
472        var residualSpace = CalculateResidualSpace(below);
473        if (IsNonZero(residualSpace)
474          && !IsWithinResidualSpaceOfAnotherExtremePoint(below, residualSpace)) {
475          // add only if the projected point's residual space is not a sub-space
476          // of another extreme point's residual space
477          var belowPoint = new PackingPosition(position.AssignedBin, below.X, below.Y, below.Z);
478          AddExtremePoint(belowPoint);
479        }
480        // Projecting onto the YZ-plane
481        var left = ProjectLeft(sourcePoint);
482        residualSpace = CalculateResidualSpace(left);
483        if (IsNonZero(residualSpace)
484          && !IsWithinResidualSpaceOfAnotherExtremePoint(left, residualSpace)) {
485          // add only if the projected point's residual space is not a sub-space
486          // of another extreme point's residual space
487          var leftPoint = new PackingPosition(position.AssignedBin, left.X, left.Y, left.Z);
488          AddExtremePoint(leftPoint);
489        }
490      }
491    }
492
493    private bool IsNonZero(Tuple<int, int, int> rs) {
494      return rs.Item1 > 0 && rs.Item2 > 0 && rs.Item3 > 0;
495    }
496
497    private bool IsWithinResidualSpaceOfAnotherExtremePoint(Vector3D pos, Tuple<int, int, int> residualSpace) {
498      var eps = ExtremePoints.Where(x => !pos.Equals(x) && pos.IsInside(x, ResidualSpace[x]));
499      return eps.Any(x => IsWithinResidualSpaceOfAnotherExtremePoint(pos, residualSpace, x, ResidualSpace[x]));
500    }
501    private bool IsWithinResidualSpaceOfAnotherExtremePoint(Vector3D pos, Tuple<int, int, int> rsPos, PackingPosition ep, Tuple<int, int, int> rsEp) {
502      return rsEp.Item1 >= pos.X - ep.X + rsPos.Item1
503          && rsEp.Item2 >= pos.Y - ep.Y + rsPos.Item2
504          && rsEp.Item3 >= pos.Z - ep.Z + rsPos.Item3;
505    }
506
507    private bool AddExtremePoint(PackingPosition pos) {
508      if (ExtremePoints.Add(pos)) {
509        var rs = CalculateResidualSpace(new Vector3D(pos));
510        ResidualSpace.Add(pos, rs);
511        // Check if existing extreme points are shadowed by the new point
512        // That is, their residual space fit entirely into the residual space of the new point
513        foreach (var ep in ExtremePoints.Where(x => x != pos && new Vector3D(x).IsInside(pos, rs)).ToList()) {
514          if (IsWithinResidualSpaceOfAnotherExtremePoint(new Vector3D(ep), ResidualSpace[ep], pos, rs)) {
515            ExtremePoints.Remove(ep);
516            ResidualSpace.Remove(ep);
517          }
518        }
519        return true;
520      }
521      return false;
522    }
523
524    private Tuple<int, int, int> CalculateResidualSpace1(Vector3D pos) {
525      var itemPos = Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] });
526      var rightLimit = ProjectRight(pos);
527      var upLimit = ProjectUp(pos);
528      var forwardLimit = ProjectForward(pos);
529      return Tuple.Create(rightLimit.X - pos.X, upLimit.Y - pos.Y, forwardLimit.Z - pos.Z);
530    }
531
532    #region Projections
533
534    private Vector3D ProjectBackward(Vector3D pos) {
535      var line = new Line3D(pos, new Vector3D(0, 0, -1));
536      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
537                  .Select(x => new Plane3D(x.Position, x.Item, Side.Front))
538                  .Concat(new[] { new Plane3D(BinShape, Side.Back) })
539                  .Select(x => x.Intersect(line))
540                  .Where(x => x != null && x.Z <= pos.Z)
541                  .MaxItems(x => x.Z).First();
542    }
543
544    private Vector3D ProjectLeft(Vector3D pos) {
545      var line = new Line3D(pos, new Vector3D(-1, 0, 0));
546      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
547                  .Select(x => new Plane3D(x.Position, x.Item, Side.Right))
548                  .Concat(new[] { new Plane3D(BinShape, Side.Left) })
549                  .Select(x => x.Intersect(line))
550                  .Where(x => x != null && x.X <= pos.X)
551                  .MaxItems(x => x.X).First();
552    }
553
554    private Vector3D ProjectDown(Vector3D pos) {
555      var line = new Line3D(pos, new Vector3D(0, -1, 0));
556      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
557                  .Select(x => new Plane3D(x.Position, x.Item, Side.Top))
558                  .Concat(new[] { new Plane3D(BinShape, Side.Bottom) })
559                  .Select(x => x.Intersect(line))
560                  .Where(x => x != null && x.Y <= pos.Y)
561                  .MaxItems(x => x.Y).First();
562    }
563
564    private Vector3D ProjectForward(Vector3D pos) {
565      var line = new Line3D(pos, new Vector3D(0, 0, 1));
566      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
567                  .Select(x => new Plane3D(x.Position, x.Item, Side.Back))
568                  .Concat(new[] { new Plane3D(BinShape, Side.Front) })
569                  .Select(x => x.Intersect(line))
570                  .Where(x => x != null && x.Z >= pos.Z)
571                  .MinItems(x => x.Z).First();
572    }
573
574    private Vector3D ProjectRight(Vector3D pos) {
575      var line = new Line3D(pos, new Vector3D(1, 0, 0));
576      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
577                  .Select(x => new Plane3D(x.Position, x.Item, Side.Left))
578                  .Concat(new[] { new Plane3D(BinShape, Side.Right) })
579                  .Select(x => x.Intersect(line))
580                  .Where(x => x != null && x.X >= pos.X)
581                  .MinItems(x => x.X).First();
582    }
583
584    private Vector3D ProjectUp(Vector3D pos) {
585      var line = new Line3D(pos, new Vector3D(0, 1, 0));
586      return Items.Select(x => new { Item = x.Value, Position = Positions[x.Key] })
587                  .Select(x => new Plane3D(x.Position, x.Item, Side.Bottom))
588                  .Concat(new[] { new Plane3D(BinShape, Side.Top) })
589                  .Select(x => x.Intersect(line))
590                  .Where(x => x != null && x.Y >= pos.Y)
591                  .MinItems(x => x.Y).First();
592    }
593    #endregion
594
595    #region Get items
596
597    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsAbove(PackingPosition pos) {
598      var line = new Line3D(pos, new Vector3D(0, 1, 0));
599      return Items.Select(x => new {
600        Item = x.Value,
601        Position = Positions[x.Key],
602        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Bottom))
603      }).Where(x => x.Intersection != null && x.Intersection.Y >= pos.Y)
604        .Select(x => Tuple.Create(x.Position, x.Item));
605    }
606
607    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsInfront(PackingPosition pos) {
608      var line = new Line3D(pos, new Vector3D(0, 0, 1));
609      return Items.Select(x => new {
610        Item = x.Value,
611        Position = Positions[x.Key],
612        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Back))
613      }).Where(x => x.Intersection != null && x.Intersection.Y >= pos.Y)
614        .Select(x => Tuple.Create(x.Position, x.Item));
615    }
616
617    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsOnRight(PackingPosition pos) {
618      var line = new Line3D(pos, new Vector3D(1, 0, 0));
619      return Items.Select(x => new {
620        Item = x.Value,
621        Position = Positions[x.Key],
622        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Left))
623      }).Where(x => x.Intersection != null && x.Intersection.Y >= pos.Y)
624        .Select(x => Tuple.Create(x.Position, x.Item));
625    }
626
627    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBelow(PackingPosition pos) {
628      var line = new Line3D(pos, new Vector3D(0, 1, 0));
629      return Items.Select(x => new {
630        Item = x.Value,
631        Position = Positions[x.Key],
632        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Top))
633      }).Where(x => x.Intersection != null && x.Intersection.Y <= pos.Y)
634        .Select(x => Tuple.Create(x.Position, x.Item));
635    }
636
637    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsBehind(PackingPosition pos) {
638      var line = new Line3D(pos, new Vector3D(0, 0, 1));
639      return Items.Select(x => new {
640        Item = x.Value,
641        Position = Positions[x.Key],
642        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Front))
643      }).Where(x => x.Intersection != null && x.Intersection.Y >= pos.Y)
644        .Select(x => Tuple.Create(x.Position, x.Item));
645    }
646
647    private IEnumerable<Tuple<PackingPosition, PackingItem>> GetItemsOnLeft(PackingPosition pos) {
648      var line = new Line3D(pos, new Vector3D(1, 0, 0));
649      return Items.Select(x => new {
650        Item = x.Value,
651        Position = Positions[x.Key],
652        Intersection = line.Intersect(new Plane3D(Positions[x.Key], x.Value, Side.Right))
653      }).Where(x => x.Intersection != null && x.Intersection.Y >= pos.Y)
654        .Select(x => Tuple.Create(x.Position, x.Item));
655    }
656
657    #endregion
658
659
660    #region Sliding based packing  and obsolet methods
661    public override PackingPosition FindExtremePointForItem(PackingItem item, bool rotated, bool stackingConstraints) {
662      throw new NotSupportedException();
663      PackingItem newItem = new PackingItem(
664        rotated ? item.Depth : item.Width,
665        item.Height,
666        rotated ? item.Width : item.Depth,
667        item.TargetBin, item.Weight, item.Material);
668
669      var ep = ExtremePoints.Where(x => IsPositionFeasible(newItem, x, stackingConstraints))
670                            .FirstOrDefault();
671      if (ep != null) {
672        var result = new PackingPosition(ep.AssignedBin, ep.X, ep.Y, ep.Z, rotated);
673        return result;
674      }
675      return null;
676    }
677
678
679
680
681    public override PackingPosition FindPositionBySliding(PackingItem item, bool rotated, bool stackingConstraints) {
682      throw new NotSupportedException();
683    }
684
685    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints) {
686      throw new NotSupportedException();
687    }
688    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, Dictionary<int, bool> rotationArray, bool stackingConstraints) {
689      throw new NotSupportedException();
690    }
691
692
693    public override void ExtremePointBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints) {
694      throw new NotSupportedException();
695    }
696
697    public override void ExtremePointBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints, Dictionary<int, bool> rotationArray) {
698      throw new NotSupportedException();
699    }
700
701    public override int ShortestPossibleSideFromPoint(PackingPosition position) {
702      throw new NotSupportedException();
703    }
704
705
706    protected override void InitializeOccupationLayers() {
707    }
708    protected override void AddNewItemToOccupationLayers(int itemID, PackingItem item, PackingPosition position) {
709    }
710
711
712    protected override List<int> GetLayerItemIDs(PackingPosition position) {
713      return null;
714    }
715    protected override List<int> GetLayerItemIDs(PackingItem item, PackingPosition position) {
716      return null;
717    }
718    #endregion
719
720
721    public void UpdateResidualSpace(PackingItem item, PackingPosition pos) {
722      foreach (var ep in ExtremePoints.ToList()) {
723        var rs = ResidualSpace[ep];
724        var depth = pos.Rotated ? item.Width : item.Depth;
725        var width = pos.Rotated ? item.Depth : item.Width;
726        var changed = false;
727        if (ep.Z >= pos.Z && ep.Z < pos.Z + depth) {
728          if (ep.X <= pos.X && ep.Y >= pos.Y && ep.Y < pos.Y + item.Height) {
729            var diff = pos.X - ep.X;
730            var newRSX = Math.Min(rs.Item1, diff);
731            rs = Tuple.Create(newRSX, rs.Item2, rs.Item3);
732            changed = true;
733          }
734          if (ep.Y <= pos.Y && ep.X >= pos.X && ep.X < pos.X + width) {
735            var diff = pos.Y - ep.Y;
736            var newRSY = Math.Min(rs.Item2, diff);
737            rs = Tuple.Create(rs.Item1, newRSY, rs.Item3);
738            changed = true;
739          }
740        }
741
742        if (ep.Z <= pos.Z &&
743            ep.Y >= pos.Y && ep.Y < pos.Y + item.Height &&
744            ep.X >= pos.X && ep.X < pos.X + width) {
745          var diff = pos.Z - ep.Z;
746          var newRSZ = Math.Min(rs.Item3, diff);
747          rs = Tuple.Create(rs.Item1, rs.Item2, newRSZ);
748          changed = true;
749        }
750
751        if (changed) {
752          if (IsNonZero(rs) && !IsWithinResidualSpaceOfAnotherExtremePoint(new Vector3D(ep), rs)) {
753            ResidualSpace[ep] = rs;
754          } else {
755            ExtremePoints.Remove(ep);
756            ResidualSpace.Remove(ep);
757          }
758        }
759      }
760      return;
761    }
762  }
763}
Note: See TracBrowser for help on using the repository browser.