// Make rows of bars in the X and Z directions. private void MakeRowColumnBars(double xmin, double ymin, double zmin, double dx, double gap, double[,] values, string[] frontLabels, string[] sideLabels, Brush[,] barBrushes, Brush[] bgBrushes, Brush[] fgBrushes, FontFamily ff, Model3DGroup group) { int numX = values.GetUpperBound(0) + 1; int numZ = values.GetUpperBound(1) + 1; double x = xmin; double z; double fontSize = 0.3; for (int ix = 0; ix < numX; ix++) { z = zmin; for (int iz = 0; iz < numZ; iz++) { // Make the bar. MeshGeometry3D barMesh = new MeshGeometry3D(); Point3D corner = new Point3D(x, ymin, z); barMesh.AddBox(corner, D3.XVector(dx), D3.YVector(YScale * values[ix, iz]), D3.ZVector(dx)); group.Children.Add(barMesh.MakeModel(barBrushes[ix, iz])); z += dx + gap; } // Display the front label. const double textWid = 2; MakeLabel(frontLabels[ix], new Point3D(x + dx, ymin, z + textWid), D3.ZVector(-textWid), D3.XVector(-dx), bgBrushes[ix], fgBrushes[ix], fontSize, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); x += dx + gap; } // Display the side labels. z = zmin + dx; double xmax = xmin + numX * dx + (numX - 1) * gap; for (int iz = 0; iz < numZ; iz++) { const double textWid = 2; MakeLabel(sideLabels[iz], new Point3D(xmax + gap, ymin, z), D3.XVector(textWid), D3.ZVector(-dx), Brushes.Transparent, Brushes.Black, fontSize, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); //MakeLabel(sideLabels[iz], // new Point3D(xmin - textWid - gap, ymin, z), // D3.XVector(textWid), D3.ZVector(-dx), // Brushes.Transparent, Brushes.Black, fontSize, ff, // HorizontalAlignment.Left, VerticalAlignment.Center, group); z += dx + gap; } }
// Make a row of bars in the X direction. private void MakeBars(double xmin, double ymin, double zmin, double dx, double gap, double[] values, string[] frontLabels, string[] topLabels, Brush[] barBrushes, Brush[] bgBrushes, Brush[] fgBrushes, FontFamily ff, Model3DGroup group) { double x = xmin; double fontSize = 0.4; for (int i = 0; i < values.Length; i++) { // Make the bar. MeshGeometry3D barMesh = new MeshGeometry3D(); Point3D corner = new Point3D(x, ymin, zmin); barMesh.AddBox(corner, D3.XVector(dx), D3.YVector(YScale * values[i]), D3.ZVector(dx)); group.Children.Add(barMesh.MakeModel(barBrushes[i])); // Display the front label. const double textWid = 1.8; MakeLabel(frontLabels[i], new Point3D(x + dx, ymin, textWid + zmin + dx + gap), D3.ZVector(-textWid), D3.XVector(-dx), bgBrushes[i], fgBrushes[i], fontSize, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); // Display the top label. MakeLabel(topLabels[i], new Point3D(x, ymin + YScale * values[i], zmin - 0.1), D3.XVector(dx), D3.YVector(dx), Brushes.Transparent, fgBrushes[i], fontSize, ff, HorizontalAlignment.Center, VerticalAlignment.Bottom, group); x += dx + gap; } }
// Make a row of stacked bars in the X direction. private void MakeStackedBars(double xmin, double ymin, double zmin, double dx, double gap, double[,] values, string[] frontLabels, Brush[] barBrushes, Brush bgBrush, Brush fgBrush, FontFamily ff, Model3DGroup group) { double x = xmin; int numX = values.GetUpperBound(0) + 1; int numZ = values.GetUpperBound(1) + 1; double fontSize = 0.45; for (int ix = 0; ix < numX; ix++) { double y = ymin; for (int iz = 0; iz < numZ; iz++) { // Make this piece of the bar. MeshGeometry3D barMesh = new MeshGeometry3D(); Point3D corner = new Point3D(x, y, zmin); barMesh.AddBox(corner, D3.XVector(dx), D3.YVector(YScale * values[ix, iz]), D3.ZVector(dx)); group.Children.Add(barMesh.MakeModel(barBrushes[iz])); y += YScale * values[ix, iz]; } // Display the front label. const double textWid = 1.5; MakeLabel(frontLabels[ix], new Point3D(x + dx, ymin, textWid + zmin + dx + gap), D3.ZVector(-textWid), D3.XVector(-dx), bgBrush, fgBrush, fontSize, FontFamily, HorizontalAlignment.Left, VerticalAlignment.Center, group); x += dx + gap; } }
// Process the models. private void ProcessModels(bool invertTextures, bool zIsUp) { // Make the dictionary of materials. foreach (ObjMaterial material in AllMaterials) { // Make the material's MaterialGroup. material.MatGroup = new MaterialGroup(); // Transparency. (Not used.) byte alpha = (byte)(material.Alpha * 255); // Diffuse. byte diffR = (byte)(material.Kd.X * 255); byte diffG = (byte)(material.Kd.Y * 255); byte diffB = (byte)(material.Kd.Z * 255); Color diffColor = Color.FromArgb(255, diffR, diffG, diffB); SolidColorBrush diffBrush = new SolidColorBrush(diffColor); DiffuseMaterial diffMat = new DiffuseMaterial(diffBrush); material.MatGroup.Children.Add(diffMat); // If it has a file, use it. if (material.Filename != null) { // Use the file. string filename = material.Filename; ImageBrush imgBrush = new ImageBrush(); imgBrush.ViewportUnits = BrushMappingMode.Absolute; imgBrush.TileMode = TileMode.Tile; // Invert the texture if necessary. if (invertTextures) { TransformGroup trans = new TransformGroup(); trans.Children.Add(new ScaleTransform(1, -1)); trans.Children.Add(new TranslateTransform(0, 1)); imgBrush.Transform = trans; } imgBrush.ImageSource = new BitmapImage(new Uri(filename, UriKind.Relative)); DiffuseMaterial imgMat = new DiffuseMaterial(imgBrush); material.MatGroup.Children.Add(imgMat); } // Specular. byte specR = (byte)(material.Ks.X * 255); byte specG = (byte)(material.Ks.Y * 255); byte specB = (byte)(material.Ks.Z * 255); Color specColor = Color.FromArgb(255, specR, specG, specB); SolidColorBrush specBrush = new SolidColorBrush(specColor); SpecularMaterial specMat = new SpecularMaterial(specBrush, material.Ns); material.MatGroup.Children.Add(specMat); // We ignore Ka and Tr. // Add it to the materials dictionary. MtlMaterials.Add(material.Name, material); } // Convert the object models into meshes. foreach (ObjModel model in AllObjectModels) { // Make the mesh. MeshGeometry3D mesh = new MeshGeometry3D(); Meshes.Add(mesh); MeshNames.Add(model.Name); MaterialNames.Add(model.MaterialName); // Make a new list of smoothing groups. Dictionary <int, Dictionary <Point3D, int> > smoothingGroups = new Dictionary <int, Dictionary <Point3D, int> >(); // Entry 0 is null (no smoothing). smoothingGroups.Add(0, null); // Make the faces. foreach (ObjFace face in model.Faces) { // Make the face's vertices. int numPoints = face.Vertices.Count; Point3D[] points = new Point3D[numPoints]; for (int i = 0; i < numPoints; i++) { points[i] = AllVertices[face.Vertices[i] - 1]; } // Get texture coordinates if present. Point[] textureCoords = null; if (face.TextureCoords.Count > 0) { textureCoords = new Point[numPoints]; for (int i = 0; i < numPoints; i++) { textureCoords[i] = AllTextureCoordinates[face.TextureCoords[i] - 1]; } } // Get normals if present. Vector3D[] normals = null; if (face.Normals.Count > 0) { normals = new Vector3D[numPoints]; for (int i = 0; i < numPoints; i++) { normals[i] = AllNormals[face.Normals[i] - 1]; } } // Get the point dictionary for this smoothing group. // Add new groups if needed. if (!smoothingGroups.ContainsKey(face.SmoothingGroup)) { smoothingGroups.Add(face.SmoothingGroup, new Dictionary <Point3D, int>()); } Dictionary <Point3D, int> pointDict = smoothingGroups[face.SmoothingGroup]; // Make the polygon. mesh.AddPolygon(pointDict: pointDict, textureCoords: textureCoords, normals: normals, points: points); } // If Z is up, rotate the model. if (zIsUp) { mesh.ApplyTransformation(D3.Rotate(D3.XVector(), D3.Origin, -90)); } } }
// Define the model. private void DefineModel(Model3DGroup group) { // Axes. //MeshExtensions.AddAxes(group); // General positioning parameters. Point3D origin = new Point3D(-2, -3, 0); double barDx = 1; double barGap = 0.25; // Load the data. double[,] values = LoadData(); int numX = values.GetUpperBound(0) + 1; int numZ = values.GetUpperBound(1) + 1; Brush[] barBrushes = { Brushes.Green, Brushes.Blue, Brushes.White, Brushes.Red }; string[] frontLabels = { " 1960", " 1970", " 1980", " 1990", " 2000", " 2010" }; // See how big the bars will be. double widX = numX * barDx + (numX - 1) * barGap; double widZ = numZ * barDx + (numZ - 1) * barGap; double hgt = YMax * YScale; double barXmin = origin.X - widX / 2; double barXmax = barXmin + widX; double barYmin = origin.Y; double barYmax = barYmin + hgt; double barZmin = origin.Z - barDx / 2; double barZmax = barZmin + barDx; // Bars. FontFamily ff = new FontFamily("Franklin Gothic Demi"); MakeStackedBars(barXmin, barYmin, barZmin, barDx, barGap, values, frontLabels, barBrushes, Brushes.Transparent, Brushes.Black, ff, group); // Title. MakeLabel("US Military", new Point3D(barXmin, barYmax + 1, barZmin - 0.1), D3.XVector(widX), D3.YVector(1), Brushes.Transparent, Brushes.Green, 0.9, ff, HorizontalAlignment.Center, VerticalAlignment.Center, group); MakeLabel("Composition", new Point3D(barXmin, barYmax, barZmin - 0.1), D3.XVector(widX), D3.YVector(1), Brushes.Transparent, Brushes.Green, 0.9, ff, HorizontalAlignment.Center, VerticalAlignment.Center, group); // Lines behind. MeshGeometry3D mesh = new MeshGeometry3D(); Point3D p1 = new Point3D(barXmin - barGap / 2, barYmin, barZmin - 0.1); Point3D p2 = new Point3D(barXmax + barGap / 2, barYmin, barZmin - 0.1); for (double y = 0; y < YMax; y += 500000) { p1.Y = barYmin + y * YScale; p2.Y = p1.Y; mesh.AddSegment(0.05, p1, p2); } group.Children.Add(mesh.MakeModel(Brushes.Red)); // Line labels. p1 = new Point3D(barXmax + barGap, barYmin, barZmin - 0.1); for (double y = 0; y < YMax; y += 1000000) { p1.Y = barYmin + y * YScale - 0.25; string text = ((int)(y / 1000000)).ToString() + " M"; MakeLabel(text, p1, D3.XVector(0.5), D3.YVector(0.5), Brushes.Transparent, Brushes.Black, 0.25, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); } // Key. const double textWidth = 1.5; Point3D point = new Point3D(barXmax + 2 * barGap + 0.5, barYmin, barZmin); MakeLabel("", point, D3.XVector(0.5), D3.YVector(0.5), Brushes.Green, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X += 0.5; MakeLabel(" Army", point, D3.XVector(textWidth), D3.YVector(0.5), Brushes.Transparent, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X -= 0.5; point.Y += 0.75; MakeLabel("", point, D3.XVector(0.5), D3.YVector(0.5), Brushes.Blue, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X += 0.5; MakeLabel(" Navy", point, D3.XVector(textWidth), D3.YVector(0.5), Brushes.Transparent, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X -= 0.5; point.Y += 0.75; MakeLabel("", point, D3.XVector(0.5), D3.YVector(0.5), Brushes.White, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X += 0.5; MakeLabel(" Air Force", point, D3.XVector(textWidth), D3.YVector(0.5), Brushes.Transparent, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.Y += 0.75; point.X -= 0.5; MakeLabel("", point, D3.XVector(0.5), D3.YVector(0.5), Brushes.Red, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); point.X += 0.5; MakeLabel(" Marines", point, D3.XVector(textWidth), D3.YVector(0.5), Brushes.Transparent, Brushes.Black, 0.3, ff, HorizontalAlignment.Left, VerticalAlignment.Center, group); }