Index: stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml
===================================================================
--- stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml	(revision 15278)
@@ -33,104 +33,41 @@
              >
     <Grid>
-        <Viewport3D Name="viewport3D1" >
-            <Viewport3D.Camera>
-                <PerspectiveCamera x:Name="camMain" Position="0.5 8 8" LookDirection="0 -1 -1"> <!-- camera position for design time-->
-                </PerspectiveCamera>
-            </Viewport3D.Camera>
-            <ModelVisual3D>
-                <ModelVisual3D.Content>
-                    <DirectionalLight x:Name="dirLightMain" Direction="0,-1,-1"/>
-                </ModelVisual3D.Content>
-            </ModelVisual3D>
-            <ModelVisual3D>
-            </ModelVisual3D>
-            <ModelVisual3D x:Name="MyModel">
-                <ModelVisual3D.Content>
-                    <Model3DGroup>
-                        <GeometryModel3D>
-                            <GeometryModel3D.Geometry>
-                                <!-- two opaque cubes, one in front one in back-->
-                                <MeshGeometry3D x:Name="meshMain" 
-                                Positions="0 0 -2.5 1 0 -2.5  0 1 -2.5  1 1 -2.5  0 0 -1.5  1 0 -1.5  0 1 -1.5  1 1 -1.5
-                                           0 0 0 1 0 0  0 1 0  1 1 0  0 0 1  1 0 1  0 1 1  1 1 1" 
-                                TriangleIndices="10 11 9  10 9 8  15 9 11  15 13 9  14 13 15  14 12 13  14 10 12  10 8 12  10 15 11  10 14 15  0 9 13  8 13 12
-                                                 2 3 1  2 1 0  7 1 3  7 5 1  6 5 7  6 4 5  6 2 4  2 0 4  2 7 3  2 6 7  0 1 5  0 5 4 ">
-                                </MeshGeometry3D>
-                            </GeometryModel3D.Geometry>
-                            <GeometryModel3D.Material>
-                                <DiffuseMaterial>
-                                    <DiffuseMaterial.Brush>
-                                        <SolidColorBrush Color="LightGreen"/>
-                                    </DiffuseMaterial.Brush>
-                                </DiffuseMaterial>
-                            </GeometryModel3D.Material>
-                        </GeometryModel3D>
-                        <GeometryModel3D>
-                            <GeometryModel3D.Geometry>
-                                <!-- two transparent cubes, one in front one in back-->
-                                <!-- draw transparent cubes from back to front and always draw outer and inner triangles and draw from front to back-->
-                                <MeshGeometry3D x:Name="meshInsides" 
-                                Positions="-1 -1 -1  2 -1 -1  -1 2 -1  2 2 -1  -1 -1 2  2 -1 2  -1 2 2  2 2 2
-                                           -1 -1 -3  2 -1 -3  -1 2 -3  2 2 -3  -1 -1 -1  2 -1 -1  -1 2 -1  2 2 -1" 
-                                TriangleIndices="9 11 10  8 9 10  11 9 15  9 13 15  15 13 14  13 12 14  12 10 14  12 8 10  11 15 10  15 14 10  13 9 8  12 13 8
-                                                 1 3 2  0 1 2  3 1 7  1 5 7  7 5 6  5 4 6  4 2 6  4 0 2  3 7 2  7 6 2  5 1 0  4 5 0 
-                                                 ">
-                                </MeshGeometry3D>
-                            </GeometryModel3D.Geometry>
-                            <GeometryModel3D.Material>
-                                <MaterialGroup>
-                                    <DiffuseMaterial>
-                                        <DiffuseMaterial.Brush>
-                                            <SolidColorBrush Opacity="0.1"  Color="DarkGray"/>
-                                        </DiffuseMaterial.Brush>
-                                    </DiffuseMaterial>
-                                </MaterialGroup>
-                            </GeometryModel3D.Material>
-                        </GeometryModel3D>
-                        <GeometryModel3D>
-                            <GeometryModel3D.Geometry>
-                                <!-- two transparent cubes, one in front one in back-->
-                                <!-- draw transparent cubes from back to front and always draw outer and inner triangles and draw from front to back-->
-                                <MeshGeometry3D x:Name="meshTransparent" 
-                                Positions="-1 -1 -1  2 -1 -1  -1 2 -1  2 2 -1  -1 -1 2  2 -1 2  -1 2 2  2 2 2
-                                           -1 -1 -3  2 -1 -3  -1 2 -3  2 2 -3  -1 -1 -1  2 -1 -1  -1 2 -1  2 2 -1" 
-                                TriangleIndices="2 3 1  2 1 0  7 1 3  7 5 1  6 5 7  6 4 5  6 2 4  2 0 4  2 7 3  2 6 7  0 1 5  0 5 4                                                 
-                                                 10 11 9  10 9 8  15 9 11  15 13 9  14 13 15  14 12 13  14 10 12  10 8 12  10 15 11  10 14 15  0 9 13  8 13 12
-                                                 ">
-                                </MeshGeometry3D>
-                            </GeometryModel3D.Geometry>
-                            <GeometryModel3D.Material>
-                                <MaterialGroup>
-                                    <DiffuseMaterial>
-                                        <DiffuseMaterial.Brush>
-                                            <SolidColorBrush Opacity="0.1"  Color="DarkGray"/>
-                                        </DiffuseMaterial.Brush>
-                                    </DiffuseMaterial>
-                                </MaterialGroup>
-                            </GeometryModel3D.Material>
-                        </GeometryModel3D>
-
-                    </Model3DGroup>
-                </ModelVisual3D.Content>
-                <ModelVisual3D.Transform>
-                    <Transform3DGroup>
-                        <ScaleTransform3D x:Name="scale" ScaleX="1" ScaleY="1" ScaleZ="1"/>
-                        <TranslateTransform3D OffsetX="-0.5" OffsetY="-0.5" OffsetZ="-0.5" />
-                        <RotateTransform3D>
-                            <RotateTransform3D.Rotation>
-                                <AxisAngleRotation3D x:Name="rotateX" Axis="0 1 0"/>
-                            </RotateTransform3D.Rotation>
-                        </RotateTransform3D>
-                        <RotateTransform3D>
-                            <RotateTransform3D.Rotation>
-                                <AxisAngleRotation3D x:Name="rotateY" Axis="1 0 0"/>
-                            </RotateTransform3D.Rotation>
-                        </RotateTransform3D>
-                        <TranslateTransform3D OffsetX="0.5" OffsetY="0.5" OffsetZ="0.5" />
-                        <ScaleTransform3D x:Name="scaleZoom" CenterX="0.5" CenterY="0.5" CenterZ="0.5" ScaleX="1" ScaleY="1" ScaleZ="1"/>
-                    </Transform3DGroup>
-                </ModelVisual3D.Transform>
-            </ModelVisual3D>
-        </Viewport3D>
+        <Border BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
+            <Viewport3D Name="viewport3D1" >
+                <Viewport3D.Camera>
+                    <PerspectiveCamera x:Name="camMain" Position="0.5 8 8" LookDirection="0 -1 -1"> <!-- camera position for design time-->
+                    </PerspectiveCamera>
+                </Viewport3D.Camera>
+                <ModelVisual3D>
+                    <ModelVisual3D.Content>
+                        <DirectionalLight x:Name="dirLightMain" Direction="0,-1,-1"/>
+                    </ModelVisual3D.Content>
+                </ModelVisual3D>
+                <ModelVisual3D>
+                </ModelVisual3D>
+                <ModelVisual3D x:Name="MyModel">
+                    <ModelVisual3D.Content>
+                        <Model3DGroup>
+                        </Model3DGroup>
+                    </ModelVisual3D.Content>
+                    <ModelVisual3D.Transform>
+                        <Transform3DGroup>
+                            <ScaleTransform3D x:Name="scale" ScaleX="1" ScaleY="1" ScaleZ="1"/>
+                            <RotateTransform3D x:Name="rotateX">
+                                <RotateTransform3D.Rotation>
+                                    <AxisAngleRotation3D Axis="0 1 0"/>
+                                </RotateTransform3D.Rotation>
+                            </RotateTransform3D>
+                            <RotateTransform3D x:Name="rotateY">
+                                <RotateTransform3D.Rotation>
+                                    <AxisAngleRotation3D Axis="1 0 0"/>
+                                </RotateTransform3D.Rotation>
+                            </RotateTransform3D>
+                            <ScaleTransform3D x:Name="scaleZoom" ScaleX="1" ScaleY="1" ScaleZ="1"/>
+                        </Transform3DGroup>
+                    </ModelVisual3D.Transform>
+                </ModelVisual3D>
+            </Viewport3D>
+        </Border>
     </Grid>
 </UserControl>
Index: stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs	(revision 15278)
@@ -19,8 +19,10 @@
 
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using System.Windows.Media;
 using System.Windows.Media.Media3D;
 using HeuristicLab.Problems.BinPacking3D;
