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 bool ctrlDown = false;


55  private double startAngleX;


56  private double startAngleY;


57  private int selectedItemKey;


58 


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


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


61  get { return packing; }


62  set {


63  if (packing != value) {


64  this.packing = value;


65  ClearSelection(); // also updates visualization


66  }


67  }


68  }


69 


70  private Dictionary<int, DiffuseMaterial> materials;


71 


72  public Container3DView() {


73  InitializeComponent();


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


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


76  Clear();


77  }


78 


79 


80  protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {


81  base.OnRenderSizeChanged(sizeInfo);


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


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


84  viewport3D1.RenderSize = mySize;


85  }


86 


87  public void SelectItem(int itemKey) {


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


89  selectedItemKey = itemKey;


90  UpdateVisualization();


91  }


92  public void ClearSelection() {


93  // remove all transparency


94  selectedItemKey = 1;


95  UpdateVisualization();


96  }


97 


98  private void UpdateVisualization() {


99  Clear();


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


101 


102  var modelGroup = (Model3DGroup)MyModel.Content;


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


104 


105  foreach (var item in packing.Items) {


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


107 


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


109  var h = item.Value.Height;


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


111 


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


113  DiffuseMaterial material;


114  if (selectedItemKey >= 0 && selectedItemKey != item.Key)


115  material = hiddenMaterial;


116  else {


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


118  var color = colors[(item.Value.Material  1) % colors.Length];


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


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


121  }


122  }


123  model.Material = material;


124  modelGroup.Children.Add(model);


125 


126  AddSolidCube((MeshGeometry3D)model.Geometry, position.X, position.Y, position.Z, w, h, d);


127  }


128 


129  var container = packing.BinShape;


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


131  modelGroup.Children.Add(containerModel);


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


133 


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


135  scale.ScaleX = 1.0 / ratio;


136  scale.ScaleY = 1.0 / ratio;


137  scale.ScaleZ = 1.0 / ratio;


138 


139  scale.CenterX = .5;


140  scale.CenterY = .5;


141  scale.CenterZ = 0;


142  }


143 


144 


145  private void Clear() {


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


147  materials.Clear();


148 


149  mouseDown = false;


150  startAngleX = 0;


151  startAngleY = 0;


152  }


153 


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


155  if (!mouseDown) return;


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


157 


158  rotateX.Angle = startAngleX + (pos.X  startPos.X) / 4;


159  rotateY.Angle = startAngleY + (pos.Y  startPos.Y) / 4;


160  }


161 


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


163  startAngleX = rotateX.Angle;


164  startAngleY = rotateY.Angle;


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


166  this.mouseDown = true;


167  }


168 


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


170  mouseDown = false;


171  }


172 


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


174  if (e.Delta > 0) {


175  scaleZoom.ScaleX *= 1.1;


176  scaleZoom.ScaleY *= 1.1;


177  scaleZoom.ScaleZ *= 1.1;


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


179  scaleZoom.ScaleX /= 1.1;


180  scaleZoom.ScaleY /= 1.1;


181  scaleZoom.ScaleZ /= 1.1;


182  }


183  }


184 


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


186  Focus(); // for mouse wheel events


187  }


188 


189  private void Container3DView_OnKeyDown(object sender, KeyEventArgs e) {


190  ctrlDown = e.Key.HasFlag(Key.LeftCtrl)  e.Key.HasFlag(Key.RightCtrl);


191  }


192 


193 


194  #region helper for cubes


195  /// <summary>


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


197  /// </summary>


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


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


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


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


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


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


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


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


206  // ground


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


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


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


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


211  // top


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


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


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


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


216 


217  // front


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


219  // right side


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


221  // back


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


223  // left side


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


225  // top


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


227  // bottom


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


229  }


230 


231  /// <summary>


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


233  /// </summary>


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


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


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


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


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


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


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


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


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


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


244  if (double.IsNaN(thickness))


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


246 


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


248  // 1. The corner point


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


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


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


252 


253  // Point 0, Front Left Bottom


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


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


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


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


258 


259  // Point 1, Front Right Bottom


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


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


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


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


264 


265  // Point 2, Back Right Bottom


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


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


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


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


270 


271  // Point 3, Back Left Bottom


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


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


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


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


276 


277  // Point 4, Front Left Top


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


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


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


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


282 


283  // Point 5, Front Right Top


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


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


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


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


288 


289  // Point 6, Back Right Top


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


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


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


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


294 


295  // Point 7, Back Left Top


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


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


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


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


300 


301  AddPlane(mesh, 0, 4, 6, 2);


302  AddPlane(mesh, 0, 3, 5, 4);


303 


304  AddPlane(mesh, 4, 8, 10, 6);


305  AddPlane(mesh, 4, 7, 9, 8);


306 


307  AddPlane(mesh, 8, 12, 14, 10);


308  AddPlane(mesh, 8, 11, 13, 12);


309 


310  AddPlane(mesh, 0, 2, 14, 12);


311  AddPlane(mesh, 0, 12, 15, 1);


312 


313  AddPlane(mesh, 0, 1, 17, 16);


314  AddPlane(mesh, 0, 16, 19, 3);


315 


316  AddPlane(mesh, 4, 20, 23, 7);


317  AddPlane(mesh, 4, 5, 21, 20);


318 


319  AddPlane(mesh, 8, 24, 27, 11);


320  AddPlane(mesh, 8, 9, 25, 24);


321 


322  AddPlane(mesh, 12, 28, 31, 15);


323  AddPlane(mesh, 12, 13, 29, 28);


324 


325  AddPlane(mesh, 16, 18, 22, 20);


326  AddPlane(mesh, 16, 20, 21, 19);


327 


328  AddPlane(mesh, 20, 22, 26, 24);


329  AddPlane(mesh, 20, 24, 25, 23);


330 


331  AddPlane(mesh, 24, 28, 29, 27);


332  AddPlane(mesh, 24, 26, 30, 28);


333 


334  AddPlane(mesh, 28, 30, 18, 16);


335  AddPlane(mesh, 28, 16, 17, 31);


336  }


337 


338  /// <summary>


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


340  /// in counterclockwise sequence.


341  /// </summary>


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


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


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


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


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


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


348  // two triangles form a plane


349  mesh.TriangleIndices.Add(a);


350  mesh.TriangleIndices.Add(b);


351  mesh.TriangleIndices.Add(d);


352  mesh.TriangleIndices.Add(c);


353  mesh.TriangleIndices.Add(d);


354  mesh.TriangleIndices.Add(b);


355  }


356  #endregion


357 


358  }


359  }

