/*
 *  Copyright (c) 1994, Riley Rainey,  riley@netcon.com
 *
 *  Permission to use, copy, modify and distribute (without charge) this
 *  software, documentation, images, etc. is granted, provided that this 
 *  comment and the author's name is retained.
 *
 *  This software is provided by the author as is, and without any expressed
 *  or implied warranties, including, but not limited to, the implied
 *  warranties of merchantability and fitness for a particular purpose.  In no
 *  event shall the author be liable for any direct, indirect, incidental, or
 *  consequential damages arising in any way out of the use of this software.
 */

#include "gedit.h"
#include "cell.h"
#include <math.h>
#include <stdio.h>
#include <Vlib.h>

struct balance_data {
	double	weight;	/* weight for this test */
	VPoint	rm;	/* rest main gear location (input) */
	VPoint	rn;	/* rest nose gear location (input) */
	double	cm, cn;	/* rest compression values of each strut */
	double	Gm, Gn; /* strut + tire lengths */
	double	Km, Kn;	/* string constants (output) */
	double  Gpz;	/* the old "grounding point" Z value */
	double	theta;
	};

void
balance (s)
struct balance_data *s;
{

	double	theta, cosTheta, sinTheta;
	double	Fmz;

/*
 *  Determine the rest pitch angle of the aircraft body
 */

	theta = - atan2 (s->rn.z - s->rm.z, s->rn.x - s->rm.x);
	cosTheta = cos(theta);
	sinTheta = sin(theta);
	s->theta = theta;

/*
 *  Determine correct rm/rn values
 */
	s->rn.z = s->rn.z - s->Gn - s->cn;
	s->rm.z = s->rm.z - s->Gm - s->cm;

/*
 *  Determine spring constants
 */

	Fmz = (s->weight * cosTheta * s->rn.x) / (s->rm.x - s->rn.x);

	s->Km = - Fmz * s->cm;
	s->Kn = (- Fmz - s->weight * cosTheta) * - s->cn;

/*
 *  Determine the initial grounding point
 */

	s->Gpz = s->rm.x * sinTheta + (s->rm.z + s->Gm + s->cm) * cosTheta;

}


extern Widget CreatePanelDialog ();
extern void SetCellValueDouble(), SetCellValueString();
extern double GetCellValueDouble();

enum {
	InfoName,
	InfoEmptyWeight,
	InfoIxx,
	InfoIyy,
	InfoIzz,
	InfoWingSpan,
	InfoWingArea,
	InfoWingChord,

	GearGm,
	GearcmMax,
	GearDm,
	GearKm,
	GearGn,
	GearcnMax,
	GearDn,
	GearKn,

	DerivClda,
	DerivCldr,
	DerivClp,
	DerivCmq,
	DerivCnr,
	DerivCmAlpha,
	DerivCmFactor,

	PowerplantFuel,
	PowerplantThrust,
	PowerplantABThrust,
	PowerplantLag,
	PowerplantSpFuelConsump,
	PowerplantSpABFuelConsump
	};

struct cell info_dialog_items[] = {
	{ InfoName,	"Aircraft Name",
	  "Unknown", 10, NULL, NULL
	},
	{ InfoEmptyWeight,	"Empty Weight [lbs]",
	  "10000", 10, NULL, NULL
	},
	{ InfoIxx,	"Ixx [slug*ft^2]",
	  "5000", 10, NULL, NULL
	},
	{ InfoIyy,	"Iyy [slug*ft^2]",
	  "50000", 10, NULL, NULL
	},
	{ InfoIzz,	"Izz [slug*ft^2]",
	  "50000", 10, NULL, NULL
	},
	{ InfoWingSpan,	"WingSpan [ft]",
	  "50000", 10, NULL, NULL
	},
	{ InfoWingArea,	"Wing Area [ft]",
	  "50000", 10, NULL, NULL
	},
	{ InfoWingChord, "Wing Chord [ft]",
	  "50000", 10, NULL, NULL
	},
	{ -1, NULL, NULL, 0, NULL, NULL }
	};