@@ -28,4 +30,24 @@
 namespace HeuristicLab.Problems.BinPacking.Views {
   public partial class Container3DView : UserControl {
+    private static readonly Color[] colors = new[] {
+      Color.FromRgb(0x40, 0x6A, 0xB7),
+      Color.FromRgb(0xB1, 0x6D, 0x01),
+      Color.FromRgb(0x4E, 0x8A, 0x06),
+      Color.FromRgb(0x75, 0x50, 0x7B),
+      Color.FromRgb(0x72, 0x9F, 0xCF),
+      Color.FromRgb(0xA4, 0x00, 0x00),
+      Color.FromRgb(0xAD, 0x7F, 0xA8),
+      Color.FromRgb(0x29, 0x50, 0xCF),
+      Color.FromRgb(0x90, 0xB0, 0x60),
+      Color.FromRgb(0xF5, 0x89, 0x30),
+      Color.FromRgb(0x55, 0x57, 0x53),
+      Color.FromRgb(0xEF, 0x59, 0x59),
+      Color.FromRgb(0xED, 0xD4, 0x30),
+      Color.FromRgb(0x63, 0xC2, 0x16),
+    };
+
+    private static readonly Color hiddenColor = Color.FromArgb(0x1A, 0xAA, 0xAA, 0xAA);
+    private static readonly Color containerColor = Color.FromArgb(0x7F, 0xAA, 0xAA, 0xAA);
+
     private Point startPos;
     private bool mouseDown = false;
@@ -45,7 +67,10 @@
     }
 
+    private Dictionary<int, DiffuseMaterial> materials;
+
     public Container3DView() {
       InitializeComponent();
       camMain.Position = new Point3D(0.5, 3, 3); // for design time we use a different camera position 
+      materials = new Dictionary<int, DiffuseMaterial>();
       Clear();
     }
@@ -74,49 +99,88 @@
       if (packing == null) return; // nothing to display
 
-      // draw all items
-      // order by Z position to reduce artifacts (because of transparent objects) 
-      // TODO: improve code to reduce artifacts 
-      //  - from triangle definitions and lighting
-      //  - from rotation and Z-ordering
-
-      foreach (var item in packing.Items.OrderBy(i => packing.Positions[i.Key].Z)) {
-        var position = packing.Positions[item.Key];
-
-        var w = position.Rotated ? item.Value.Depth : item.Value.Width;
-        var h = item.Value.Height;
-        var d = position.Rotated ? item.Value.Width : item.Value.Depth;
-
-        // ignore the item.Material
-
-        // if nothing is selected then draw all cubes opaque 
-        // otherwise draw only the selected cube opaque and all others transparent
-        if (selectedItemKey < 0 || selectedItemKey == item.Key) {
-          AddCube(meshMain, position.X, position.Y, position.Z, w, h, d);
-        } else {
-          AddCube(meshTransparent, position.X, position.Y, position.Z, w, h, d, addInsideTriangles: true);
+      var modelGroup = (Model3DGroup)MyModel.Content;
+      var hiddenMaterial = new DiffuseMaterial(new SolidColorBrush(hiddenColor));
+
+      if (selectedItemKey >= 0) {
+        var selectedItem = packing.Items.Single(x => selectedItemKey == x.Key);
+        var selectedPos = packing.Positions[selectedItem.Key];
+
+        var colorIdx = selectedItem.Value.Material;
+        while (colorIdx < 0) colorIdx += colors.Length;
+        colorIdx = colorIdx % colors.Length;
+        var color = colors[colorIdx];
+        var material = new DiffuseMaterial { Brush = new SolidColorBrush(color) };
+        materials[selectedItem.Value.Material] = material;
+
+        var selectedModel = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = material };
+        AddSolidCube((MeshGeometry3D)selectedModel.Geometry, selectedPos.X, selectedPos.Y, selectedPos.Z,
+          selectedPos.Rotated ? selectedItem.Value.Depth : selectedItem.Value.Width,
+          selectedItem.Value.Height,
+          selectedPos.Rotated ? selectedItem.Value.Width : selectedItem.Value.Depth);
+        modelGroup.Children.Add(selectedModel);
+
+        foreach (var item in packing.Items.Where(x => selectedItemKey != x.Key)) {
+          var position = packing.Positions[item.Key];
+
+          var w = position.Rotated ? item.Value.Depth : item.Value.Width;
+          var h = item.Value.Height;
+          var d = position.Rotated ? item.Value.Width : item.Value.Depth;
+
+          var model = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = hiddenMaterial };
+          AddWireframeCube((MeshGeometry3D)model.Geometry, position.X, position.Y, position.Z, w, h, d, 1);
+          modelGroup.Children.Add(model);
+        }
+      } else {
+        foreach (var item in packing.Items) {
+          var position = packing.Positions[item.Key];
+
+          var w = position.Rotated ? item.Value.Depth : item.Value.Width;
+          var h = item.Value.Height;
+          var d = position.Rotated ? item.Value.Width : item.Value.Depth;
+
+          var model = new GeometryModel3D { Geometry = new MeshGeometry3D() };
+          DiffuseMaterial material;
+          if (!materials.TryGetValue(item.Value.Material, out material)) {
+            var colorIdx = item.Value.Material;
+            while (colorIdx < 0) colorIdx += colors.Length;
+            colorIdx = colorIdx % colors.Length;
+            var color = colors[colorIdx];
+            material = new DiffuseMaterial { Brush = new SolidColorBrush(color) };
+            materials[item.Value.Material] = material;
+          }
+          var selectedModel = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = material };
+          AddSolidCube((MeshGeometry3D)selectedModel.Geometry, position.X, position.Y, position.Z, w, h, d);
+          modelGroup.Children.Add(selectedModel);
         }
       }
 
       var container = packing.BinShape;
-      // draw a transparent container
-      AddCube(meshTransparent, container.Origin.X, container.Origin.Y, container.Origin.Z, container.Width, container.Height, container.Depth, addInsideTriangles: true);
-
-      // TODO: support cuboids with different side lengths
-      // apply scaling so that the container fits into the unit cube (necessary for the transformations)
-      scale.ScaleX = 1.0 / (container.Width);
-      scale.ScaleY = 1.0 / (container.Height);
-      scale.ScaleZ = 1.0 / (container.Depth);
+      var containerModel = new GeometryModel3D(new MeshGeometry3D(), new DiffuseMaterial(new SolidColorBrush(containerColor)));
+      modelGroup.Children.Add(containerModel);
+      AddWireframeCube((MeshGeometry3D)containerModel.Geometry, container.Origin.X - .5, container.Origin.Y - .5, container.Origin.Z - .5, container.Width + 1, container.Height + 1, container.Depth + 1);
+
+      var ratio = Math.Max(container.Width, Math.Max(container.Height, container.Depth));
+      scale.ScaleX = 1.0 / ratio;
+      scale.ScaleY = 1.0 / ratio;
+      scale.ScaleZ = 1.0 / ratio;
+
+      scaleZoom.CenterX = rotateX.CenterX = rotateY.CenterX = container.Width / (2.0 * ratio);
+      scaleZoom.CenterY = rotateX.CenterY = rotateY.CenterY = container.Height / (2.0 * ratio);
+      scaleZoom.CenterZ = rotateX.CenterZ = rotateY.CenterZ = container.Depth / (2.0 * ratio);
+
+      camMain.Position = new Point3D(
+        scaleZoom.CenterX,
+        3,
+        3);
+      camMain.LookDirection = new Vector3D(
+        0,
+        scaleZoom.CenterY - camMain.Position.Y,
+        scaleZoom.CenterZ - camMain.Position.Z);
     }
 
 
     private void Clear() {
-      meshInsides.Positions.Clear();
-      meshInsides.TriangleIndices.Clear();
-
-      meshMain.Positions.Clear();
-      meshMain.TriangleIndices.Clear();
-
-      meshTransparent.Positions.Clear();
-      meshTransparent.TriangleIndices.Clear();
+      ((Model3DGroup)MyModel.Content).Children.Clear();
+      materials.Clear();
 
       mouseDown = false;
@@ -128,11 +192,12 @@
       if (!mouseDown) return;
       var pos = e.GetPosition((IInputElement)this);
-      rotateX.Angle = startAngleX + (pos.X - startPos.X) / 4;
-      rotateY.Angle = startAngleY + (pos.Y - startPos.Y) / 4;
+
+      ((AxisAngleRotation3D)rotateX.Rotation).Angle = startAngleX + (pos.X - startPos.X) / 4;
+      ((AxisAngleRotation3D)rotateY.Rotation).Angle = startAngleY + (pos.Y - startPos.Y) / 4;
     }
 
     private void Container3DView_MouseDown(object sender, MouseButtonEventArgs e) {
-      startAngleX = rotateX.Angle;
-      startAngleY = rotateY.Angle;
+      startAngleX = ((AxisAngleRotation3D)rotateX.Rotation).Angle;
+      startAngleY = ((AxisAngleRotation3D)rotateY.Rotation).Angle;
       this.startPos = e.GetPosition((IInputElement)this);
       this.mouseDown = true;
@@ -155,147 +220,249 @@
     }
 
+    private void Container3DView_OnMouseEnter(object sender, MouseEventArgs e) {
+      Focus(); // for mouse wheel events
+    }
 
     #region helper for cubes
