A visual element that contains a text billboard.
Inheritance: BillboardVisual3D
        /// <summary>
        /// This function contains all the "business logic" for constructing a SurfacePlot 3D. 
        /// </summary>
        /// <returns>A Model3DGroup containing all the component models (mesh, surface definition, grid objects, etc).</returns>
        private Model3DGroup CreateModel()
        {
            var newModelGroup = new Model3DGroup();
            double lineThickness = 0.01;
            double axesOffset = 0.05;

            // Get relevant constaints from the DataPoints object
            int numberOfRows = DataPoints.GetUpperBound(0) + 1;
            int numberOfColumns = DataPoints.GetUpperBound(1) + 1;

            // Determine the x, y, and z ranges of the DataPoints collection
            double minX = double.MaxValue;
            double maxX = double.MinValue;
            double minY = double.MaxValue;
            double maxY = double.MinValue;
            double minZ = double.MaxValue;
            double maxZ = double.MinValue;

            double minColorValue = double.MaxValue;
            double maxColorValue = double.MinValue;

            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    double x = DataPoints[i, j].X;
                    double y = DataPoints[i, j].Y;
                    double z = DataPoints[i, j].Z;
                    maxX = Math.Max(maxX, x);
                    maxY = Math.Max(maxY, y);
                    maxZ = Math.Max(maxZ, z);
                    minX = Math.Min(minX, x);
                    minY = Math.Min(minY, y);
                    minZ = Math.Min(minZ, z);
                    if (ColorValues != null)
                    {
                        maxColorValue = Math.Max(maxColorValue, ColorValues[i, j]);
                        minColorValue = Math.Min(minColorValue, ColorValues[i, j]);
                    }
                }
            }

            /* TEMP */
            int numberOfXAxisTicks = 10;
            int numberOfYAxisTicks = 10;
            int numberOfZAxisTicks = 5;
            double XAxisInterval = (maxX - minX) / numberOfXAxisTicks;
            double YAxisInterval = (maxY - minY) / numberOfYAxisTicks;
            double ZAxisInterval = (maxZ - minZ) / numberOfZAxisTicks;
            /* /TEMP */

            // Set color value to 0 at texture coordinate 0.5, with an even spread in either direction
            if (Math.Abs(minColorValue) < Math.Abs(maxColorValue)) { minColorValue = -maxColorValue; }
            else                                                   { maxColorValue = -minColorValue; }

            // Set the texture coordinates by either z-value or ColorValue
            var textureCoordinates = new Point[numberOfRows, numberOfColumns];
            for (int i = 0; i < numberOfRows; i++)
            {
                for (int j = 0; j < numberOfColumns; j++)
                {
                    double tc;
                    if (ColorValues != null) { tc = (ColorValues[i, j] - minColorValue) / (maxColorValue - minColorValue); }
                    else                     { tc = (DataPoints[i, j].Z - minZ) / (maxZ - minZ); }
                    textureCoordinates[i, j] = new Point(tc, tc);
                }
            }

            // Build the surface model (i.e. the coloured surface model)
            MeshBuilder surfaceModelBuilder = new MeshBuilder();
            surfaceModelBuilder.AddRectangularMesh(DataPoints, textureCoordinates);

            GeometryModel3D surfaceModel = new GeometryModel3D(surfaceModelBuilder.ToMesh(), MaterialHelper.CreateMaterial(SurfaceBrush, null, null, 1, 0));
            surfaceModel.BackMaterial = surfaceModel.Material;

            // Instantiate MeshBuilder objects for the Grid and SurfaceMeshLines meshes
            MeshBuilder surfaceMeshLinesBuilder = new MeshBuilder();
            MeshBuilder surfaceContourLinesBuilder = new MeshBuilder();
            MeshBuilder gridBuilder = new MeshBuilder();

            // Build the axes labels model (i.e. the object that holds the axes labels and ticks)
            ModelVisual3D axesLabelsModel = new ModelVisual3D();

            // Loop through x intervals - for the surface meshlines, the grid, and X axes ticks
            for (double x = minX; x <= maxX + 0.0001; x += XAxisInterval)
            {
                // Add surface mesh lines which denote intervals along the x-axis
                var surfacePath = new List<Point3D>();
                double i = (x - minX) / (maxX - minX) * (numberOfColumns - 1);
                for (int j = 0; j < numberOfColumns; j++)
                {
                    surfacePath.Add(DoBilinearInterpolation(DataPoints, i, j));
                }
                surfaceMeshLinesBuilder.AddTube(surfacePath, lineThickness, 9, false);

                // Axes labels
                BillboardTextVisual3D label = new BillboardTextVisual3D();
                label.Text = string.Format("{0:F2}", x);
                label.Position = new Point3D(x, minY - axesOffset, minZ - axesOffset);
                axesLabelsModel.Children.Add(label);

                // Grid lines
                var gridPath = new List<Point3D>();
                gridPath.Add(new Point3D(x, minY, minZ));
                gridPath.Add(new Point3D(x, maxY, minZ));
                gridPath.Add(new Point3D(x, maxY, maxZ));
                gridBuilder.AddTube(gridPath, lineThickness, 9, false);

            }

            // Loop through y intervals - for the surface meshlines, the grid, and Y axes ticks
            for (double y = minY; y <= maxY + 0.0001; y += YAxisInterval)
            {
                // Add surface mesh lines which denote intervals along the y-axis
                var path = new List<Point3D>();
                double j = (y - minY) / (maxY - minY) * (numberOfRows - 1);
                for (int i = 0; i < numberOfRows; i++)
                {
                    path.Add(DoBilinearInterpolation(DataPoints, i, j));
                }
                surfaceMeshLinesBuilder.AddTube(path, lineThickness, 9, false);

                // Axes labels
                BillboardTextVisual3D label = new BillboardTextVisual3D();
                label.Text = string.Format("{0:F2}", y);
                label.Position = new Point3D(minX - axesOffset, y, minZ - axesOffset);
                axesLabelsModel.Children.Add(label);

                // Grid lines
                var gridPath = new List<Point3D>();
                gridPath.Add(new Point3D(minX, y, minZ));
                gridPath.Add(new Point3D(maxX, y, minZ));
                gridPath.Add(new Point3D(maxX, y, maxZ));
                gridBuilder.AddTube(gridPath, lineThickness, 9, false);
            }

            // Loop through z intervals - for the grid, and Z axes ticks
            for (double z = minZ; z <= maxZ + 0.0001; z += ZAxisInterval)
            {
                // Grid lines
                var path = new List<Point3D>();
                path.Add(new Point3D(minX, maxY, z));
                path.Add(new Point3D(maxX, maxY, z));
                path.Add(new Point3D(maxX, minY, z));
                gridBuilder.AddTube(path, lineThickness, 9, false);

                // Axes labels
                BillboardTextVisual3D label = new BillboardTextVisual3D();
                label.Text = string.Format("{0:F2}", z);
                label.Position = new Point3D(minX - axesOffset, maxY + axesOffset, z);
                axesLabelsModel.Children.Add(label);
            }

            // Add axes labels
            BillboardTextVisual3D xLabel = new BillboardTextVisual3D();
            xLabel.Text = "X Axis";
            xLabel.Position = new Point3D((maxX - minX) / 2, minY - 3 * axesOffset, minZ - 5 * axesOffset);
            axesLabelsModel.Children.Add(xLabel);
            BillboardTextVisual3D yLabel = new BillboardTextVisual3D();
            yLabel.Text = "Y Axis";
            yLabel.Position = new Point3D(minX - 3 * axesOffset, (maxY - minY) / 2, minZ - 5 * axesOffset);
            axesLabelsModel.Children.Add(yLabel);
            BillboardTextVisual3D zLabel = new BillboardTextVisual3D();
            zLabel.Text = "Z Axis";
            zLabel.Position = new Point3D(minX - 5 * axesOffset, maxY + 5 * axesOffset, 0); // Note: trying to find the midpoint of minZ, maxZ doesn't work when minZ = -0.5 and maxZ = 0.5...
            axesLabelsModel.Children.Add(zLabel);

            // Create models from MeshBuilders
            GeometryModel3D surfaceMeshLinesModel = new GeometryModel3D(surfaceMeshLinesBuilder.ToMesh(), Materials.Black);
            GeometryModel3D gridModel = new GeometryModel3D(gridBuilder.ToMesh(), Materials.Black);

            // Update model group
            //this.Children.Add(axesLabelsModel);
            newModelGroup.Children.Add(surfaceModel);
            newModelGroup.Children.Add(surfaceMeshLinesModel);
            newModelGroup.Children.Add(gridModel);

            //ScaleTransform3D surfaceTransform = new ScaleTransform3D(20, 20, 20, 0, 0, 0);
            //newModelGroup.Transform = surfaceTransform;

            return newModelGroup;
        }
 internal void add3DText(Point3D point, string text)
 {
   BillboardTextVisual3D txt = new BillboardTextVisual3D();
   point.Y = point.Y + 5;
   txt.Position = point;
   txt.FontSize = 12;
   txt.Text = text;
   txt.Height = 25;
   this.Children.Add(txt);
   _text.Add(point, txt);
 }
        private void Initializer()
        {
            Inspector1StatusText = new BillboardTextVisual3D();
            Inspector1StatusText.DepthOffset = 0.01;
            Inspector1StatusText.Position = new Point3D(0, 0, 0);
            Inspector1StatusText.Text = "Created!";
            World.Instance.Mother.Children.Add(Inspector1StatusText);

            Inspector2StatusText = new BillboardTextVisual3D();
            Inspector2StatusText.DepthOffset = 0.01;
            Inspector2StatusText.Position = new Point3D(0, 0, 0);
            Inspector2StatusText.Text = "Created!";
            World.Instance.Mother.Children.Add(Inspector2StatusText);

            InspectorQStatusText = new BillboardTextVisual3D();
            InspectorQStatusText.DepthOffset = 0.01;
            InspectorQStatusText.Position = new Point3D(0, 0, 0);
            InspectorQStatusText.Text = "Created!";
            World.Instance.Mother.Children.Add(InspectorQStatusText);

            Tranformer = new TranslateTransform3D();
            Transform = Tranformer;

            InspectorQueue = new Queue<ServiceBoxElement>();

            Inspector1Status = WorkerStatus.Idle;
            Inspector2Status = WorkerStatus.Idle;
            Inspector1Box = null;
            Inspector2Box = null;
        }
        public void Initializer()
        {
            PlatformStatusText = new BillboardTextVisual3D();
            PlatformStatusText.DepthOffset = 0.01;
            PlatformStatusText.Position = new Point3D(0, 0, 0);
            PlatformStatusText.Text = "Created!";
            World.Instance.Mother.Children.Add(PlatformStatusText);

            Status = StationStatus.Empty;
            InnerElement = null;
            TotalServiceTime = 0;
            Name = "NewPlatfrom";

            Tranformer = new TranslateTransform3D();
            Transform = Tranformer;
        }