struct cell gear_dialog_items[] = {
	{
	  GearGm,	"Main Gear Assembly Length (Gm) [ft]",
	  "2.0", 10, NULL, NULL
	},
	{
	  GearcmMax,	"Main Gear Max Extension (cmMax) [ft]",
	  "1.0", 10, NULL, NULL
	},
	{
	  GearDm,	"Main Gear Damping Factor (Dm) [lb/ft/sec]",
	  "2.0", 10, NULL, NULL
	},
	{
	  GearKm, "Main Gear Spring Factor (Km) [*]",
	  "0.0", 10, NULL, NULL
	},
	{
	  GearGn, "Nose Gear Assembly Length (Gn) [ft]",
	  "2.0", 10, NULL, NULL
	},
	{
	  GearcnMax, "Nose Gear Max Extension (cnMax) [ft]",
	  "1.0", 10, NULL, NULL
	},
	{
	  GearDn, "Nose Gear Damping Factor (Dn) [lb/ft/sec]",
	  "2.0", 10, NULL, NULL
	},
	{
	  GearKn, "Nose Gear Spring Factor (Kn) [*]",
	  "0.0", 10, NULL, NULL
	},
	{ -1, NULL, NULL, 0, NULL, NULL }
};
	
struct cell deriv_dialog_items[] = {
	{
	  DerivClda,	"Roll moment from aileron offset",
	  "0.03", 10, NULL, NULL
	},
	{
	  DerivCldr,	"Roll moment from rudder offset",
	  "0.003", 10, NULL, NULL
	},
	{
	  DerivClp,	"Roll damping",
	  "-0.3", 10, NULL, NULL
	},
	{
	  DerivCmq,	"Pitch damping",
	  "-8.0", 10, NULL, NULL
	},
	{
	  DerivCnr,	"Yaw damping",
	  "-2.0", 10, NULL, NULL
	},
	{
	  DerivCmAlpha,	"Pitch due to angle of attack",
	  "-0.3", 10, NULL, NULL
	},
	{
	  DerivClda,	"Pitch due to angle of attack [stalled]",
	  "-0.2", 10, NULL, NULL
	},
	{ -1, NULL, NULL, 0, NULL, NULL }
	};

struct cell pwr_dialog_items[] = {
	{
	  PowerplantFuel,	"Internal Fuel Capacity [lbs]",
	  "1000", 10, NULL, NULL
	},
	{
	  PowerplantThrust,	"Military Thrust [lbs]",
	  "10000", 10, NULL, NULL
	},
	{
	  PowerplantABThrust,	"Afterburner Thrust [lbs]",
	  "10000", 10, NULL, NULL
	},
	{
	  PowerplantLag,	"Engine response lag [negative value]",
	  "-3.0", 10, NULL, NULL
	},
	{
	  PowerplantSpFuelConsump,
	  "Specific fuel consumption, afterburner off [lb fuel/lb T * hr]",
	  "0.7", 10, NULL, NULL
	},
	{
	  PowerplantSpABFuelConsump,
	  "Specific fuel consumption, afterburner on [lb fuel/lb T * hr]",
	  "2.50", 10, NULL, NULL
	},
	{ -1, NULL, NULL, 0, NULL, NULL }
	};

Widget
CreateInfoDialog(parent)
Widget parent;
{
	return CreatePanelDialog("info_dialog", parent, info_dialog_items,
		XtNumber(info_dialog_items), MENU_INFO_CALCULATE,
		MENU_INFO_CANCEL);
}

Widget
CreateGearDialog(parent)
Widget parent;
{
	return CreatePanelDialog("gear_dialog", parent, gear_dialog_items,
		XtNumber(gear_dialog_items), MENU_GEAR_CALCULATE,
		MENU_GEAR_CANCEL);
}