-
-    private void AddCube(MeshGeometry3D mesh, int x, int y, int z, int width, int height, int depth, bool addInsideTriangles = false) {
-      AddOutsideTriangles(mesh, AddPoints(mesh, x, y, z, width, height, depth));
-      if (addInsideTriangles) AddInsideTriangles(meshInsides, AddPoints(meshInsides, x, y, z, width, height, depth));
-    }
-
-    private void AddOutsideTriangles(MeshGeometry3D mesh, int[] pointIdx) {
-      // point indices counter-clockwise
-      // back side
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[1]);
-
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-
-      // bottom side
-      mesh.TriangleIndices.Add(pointIdx[5]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-
-      mesh.TriangleIndices.Add(pointIdx[5]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[1]);
-
-      // right side
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[5]);
-
-      mesh.TriangleIndices.Add(pointIdx[1]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[5]);
-
-      // left side
-      mesh.TriangleIndices.Add(pointIdx[7]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-
-      // top side
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[7]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-
-      // front side
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[7]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[5]);
-    }
-
-    private void AddInsideTriangles(MeshGeometry3D mesh, int[] pointIdx) {
-      // for each cube we also draw the triangles facing inside because they are visible when a cube is transparent
-      // point indices clockwise
-
-      // back side
-      mesh.TriangleIndices.Add(pointIdx[1]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-
-      // bottom side
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[5]);
-
-      mesh.TriangleIndices.Add(pointIdx[1]);
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[5]);
-
-      // right side
-      mesh.TriangleIndices.Add(pointIdx[5]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-
-      mesh.TriangleIndices.Add(pointIdx[5]);
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[1]);
-
-      // left side
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[7]);
-
-      mesh.TriangleIndices.Add(pointIdx[0]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-
-      // top side
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[7]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-
-      mesh.TriangleIndices.Add(pointIdx[2]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-      mesh.TriangleIndices.Add(pointIdx[3]);
-
-      // front side
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[7]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-
-      mesh.TriangleIndices.Add(pointIdx[5]);
-      mesh.TriangleIndices.Add(pointIdx[4]);
-      mesh.TriangleIndices.Add(pointIdx[6]);
-    }
-
-    private int[] AddPoints(MeshGeometry3D mesh, int x, int y, int z, int w, int h, int d) {
+    /// <summary>
+    /// Creates a solid cube by adding the respective points and triangles.
+    /// </summary>
+    /// <param name="mesh">The mesh to which points and triangles are added.</param>
+    /// <param name="x">The leftmost point</param>
+    /// <param name="y">The frontmost point</param>
+    /// <param name="z">The lowest point</param>
+    /// <param name="width">The extension to the right</param>
+    /// <param name="height">The extension to the back</param>
+    /// <param name="depth">The extension to the top</param>
+    private void AddSolidCube(MeshGeometry3D mesh, int x, int y, int z, int width, int height, int depth) {
       // ground
       mesh.Positions.Add(new Point3D(x, y, z));
-      mesh.Positions.Add(new Point3D(x + w, y, z));
-      mesh.Positions.Add(new Point3D(x + w, y + h, z));
-      mesh.Positions.Add(new Point3D(x, y + h, z));
+      mesh.Positions.Add(new Point3D(x + width, y, z));
+      mesh.Positions.Add(new Point3D(x + width, y + height, z));
+      mesh.Positions.Add(new Point3D(x, y + height, z));
       // top
-      mesh.Positions.Add(new Point3D(x, y, z + d));
-      mesh.Positions.Add(new Point3D(x + w, y, z + d));
-      mesh.Positions.Add(new Point3D(x + w, y + h, z + d));
-      mesh.Positions.Add(new Point3D(x, y + h, z + d));
-
-      return Enumerable.Range(mesh.Positions.Count - 8, 8).ToArray();
+      mesh.Positions.Add(new Point3D(x, y, z + depth));
+      mesh.Positions.Add(new Point3D(x + width, y, z + depth));
+      mesh.Positions.Add(new Point3D(x + width, y + height, z + depth));
+      mesh.Positions.Add(new Point3D(x, y + height, z + depth));
+
+      // front
+      AddPlane(mesh, 0, 1, 5, 4);
+      // right side
+      AddPlane(mesh, 1, 2, 6, 5);
+      // back
+      AddPlane(mesh, 3, 7, 6, 2);
+      // left side
+      AddPlane(mesh, 0, 4, 7, 3);
+      // top
+      AddPlane(mesh, 4, 5, 6, 7);
+      // bottom
+      AddPlane(mesh, 0, 3, 2, 1);
+    }
+
+    /// <summary>
+    /// Creates a wireframe cube by adding the respective points and triangles.
+    /// </summary>
+    /// <param name="mesh">The mesh to which points and triangles are added.</param>
+    /// <param name="x">The leftmost point</param>
+    /// <param name="y">The frontmost point</param>
+    /// <param name="z">The lowest point</param>
+    /// <param name="width">The extension to the right</param>
+    /// <param name="height">The extension to the back</param>
+    /// <param name="depth">The extension to the top</param>
+    /// <param name="thickness">The thickness of the frame</param>
+    private void AddWireframeCube(MeshGeometry3D mesh, double x, double y, double z, double width, double height, double depth, double thickness = double.NaN) {
+      // default thickness of the wireframe is 5% of smallest dimension
+      if (double.IsNaN(thickness))
+        thickness = Math.Min(width, Math.Min(height, depth)) * 0.05;
+
+      // The cube contains of 8 corner, each corner has 4 points:
+      // 1. The corner point
+      // 2. A point on the edge to the right of the corner
+      // 3. A point on the edge atop or below the corner
+      // 4. A point on the edge to the left of the corner
+
+      // Point 0, Front Left Bottom
+      mesh.Positions.Add(new Point3D(x, y, z));
+      mesh.Positions.Add(new Point3D(x + thickness, y, z));
+      mesh.Positions.Add(new Point3D(x, y, z + thickness));
+      mesh.Positions.Add(new Point3D(x, y + thickness, z));
+
+      // Point 1, Front Right Bottom
+      mesh.Positions.Add(new Point3D(x + width, y, z));
+      mesh.Positions.Add(new Point3D(x + width, y + thickness, z));
+      mesh.Positions.Add(new Point3D(x + width, y, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y, z));
+
+      // Point 2, Back Right Bottom
+      mesh.Positions.Add(new Point3D(x + width, y + height, z));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height, z));
+      mesh.Positions.Add(new Point3D(x + width, y + height, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width, y + height - thickness, z));
+
+      // Point 3, Back Left Bottom
+      mesh.Positions.Add(new Point3D(x, y + height, z));
+      mesh.Positions.Add(new Point3D(x, y + height - thickness, z));
+      mesh.Positions.Add(new Point3D(x, y + height, z + thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height, z));
+
+      // Point 4, Front Left Top
+      mesh.Positions.Add(new Point3D(x, y, z + depth));
+      mesh.Positions.Add(new Point3D(x + thickness, y, z + depth));
+      mesh.Positions.Add(new Point3D(x, y, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x, y + thickness, z + depth));
+
+      // Point 5, Front Right Top
+      mesh.Positions.Add(new Point3D(x + width, y, z + depth));
+      mesh.Positions.Add(new Point3D(x + width, y + thickness, z + depth));
+      mesh.Positions.Add(new Point3D(x + width, y, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y, z + depth));
+
+      // Point 6, Back Right Top
+      mesh.Positions.Add(new Point3D(x + width, y + height, z + depth));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height, z + depth));
+      mesh.Positions.Add(new Point3D(x + width, y + height, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width, y + height - thickness, z + depth));
+
+      // Point 7, Back Left Top
+      mesh.Positions.Add(new Point3D(x, y + height, z + depth));
+      mesh.Positions.Add(new Point3D(x, y + height - thickness, z + depth));
+      mesh.Positions.Add(new Point3D(x, y + height, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height, z + depth));
+
+      // Point 0, non-edge
+      mesh.Positions.Add(new Point3D(x + thickness, y, z + thickness));
+      mesh.Positions.Add(new Point3D(x, y + thickness, z + thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + thickness, z));
+
+      // Point 1, non-edge
+      mesh.Positions.Add(new Point3D(x + width, y + thickness, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + thickness, z));
+
+      // Point 2, non-edge
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width, y + height - thickness, z + thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height - thickness, z));
+
+      // Point 3, non-edge
+      mesh.Positions.Add(new Point3D(x, y + height - thickness, z + thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height, z + thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height - thickness, z));
+
+      // Point 4, non-edge
+      mesh.Positions.Add(new Point3D(x + thickness, y, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x, y + thickness, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + thickness, z + depth));
+
+      // Point 5, non-edge
+      mesh.Positions.Add(new Point3D(x + width, y + thickness, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + thickness, z + depth));
+
+      // Point 6, non-edge
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width, y + height - thickness, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + width - thickness, y + height - thickness, z + depth));
+
+      // Point 7, non-edge
+      mesh.Positions.Add(new Point3D(x, y + height - thickness, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height, z + depth - thickness));
+      mesh.Positions.Add(new Point3D(x + thickness, y + height - thickness, z + depth));
+
+      // Draw the 24 corner plates
+      AddPlane(mesh, 0, 1, 32, 2);
+      AddPlane(mesh, 0, 2, 33, 3);
+      AddPlane(mesh, 0, 3, 34, 1);
+
+      AddPlane(mesh, 4, 6, 36, 7);
+      AddPlane(mesh, 4, 5, 35, 6);
+      AddPlane(mesh, 4, 7, 37, 5);
+
+      AddPlane(mesh, 8, 10, 39, 11);
+      AddPlane(mesh, 8, 9, 38, 10);
+      AddPlane(mesh, 8, 11, 40, 9);
+
+      AddPlane(mesh, 12, 13, 41, 14);
+      AddPlane(mesh, 12, 14, 42, 15);
+      AddPlane(mesh, 12, 15, 43, 13);
+
+      AddPlane(mesh, 16, 18, 44, 17);
+      AddPlane(mesh, 16, 19, 45, 18);
+      AddPlane(mesh, 16, 17, 46, 19);
+
+      AddPlane(mesh, 20, 23, 48, 22);
+      AddPlane(mesh, 20, 22, 47, 21);
+      AddPlane(mesh, 20, 21, 49, 23);
+
+      AddPlane(mesh, 24, 27, 51, 26);
+      AddPlane(mesh, 24, 26, 50, 25);
+      AddPlane(mesh, 24, 25, 52, 27);
+
+      AddPlane(mesh, 28, 31, 54, 30);
+      AddPlane(mesh, 28, 30, 53, 29);
+      AddPlane(mesh, 28, 29, 55, 31);
+
+      // Draw the connecting plates
+      // on the bottom
+      AddPlane(mesh, 1, 7, 36, 32);
+      AddPlane(mesh, 1, 34, 37, 7);
+
+      AddPlane(mesh, 5, 11, 39, 35);
+      AddPlane(mesh, 5, 37, 40, 11);
+
+      AddPlane(mesh, 9, 15, 42, 38);
+      AddPlane(mesh, 9, 40, 43, 15);
+
+      AddPlane(mesh, 13, 3, 33, 41);
+      AddPlane(mesh, 13, 43, 34, 3);
+
+      // between bottom and top
+      AddPlane(mesh, 2, 32, 44, 18);
+      AddPlane(mesh, 2, 18, 45, 33);
+
+      AddPlane(mesh, 6, 22, 48, 36);
+      AddPlane(mesh, 6, 35, 47, 22);
+
+      AddPlane(mesh, 10, 26, 51, 39);
+      AddPlane(mesh, 10, 38, 50, 26);
+
+      AddPlane(mesh, 14, 30, 54, 42);
+      AddPlane(mesh, 14, 41, 53, 30);
+
+      // on the top
+      AddPlane(mesh, 17, 44, 48, 23);
+      AddPlane(mesh, 17, 23, 49, 46);
+
+      AddPlane(mesh, 21, 47, 51, 27);
+      AddPlane(mesh, 21, 27, 52, 49);
+
+      AddPlane(mesh, 25, 50, 54, 31);
+      AddPlane(mesh, 25, 31, 55, 52);
+
+      AddPlane(mesh, 29, 19, 46, 55);
+      AddPlane(mesh, 29, 53, 45, 19);
+    }
+
+    /// <summary>
+    /// Adds a plane by two triangles. The indices of the points have to be given
+    /// in counter-clockwise sequence.
+    /// </summary>
+    /// <param name="mesh">The mesh to add the triangles to</param>
+    /// <param name="a">The index of the first point</param>
+    /// <param name="b">The index of the second point</param>
+    /// <param name="c">The index of the third point</param>
+    /// <param name="d">The index of the fourth point</param>
+    private void AddPlane(MeshGeometry3D mesh, int a, int b, int c, int d) {
+      // two triangles form a plane
+      mesh.TriangleIndices.Add(a);
+      mesh.TriangleIndices.Add(b);
+      mesh.TriangleIndices.Add(d);
+      mesh.TriangleIndices.Add(c);
+      mesh.TriangleIndices.Add(d);
+      mesh.TriangleIndices.Add(b);
     }
     #endregion
 
