Free cookie consent management tool by TermsFeed Policy Generator

source: stable/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs @ 15092

Last change on this file since 15092 was 14162, checked in by gkronber, 8 years ago

#2641: first import of bin packing problem (TODO: persistence and sample)

File size: 10.5 KB
Line 
1/* HeuristicLab
2 * Copyright (C) 2002-2016 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
20using System;
21using System.Linq;
22using System.Windows;
23using System.Windows.Controls;
24using System.Windows.Input;
25using System.Windows.Media.Media3D;
26using HeuristicLab.Problems.BinPacking3D;
27
28namespace HeuristicLab.Problems.BinPacking.Views {
29  public partial class Container3DView : UserControl {
30    private Point startPos;
31    private bool mouseDown = false;
32    private double startAngleX;
33    private double startAngleY;
34    private int selectedItemKey;
35
36    private BinPacking<BinPacking3D.PackingPosition, PackingShape, PackingItem> packing;
37    public BinPacking<BinPacking3D.PackingPosition, PackingShape, PackingItem> Packing {
38      get { return packing; }
39      set {
40        if (packing != value) {
41          this.packing = value;
42          ClearSelection(); // also updates visualization
43        }
44      }
45    }
46
47    public Container3DView() {
48      InitializeComponent();
49      camMain.Position = new Point3D(0.5, 3, 3); // for design time we use a different camera position
50      Clear();
51    }
52
53
54    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) {
55      base.OnRenderSizeChanged(sizeInfo);
56      var s = Math.Min(sizeInfo.NewSize.Height, sizeInfo.NewSize.Width);
57      var mySize = new Size(s, s);
58      viewport3D1.RenderSize = mySize;
59    }
60
61    public void SelectItem(int itemKey) {
62      // selection of an item should make all other items semi-transparent
63      selectedItemKey = itemKey;
64      UpdateVisualization();
65    }
66    public void ClearSelection() {
67      // remove all transparency
68      selectedItemKey = -1;
69      UpdateVisualization();
70    }
71
72    private void UpdateVisualization() {
73      Clear();
74      if (packing == null) return; // nothing to display
75
76      // draw all items
77      // order by Z position to reduce artifacts (because of transparent objects)
78      // TODO: improve code to reduce artifacts
79      //  - from triangle definitions and lighting
80      //  - from rotation and Z-ordering
81
82      foreach (var item in packing.Items.OrderBy(i => packing.Positions[i.Key].Z)) {
83        var position = packing.Positions[item.Key];
84
85        var w = position.Rotated ? item.Value.Depth : item.Value.Width;
86        var h = item.Value.Height;
87        var d = position.Rotated ? item.Value.Width : item.Value.Depth;
88
89        // ignore the item.Material
90
91        // if nothing is selected then draw all cubes opaque
92        // otherwise draw only the selected cube opaque and all others transparent
93        if (selectedItemKey < 0 || selectedItemKey == item.Key) {
94          AddCube(meshMain, position.X, position.Y, position.Z, w, h, d);
95        } else {
96          AddCube(meshTransparent, position.X, position.Y, position.Z, w, h, d, addInsideTriangles: true);
97        }
98      }
99
100      var container = packing.BinShape;
101      // draw a transparent container
102      AddCube(meshTransparent, container.Origin.X, container.Origin.Y, container.Origin.Z, container.Width, container.Height, container.Depth, addInsideTriangles: true);
103
104      // TODO: support cuboids with different side lengths
105      // apply scaling so that the container fits into the unit cube (necessary for the transformations)
106      scale.ScaleX = 1.0 / (container.Width);
107      scale.ScaleY = 1.0 / (container.Height);
108      scale.ScaleZ = 1.0 / (container.Depth);
109    }
110
111
112    private void Clear() {
113      meshInsides.Positions.Clear();
114      meshInsides.TriangleIndices.Clear();
115
116      meshMain.Positions.Clear();
117      meshMain.TriangleIndices.Clear();
118
119      meshTransparent.Positions.Clear();
120      meshTransparent.TriangleIndices.Clear();
121
122      mouseDown = false;
123      startAngleX = 0;
124      startAngleY = 0;
125    }
126
127    private void Container3DView_MouseMove(object sender, MouseEventArgs e) {
128      if (!mouseDown) return;
129      var pos = e.GetPosition((IInputElement)this);
130      rotateX.Angle = startAngleX + (pos.X - startPos.X) / 4;
131      rotateY.Angle = startAngleY + (pos.Y - startPos.Y) / 4;
132    }
133
134    private void Container3DView_MouseDown(object sender, MouseButtonEventArgs e) {
135      startAngleX = rotateX.Angle;
136      startAngleY = rotateY.Angle;
137      this.startPos = e.GetPosition((IInputElement)this);
138      this.mouseDown = true;
139    }
140
141    private void Container3DView_MouseUp(object sender, MouseButtonEventArgs e) {
142      mouseDown = false;
143    }
144
145    private void Container3DView_OnMouseWheel(object sender, MouseWheelEventArgs e) {
146      if (e.Delta > 0) {
147        scaleZoom.ScaleX *= 1.1;
148        scaleZoom.ScaleY *= 1.1;
149        scaleZoom.ScaleZ *= 1.1;
150      } else if (e.Delta < 0) {
151        scaleZoom.ScaleX /= 1.1;
152        scaleZoom.ScaleY /= 1.1;
153        scaleZoom.ScaleZ /= 1.1;
154      }
155    }
156
157
158    #region helper for cubes
159
160    private void AddCube(MeshGeometry3D mesh, int x, int y, int z, int width, int height, int depth, bool addInsideTriangles = false) {
161      AddOutsideTriangles(mesh, AddPoints(mesh, x, y, z, width, height, depth));
162      if (addInsideTriangles) AddInsideTriangles(meshInsides, AddPoints(meshInsides, x, y, z, width, height, depth));
163    }
164
165    private void AddOutsideTriangles(MeshGeometry3D mesh, int[] pointIdx) {
166      // point indices counter-clockwise
167      // back side
168      mesh.TriangleIndices.Add(pointIdx[0]);
169      mesh.TriangleIndices.Add(pointIdx[2]);
170      mesh.TriangleIndices.Add(pointIdx[1]);
171
172      mesh.TriangleIndices.Add(pointIdx[0]);
173      mesh.TriangleIndices.Add(pointIdx[3]);
174      mesh.TriangleIndices.Add(pointIdx[2]);
175
176      // bottom side
177      mesh.TriangleIndices.Add(pointIdx[5]);
178      mesh.TriangleIndices.Add(pointIdx[4]);
179      mesh.TriangleIndices.Add(pointIdx[0]);
180
181      mesh.TriangleIndices.Add(pointIdx[5]);
182      mesh.TriangleIndices.Add(pointIdx[0]);
183      mesh.TriangleIndices.Add(pointIdx[1]);
184
185      // right side
186      mesh.TriangleIndices.Add(pointIdx[2]);
187      mesh.TriangleIndices.Add(pointIdx[6]);
188      mesh.TriangleIndices.Add(pointIdx[5]);
189
190      mesh.TriangleIndices.Add(pointIdx[1]);
191      mesh.TriangleIndices.Add(pointIdx[2]);
192      mesh.TriangleIndices.Add(pointIdx[5]);
193
194      // left side
195      mesh.TriangleIndices.Add(pointIdx[7]);
196      mesh.TriangleIndices.Add(pointIdx[3]);
197      mesh.TriangleIndices.Add(pointIdx[4]);
198
199      mesh.TriangleIndices.Add(pointIdx[4]);
200      mesh.TriangleIndices.Add(pointIdx[3]);
201      mesh.TriangleIndices.Add(pointIdx[0]);
202
203      // top side
204      mesh.TriangleIndices.Add(pointIdx[3]);
205      mesh.TriangleIndices.Add(pointIdx[7]);
206      mesh.TriangleIndices.Add(pointIdx[6]);
207
208      mesh.TriangleIndices.Add(pointIdx[3]);
209      mesh.TriangleIndices.Add(pointIdx[6]);
210      mesh.TriangleIndices.Add(pointIdx[2]);
211
212      // front side
213      mesh.TriangleIndices.Add(pointIdx[6]);
214      mesh.TriangleIndices.Add(pointIdx[7]);
215      mesh.TriangleIndices.Add(pointIdx[4]);
216
217      mesh.TriangleIndices.Add(pointIdx[6]);
218      mesh.TriangleIndices.Add(pointIdx[4]);
219      mesh.TriangleIndices.Add(pointIdx[5]);
220    }
221
222    private void AddInsideTriangles(MeshGeometry3D mesh, int[] pointIdx) {
223      // for each cube we also draw the triangles facing inside because they are visible when a cube is transparent
224      // point indices clockwise
225
226      // back side
227      mesh.TriangleIndices.Add(pointIdx[1]);
228      mesh.TriangleIndices.Add(pointIdx[2]);
229      mesh.TriangleIndices.Add(pointIdx[0]);
230
231      mesh.TriangleIndices.Add(pointIdx[2]);
232      mesh.TriangleIndices.Add(pointIdx[3]);
233      mesh.TriangleIndices.Add(pointIdx[0]);
234
235      // bottom side
236      mesh.TriangleIndices.Add(pointIdx[0]);
237      mesh.TriangleIndices.Add(pointIdx[4]);
238      mesh.TriangleIndices.Add(pointIdx[5]);
239
240      mesh.TriangleIndices.Add(pointIdx[1]);
241      mesh.TriangleIndices.Add(pointIdx[0]);
242      mesh.TriangleIndices.Add(pointIdx[5]);
243
244      // right side
245      mesh.TriangleIndices.Add(pointIdx[5]);
246      mesh.TriangleIndices.Add(pointIdx[6]);
247      mesh.TriangleIndices.Add(pointIdx[2]);
248
249      mesh.TriangleIndices.Add(pointIdx[5]);
250      mesh.TriangleIndices.Add(pointIdx[2]);
251      mesh.TriangleIndices.Add(pointIdx[1]);
252
253      // left side
254      mesh.TriangleIndices.Add(pointIdx[4]);
255      mesh.TriangleIndices.Add(pointIdx[3]);
256      mesh.TriangleIndices.Add(pointIdx[7]);
257
258      mesh.TriangleIndices.Add(pointIdx[0]);
259      mesh.TriangleIndices.Add(pointIdx[3]);
260      mesh.TriangleIndices.Add(pointIdx[4]);
261
262      // top side
263      mesh.TriangleIndices.Add(pointIdx[6]);
264      mesh.TriangleIndices.Add(pointIdx[7]);
265      mesh.TriangleIndices.Add(pointIdx[3]);
266
267      mesh.TriangleIndices.Add(pointIdx[2]);
268      mesh.TriangleIndices.Add(pointIdx[6]);
269      mesh.TriangleIndices.Add(pointIdx[3]);
270
271      // front side
272      mesh.TriangleIndices.Add(pointIdx[4]);
273      mesh.TriangleIndices.Add(pointIdx[7]);
274      mesh.TriangleIndices.Add(pointIdx[6]);
275
276      mesh.TriangleIndices.Add(pointIdx[5]);
277      mesh.TriangleIndices.Add(pointIdx[4]);
278      mesh.TriangleIndices.Add(pointIdx[6]);
279    }
280
281    private int[] AddPoints(MeshGeometry3D mesh, int x, int y, int z, int w, int h, int d) {
282      // ground
283      mesh.Positions.Add(new Point3D(x, y, z));
284      mesh.Positions.Add(new Point3D(x + w, y, z));
285      mesh.Positions.Add(new Point3D(x + w, y + h, z));
286      mesh.Positions.Add(new Point3D(x, y + h, z));
287      // top
288      mesh.Positions.Add(new Point3D(x, y, z + d));
289      mesh.Positions.Add(new Point3D(x + w, y, z + d));
290      mesh.Positions.Add(new Point3D(x + w, y + h, z + d));
291      mesh.Positions.Add(new Point3D(x, y + h, z + d));
292
293      return Enumerable.Range(mesh.Positions.Count - 8, 8).ToArray();
294    }
295    #endregion
296
297    private void Container3DView_OnMouseEnter(object sender, MouseEventArgs e) {
298      Focus(); // for mouse wheel events
299    }
300  }
301}
Note: See TracBrowser for help on using the repository browser.