1  /* HeuristicLab


2  * Copyright (C) 20022016 Joseph Helm and Heuristic and Evolutionary Algorithms Laboratory (HEAL)


3  *


4  * This file is part of HeuristicLab.


5  *


6  * HeuristicLab is free software: you can redistribute it and/or modify


7  * it under the terms of the GNU General Public License as published by


8  * the Free Software Foundation, either version 3 of the License, or


9  * (at your option) any later version.


10  *


11  * HeuristicLab is distributed in the hope that it will be useful,


12  * but WITHOUT ANY WARRANTY; without even the implied warranty of


13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the


14  * GNU General Public License for more details.


15  *


16  * You should have received a copy of the GNU General Public License


17  * along with HeuristicLab. If not, see<http://www.gnu.org/licenses/> .


18  */


19 


20  using System;


21  using System.Collections.Generic;


22  using System.Linq;


23  using System.Windows;


24  using System.Windows.Controls;


25  using System.Windows.Input;


26  using System.Windows.Media;


27  using System.Windows.Media.Media3D;


28  using HeuristicLab.Problems.BinPacking3D;


29 


30  namespace HeuristicLab.Problems.BinPacking.Views {


31  public partial class Container3DView : UserControl {


32  private static readonly Color[] colors = new[] {


33  Color.FromRgb(0x40, 0x6A, 0xB7),


34  Color.FromRgb(0xB1, 0x6D, 0x01),


35  Color.FromRgb(0x4E, 0x8A, 0x06),


36  Color.FromRgb(0x75, 0x50, 0x7B),


37  Color.FromRgb(0x72, 0x9F, 0xCF),


38  Color.FromRgb(0xA4, 0x00, 0x00),


39  Color.FromRgb(0xAD, 0x7F, 0xA8),


40  Color.FromRgb(0x29, 0x50, 0xCF),


41  Color.FromRgb(0x90, 0xB0, 0x60),


42  Color.FromRgb(0xF5, 0x89, 0x30),


43  Color.FromRgb(0x55, 0x57, 0x53),


44  Color.FromRgb(0xEF, 0x59, 0x59),


45  Color.FromRgb(0xED, 0xD4, 0x30),


46  Color.FromRgb(0x63, 0xC2, 0x16),


47  };


48 


49  private static readonly Color hiddenColor = Color.FromArgb(0x1A, 0xAA, 0xAA, 0xAA);


50  private static readonly Color containerColor = Color.FromArgb(0x7F, 0xAA, 0xAA, 0xAA);


51 


52  private Point startPos;


53  private bool mouseDown = false;


54  private double startAngleX;


55  private double startAngleY;


56  private int selectedItemKey;


57 


58  private BinPacking<BinPacking3D.PackingPosition, PackingShape, PackingItem> packing;


59  public BinPacking<BinPacking3D.PackingPosition, PackingShape, PackingItem> Packing {


60  get { return packing; }


61  set {


62  if (packing != value) {


63  this.packing = value;


64  ClearSelection(); // also updates visualization


65  }


66  }


67  }


68 


69  private Dictionary<int, DiffuseMaterial> materials;


70 


71  public Container3DView() {


72  InitializeComponent();


73  camMain.Position = new Point3D(0.5, 3, 3); // for design time we use a different camera position


74  materials = new Dictionary<int, DiffuseMaterial>();


75  Clear();


76  }


77 


78 


79  protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {


80  base.OnRenderSizeChanged(sizeInfo);


81  var s = Math.Min(sizeInfo.NewSize.Height, sizeInfo.NewSize.Width);


82  var mySize = new Size(s, s);


83  viewport3D1.RenderSize = mySize;


84  }


85 


86  public void SelectItem(int itemKey) {


87  // selection of an item should make all other items semitransparent


88  selectedItemKey = itemKey;


89  UpdateVisualization();


90  }


91  public void ClearSelection() {


92  // remove all transparency


93  selectedItemKey = 1;


94  UpdateVisualization();


95  }


96 


97  private void UpdateVisualization() {


98  Clear();


99  if (packing == null) return; // nothing to display


100 


101  var modelGroup = (Model3DGroup)MyModel.Content;


102  var hiddenMaterial = new DiffuseMaterial(new SolidColorBrush(hiddenColor));


103 


104  if (selectedItemKey >= 0) {


105  var selectedItem = packing.Items.Single(x => selectedItemKey == x.Key);


106  var selectedPos = packing.Positions[selectedItem.Key];


107 


108  var colorIdx = selectedItem.Value.Material;


109  while (colorIdx < 0) colorIdx += colors.Length;


110  colorIdx = colorIdx % colors.Length;


111  var color = colors[colorIdx];


112  var material = new DiffuseMaterial { Brush = new SolidColorBrush(color) };


113  materials[selectedItem.Value.Material] = material;


114 


115  var selectedModel = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = material };


116  AddSolidCube((MeshGeometry3D)selectedModel.Geometry, selectedPos.X, selectedPos.Y, selectedPos.Z,


117  selectedPos.Rotated ? selectedItem.Value.Depth : selectedItem.Value.Width,


118  selectedItem.Value.Height,


119  selectedPos.Rotated ? selectedItem.Value.Width : selectedItem.Value.Depth);


120  modelGroup.Children.Add(selectedModel);


121 


122  foreach (var item in packing.Items.Where(x => selectedItemKey != x.Key)) {


123  var position = packing.Positions[item.Key];


124 


125  var w = position.Rotated ? item.Value.Depth : item.Value.Width;


126  var h = item.Value.Height;


127  var d = position.Rotated ? item.Value.Width : item.Value.Depth;


128 


129  var model = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = hiddenMaterial };


130  AddWireframeCube((MeshGeometry3D)model.Geometry, position.X, position.Y, position.Z, w, h, d, 1);


131  modelGroup.Children.Add(model);


132  }


133  } else {


134  foreach (var item in packing.Items) {


135  var position = packing.Positions[item.Key];


136 


137  var w = position.Rotated ? item.Value.Depth : item.Value.Width;


138  var h = item.Value.Height;


139  var d = position.Rotated ? item.Value.Width : item.Value.Depth;


140 


141  var model = new GeometryModel3D { Geometry = new MeshGeometry3D() };


142  DiffuseMaterial material;


143  if (!materials.TryGetValue(item.Value.Material, out material)) {


144  var colorIdx = item.Value.Material;


145  while (colorIdx < 0) colorIdx += colors.Length;


146  colorIdx = colorIdx % colors.Length;


147  var color = colors[colorIdx];


148  material = new DiffuseMaterial { Brush = new SolidColorBrush(color) };


149  materials[item.Value.Material] = material;


150  }


151  var selectedModel = new GeometryModel3D { Geometry = new MeshGeometry3D(), Material = material };


152  AddSolidCube((MeshGeometry3D)selectedModel.Geometry, position.X, position.Y, position.Z, w, h, d);


153  modelGroup.Children.Add(selectedModel);


154  }


155  }


156 


157  var container = packing.BinShape;


158  var containerModel = new GeometryModel3D(new MeshGeometry3D(), new DiffuseMaterial(new SolidColorBrush(containerColor)));


159  modelGroup.Children.Add(containerModel);


160  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);


