public Bar3DProps(Axis3DProps axis, AllBar3D parent, int index, int x, int y)
            {
                _axis = axis;
                _parent = parent;

                this.Index = index;
                this.X = x;
                this.Y = y;
            }
        private static Bar3DProps RebuildBars_Bar(Axis3DProps axis, AllBar3D bars, int index, int x, int y, double value)
        {
            Bar3DProps retVal = new Bar3DProps(axis, bars, index, x, y);

            retVal.Model = new GeometryModel3D();

            //NOTE: Material is updated by bars.UpdateColors

            double xPos = -axis.HalfX + (x * axis.BarSize);
            double yPos = axis.HalfY - (y * axis.BarSize);

            retVal.Model.Geometry = UtilityWPF.GetCube(new Point3D(xPos, yPos, 0), new Point3D(xPos + axis.BarSize, yPos - axis.BarSize, 1));

            Transform3DGroup transform = new Transform3DGroup();
            retVal.HeightTransform = new ScaleTransform3D(1, 1, 1);
            transform.Children.Add(retVal.HeightTransform);
            transform.Children.Add(new TranslateTransform3D(0, 0, axis.AxisOffset));
            retVal.Model.Transform = transform;

            retVal.Height = value;

            return retVal;
        }
        private static Visual3D GetHoverVisual(Axis3DProps axis, Bar3DProps bar, bool isHover)
        {
            //TODO:
            //  probably a flattened semitransparent dome over top and bottom of bar
            //  or maybe a semitransparent plate that hovers over top and bottom of bar

            double halfBarSize = axis.BarSize / 2d;

            double x = -axis.HalfX + (bar.X * axis.BarSize) + halfBarSize;
            double y = axis.HalfY - (bar.Y * axis.BarSize) - halfBarSize;

            double zPos = axis.AxisOffset + (axis.ZHeight * 1.5);
            double zNeg;
            if (axis.AxisOffset.IsNearZero())
            {
                zNeg = -zPos;
            }
            else
            {
                zNeg = axis.AxisOffset - (axis.ZHeight * .1);
            }

            ScreenSpaceLines3D retVal = new ScreenSpaceLines3D();

            if (isHover)
            {
                retVal.Color = UtilityWPF.AlphaBlend(Colors.LimeGreen, Colors.Gray, .33);
                retVal.Thickness = 1.5;
            }
            else
            {
                retVal.Color = Colors.LimeGreen;
                retVal.Thickness = 4;
            }

            retVal.AddLine(new Point3D(x, y, zNeg), new Point3D(x, y, zPos));

            return retVal;
        }
        //NOTE: Making Y go down instead of up to match the way the 2D image is drawn
        private void RedrawAxis()
        {
            const double AXISRADIUS = .015;
            const double CONERADIUS = AXISRADIUS * 3;
            const double CONEHEIGHT = AXISRADIUS * 7;

            if (_axis != null)
            {
                _viewport.Children.Remove(_axis.Visual);
                _axis = null;
            }

            Axis3DProps axis = new Axis3DProps();

            #region Calculate sizes

            axis.BarSize = 1d;

            axis.HalfX = (_width * axis.BarSize) / 2d;
            axis.HalfY = (_height * axis.BarSize) / 2d;

            axis.ZHeight = Math.Max(1, Math1D.Avg(_width, _height) / 8);

            //TODO: May want to multiply this height by a slider
            //axis.ZHeight *= trkZAxisMult.Value;

            if (radRangeNegPos.IsChecked.Value)
            {
                axis.AxisOffset = 0;
            }
            else
            {
                // It doesn't look better being double height
                axis.AxisOffset = axis.ZHeight * -.66666666;
                axis.ZHeight *= 1.3333333;
            }

            #endregion

            MaterialGroup material_Axis = new MaterialGroup();
            material_Axis.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("72BF77"))));
            material_Axis.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("50FFFFFF")), 2));

            Model3DGroup models = new Model3DGroup();

            #region X Axis

            GeometryModel3D model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCylinder_AlongX(20, AXISRADIUS, axis.HalfX * 2);

            model.Transform = new TranslateTransform3D(0, axis.HalfY, axis.AxisOffset);

            models.Children.Add(model);

            #endregion
            #region X Cone

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCone_AlongX(20, CONERADIUS, CONEHEIGHT);

            model.Transform = new TranslateTransform3D(axis.HalfX + (CONEHEIGHT / 2), axis.HalfY, axis.AxisOffset);

            models.Children.Add(model);

            #endregion

            #region Y Axis

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCylinder_AlongX(20, AXISRADIUS, axis.HalfY * 2);

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 90)));
            transform.Children.Add(new TranslateTransform3D(-axis.HalfX, 0, axis.AxisOffset));
            model.Transform = transform;

            models.Children.Add(model);

            #endregion
            #region Y Cone

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCone_AlongX(20, CONERADIUS, CONEHEIGHT);

            transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), -90)));
            transform.Children.Add(new TranslateTransform3D(-axis.HalfX, -axis.HalfY - (CONEHEIGHT / 2), axis.AxisOffset));
            model.Transform = transform;

            models.Children.Add(model);

            #endregion

            #region Z Axis

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCylinder_AlongX(20, AXISRADIUS, axis.ZHeight);

            transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90)));
            transform.Children.Add(new TranslateTransform3D(-axis.HalfX, axis.HalfY, axis.AxisOffset + (axis.ZHeight / 2)));
            model.Transform = transform;

            models.Children.Add(model);

            #endregion
            #region Z Cone

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetCone_AlongX(20, CONERADIUS, CONEHEIGHT);

            transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), -90)));
            transform.Children.Add(new TranslateTransform3D(-axis.HalfX, axis.HalfY, axis.AxisOffset + axis.ZHeight + (CONEHEIGHT / 2)));
            model.Transform = transform;

            models.Children.Add(model);

            #endregion

            #region Origin Dot

            model = new GeometryModel3D() { Material = material_Axis, BackMaterial = material_Axis, };

            model.Geometry = UtilityWPF.GetSphere_Ico(AXISRADIUS, 4, true);

            model.Transform = new TranslateTransform3D(-axis.HalfX, axis.HalfY, axis.AxisOffset);

            models.Children.Add(model);

            #endregion

            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = models;
            axis.Visual = visual;

            _axis = axis;
            _viewport.Children.Add(_axis.Visual);
        }