-    private void Container3DView_OnMouseEnter(object sender, MouseEventArgs e) {
-      Focus(); // for mouse wheel events
-    }
   }
 }
Index: stable/HeuristicLab.Problems.BinPacking.Views/3.3/HeuristicLab.Problems.BinPacking.Views-3.3.csproj
===================================================================
--- stable/HeuristicLab.Problems.BinPacking.Views/3.3/HeuristicLab.Problems.BinPacking.Views-3.3.csproj	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking.Views/3.3/HeuristicLab.Problems.BinPacking.Views-3.3.csproj	(revision 15278)
@@ -75,7 +75,9 @@
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Data" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xaml" />
+    <Reference Include="System.Xml" />
     <Reference Include="UIAutomationProvider" />
     <Reference Include="WindowsBase" />
Index: stable/HeuristicLab.Problems.BinPacking/3.3/2D/BinPacking2D.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/2D/BinPacking2D.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/2D/BinPacking2D.cs	(revision 15278)
@@ -34,5 +34,4 @@
     public BinPacking2D(PackingShape binShape)
       : base(binShape) {
-      ExtremePoints = new SortedSet<PackingPosition>();
       ExtremePoints.Add(binShape.Origin);
       InitializeOccupationLayers();
@@ -41,8 +40,5 @@
     [StorableConstructor]
     protected BinPacking2D(bool deserializing) : base(deserializing) { }
-    protected BinPacking2D(BinPacking2D original, Cloner cloner)
-      : base(original, cloner) {
-      this.ExtremePoints = new SortedSet<PackingPosition>(original.ExtremePoints.Select(p => cloner.Clone(p)));
-    }
+    protected BinPacking2D(BinPacking2D original, Cloner cloner) : base(original, cloner) { }
     public override IDeepCloneable Clone(Cloner cloner) {
       return new BinPacking2D(this, cloner);
@@ -88,38 +84,34 @@
       };
 
-      int epIndex = 0;
-      while (epIndex < ExtremePoints.Count && (!IsPositionFeasible(rotatedItem, ExtremePoints.ElementAt(epIndex)))) { epIndex++; }
-
-      if (epIndex < ExtremePoints.Count) {
-        var currentPoint = ExtremePoints.ElementAt(epIndex);
-
-        var result = new PackingPosition(currentPoint.AssignedBin, currentPoint.X, currentPoint.Y, rotated);
+      var ep = ExtremePoints.Where(x => IsPositionFeasible(rotatedItem, x, stackingConstraints)).FirstOrDefault();
+      if (ep != null) {
+        var result = new PackingPosition(ep.AssignedBin, ep.X, ep.Y, rotated);
         return result;
       }
       return null;
     }
-    public override PackingPosition FindPositionBySliding(PackingItem item, bool rotated) {
+    public override PackingPosition FindPositionBySliding(PackingItem item, bool rotated, bool stackingConstraints) {
       PackingPosition currentPosition = new PackingPosition(0,
         BinShape.Width - (rotated ? item.Height : item.Width),
         BinShape.Height - (rotated ? item.Width : item.Height), rotated);
       //Slide the item as far as possible to the left
-      while (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition))
-        || IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition))) {
+      while (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition), stackingConstraints)
+        || IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition), stackingConstraints)) {
         //Slide the item as far as possible to the bottom
-        while (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition))) {
+        while (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition), stackingConstraints)) {
           currentPosition = PackingPosition.MoveDown(currentPosition);
         }
-        if (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition)))
+        if (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition), stackingConstraints))
           currentPosition = PackingPosition.MoveLeft(currentPosition);
       }
 
-      return IsPositionFeasible(item, currentPosition) ? currentPosition : null;
-    }
-
-    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items) {
+      return IsPositionFeasible(item, currentPosition, stackingConstraints) ? currentPosition : null;
+    }
+
+    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints) {
       var temp = new List<int>(sequence);
       for (int i = 0; i < temp.Count; i++) {
         var item = items[temp[i]];
-        var position = FindPositionBySliding(item, false);
+        var position = FindPositionBySliding(item, false, stackingConstraints);
         if (position != null) {
           PackItem(temp[i], item, position);
@@ -128,9 +120,9 @@
       }
     }
-    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, Dictionary<int, bool> rotationArray) {
+    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, Dictionary<int, bool> rotationArray, bool stackingConstraints) {
       var temp = new List<int>(sequence);
       for (int i = 0; i < temp.Count; i++) {
         var item = items[temp[i]];
-        var position = FindPositionBySliding(item, rotationArray[temp[i]]);
+        var position = FindPositionBySliding(item, rotationArray[temp[i]], stackingConstraints);
         if (position != null) {
           PackItem(temp[i], item, position);
@@ -150,4 +142,5 @@
       }
     }
+    
     public override void ExtremePointBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints, Dictionary<int, bool> rotationArray) {
       var temp = new List<int>(sequence);
@@ -186,5 +179,4 @@
       throw new NotSupportedException();
     }
-
     protected override void InitializeOccupationLayers() {
       for (int i = 0; i * 10 <= BinShape.Width; i += 1) {
Index: stable/HeuristicLab.Problems.BinPacking/3.3/2D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/2D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/2D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs	(revision 15278)
@@ -47,5 +47,5 @@
 
     protected override PackingPosition FindPositionForItem(BinPacking2D bp, PackingItem item) {
-      return bp.FindPositionBySliding(item, rotated: false);
+      return bp.FindPositionBySliding(item, rotated: false, stackingConstraints: false);
     }
 
@@ -54,5 +54,5 @@
       ref IList<int> remainingIDs, IList<PackingItem> items) {
       var bp = new BinPacking2D(partialSolution.BinShape);
-      bp.SlidingBasedPacking(ref remainingIDs, items);
+      bp.SlidingBasedPacking(ref remainingIDs, items, stackingConstraints: false);
       return bp;
     }
Index: stable/HeuristicLab.Problems.BinPacking/3.3/2D/PermutationEncoding/BottomLeftPermutationDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/2D/PermutationEncoding/BottomLeftPermutationDecoder.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/2D/PermutationEncoding/BottomLeftPermutationDecoder.cs	(revision 15278)
@@ -46,5 +46,5 @@
       while (remainingIDs.Count > 0) {
         var bp = new BinPacking2D(binShape);
-        bp.SlidingBasedPacking(ref remainingIDs, items);
+        bp.SlidingBasedPacking(ref remainingIDs, items, stackingConstraints: false);
         result.Bins.Add(bp);
       }
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/BinPacking3D.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/BinPacking3D.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/BinPacking3D.cs	(revision 15278)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -32,8 +33,11 @@
   public class BinPacking3D : BinPacking<PackingPosition, PackingShape, PackingItem> {
 
+    [Storable]
+    public Dictionary<PackingPosition, Tuple<int, int, int>> ResidualSpace { get; protected set; }
+
     public BinPacking3D(PackingShape binShape)
       : base(binShape) {
-      ExtremePoints = new SortedSet<PackingPosition>();
-      ExtremePoints.Add(binShape.Origin);
+      ResidualSpace = new Dictionary<PackingPosition, Tuple<int,int,int>>();
+      AddExtremePoint(binShape.Origin);
       InitializeOccupationLayers();
     }
@@ -42,8 +46,25 @@
     protected BinPacking3D(BinPacking3D original, Cloner cloner)
       : base(original, cloner) {
-      this.ExtremePoints = new SortedSet<PackingPosition>(original.ExtremePoints.Select(p => cloner.Clone(p)));
+      this.ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
+      foreach (var o in original.ResidualSpace)
+        this.ResidualSpace.Add(cloner.Clone(o.Key), Tuple.Create(o.Value.Item1, o.Value.Item2, o.Value.Item3));
     }
     public override IDeepCloneable Clone(Cloner cloner) {
       return new BinPacking3D(this, cloner);
+    }
+
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (ResidualSpace == null)
+        ResidualSpace = new Dictionary<PackingPosition, Tuple<int, int, int>>();
+      #endregion
+    }
+
+    public override void PackItem(int itemID, PackingItem item, PackingPosition position) {
+      ResidualSpace.Remove(position);
+      base.PackItem(itemID, item, position);
     }
 
@@ -60,9 +81,9 @@
           current = PackingPosition.MoveDown(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
+        AddExtremePoint((PackingPosition)current.Clone());
         while (current.X > 0 && !IsPointOccupied(PackingPosition.MoveLeft(current))) {
           current = PackingPosition.MoveLeft(current);
         }
-        ExtremePoints.Add(current);
+        AddExtremePoint(current);
 
         //Traversing down the z-axis
@@ -71,9 +92,9 @@
           current = PackingPosition.MoveBack(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
-        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
-          current = PackingPosition.MoveDown(current);
-        }
-        ExtremePoints.Add(current);
+        AddExtremePoint((PackingPosition)current.Clone());
+        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
+          current = PackingPosition.MoveDown(current);
+        }
+        AddExtremePoint(current);
       }
 
@@ -86,9 +107,9 @@
           current = PackingPosition.MoveLeft(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
-        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
-          current = PackingPosition.MoveDown(current);
-        }
-        ExtremePoints.Add(current);
+        AddExtremePoint((PackingPosition)current.Clone());
+        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
+          current = PackingPosition.MoveDown(current);
+        }
+        AddExtremePoint(current);
 
         //Traversing down the z-axis