161 


162  var ratio = Math.Max(container.Width, Math.Max(container.Height, container.Depth));


163  scale.ScaleX = 1.0 / ratio;


164  scale.ScaleY = 1.0 / ratio;


165  scale.ScaleZ = 1.0 / ratio;


166 


167  scaleZoom.CenterX = rotateX.CenterX = rotateY.CenterX = container.Width / (2.0 * ratio);


168  scaleZoom.CenterY = rotateX.CenterY = rotateY.CenterY = container.Height / (2.0 * ratio);


169  scaleZoom.CenterZ = rotateX.CenterZ = rotateY.CenterZ = container.Depth / (2.0 * ratio);


170 


171  camMain.Position = new Point3D(


172  scaleZoom.CenterX,


173  3,


174  3);


175  camMain.LookDirection = new Vector3D(


176  0,


177  scaleZoom.CenterY  camMain.Position.Y,


178  scaleZoom.CenterZ  camMain.Position.Z);


179  }


180 


181 


182  private void Clear() {


183  ((Model3DGroup)MyModel.Content).Children.Clear();


184  materials.Clear();


185 


186  mouseDown = false;


187  startAngleX = 0;


188  startAngleY = 0;


189  }


190 


191  private void Container3DView_MouseMove(object sender, MouseEventArgs e) {


192  if (!mouseDown) return;


193  var pos = e.GetPosition((IInputElement)this);


194 


195  ((AxisAngleRotation3D)rotateX.Rotation).Angle = startAngleX + (pos.X  startPos.X) / 4;


196  ((AxisAngleRotation3D)rotateY.Rotation).Angle = startAngleY + (pos.Y  startPos.Y) / 4;


197  }


198 