Widget
CreateDerivDialog(parent)
Widget parent;
{
	return CreatePanelDialog("stability_dialog", parent, deriv_dialog_items,
		XtNumber(deriv_dialog_items), MENU_DERIV_CALCULATE,
		MENU_DERIV_CANCEL);
}

Widget
CreatePowerplantDialog(parent)
Widget parent;
{
	return CreatePanelDialog("powerplant_dialog", parent, pwr_dialog_items,
		XtNumber(pwr_dialog_items), MENU_PWR_CALCULATE,
		MENU_PWR_CANCEL);
}

void
InitializeDialogs(c)
craftType *c;
{
	SetCellValueString (info_dialog_items, InfoName, craft_name);
	SetCellValueDouble (info_dialog_items, InfoEmptyWeight,
		c->emptyWeight);
	SetCellValueDouble (info_dialog_items, InfoIxx, c->I.m[0][0]);
	SetCellValueDouble (info_dialog_items, InfoIyy, c->I.m[1][1]);
	SetCellValueDouble (info_dialog_items, InfoIzz, c->I.m[2][2]);
	SetCellValueDouble (info_dialog_items, InfoWingSpan, c->wings * 2.0);
	SetCellValueDouble (info_dialog_items, InfoWingArea, c->wingS);
	SetCellValueDouble (info_dialog_items, InfoWingChord, c->c);

	SetCellValueDouble (gear_dialog_items, GearGm, c->Gm);
	SetCellValueDouble (gear_dialog_items, GearcmMax, c->cmMax);
	SetCellValueDouble (gear_dialog_items, GearDm, c->Dm);
	SetCellValueDouble (gear_dialog_items, GearKm, c->Km);
	SetCellValueDouble (gear_dialog_items, GearGn, c->Gn);
	SetCellValueDouble (gear_dialog_items, GearcnMax, c->cnMax);
	SetCellValueDouble (gear_dialog_items, GearDn, c->Dn);
	SetCellValueDouble (gear_dialog_items, GearKn, c->Kn);

	SetCellValueDouble (pwr_dialog_items, PowerplantFuel,
		c->maxFuel);
	SetCellValueDouble (pwr_dialog_items, PowerplantThrust,
		c->maxThrust);
	SetCellValueDouble (pwr_dialog_items, PowerplantABThrust,
		c->maxABThrust);
	SetCellValueDouble (pwr_dialog_items, PowerplantLag,
		c->engineLag);
	SetCellValueDouble (pwr_dialog_items, PowerplantSpFuelConsump,
		c->spFuelConsump);
	SetCellValueDouble (pwr_dialog_items, PowerplantSpABFuelConsump,
		c->spABFuelConsump);
}

void
GetCraftInfo(c)
craftType *c;
{
	GetCellValueString (info_dialog_items, InfoName, craft_name);
	GetCellValueDouble (info_dialog_items, InfoEmptyWeight,
		&c->emptyWeight);
	GetCellValueDouble (info_dialog_items, InfoIxx, &c->I.m[0][0]);
	GetCellValueDouble (info_dialog_items, InfoIyy, &c->I.m[1][1]);
	GetCellValueDouble (info_dialog_items, InfoIzz, &c->I.m[2][2]);
	GetCellValueDouble (info_dialog_items, InfoWingSpan, &c->wings);
	c->wings /= 2.0;
	GetCellValueDouble (info_dialog_items, InfoWingArea, &c->wingS);
	GetCellValueDouble (info_dialog_items, InfoWingChord, &c->c);

	GetCellValueDouble (gear_dialog_items, GearGm, &c->Gm);
	GetCellValueDouble (gear_dialog_items, GearcmMax, &c->cmMax);
	GetCellValueDouble (gear_dialog_items, GearDm, &c->Dm);
	GetCellValueDouble (gear_dialog_items, GearKm, &c->Km);
	GetCellValueDouble (gear_dialog_items, GearGn, &c->Gn);
	GetCellValueDouble (gear_dialog_items, GearcnMax, &c->cnMax);
	GetCellValueDouble (gear_dialog_items, GearDn, &c->Dn);
	GetCellValueDouble (gear_dialog_items, GearKn, &c->Kn);

	GetCellValueDouble (pwr_dialog_items, PowerplantFuel,
		&c->maxFuel);
	GetCellValueDouble (pwr_dialog_items, PowerplantThrust,
		&c->maxThrust);
	GetCellValueDouble (pwr_dialog_items, PowerplantABThrust,
		&c->maxABThrust);
	GetCellValueDouble (pwr_dialog_items, PowerplantLag,
		&c->engineLag);
	GetCellValueDouble (pwr_dialog_items, PowerplantSpFuelConsump,
		&c->spFuelConsump);
	GetCellValueDouble (pwr_dialog_items, PowerplantSpABFuelConsump,
		&c->spABFuelConsump);
	
	c->viewPoint = 	marker_list[MARKER_HEAD].location.point;

}

