// This function easily wins when run under a profiler - gprof puts it
        // at around 17%. Almost all of this is this function - not any
        // (profiled) function it calls.
        public void get_lift_and_drag(FlightModel flightModel,
                                        Vec3 wind_rel_in, // in
                                        out Vec3 linear_lift, // lift force
                                        out Vec3 linear_drag, // drag force
                                        out Vec3 linear_position, // loc of force  
                                        out Vec3 pitch_force,
                                        out Vec3 pitch_position,
                                        float density,
                                        int num,
                                        float aileron, float elevator, float rudder)
        {
            float CL, CD, lift_force, drag_force;

            SwitchVec(ref wind_rel_in);

            debugWind = wind_rel_in;

            if (Utils.LogOn)
            {
                int abc = 123;
                abc++;
            }

            Quat Qalpha_beta = Mat3.FromRotateByZ(MathFunctions.DegToRad(rotation)).ToQuat() *
                               Mat3.FromRotateByX(MathFunctions.DegToRad(-inc)).ToQuat();
            Mat3 alpha_beta = Qalpha_beta.ToMat3();
            Mat3 alpha_beta_inv;
            Quat temp = Qalpha_beta;
            temp.Inverse();
            temp.ToMat3(out alpha_beta_inv);

            Vec3 wind_rel = alpha_beta * wind_rel_in;

            float alph = MathFunctions.RadToDeg((float)Math.Atan2(wind_rel.Y, -wind_rel.Z)); // angle of inclination
            float speed2 = wind_rel.Y * wind_rel.Y + wind_rel.Z * wind_rel.Z;
            float speed = MathFunctions.Sqrt(speed2);

            if (alph > 180)
                alph -= 360;
            else if (alph < -180)
                alph += 360;

            FlyingMode flying;
            float flying_float;
            // calculate and store the control input (might be used in the
            // display)
            float control_input =
                control_per_chan_1 * aileron +
                control_per_chan_2 * elevator +
                control_per_chan_3 * rudder;
            debugControl = control_input;

            CL = get_CL(alph, control_input, out flying, out flying_float);
            CD = get_CD(alph, control_input, flying, CL);

            float force_scale = get_area * 0.5f * speed2;
            lift_force = force_scale * CL; // main variation in density is air/water
            drag_force = density * force_scale * CD;

            float flying_offset;
            if (flying_float > 0)
            {
                flying_offset = x_offset[(int)FlyingMode.STALLED] +
                                     flying_float * (x_offset[(int)FlyingMode.FORWARD] -
                                     x_offset[(int)FlyingMode.STALLED]);
            }
            else
            {
                flying_offset = x_offset[(int)FlyingMode.STALLED] +
                                     -flying_float * (x_offset[(int)FlyingMode.REVERSE] -
                                     x_offset[(int)FlyingMode.STALLED]);
            }

            // we need cos(alph) etc. Rather than using trig, we can calculate the
            // value directly...
            //  const float cos_deg_alph = cos_deg(alph);
            //  const float sin_deg_alph = sin_deg(alph);
            bool doit = (Math.Abs(speed) > 0.01);
            float cos_deg_alph = doit ? -wind_rel.Z / speed : 0.0f;
            float sin_deg_alph = doit ? wind_rel.Y / speed : 0.0f; ;

            float force_up = lift_force * cos_deg_alph + drag_force * sin_deg_alph;
            float force_forward = lift_force * sin_deg_alph - drag_force * cos_deg_alph;

            linear_lift = new Vec3(0, lift_force, 0);
            linear_drag = new Vec3(0, 0, -drag_force);

            linear_position = position + new Vec3(0, flying_offset, 0);
            debugLinearPosition = flying_offset;

            // calculate the pitching moment - represented by a single
            // force at the trailing edge
            float pitching_force = get_area * 0.5f * wind_rel.Z * Math.Abs(wind_rel.Z) *
                                          (CM_0 + CM_per_deg * control_input);
            pitch_force = new Vec3(0.0f, pitching_force, 0.0f);
            pitch_position = position;
            pitch_position.Y -= 0.5f * chord;
            debugPitchPosition = pitch_position.Y;

            // need to rotate the force back...
            linear_lift = alpha_beta_inv * linear_lift;
            linear_drag = alpha_beta_inv * linear_drag;
            pitch_force = alpha_beta_inv * pitch_force;

            linear_lift /= 500;
            linear_drag /= 500;
            pitch_force /= 500;
            linear_position /= 4;
            pitch_position /= 4;

            linear_lift *= flightModel.param.Mult_Lift;
            linear_drag *= flightModel.param.Mult_Drag;

            SwitchVec(ref linear_lift);
            SwitchVec(ref linear_drag);
            SwitchVec(ref pitch_force);

            debugLift = linear_lift;
            debugDrag = linear_drag;
            debugPitchForce = pitch_force;
        }
        public void CreateGeometry(MapObject parent, FlightModel flightModel)
        {
            MapObjectAttachedMesh obj = new MapObjectAttachedMesh();
            obj.MeshName = "Models\\DefaultBox\\DefaultBox.mesh";
            float mScale = .2f;
            obj.ScaleOffset = new Vec3(span * mScale, chord * mScale, .1f * mScale) * flightModel.scale;

            obj.RotationOffset =
                Mat3.FromRotateByY(MathFunctions.DegToRad(-rotation)).ToQuat() *
                Mat3.FromRotateByX(MathFunctions.DegToRad(+inc)).ToQuat();
            obj.PositionOffset = (position + Vec3.YAxis * flightModel.param.geometry_offset_for_wheels) * flightModel.scale;

            parent.Attach(obj);
        }