199  private void Container3DView_MouseDown(object sender, MouseButtonEventArgs e) {


200  startAngleX = ((AxisAngleRotation3D)rotateX.Rotation).Angle;


201  startAngleY = ((AxisAngleRotation3D)rotateY.Rotation).Angle;


202  this.startPos = e.GetPosition((IInputElement)this);


203  this.mouseDown = true;


204  }


205 


206  private void Container3DView_MouseUp(object sender, MouseButtonEventArgs e) {


207  mouseDown = false;


208  }


209 


210  private void Container3DView_OnMouseWheel(object sender, MouseWheelEventArgs e) {


211  if (e.Delta > 0) {


212  scaleZoom.ScaleX *= 1.1;


213  scaleZoom.ScaleY *= 1.1;


214  scaleZoom.ScaleZ *= 1.1;


215  } else if (e.Delta < 0) {


216  scaleZoom.ScaleX /= 1.1;


217  scaleZoom.ScaleY /= 1.1;


218  scaleZoom.ScaleZ /= 1.1;


219  }


220  }


221 


222  private void Container3DView_OnMouseEnter(object sender, MouseEventArgs e) {


223  Focus(); // for mouse wheel events


224  }


225 


226  #region helper for cubes


227  /// <summary>


228  /// Creates a solid cube by adding the respective points and triangles.


229  /// </summary>


230  /// <param name="mesh">The mesh to which points and triangles are added.</param>


231  /// <param name="x">The leftmost point</param>


232  /// <param name="y">The frontmost point</param>


233  /// <param name="z">The lowest point</param>


234  /// <param name="width">The extension to the right</param>


235  /// <param name="height">The extension to the back</param>


236  /// <param name="depth">The extension to the top</param>


237  private void AddSolidCube(MeshGeometry3D mesh, int x, int y, int z, int width, int height, int depth) {


238  // ground


239  mesh.Positions.Add(new Point3D(x, y, z));


240  mesh.Positions.Add(new Point3D(x + width, y, z));


241  mesh.Positions.Add(new Point3D(x + width, y + height, z));


242  mesh.Positions.Add(new Point3D(x, y + height, z));


243  // top


244  mesh.Positions.Add(new Point3D(x, y, z + depth));


245  mesh.Positions.Add(new Point3D(x + width, y, z + depth));


246  mesh.Positions.Add(new Point3D(x + width, y + height, z + depth));


247  mesh.Positions.Add(new Point3D(x, y + height, z + depth));


248 


249  // front


250  AddPlane(mesh, 0, 1, 5, 4);


251  // right side


252  AddPlane(mesh, 1, 2, 6, 5);


253  // back


254  AddPlane(mesh, 3, 7, 6, 2);


255  // left side


256  AddPlane(mesh, 0, 4, 7, 3);


257  // top


258  AddPlane(mesh, 4, 5, 6, 7);


259  // bottom


260  AddPlane(mesh, 0, 3, 2, 1);


261  }


262 


263  /// <summary>


264  /// Creates a wireframe cube by adding the respective points and triangles.


265  /// </summary>


266  /// <param name="mesh">The mesh to which points and triangles are added.</param>


267  /// <param name="x">The leftmost point</param>


268  /// <param name="y">The frontmost point</param>


269  /// <param name="z">The lowest point</param>


270  /// <param name="width">The extension to the right</param>


271  /// <param name="height">The extension to the back</param>


272  /// <param name="depth">The extension to the top</param>


273  /// <param name="thickness">The thickness of the frame</param>


