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