Index: /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml
===================================================================
--- /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml (revision 14707)
+++ /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml (revision 14708)
@@ -30,4 +30,5 @@
MouseWheel="Container3DView_OnMouseWheel"
MouseEnter="Container3DView_OnMouseEnter"
+ KeyDown="Container3DView_OnKeyDown"
Focusable="true"
>
@@ -48,67 +49,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Index: /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs (revision 14707)
+++ /trunk/sources/HeuristicLab.Problems.BinPacking.Views/3.3/Container3DView.xaml.cs (revision 14708)
@@ -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,6 +30,27 @@
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;
+ private bool ctrlDown = false;
private double startAngleX;
private double startAngleY;
@@ -45,7 +68,10 @@
}
+ private Dictionary materials;
+
public Container3DView() {
InitializeComponent();
camMain.Position = new Point3D(0.5, 3, 3); // for design time we use a different camera position
+ materials = new Dictionary();
Clear();
}
@@ -74,11 +100,8 @@
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 modelGroup = (Model3DGroup)MyModel.Content;
+ var hiddenMaterial = new DiffuseMaterial(new SolidColorBrush(hiddenColor));
+
+ foreach (var item in packing.Items) {
var position = packing.Positions[item.Key];
@@ -87,37 +110,41 @@
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 model = new GeometryModel3D { Geometry = new MeshGeometry3D() };
+ DiffuseMaterial material;
+ if (selectedItemKey >= 0 && selectedItemKey != item.Key)
+ material = hiddenMaterial;
+ else {
+ if (!materials.TryGetValue(item.Value.Material, out material)) {
+ var color = colors[(item.Value.Material - 1) % colors.Length];
+ material = new DiffuseMaterial { Brush = new SolidColorBrush(color) };
+ materials[item.Value.Material] = material;
+ }
}
+ model.Material = material;
+ modelGroup.Children.Add(model);
+
+ AddSolidCube((MeshGeometry3D)model.Geometry, position.X, position.Y, position.Z, w, h, d);
}
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;
+
+ scale.CenterX = .5;
+ scale.CenterY = .5;
+ scale.CenterZ = 0;
}
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;
startAngleX = 0;
@@ -128,4 +155,5 @@
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;
@@ -155,147 +183,177 @@
}
+ private void Container3DView_OnMouseEnter(object sender, MouseEventArgs e) {
+ Focus(); // for mouse wheel events
+ }
+
+ private void Container3DView_OnKeyDown(object sender, KeyEventArgs e) {
+ ctrlDown = e.Key.HasFlag(Key.LeftCtrl) || e.Key.HasFlag(Key.RightCtrl);
+ }
+
#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) {
+ ///
+ /// Creates a solid cube by adding the respective points and triangles.
+ ///
+ /// The mesh to which points and triangles are added.
+ /// The leftmost point
+ /// The frontmost point
+ /// The lowest point
+ /// The extension to the right
+ /// The extension to the back
+ /// The extension to the top
+ 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);
+ }
+
+ ///
+ /// Creates a wireframe cube by adding the respective points and triangles.
+ ///
+ /// The mesh to which points and triangles are added.
+ /// The leftmost point
+ /// The frontmost point
+ /// The lowest point
+ /// The extension to the right
+ /// The extension to the back
+ /// The extension to the top
+ /// The thickness of the frame
+ 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));
+
+ AddPlane(mesh, 0, 4, 6, 2);
+ AddPlane(mesh, 0, 3, 5, 4);
+
+ AddPlane(mesh, 4, 8, 10, 6);
+ AddPlane(mesh, 4, 7, 9, 8);
+
+ AddPlane(mesh, 8, 12, 14, 10);
+ AddPlane(mesh, 8, 11, 13, 12);
+
+ AddPlane(mesh, 0, 2, 14, 12);
+ AddPlane(mesh, 0, 12, 15, 1);
+
+ AddPlane(mesh, 0, 1, 17, 16);
+ AddPlane(mesh, 0, 16, 19, 3);
+
+ AddPlane(mesh, 4, 20, 23, 7);
+ AddPlane(mesh, 4, 5, 21, 20);
+
+ AddPlane(mesh, 8, 24, 27, 11);
+ AddPlane(mesh, 8, 9, 25, 24);
+
+ AddPlane(mesh, 12, 28, 31, 15);
+ AddPlane(mesh, 12, 13, 29, 28);
+
+ AddPlane(mesh, 16, 18, 22, 20);
+ AddPlane(mesh, 16, 20, 21, 19);
+
+ AddPlane(mesh, 20, 22, 26, 24);
+ AddPlane(mesh, 20, 24, 25, 23);
+
+ AddPlane(mesh, 24, 28, 29, 27);
+ AddPlane(mesh, 24, 26, 30, 28);
+
+ AddPlane(mesh, 28, 30, 18, 16);
+ AddPlane(mesh, 28, 16, 17, 31);
+ }
+
+ ///
+ /// Adds a plane by two triangles. The indices of the points have to be given
+ /// in counter-clockwise sequence.
+ ///
+ /// The mesh to add the triangles to
+ /// The index of the first point
+ /// The index of the second point
+ /// The index of the third point
+ /// The index of the fourth point
+ 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
- }
}
}