274  private void AddWireframeCube(MeshGeometry3D mesh, double x, double y, double z, double width, double height, double depth, double thickness = double.NaN) {


275  // default thickness of the wireframe is 5% of smallest dimension


276  if (double.IsNaN(thickness))


277  thickness = Math.Min(width, Math.Min(height, depth)) * 0.05;


278 


279  // The cube contains of 8 corner, each corner has 4 points:


280  // 1. The corner point


281  // 2. A point on the edge to the right of the corner


282  // 3. A point on the edge atop or below the corner


283  // 4. A point on the edge to the left of the corner


284 


285  // Point 0, Front Left Bottom


286  mesh.Positions.Add(new Point3D(x, y, z));


287  mesh.Positions.Add(new Point3D(x + thickness, y, z));


288  mesh.Positions.Add(new Point3D(x, y, z + thickness));


289  mesh.Positions.Add(new Point3D(x, y + thickness, z));


290 


291  // Point 1, Front Right Bottom


292  mesh.Positions.Add(new Point3D(x + width, y, z));


293  mesh.Positions.Add(new Point3D(x + width, y + thickness, z));


294  mesh.Positions.Add(new Point3D(x + width, y, z + thickness));


295  mesh.Positions.Add(new Point3D(x + width  thickness, y, z));


296 


297  // Point 2, Back Right Bottom


298  mesh.Positions.Add(new Point3D(x + width, y + height, z));


299  mesh.Positions.Add(new Point3D(x + width  thickness, y + height, z));


300  mesh.Positions.Add(new Point3D(x + width, y + height, z + thickness));


301  mesh.Positions.Add(new Point3D(x + width, y + height  thickness, z));


302 


303  // Point 3, Back Left Bottom


304  mesh.Positions.Add(new Point3D(x, y + height, z));


305  mesh.Positions.Add(new Point3D(x, y + height  thickness, z));


306  mesh.Positions.Add(new Point3D(x, y + height, z + thickness));


307  mesh.Positions.Add(new Point3D(x + thickness, y + height, z));


308 


309  // Point 4, Front Left Top


310  mesh.Positions.Add(new Point3D(x, y, z + depth));


311  mesh.Positions.Add(new Point3D(x + thickness, y, z + depth));


312  mesh.Positions.Add(new Point3D(x, y, z + depth  thickness));


313  mesh.Positions.Add(new Point3D(x, y + thickness, z + depth));


314 


315  // Point 5, Front Right Top


316  mesh.Positions.Add(new Point3D(x + width, y, z + depth));


317  mesh.Positions.Add(new Point3D(x + width, y + thickness, z + depth));


318  mesh.Positions.Add(new Point3D(x + width, y, z + depth  thickness));


319  mesh.Positions.Add(new Point3D(x + width  thickness, y, z + depth));


320 


321  // Point 6, Back Right Top


322  mesh.Positions.Add(new Point3D(x + width, y + height, z + depth));


323  mesh.Positions.Add(new Point3D(x + width  thickness, y + height, z + depth));


324  mesh.Positions.Add(new Point3D(x + width, y + height, z + depth  thickness));


325  mesh.Positions.Add(new Point3D(x + width, y + height  thickness, z + depth));


326 


327  // Point 7, Back Left Top


328  mesh.Positions.Add(new Point3D(x, y + height, z + depth));


329  mesh.Positions.Add(new Point3D(x, y + height  thickness, z + depth));


330  mesh.Positions.Add(new Point3D(x, y + height, z + depth  thickness));


331  mesh.Positions.Add(new Point3D(x + thickness, y + height, z + depth));


332 


333  // Point 0, nonedge


334  mesh.Positions.Add(new Point3D(x + thickness, y, z + thickness));


335  mesh.Positions.Add(new Point3D(x, y + thickness, z + thickness));


336  mesh.Positions.Add(new Point3D(x + thickness, y + thickness, z));


337 


338  // Point 1, nonedge


339  mesh.Positions.Add(new Point3D(x + width, y + thickness, z + thickness));


340  mesh.Positions.Add(new Point3D(x + width  thickness, y, z + thickness));


341  mesh.Positions.Add(new Point3D(x + width  thickness, y + thickness, z));


342 


343  // Point 2, nonedge


344  mesh.Positions.Add(new Point3D(x + width  thickness, y + height, z + thickness));


345  mesh.Positions.Add(new Point3D(x + width, y + height  thickness, z + thickness));


346  mesh.Positions.Add(new Point3D(x + width  thickness, y + height  thickness, z));


347 


348  // Point 3, nonedge


349  mesh.Positions.Add(new Point3D(x, y + height  thickness, z + thickness));


350  mesh.Positions.Add(new Point3D(x + thickness, y + height, z + thickness));


351  mesh.Positions.Add(new Point3D(x + thickness, y + height  thickness, z));


352 


353  // Point 4, nonedge


354  mesh.Positions.Add(new Point3D(x + thickness, y, z + depth  thickness));


355  mesh.Positions.Add(new Point3D(x, y + thickness, z + depth  thickness));


356  mesh.Positions.Add(new Point3D(x + thickness, y + thickness, z + depth));


357 


358  // Point 5, nonedge


359  mesh.Positions.Add(new Point3D(x + width, y + thickness, z + depth  thickness));


360  mesh.Positions.Add(new Point3D(x + width  thickness, y, z + depth  thickness));


361  mesh.Positions.Add(new Point3D(x + width  thickness, y + thickness, z + depth));


362 


363  // Point 6, nonedge


364  mesh.Positions.Add(new Point3D(x + width  thickness, y + height, z + depth  thickness));


365  mesh.Positions.Add(new Point3D(x + width, y + height  thickness, z + depth  thickness));


366  mesh.Positions.Add(new Point3D(x + width  thickness, y + height  thickness, z + depth));


367 


368  // Point 7, nonedge


369  mesh.Positions.Add(new Point3D(x, y + height  thickness, z + depth  thickness));


370  mesh.Positions.Add(new Point3D(x + thickness, y + height, z + depth  thickness));


371  mesh.Positions.Add(new Point3D(x + thickness, y + height  thickness, z + depth));


372 


373  // Draw the 24 corner plates


374  AddPlane(mesh, 0, 1, 32, 2);


375  AddPlane(mesh, 0, 2, 33, 3);


376  AddPlane(mesh, 0, 3, 34, 1);


377 


378  AddPlane(mesh, 4, 6, 36, 7);


379  AddPlane(mesh, 4, 5, 35, 6);


380  AddPlane(mesh, 4, 7, 37, 5);


381 


382  AddPlane(mesh, 8, 10, 39, 11);


383  AddPlane(mesh, 8, 9, 38, 10);


384  AddPlane(mesh, 8, 11, 40, 9);


385 


386  AddPlane(mesh, 12, 13, 41, 14);


387  AddPlane(mesh, 12, 14, 42, 15);


388  AddPlane(mesh, 12, 15, 43, 13);


389 


390  AddPlane(mesh, 16, 18, 44, 17);


391  AddPlane(mesh, 16, 19, 45, 18);


392  AddPlane(mesh, 16, 17, 46, 19);


393 


394  AddPlane(mesh, 20, 23, 48, 22);


395  AddPlane(mesh, 20, 22, 47, 21);


396  AddPlane(mesh, 20, 21, 49, 23);


397 


398  AddPlane(mesh, 24, 27, 51, 26);


399  AddPlane(mesh, 24, 26, 50, 25);


400  AddPlane(mesh, 24, 25, 52, 27);


401 


402  AddPlane(mesh, 28, 31, 54, 30);


403  AddPlane(mesh, 28, 30, 53, 29);


404  AddPlane(mesh, 28, 29, 55, 31);


405 


406  // Draw the connecting plates


407  // on the bottom


408  AddPlane(mesh, 1, 7, 36, 32);


409  AddPlane(mesh, 1, 34, 37, 7);


410 


411  AddPlane(mesh, 5, 11, 39, 35);


412  AddPlane(mesh, 5, 37, 40, 11);


413 


414  AddPlane(mesh, 9, 15, 42, 38);


415  AddPlane(mesh, 9, 40, 43, 15);


416 


417  AddPlane(mesh, 13, 3, 33, 41);


418  AddPlane(mesh, 13, 43, 34, 3);


419 


420  // between bottom and top


421  AddPlane(mesh, 2, 32, 44, 18);


422  AddPlane(mesh, 2, 18, 45, 33);


423 


424  AddPlane(mesh, 6, 22, 48, 36);


425  AddPlane(mesh, 6, 35, 47, 22);


426 


427  AddPlane(mesh, 10, 26, 51, 39);


428  AddPlane(mesh, 10, 38, 50, 26);


429 


430  AddPlane(mesh, 14, 30, 54, 42);


431  AddPlane(mesh, 14, 41, 53, 30);


432 


433  // on the top


434  AddPlane(mesh, 17, 44, 48, 23);


435  AddPlane(mesh, 17, 23, 49, 46);


436 


437  AddPlane(mesh, 21, 47, 51, 27);


438  AddPlane(mesh, 21, 27, 52, 49);


439 


440  AddPlane(mesh, 25, 50, 54, 31);


441  AddPlane(mesh, 25, 31, 55, 52);


442 


443  AddPlane(mesh, 29, 19, 46, 55);


444  AddPlane(mesh, 29, 53, 45, 19);


445  }


446 


447  /// <summary>


448  /// Adds a plane by two triangles. The indices of the points have to be given


449  /// in counterclockwise sequence.


450  /// </summary>


451  /// <param name="mesh">The mesh to add the triangles to</param>


452  /// <param name="a">The index of the first point</param>


453  /// <param name="b">The index of the second point</param>


454  /// <param name="c">The index of the third point</param>


455  /// <param name="d">The index of the fourth point</param>


456  private void AddPlane(MeshGeometry3D mesh, int a, int b, int c, int d) {


457  // two triangles form a plane


458  mesh.TriangleIndices.Add(a);


459  mesh.TriangleIndices.Add(b);


460  mesh.TriangleIndices.Add(d);


461  mesh.TriangleIndices.Add(c);


462  mesh.TriangleIndices.Add(d);


463  mesh.TriangleIndices.Add(b);


464  }


465  #endregion


466 


467  }


468  }