@@ -97,9 +118,9 @@
           current = PackingPosition.MoveBack(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
-        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
-          current = PackingPosition.MoveDown(current);
-        }
-        ExtremePoints.Add(current);
+        AddExtremePoint((PackingPosition)current.Clone());
+        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
+          current = PackingPosition.MoveDown(current);
+        }
+        AddExtremePoint(current);
       }
 
@@ -112,9 +133,9 @@
           current = PackingPosition.MoveLeft(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
-        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
-          current = PackingPosition.MoveDown(current);
-        }
-        ExtremePoints.Add(current);
+        AddExtremePoint((PackingPosition)current.Clone());
+        while (current.Y > 0 && !IsPointOccupied(PackingPosition.MoveDown(current))) {
+          current = PackingPosition.MoveDown(current);
+        }
+        AddExtremePoint(current);
 
         //Traversing down the y-axis
@@ -123,14 +144,20 @@
           current = PackingPosition.MoveDown(current);
         }
-        ExtremePoints.Add((PackingPosition)current.Clone());
+        AddExtremePoint((PackingPosition)current.Clone());
         while (current.X > 0 && !IsPointOccupied(PackingPosition.MoveLeft(current))) {
           current = PackingPosition.MoveLeft(current);
         }
-        ExtremePoints.Add(current);
+        AddExtremePoint(current);
+      }
+    }
+
+    private void AddExtremePoint(PackingPosition current) {
+      if (ExtremePoints.Add(current)) {
+        var tuple = Tuple.Create(BinShape.Width - current.X, BinShape.Height - current.Y, BinShape.Depth - current.Z);
+        ResidualSpace.Add(current, tuple);
       }
     }
 
     public override PackingPosition FindExtremePointForItem(PackingItem item, bool rotated, bool stackingConstraints) {
-
       PackingItem newItem = new PackingItem(
         rotated ? item.Depth : item.Width,
@@ -139,15 +166,7 @@
         item.TargetBin, item.Weight, item.Material);
 
-      int epIndex = 0;
-      while (epIndex < ExtremePoints.Count && (
-        !IsPositionFeasible(newItem, ExtremePoints.ElementAt(epIndex))
-        || !IsSupportedByAtLeastOnePoint(newItem, ExtremePoints.ElementAt(epIndex))
-        || (stackingConstraints && !IsStaticStable(newItem, ExtremePoints.ElementAt(epIndex)))
-        || (stackingConstraints && !IsWeightSupported(newItem, ExtremePoints.ElementAt(epIndex)))
-      )) { epIndex++; }
-
-      if (epIndex < ExtremePoints.Count) {
-        var origPoint = ExtremePoints.ElementAt(epIndex);
-        var result = new PackingPosition(origPoint.AssignedBin, origPoint.X, origPoint.Y, origPoint.Z, rotated);
+      var ep = ExtremePoints.Where(x => IsPositionFeasible(newItem, x, stackingConstraints)).FirstOrDefault();
+      if (ep != null) {
+        var result = new PackingPosition(ep.AssignedBin, ep.X, ep.Y, ep.Z, rotated);
         return result;
       }
@@ -155,6 +174,12 @@
     }
 
-    public override PackingPosition FindPositionBySliding(PackingItem item, bool rotated) {
-      //TODO: does not support stacking constraints yet
+    public override bool IsPositionFeasible(PackingItem item, PackingPosition position, bool stackingConstraints) {
+      var feasible = base.IsPositionFeasible(item, position, stackingConstraints);
+      return feasible
+        && IsSupportedByAtLeastOnePoint(item, position)
+        && (!stackingConstraints || (IsStaticStable(item, position) && IsWeightSupported(item, position)));
+    }
+
+    public override PackingPosition FindPositionBySliding(PackingItem item, bool rotated, bool stackingConstraints) {
       //Starting-position at upper right corner (=left bottom point of item-rectangle is at position item.width,item.height)
       PackingPosition currentPosition = new PackingPosition(0,
@@ -163,29 +188,29 @@
         BinShape.Depth - (rotated ? item.Width : item.Depth), rotated);
       //Slide the item as far as possible to the bottom
-      while (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition))
-        || IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition))
-        || IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition))) {
+      while (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition), stackingConstraints)
+        || IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition), stackingConstraints)
+        || IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition), stackingConstraints)) {
         //Slide the item as far as possible to the left
-        while (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition))
-      || IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition))) {
+        while (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition), stackingConstraints)
+      || IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition), stackingConstraints)) {
           //Slide the item as far as possible to the back
-          while (IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition))) {
+          while (IsPositionFeasible(item, PackingPosition.MoveBack(currentPosition), stackingConstraints)) {
             currentPosition = PackingPosition.MoveBack(currentPosition);
           }
-          if (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition)))
+          if (IsPositionFeasible(item, PackingPosition.MoveLeft(currentPosition), stackingConstraints))
             currentPosition = PackingPosition.MoveLeft(currentPosition);
         }
-        if (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition)))
+        if (IsPositionFeasible(item, PackingPosition.MoveDown(currentPosition), stackingConstraints))
           currentPosition = PackingPosition.MoveDown(currentPosition);
       }
 
