/// <summary>
        /// Recalculate Feed rate.
        /// </summary>
        void Calculate_Vf_from_vc()
        {
            // Vf = (Vc fz Z)/(pi D)
            var v1_3 = new DoubleST((long)tool.Z.GetValue(), "[tooth]");
            var v1   = (DoubleST)material.Vc * (DoubleST)material.fz * v1_3;
            var v2   = Math.PI * (DoubleST)tool.D;

#if TRACE_EVENTS
            log.Debug($"Calculator: Vf from vc({v2})");
#endif
            Vf.SetValueScaled(v1 / v2);
        }
            /// <summary>
            /// Information about the material
            /// </summary>
            /// <param name="tool">Tool to use on the material</param>
            public Material(Tool tool)
            {
                this.tool = tool;

                Vc = new DoubleST(1.0, "[mm/s]");
                n  = new DoubleST(1.0, "[rpm]");
                fz = new DoubleST(1.0, "[mm/tooth]");

                this.tool.D.OnChanged += tool_D_OnChanged;

                Vc.OnChanged += Vc_OnChanged;
                n.OnChanged  += n_OnChanged;
            }
        /// <summary>
        /// Recalculate Feed rate.
        /// </summary>
        void Calculate_Vf_from_n()
        {
            // Vf = n fz Z

            // n from rotations to time domain. (not yet done automatic)
            var v1_1 = new DoubleST(1, "[1/s]") * (DoubleST)n / n.BaseNormal();
            var v1_3 = new DoubleST((long)tool.Z.GetValue(), "[tooth]");
            var v1   = v1_1 * (DoubleST)material.fz * v1_3;

#if TRACE_EVENTS
            log.Debug($"Calculator: Vf from n({v1})");
#endif
            Vf.SetValueScaled(v1);
        }
            /// <summary>
            /// Recalculate Vc value.
            /// </summary>
            void Calculate_Vc()
            {
                // calculate Vc from n and tool D
                // Vc = pi D n

                // n from rotations to time domain. (not yet done automatic)
                var v1_3 = new DoubleST(1, "[1/s]") * (DoubleST)n / n.BaseNormal();
                var v1   = Math.PI * (DoubleST)tool.D * v1_3;

#if TRACE_EVENTS
                log.Debug($"Calculator.Material: Vc({v1})");
#endif
                Vc.SetValueScaled(v1);
            }
            /// <summary>
            /// Recalculate spindle speed.
            /// </summary>
            void Calculate_n()
            {
                // calculate n from Vc and tool D
                // n = Vc / (pi D)
                var v1 = (DoubleST)Vc;
                var v2 = Math.PI * (DoubleST)tool.D;

                // n from time to rotations domain. (not yet done automatic)
                var v3 = new DoubleST(1, "[rps s]") * v1 / v2;

#if TRACE_EVENTS
                log.Debug($"Calculator.Material: n({v3})");
#endif
                n.SetValueScaled(v3);
            }
        /// <summary>
        /// New material selected from the list.
        /// </summary>
        /// <param name="selected">New selected material</param>
        public void SelectMaterial(object selected)
        {
            Data.Material m = null;
            try
            {
                if (selected is System.Collections.Generic.KeyValuePair <string, Data.Material> )
                {
                    m = ((System.Collections.Generic.KeyValuePair <string, Data.Material>)selected).Value;
                }
            }
            catch
            {
                m = null;
            }
#if TRACE_EVENTS
            log.Debug($"Calculator.Material: SelectMaterial(material: {(m != null)})");
#endif
            if (m == null)
            {
                return;
            }

            // Set Use.
            if (m.UseCuttingSpeed)
            {
                // Set Vc.
                material.VcEnabled = true;
                material.Vc.SetValue(DoubleST.Scan(m.CuttingSpeed, 1.0, "mm/s"));
            }
            else
            {
                // Set n.
                material.NEnabled = true;
                material.n.SetValue(DoubleST.Scan(m.SpindleSpeed, 1.0, "rpm"));
            }

            // set fz.
            material.fz.SetValue(DoubleST.Scan(m.FeedPerTooth, 1.0, "mm/tooth"));
        }
        /// <summary>
        /// New tool selected from the list.
        /// </summary>
        /// <param name="selected">Selected tool</param>
        public void SelectTool(object selected)
        {
#if TRACE_EVENTS
            log.Debug($"Calculator.Material: SelectTool(bit: {(selected as Bit)})");
#endif

            var b = (selected as Bit);
            if (b == null)
            {
                return;
            }

            // set h?
            tool.D.SetValue(new DoubleST(1.0, "[mm]"));

            // set D.
            var Ds = b.Parameter.ContainsKey("Diameter") ? b.Parameter["Diameter"] : null;
            tool.D.SetValue(DoubleST.Scan(Ds, 1.0, "mm"));

            // set Z.
            var Zs = b.Parameter.ContainsKey("Flutes") ? b.Parameter["Flutes"] : null;
            tool.Z.SetValue(LongST.Scan(Zs, 1L, "tooth"));
        }
        /// <summary>
        /// Calculator: Do the maths for CNC Feeds and Speeds.
        /// </summary>
        public Calculator()
        {
            InitialiseSettings();
            InitialseToolsList();
            InitialseMaterialsList();

            tool     = new Tool();
            material = new Material(tool);

            Vc = new DoubleST(1.0, "[mm/s]");
            n  = new DoubleST(1.0, "[rpm]");
            Vf = new DoubleST(1.0, "[mm/s]");

            tool.D.OnChanged += tool_D_OnChanged;
            tool.Z.OnChanged += tool_Z_OnChanged;

            material.OnVcEnabledChanged += material_Vc_OnChanged;
            material.OnNEnabledChanged  += material_n_OnChanged;

            material.Vc.OnChanged += material_Vc_OnChanged;
            material.n.OnChanged  += material_n_OnChanged;
            material.fz.OnChanged += material_Fz_OnChanged;
        }
 /// <summary>
 /// InitialiseScale: Initialise application details.
 /// </summary>
 void InitialiseApplication()
 {
     InitialiseScale();
     ScaledValue = new DoubleST();
 }
 /// <summary>
 /// Tool: information about the tool
 /// </summary>
 public Tool()
 {
     h = new DoubleST(1.0, "[mm]");
     D = new DoubleST(1.0, "[mm]");
     Z = new LongST(1, "[tooth]");
 }