void
GearCalculate(c)
craftType *c;
{
	struct balance_data b;
			
	b.weight = c->emptyWeight + c->maxFuel;
	b.rm = marker_list[MARKER_MAIN_GEAR].location.point;
	b.rn = marker_list[MARKER_NOSE_GEAR].location.point;
	b.cm = GetCellValueDouble (gear_dialog_items, GearcmMax, &c->cmMax);
	b.cm *= 0.6;
	b.cn = GetCellValueDouble (gear_dialog_items, GearcnMax, &c->cnMax);
	b.cn *= 0.6;
	b.Gm = GetCellValueDouble (gear_dialog_items, GearGm, &c->Gm);
	b.Gn = GetCellValueDouble (gear_dialog_items, GearGn, &c->Gn);

#ifdef notdef
	printf ("Input:\n");
	printf ("nose   contact = %lf  %lf  %lf\n", b.rn.x, b.rn.y, b.rn.z);
	printf ("main's contact = %lf  %lf  %lf\n", b.rm.x, b.rm.y, b.rm.z);
	printf ("Weight = %lf\n", b.weight);
#endif	

	balance (&b);

#ifdef notdef
	printf ("\nOutput:\n");
	printf ("rm = %lf,  %lf,  %lf\n", b.rm.x, b.rm.y, b.rm.z);
	printf ("rn = %lf,  %lf,  %lf\n", b.rn.x, b.rn.y, b.rn.z);
	printf ("Km = %lf\n", b.Km);
	printf ("Kn = %lf\n", b.Kn);
	printf ("Grounding point (z) = %lf\n", b.Gpz);
	printf ("\n\"inventory\" form:\n\n");
	printf ("\tRm\t\t{%lg,  %lg,  %lg}\n", b.rm.x, b.rm.y, b.rm.z);
	printf ("\tRn\t\t{%lg,  %lg,  %lg}\n", b.rn.x, b.rn.y, b.rn.z);
	printf ("\tKm\t\t%lg\n", b.Km);
	printf ("\tKn\t\t%lg\n", b.Kn);
	printf ("\tGm\t\t%lg\n", b.Gm);
	printf ("\tGn\t\t%lg\n", b.Gn);
	printf ("\tCmMax\t\t%lg\n", c->cmMax);
	printf ("\tCnMax\t\t%lg\n", c->cnMax);
	printf ("\tGroundingPoint\t{0.0, 0.0, %lg}\n", b.Gpz);
#endif

	c->rm = b.rm;
	c->rn = b.rn;
	c->Km = b.Km;	
	c->Kn = b.Kn;
	c->groundingPoint.x = c->groundingPoint.y = 0.0;
	c->groundingPoint.z = b.Gpz;
	SetCellValueDouble (gear_dialog_items, GearKm, c->Km);
	SetCellValueDouble (gear_dialog_items, GearKn, c->Kn);
}
	
	
