public void TestFuselageForceDirections()
        {
            SingleMainRotorHelicopter model = (SingleMainRotorHelicopter) new SingleMainRotorHelicopter().LoadDefault();

            model.MainRotor.useDynamicInflow = false;
            model.TailRotor.useDynamicInflow = false;
            model.AbsoluteVelocity           = Vector <double> .Build.DenseOfArray(new double[] { 0, 0, 0 });

            model.AngularVelocity = Vector <double> .Build.Zero3();

            model.TrimInit();
            model.Trim();

            // In a hover, the fuselage should mainly contribute with a down-force (due to main rotor downwash)
            Console.WriteLine("Fuselage hover F " + model.Fuselage.ForceContribution.ToStr() + " M " + model.Fuselage.TorqueContribution.ToStr());
            Assert.IsTrue(model.Fuselage.ForceContribution.z() > 100);
            Assert.IsTrue(Math.Abs(model.Fuselage.ForceContribution.z()) / model.Fuselage.ForceContribution.Norm(2) > 0.9);

            // In forward flight, the fuselage should mainly contribute with drag
            model.AbsoluteVelocity = Vector <double> .Build.DenseOfArray(new double[] { 30, 0, 0 });

            model.Update(0.1);
            Console.WriteLine("Fuselage forward F " + model.Fuselage.ForceContribution.ToStr() + " M " + model.Fuselage.TorqueContribution.ToStr());
            Assert.IsTrue(model.Fuselage.ForceContribution.x() < -100);
            Assert.IsTrue(Math.Abs(model.Fuselage.ForceContribution.x()) / model.Fuselage.ForceContribution.Norm(2) > 0.9);
        }
        public void TestStabilizersForceDirections()
        {
            SingleMainRotorHelicopter model = (SingleMainRotorHelicopter) new SingleMainRotorHelicopter().LoadDefault();

            model.MainRotor.useDynamicInflow = false;
            model.TailRotor.useDynamicInflow = false;
            // Trim going downward and right
            model.AbsoluteVelocity = Vector <double> .Build.DenseOfArray(new double[] { 0, 5, 5 });

            model.AngularVelocity = Vector <double> .Build.Zero3();

            model.TrimInit();
            model.Trim();
            Console.WriteLine("H/S F " + model.HorizontalStabilizer.ForceContribution.ToStr() + " M " + model.HorizontalStabilizer.TorqueContribution.ToStr());
            Console.WriteLine("V/S F " + model.VerticalStabilizer.ForceContribution.ToStr() + " M " + model.VerticalStabilizer.TorqueContribution.ToStr());

            // Horizontal stabilizer should give nose-down pitching moment
            Assert.IsTrue(model.HorizontalStabilizer.TorqueContribution.y() < -100);
            // Vertical stabilizer should give nose-right yaw moment
            Assert.IsTrue(model.VerticalStabilizer.TorqueContribution.z() > 100);

            // Nose-right angular velocity should give nose-left yaw moment
            model.AbsoluteVelocity = Vector <double> .Build.Zero3();

            model.AngularVelocity = Vector <double> .Build.DenseOfArray(new double[] { 0, 0, 5 });

            model.Update(0.1);
            Console.WriteLine("A/V nose right V/S F " + model.VerticalStabilizer.ForceContribution.ToStr() + " M " + model.VerticalStabilizer.TorqueContribution.ToStr());
            Assert.IsTrue(model.VerticalStabilizer.TorqueContribution.z() < -100);

            // Nose-down angular velocity should give nose-up pitching moment
            model.AbsoluteVelocity = Vector <double> .Build.Zero3();

            model.AngularVelocity = Vector <double> .Build.DenseOfArray(new double[] { 0, -5, 0 });

            model.Update(0.1);
            Console.WriteLine("A/V nose down H/S F " + model.HorizontalStabilizer.ForceContribution.ToStr() + " M " + model.HorizontalStabilizer.TorqueContribution.ToStr());
            Assert.IsTrue(model.HorizontalStabilizer.TorqueContribution.y() > 100);
        }