-      return IsPositionFeasible(item, currentPosition) ? currentPosition : null;
-    }
-
-    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items) {
+      return IsPositionFeasible(item, currentPosition, stackingConstraints) ? currentPosition : null;
+    }
+
+    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, bool stackingConstraints) {
       var temp = new List<int>(sequence);
       for (int i = 0; i < temp.Count; i++) {
         var item = items[temp[i]];
-        var position = FindPositionBySliding(item, false);
+        var position = FindPositionBySliding(item, false, stackingConstraints);
         if (position != null) {
           PackItem(temp[i], item, position);
@@ -194,9 +219,9 @@
       }
     }
-    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, Dictionary<int, bool> rotationArray) {
+    public override void SlidingBasedPacking(ref IList<int> sequence, IList<PackingItem> items, Dictionary<int, bool> rotationArray, bool stackingConstraints) {
       var temp = new List<int>(sequence);
       for (int i = 0; i < temp.Count; i++) {
         var item = items[temp[i]];
-        var position = FindPositionBySliding(item, rotationArray[i]);
+        var position = FindPositionBySliding(item, rotationArray[i], stackingConstraints);
         if (position != null) {
           PackItem(temp[i], item, position);
@@ -212,4 +237,6 @@
         if (positionFound != null) {
           PackItem(itemID, item, positionFound);
+          if (Items.Count > 1)
+            UpdateResidualSpace(item, positionFound);
           sequence.Remove(itemID);
         }
@@ -227,5 +254,4 @@
       }
     }
-
     public override int ShortestPossibleSideFromPoint(PackingPosition position) {
 
@@ -297,5 +323,4 @@
     }
 
-
     protected override void InitializeOccupationLayers() {
       for (int i = 0; i * 10 <= BinShape.Depth; i += 1) {
@@ -320,8 +345,31 @@
       for (int i = z1; i <= z2; i++)
         result.AddRange(OccupationLayers[i]);
-
       return result;
     }
+    
+    public void UpdateResidualSpace(PackingItem item, PackingPosition pos) {
+      foreach (var ep in ExtremePoints) {
+        if (ep.Z >= pos.Z && ep.Z <= pos.Z + item.Depth) {
+          if (ep.X <= pos.X && ep.Y > pos.Y && ep.Y < pos.Y + item.Height) {
+            var diff = pos.X - ep.X;
+            var newRSX = ResidualSpace[ep].Item1 < diff ? ResidualSpace[ep].Item1 : diff;
+            ResidualSpace[ep] = Tuple.Create(newRSX, ResidualSpace[ep].Item2, ResidualSpace[ep].Item3);
+          }
+          if (ep.Y <= pos.Y && ep.X > pos.X && ep.X < pos.X + item.Width) {
+            var diff = pos.Y - ep.Y;
+            var newRSY = ResidualSpace[ep].Item2 < diff ? ResidualSpace[ep].Item2 : diff;
+            ResidualSpace[ep] = Tuple.Create(ResidualSpace[ep].Item1, newRSY, ResidualSpace[ep].Item3);
+          }
+        }
+        if (ep.Z <= pos.Z && 
+          ep.Y > pos.Y && ep.Y < pos.Y + item.Height &&
+          ep.X > pos.X && ep.X < pos.X + item.Width) {
+            var diff = pos.Z - ep.Z;
+            var newRSZ = ResidualSpace[ep].Item3 < diff ? ResidualSpace[ep].Item3 : diff;
+            ResidualSpace[ep] = Tuple.Create(ResidualSpace[ep].Item1, ResidualSpace[ep].Item2, newRSZ);
+        }
+      }
+      return;
+    }
   }
-
 }
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/RealWorldContainerPackingInstanceProvider.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/RealWorldContainerPackingInstanceProvider.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/RealWorldContainerPackingInstanceProvider.cs	(revision 15278)
@@ -0,0 +1,139 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  public sealed class RealWorldContainerPackingInstanceProvider : ProblemInstanceProvider<BPPData> {
+    private string FileName { get { return "ContainerPackingInstances"; } }
+    
+    public override string Name {
+      get { return "Real-world Container Packing"; }
+    }
+
+    public override string Description {
+      get { return "Problem instances derived from real-world container packing data."; }
+    }
+
+    public override Uri WebLink {
+      get { return null; }
+    }
+
+    public override string ReferencePublication {
+      get { return null; }
+    }
+
+    public RealWorldContainerPackingInstanceProvider() : base() { }
+
+    public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
+      var instanceArchiveName = GetResourceName(FileName + @"\.zip");
+      if (String.IsNullOrEmpty(instanceArchiveName)) yield break;
+
+      using (var instanceStream = new ZipArchive(GetType().Assembly.GetManifestResourceStream(instanceArchiveName), ZipArchiveMode.Read)) {
+        foreach (var entry in instanceStream.Entries.Select(x => x.Name).OrderBy(x => x)) {
+          yield return new ThreeDInstanceDescriptor(Path.GetFileNameWithoutExtension(entry), GetDescription(), entry);
+        }
+      }
+    }
+
+    private string GetResourceName(string fileName) {
+      return Assembly.GetExecutingAssembly().GetManifestResourceNames()
+              .Where(x => Regex.Match(x, @".*\.Instances\." + fileName).Success).SingleOrDefault();
+    }
+
+    private string GetDescription() {
+      return "Embedded instance of plugin version " + Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true).Cast<AssemblyFileVersionAttribute>().First().Version + ".";
+    }
+
+    public override BPPData LoadData(IDataDescriptor dd) {
+      var desc = dd as ThreeDInstanceDescriptor;
+      if (desc == null) throw new NotSupportedException("Cannot load data descriptor " + dd);
+      var instanceArchiveName = GetResourceName(FileName + @"\.zip");
+      using (
+        var instancesZipFile = new ZipArchive(GetType().Assembly.GetManifestResourceStream(instanceArchiveName),
+          ZipArchiveMode.Read)) {
+        var entry = instancesZipFile.GetEntry(desc.InstanceIdentifier);
+
+        using (var stream = entry.Open()) {
+          var parser = new ThreeDInstanceParser();
+          parser.Parse(stream);
+
+          return new BPPData() {
+            Name = desc.Name,
+            Description = desc.Description,
+            BinShape = parser.Bin,
+            Items = parser.Items.ToArray()
+          };
+        }
+      }
+    }
+
+    public override bool CanImportData {
+      get { return true; }
+    }
+
+    public override BPPData ImportData(string path) {
+      using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
+        var parser = new ThreeDInstanceParser();
+        parser.Parse(stream);
+
+        return new BPPData() {
+          Name = Path.GetFileNameWithoutExtension(path),
+          Description = "Imported instance from " + path,
+          BinShape = parser.Bin,
+          Items = parser.Items.ToArray()
+        };
+      }
+    }
+
+    public override bool CanExportData {
+      get { return true; }
+    }
+
+    public override void ExportData(BPPData instance, string file) {
+      using (Stream stream = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Write)) {
+        Export(instance, stream);
+      }
+    }
+    public static void Export(BPPData instance, Stream stream) {
+
+      using (var writer = new StreamWriter(stream)) {
+        writer.WriteLine(String.Format("{0,-5} {1,-5} {2,-5}   WBIN,HBIN,DBIN", instance.BinShape.Width, instance.BinShape.Height, instance.BinShape.Depth));
+        for (int i = 0; i < instance.NumItems; i++) {
+          if (i == 0)
+            writer.WriteLine("{0,-5} {1,-5} {2,-5}   W(I),H(I),D(I),I=1,...,N", instance.Items[i].Width, instance.Items[i].Height, instance.Items[i].Depth);
+          else
+            writer.WriteLine("{0,-5} {1,-5} {2,-5}", instance.Items[i].Width, instance.Items[i].Height, instance.Items[i].Depth);
+
+        }
+        writer.Flush();
+      }
+    }
+
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceDescriptor.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceDescriptor.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceDescriptor.cs	(revision 15278)
@@ -0,0 +1,39 @@
+﻿#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#endregion
+
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  internal sealed class ThreeDInstanceDescriptor : IDataDescriptor {
+    public string Name { get; private set; }
+    public string Description { get; private set; }
+
+    public string InstanceIdentifier { get; private set; }
+
+    internal ThreeDInstanceDescriptor(string name, string description, string instanceIdentifier) {
+      this.Name = name;
+      this.Description = description;
+      this.InstanceIdentifier = instanceIdentifier;
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceParser.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceParser.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/Instances/ThreeDInstanceParser.cs	(revision 15278)
@@ -0,0 +1,76 @@
+﻿#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  public class ThreeDInstanceParser {
+    public PackingShape Bin { get; private set; }
+    public List<PackingItem> Items { get; private set; }
+
+    public void Parse(Stream stream) {
+      var reader = new StreamReader(stream);
+      var length = GetNextInteger(reader);
+      var width = GetNextInteger(reader);
+      var height = GetNextInteger(reader);
+      var maxWeight = GetNextInteger(reader);
+      Bin = new PackingShape(width, height, length);
+      Items = new List<PackingItem>();
+      while (true) {
+        try {
+          var id = GetNextInteger(reader);
+          var pieces = GetNextInteger(reader);
+          length = GetNextInteger(reader);
+          width = GetNextInteger(reader);
+          height = GetNextInteger(reader);
+          var weight = GetNextInteger(reader);
+          var stack = GetNextInteger(reader);
+          var material = GetNextInteger(reader);
+          var rotate = GetNextInteger(reader);
+          var tilt = GetNextInteger(reader);
+          for (var i = 0; i < pieces; i++) {
+            Items.Add(new PackingItem(width, height, length, Bin, weight, material));
+          }
+        } catch (InvalidOperationException) {
+          break;
+        }
+      }
+    }
+
+    private int GetNextInteger(StreamReader reader) {
+      var next = reader.Read();
+      var builder = new StringBuilder();
+      while (next >= 0 && !char.IsDigit((char)next)) next = reader.Read();
+      if (next == -1) throw new InvalidOperationException("No further integer available");
+      while (char.IsDigit((char)next)) {
+        builder.Append((char)next);
+        next = reader.Read();
+        if (next == -1) break;
+      }
+      return int.Parse(builder.ToString());
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/IntegerVectorEncoding/BottomLeftIntegerVectorDecoder.cs	(revision 15278)
@@ -54,5 +54,5 @@
 
     protected override PackingPosition FindPositionForItem(BinPacking3D bp, PackingItem item, bool useStackingConstraints) {
-      return bp.FindPositionBySliding(item, rotated: false);
+      return bp.FindPositionBySliding(item, rotated: false, stackingConstraints: useStackingConstraints);
     }
 
@@ -61,5 +61,5 @@
       ref IList<int> remainingIDs, IList<PackingItem> items, bool useStackingConstraints) {
       var bp = new BinPacking3D(partialSolution.BinShape);
-      bp.SlidingBasedPacking(ref remainingIDs, items);
+      bp.SlidingBasedPacking(ref remainingIDs, items, useStackingConstraints);
       return bp;
     }
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/BottomLeftPermutationDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/BottomLeftPermutationDecoder.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/BottomLeftPermutationDecoder.cs	(revision 15278)
@@ -46,5 +46,5 @@
       while (remainingIDs.Count > 0) {
         var bp = new BinPacking3D(binShape);
-        bp.SlidingBasedPacking(ref remainingIDs, items);
+        bp.SlidingBasedPacking(ref remainingIDs, items, useStackingConstraints);
         result.Bins.Add(bp);
       }
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoder.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoder.cs	(revision 15278)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using HeuristicLab.Core;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -25,9 +26,11 @@
 using System.Collections.Generic;
 using HeuristicLab.Encodings.PermutationEncoding;
+using System.Linq;
+
 
 namespace HeuristicLab.Problems.BinPacking3D {
   [Item("Extreme-point Permutation Decoder (3d)", "Decodes the permutation and creates a packing solution candidate")]
   [StorableClass]
-  public class ExtremePointPermutationDecoder : Item, IDecoder<Permutation> {
+  public class ExtremePointPermutationDecoder : ExtremePointPermutationDecoderBase {
 
     [StorableConstructor]
@@ -41,5 +44,9 @@
     }
 
-    public Solution Decode(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+    public override Solution Decode(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+      return Apply(permutation, binShape, items, useStackingConstraints);
+    }
+
+    public static Solution Apply(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
       Solution result = new Solution(binShape, useExtremePoints: true, stackingConstraints: useStackingConstraints);
       IList<int> remainingIDs = new List<int>(permutation);
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoderBase.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoderBase.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ExtremePointPermutationDecoderBase.cs	(revision 15278)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+ 
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  [Item("Extreme-point Permutation Decoder (3d) Base", "Base class for decoders")]
+  [StorableClass]
+  public abstract class ExtremePointPermutationDecoderBase : Item, IDecoder<Permutation> {
+
+    [StorableConstructor]
+    protected ExtremePointPermutationDecoderBase(bool deserializing) : base(deserializing) { }
+    protected ExtremePointPermutationDecoderBase(ExtremePointPermutationDecoderBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ExtremePointPermutationDecoderBase() : base() { }
+
+    public abstract Solution Decode(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints);
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/FreeVolumeBestFitExtremePointPermutationDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/FreeVolumeBestFitExtremePointPermutationDecoder.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/FreeVolumeBestFitExtremePointPermutationDecoder.cs	(revision 15278)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  [Item("Free Volume Best Fit Extreme-point Permutation Decoder (3d)", "Decodes the permutation and creates a packing solution candidate")]
+  [StorableClass]
+  public class FreeVolumeBestFitExtremePointPermutationDecoder : ExtremePointPermutationDecoderBase {
+
+    [StorableConstructor]
+    protected FreeVolumeBestFitExtremePointPermutationDecoder(bool deserializing) : base(deserializing) { }
+    protected FreeVolumeBestFitExtremePointPermutationDecoder(FreeVolumeBestFitExtremePointPermutationDecoder original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public FreeVolumeBestFitExtremePointPermutationDecoder() : base() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FreeVolumeBestFitExtremePointPermutationDecoder(this, cloner);
+    }
+
+    public override Solution Decode(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+      return Apply(permutation, binShape, items, useStackingConstraints);
+    }
+
+    public static Solution Apply(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+      Solution result = new Solution(binShape, useExtremePoints: true, stackingConstraints: useStackingConstraints);
+      IList<int> remainingIDs = new List<int>(permutation);
+      var bpg = new BinPacking3D(binShape);
+      bpg.ExtremePointBasedPacking(ref remainingIDs, items, stackingConstraints: useStackingConstraints);
+      result.Bins.Add(bpg);
+      foreach (int ID in remainingIDs) {
+        var sortedBins = result.Bins.OrderBy(x => x.FreeVolume);
+        var item = items[ID];
+        var posFound = false;
+        foreach (var bp in sortedBins) {
+          var pos = bp.FindExtremePointForItem(item, false, useStackingConstraints);
+          posFound = pos != null;
+          if (posFound) {
+            bp.PackItem(ID, item, pos);
+            break;
+          }
+        }
+        if (!posFound) {
+          var bp = new BinPacking3D(binShape);
+          var pos = bp.FindExtremePointForItem(item, false, useStackingConstraints);
+          if (pos == null) throw new InvalidOperationException("Item " + ID + " cannot be packed in empty bin.");
+          bp.PackItem(ID, item, pos);
+          result.Bins.Add(bp);
+        }
+      }
+      result.UpdateBinPackings();
+      return result;
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ResidualSpaceBestFitExtremePointPermutationDecoder.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ResidualSpaceBestFitExtremePointPermutationDecoder.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/PermutationEncoding/ResidualSpaceBestFitExtremePointPermutationDecoder.cs	(revision 15278)
@@ -0,0 +1,96 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  [Item("Residual Space Best Fit Extreme-point Permutation Decoder (3d)", "Decodes the permutation and creates a packing solution candidate")]
+  [StorableClass]
+  public class ResidualSpaceBestFitExtremePointPermutationDecoder : ExtremePointPermutationDecoderBase {
+
+    [StorableConstructor]
+    protected ResidualSpaceBestFitExtremePointPermutationDecoder(bool deserializing) : base(deserializing) { }
+    protected ResidualSpaceBestFitExtremePointPermutationDecoder(ResidualSpaceBestFitExtremePointPermutationDecoder original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ResidualSpaceBestFitExtremePointPermutationDecoder() : base() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ResidualSpaceBestFitExtremePointPermutationDecoder(this, cloner);
+    }
+
+    public override Solution Decode(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+      return Apply(permutation, binShape, items, useStackingConstraints);
+    }
+
+    public static Solution Apply(Permutation permutation, PackingShape binShape, IList<PackingItem> items, bool useStackingConstraints) {
+      Solution result = new Solution(binShape, useExtremePoints: true, stackingConstraints: useStackingConstraints);
+      IList<int> remainingIDs = new List<int>(permutation);
+      var bpg = new BinPacking3D(binShape);
+      bpg.ExtremePointBasedPacking(ref remainingIDs, items, stackingConstraints: useStackingConstraints);
+      result.Bins.Add(bpg);
+      foreach (int ID in remainingIDs) {
+        var item = items[ID];
+        var points = GetResidualSpaceAllPoints(result, item);
+        var sortedPoints = points.OrderBy(x => x.Item3);
+        var packed = false;
+        foreach (var p in sortedPoints) {
+          packed = p.Item1.PackItemIfFeasible(ID, item, p.Item2, useStackingConstraints);
+          if (packed) break;
+        }
+        if (!packed) {
+          // pack item in a new bin
+          var bp = new BinPacking3D(binShape);
+          var positionFound = bp.FindExtremePointForItem(item, false, useStackingConstraints);
+          if (positionFound != null) {
+            bp.PackItem(ID, item, positionFound);
+          } else throw new InvalidOperationException("Item " + ID + " cannot be packed in an empty bin.");
+          result.Bins.Add(bp);
+        }
+      }
+      result.UpdateBinPackings();
+      return result;
+    }
+
+    public static IList<Tuple<BinPacking3D, PackingPosition, int>> GetResidualSpaceAllPoints(Solution solution, PackingItem item) {
+      var result = new List<Tuple<BinPacking3D, PackingPosition, int>>();
+      foreach (BinPacking3D bp in solution.Bins) {
+        foreach (var ep in bp.ExtremePoints) {
+          var rs = bp.ResidualSpace[ep];
+          if (rs.Item1 < item.Width || rs.Item2 < item.Height || rs.Item3 < item.Depth) continue;
+          result.Add(Tuple.Create(bp, ep, GetResidualMerit(rs, item, ep)));
+        }
+      }
+      return result;
+    }
+
+    private static int GetResidualMerit(Tuple<int, int, int> rs, PackingItem item, PackingPosition ep) {
+      return ((rs.Item1 - item.Width) +
+          (rs.Item2 - item.Height) +
+          (rs.Item3 - item.Depth));
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/3D/ProblemBase.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/3D/ProblemBase.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/3D/ProblemBase.cs	(revision 15278)
@@ -175,5 +175,4 @@
     public override bool Maximization { get { return true; } }
 
-
     public override double Evaluate(Individual individual, IRandom random) {
       var encodedSolutionCand = (TSol)individual[EncodedSolutionName];
Index: stable/HeuristicLab.Problems.BinPacking/3.3/Algorithms/3D/ExtremePointAlgorithm.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/Algorithms/3D/ExtremePointAlgorithm.cs	(revision 15278)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/Algorithms/3D/ExtremePointAlgorithm.cs	(revision 15278)
@@ -0,0 +1,241 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Joseph Helm and Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.BinPacking3D {
+  
+  public enum SortingMethod { All, Given, VolumeHeight, HeightVolume, AreaHeight, HeightArea, ClusteredAreaHeight, ClusteredHeightArea }
+  public enum FittingMethod { All, FirstFit, ResidualSpaceBestFit, FreeVolumeBestFit }
+
+  [Item("Extreme-point-based Bin Packing (3d)", "An implementation of the extreme-point based packing described in Crainic, T. G., Perboli, G., & Tadei, R. (2008). Extreme point-based heuristics for three-dimensional bin packing. Informs Journal on computing, 20(3), 368-384.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms, Priority = 180)]
+  public sealed class ExtremePointAlgorithm : BasicAlgorithm {
+
+    public override Type ProblemType {
+      get { return typeof(PermutationProblem); }
+    }
+
+    public new PermutationProblem Problem {
+      get { return (PermutationProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    public override bool SupportsPause {
+      get { return false; }
+    }
+
+    [Storable]
+    private readonly IValueParameter<EnumValue<SortingMethod>> sortingMethodParameter;
+    public IValueParameter<EnumValue<SortingMethod>> SortingMethodParameter {
+      get { return sortingMethodParameter; }
+    }
+
+    [Storable]
+    private readonly IValueParameter<EnumValue<FittingMethod>> fittingMethodParameter;
+    public IValueParameter<EnumValue<FittingMethod>> FittingMethodParameter {
+      get { return fittingMethodParameter; }
+    }
+
+    [Storable]
+    private readonly IValueParameter<PercentValue> deltaParameter;
+    public IValueParameter<PercentValue> DeltaParameter {
+      get { return deltaParameter; }
+    }
+
+    [StorableConstructor]
+    private ExtremePointAlgorithm(bool deserializing) : base(deserializing) { }
+    private ExtremePointAlgorithm(ExtremePointAlgorithm original, Cloner cloner)
+      : base(original, cloner) {
+      sortingMethodParameter = cloner.Clone(original.sortingMethodParameter);
+      fittingMethodParameter = cloner.Clone(original.fittingMethodParameter);
+      deltaParameter = cloner.Clone(original.deltaParameter);
+    }
+    public ExtremePointAlgorithm() {
+      Parameters.Add(sortingMethodParameter = new ValueParameter<EnumValue<SortingMethod>>("SortingMethod", "In which order the items should be packed.", new EnumValue<SortingMethod>(SortingMethod.All)));
+      Parameters.Add(fittingMethodParameter = new ValueParameter<EnumValue<FittingMethod>>("FittingMethod", "Which method to fit should be used.", new EnumValue<FittingMethod>(FittingMethod.All)));
+      Parameters.Add(deltaParameter = new ValueParameter<PercentValue>("Delta", "[1;100]% Clustered sorting methods use a delta parameter to determine the clusters.", new PercentValue(.1)));
+      
+      Problem = new PermutationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ExtremePointAlgorithm(this, cloner);
+    }
+    
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+    protected override void Run(CancellationToken token) {
+      var items = Problem.Items;
+      var bin = Problem.BinShape;
+      var sorting = new[] { SortingMethodParameter.Value.Value };
+      if (sorting[0] == SortingMethod.All) {
+        sorting = Enum.GetValues(typeof(SortingMethod)).Cast<SortingMethod>().Where(x => x != SortingMethod.All).ToArray();
+      }
+      var fitting = new[] { fittingMethodParameter.Value.Value };
+      if (fitting[0] == FittingMethod.All) {
+        fitting = Enum.GetValues(typeof(FittingMethod)).Cast<FittingMethod>().Where(x => x != FittingMethod.All).ToArray();
+      }
+      var result = GetBest(bin, items, sorting, fitting, token);
+      if (result == null) throw new InvalidOperationException("No result obtained!");
+
+      Results.Add(new Result("Best Solution",
+        "The best found solution",
+        result.Item1));
+      Results.Add(new Result("Best Solution Quality",
+        "The quality of the best found solution according to the evaluator",
+        new DoubleValue(result.Item2)));
+
+      var binUtil = new BinUtilizationEvaluator();
+      var packRatio = new PackingRatioEvaluator();
+      Results.Add(new Result("Best Solution Bin Count",
+        "The number of bins in the best found solution",
+        new IntValue(result.Item1.NrOfBins)));
+      Results.Add(new Result("Best Solution Bin Utilization",
+        "The utilization given in percentage as calculated by the BinUtilizationEvaluator (total used space / total available space)",
+        new PercentValue(Math.Round(binUtil.Evaluate(result.Item1), 3))));
+
+      if (result.Item3.HasValue && sorting.Length > 1)
+        Results.Add(new Result("Best Sorting Method",
+          "The sorting method that found the best solution",
+          new EnumValue<SortingMethod>(result.Item3.Value)));
+      if (result.Item4.HasValue && fitting.Length > 1)
+        Results.Add(new Result("Best Fitting Method",
+          "The fitting method that found the best solution",
+          new EnumValue<FittingMethod>(result.Item4.Value)));
+    }
+
+    private Tuple<Solution, double, SortingMethod?, FittingMethod?> GetBest(PackingShape bin, IList<PackingItem> items, SortingMethod[] sortings, FittingMethod[] fittings, CancellationToken token) {
+      SortingMethod? bestSorting = null;
+      FittingMethod? bestFitting = null;
+      var best = double.NaN;
+      Solution bestSolution = null;
+      foreach (var fit in fittings) {
+        foreach (var sort in sortings) {
+          var result = Optimize(bin, items, sort, fit, DeltaParameter.Value.Value, Problem.UseStackingConstraints, Problem.SolutionEvaluator, token);
+          if (double.IsNaN(result.Item2) || double.IsInfinity(result.Item2)) continue;
+          if (double.IsNaN(best)
+            || Problem.Maximization && result.Item2 > best
+            || !Problem.Maximization && result.Item2 < best) {
+            bestSolution = result.Item1;
+            best = result.Item2;
+            bestSorting = sort;
+            bestFitting = fit;
+          }
+          if (token.IsCancellationRequested) return Tuple.Create(bestSolution, best, bestSorting, bestFitting);
+        }
+      }
+      if (double.IsNaN(best)) return null;
+      return Tuple.Create(bestSolution, best, bestSorting, bestFitting);
+    }
+
+    private static Tuple<Solution, double> Optimize(PackingShape bin, IList<PackingItem> items, SortingMethod sorting, FittingMethod fitting, double delta, bool stackingConstraints, IEvaluator evaluator, CancellationToken token) {
+      Permutation sorted = null;
+      switch (sorting) {
+        case SortingMethod.Given:
+          sorted = new Permutation(PermutationTypes.Absolute, Enumerable.Range(0, items.Count).ToArray());
+          break;
+        case SortingMethod.VolumeHeight:
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v })
+                         .OrderByDescending(x => x.Item.Depth * x.Item.Width * x.Item.Height)
+                         .ThenByDescending(x => x.Item.Height)
+                         .Select(x => x.Index).ToArray());
+          break;
+        case SortingMethod.HeightVolume:
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v })
+                         .OrderByDescending(x => x.Item.Height)
+                         .ThenByDescending(x => x.Item.Depth * x.Item.Width * x.Item.Height)
+                         .Select(x => x.Index).ToArray());
+          break;
+        case SortingMethod.AreaHeight:
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v })
+                         .OrderByDescending(x => x.Item.Depth * x.Item.Width)
+                         .ThenByDescending(x => x.Item.Height)
+                         .Select(x => x.Index).ToArray());
+          break;
+        case SortingMethod.HeightArea:
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v })
+                         .OrderByDescending(x => x.Item.Height)
+                         .ThenByDescending(x => x.Item.Depth * x.Item.Width)
+                         .Select(x => x.Index).ToArray());
+          break;
+        case SortingMethod.ClusteredAreaHeight:
+          double clusterRange = bin.Width * bin.Depth * delta;
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v, ClusterId = (int)(Math.Ceiling(v.Width * v.Depth / clusterRange)) })
+                        .GroupBy(x => x.ClusterId)
+                        .Select(x => new { Cluster = x.Key, Items = x.OrderByDescending(y => y.Item.Height).ToList() })
+                        .OrderByDescending(x => x.Cluster)
+                        .SelectMany(x => x.Items)
+                        .Select(x => x.Index).ToArray());
+          break;
+        case SortingMethod.ClusteredHeightArea:
+          double clusterRange2 = bin.Height * delta;
+          sorted = new Permutation(PermutationTypes.Absolute,
+                    items.Select((v, i) => new { Index = i, Item = v, ClusterId = (int)(Math.Ceiling(v.Height / clusterRange2)) })
+                        .GroupBy(x => x.ClusterId)
+                        .Select(x => new { Cluster = x.Key, Items = x.OrderByDescending(y => y.Item.Depth * y.Item.Width).ToList() })
+                        .OrderByDescending(x => x.Cluster)
+                        .SelectMany(x => x.Items)
+                        .Select(x => x.Index).ToArray());
+          break;
+        default: throw new ArgumentException("Unknown sorting method: " + sorting);
+      }
+      
+      ExtremePointPermutationDecoderBase decoder = null;
+      switch (fitting) {
+        case FittingMethod.FirstFit:
+          decoder = new ExtremePointPermutationDecoder();
+          break;
+        case FittingMethod.FreeVolumeBestFit:
+          decoder = new FreeVolumeBestFitExtremePointPermutationDecoder();
+          break;
+        case FittingMethod.ResidualSpaceBestFit:
+          decoder = new ResidualSpaceBestFitExtremePointPermutationDecoder();
+          break;
+        default: throw new ArgumentException("Unknown fitting method: " + fitting);
+      }
+
+      var sol = decoder.Decode(sorted, bin, items, stackingConstraints);
+      var fit = evaluator.Evaluate(sol);
+
+      return Tuple.Create(sol, fit);
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.BinPacking/3.3/BinPacking.cs
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/BinPacking.cs	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/BinPacking.cs	(revision 15278)
@@ -50,6 +50,10 @@
     [Storable]
     protected Dictionary<int, List<int>> OccupationLayers { get; set; }
+    
+    #endregion Properties
 
-    #endregion Properties
+    public int FreeVolume {
+      get { return BinShape.Volume - Items.Sum(x => x.Value.Volume); }
+    }
 
     protected BinPacking(TBin binShape)
@@ -58,7 +62,7 @@
       Items = new ObservableDictionary<int, TItem>();
       BinShape = (TBin)binShape.Clone();
+      ExtremePoints = new SortedSet<TPos>();
       OccupationLayers = new Dictionary<int, List<int>>();
     }
-
 
     [StorableConstructor]
@@ -75,4 +79,5 @@
       }
       this.BinShape = (TBin)original.BinShape.Clone(cloner);
+      this.ExtremePoints = new SortedSet<TPos>(original.ExtremePoints.Select(p => cloner.Clone(p)));
       this.OccupationLayers = new Dictionary<int, List<int>>();
       foreach (var kvp in original.OccupationLayers) {
@@ -84,12 +89,12 @@
 
     public abstract TPos FindExtremePointForItem(TItem item, bool rotated, bool stackingConstraints);
-    public abstract TPos FindPositionBySliding(TItem item, bool rotated);
+    public abstract TPos FindPositionBySliding(TItem item, bool rotated, bool stackingConstraints);
 
-    public abstract void SlidingBasedPacking(ref IList<int> sequence, IList<TItem> items);
-    public abstract void SlidingBasedPacking(ref IList<int> sequence, IList<TItem> items, Dictionary<int, bool> rotationArray);
+    public abstract void SlidingBasedPacking(ref IList<int> sequence, IList<TItem> items, bool stackingConstraints);
+    public abstract void SlidingBasedPacking(ref IList<int> sequence, IList<TItem> items, Dictionary<int, bool> rotationArray, bool stackingConstraints);
     public abstract void ExtremePointBasedPacking(ref IList<int> sequence, IList<TItem> items, bool stackingConstraints);
     public abstract void ExtremePointBasedPacking(ref IList<int> sequence, IList<TItem> items, bool stackingConstraints, Dictionary<int, bool> rotationArray);
 
-    public void PackItem(int itemID, TItem item, TPos position) {
+    public virtual void PackItem(int itemID, TItem item, TPos position) {
       Items[itemID] = item;
       Positions[itemID] = position;
@@ -97,6 +102,13 @@
       foreach (int id in Items.Select(x => x.Key))
         GenerateNewExtremePointsForNewItem(Items[id], Positions[id]);
-
+      
       AddNewItemToOccupationLayers(itemID, item, position);
+    }
+    public virtual bool PackItemIfFeasible(int itemID, TItem item, TPos position, bool stackingConstraints) {
+      if (IsPositionFeasible(item, position, stackingConstraints)) {
+        PackItem(itemID, item, position);
+        return true;
+      }
+      return false;
     }
 
@@ -127,5 +139,5 @@
       return false;
     }
-    public bool IsPositionFeasible(TItem item, TPos position) {
+    public virtual bool IsPositionFeasible(TItem item, TPos position, bool stackingConstraints) {
       //In this case feasability is defined as following: 1. the item fits into the bin-borders; 2. the point is supported by something; 3. the item does not collide with another already packed item
       if (!BinShape.Encloses(position, item))
@@ -139,7 +151,7 @@
       return true;
     }
+    
     public abstract int ShortestPossibleSideFromPoint(TPos position);
     public abstract bool IsStaticStable(TItem measures, TPos position);
-
 
     protected abstract void InitializeOccupationLayers();
Index: stable/HeuristicLab.Problems.BinPacking/3.3/HeuristicLab.Problems.BinPacking-3.3.csproj
===================================================================
--- stable/HeuristicLab.Problems.BinPacking/3.3/HeuristicLab.Problems.BinPacking-3.3.csproj	(revision 15277)
+++ stable/HeuristicLab.Problems.BinPacking/3.3/HeuristicLab.Problems.BinPacking-3.3.csproj	(revision 15278)
@@ -106,7 +106,11 @@
     <Compile Include="3D\Evaluators\BinUtilizationEvaluator.cs" />
     <Compile Include="3D\Evaluators\PackingRatioEvaluator.cs" />
+    <Compile Include="Algorithms\3D\ExtremePointAlgorithm.cs" />
+    <Compile Include="3D\Instances\ThreeDInstanceDescriptor.cs" />
     <Compile Include="3D\Instances\BPPData.cs" />
     <Compile Include="3D\Instances\RandomDataDescriptor.cs" />
+    <Compile Include="3D\Instances\RealWorldContainerPackingInstanceProvider.cs" />
     <Compile Include="3D\Instances\RandomInstanceProvider.cs" />
+    <Compile Include="3D\Instances\ThreeDInstanceParser.cs" />
     <Compile Include="3D\IntegerVectorEncoding\BottomLeftIntegerVectorDecoder.cs" />
     <Compile Include="3D\IntegerVectorEncoding\ExtremePointIntegerVectorDecoder.cs" />
@@ -121,4 +125,7 @@
     <Compile Include="3D\PackingShape.cs" />
     <Compile Include="3D\PermutationEncoding\BottomLeftPermutationDecoder.cs" />
+    <Compile Include="3D\PermutationEncoding\ResidualSpaceBestFitExtremePointPermutationDecoder.cs" />
+    <Compile Include="3D\PermutationEncoding\FreeVolumeBestFitExtremePointPermutationDecoder.cs" />
+    <Compile Include="3D\PermutationEncoding\ExtremePointPermutationDecoderBase.cs" />
     <Compile Include="3D\PermutationEncoding\ExtremePointPermutationDecoder.cs" />
     <Compile Include="3D\PermutationEncoding\PermutationProblem.cs" />
@@ -144,4 +151,5 @@
   </ItemGroup>
   <ItemGroup>
+    <EmbeddedResource Include="3D\Instances\ContainerPackingInstances.zip" />
     <None Include="HeuristicLab.snk" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
